Remove names and decorations of imported symbols (#3081)

* Remove names and decorations of imported symbols

* Added test case
diff --git a/source/link/linker.cpp b/source/link/linker.cpp
index d99a1e8..14e61a8 100644
--- a/source/link/linker.cpp
+++ b/source/link/linker.cpp
@@ -137,8 +137,6 @@
 // TODO(pierremoreau): Linkage attributes applied by a group decoration are
 //                     currently not handled. (You could have a group being
 //                     applied to a single ID.)
-// TODO(pierremoreau): Run a pass for removing dead instructions, for example
-//                     OpName for prototypes of imported funcions.
 spv_result_t RemoveLinkageSpecificInstructions(
     const MessageConsumer& consumer, const LinkerOptions& options,
     const LinkageTable& linkings_to_do, DecorationManager* decoration_manager,
@@ -531,24 +529,6 @@
   // TODO(pierremoreau): Remove FuncParamAttr decorations of imported
   // functions' return type.
 
-  // Remove FuncParamAttr decorations of imported functions' parameters.
-  // From the SPIR-V specification, Sec. 2.13:
-  //   When resolving imported functions, the Function Control and all Function
-  //   Parameter Attributes are taken from the function definition, and not
-  //   from the function declaration.
-  for (const auto& linking_entry : linkings_to_do) {
-    for (const auto parameter_id :
-         linking_entry.imported_symbol.parameter_ids) {
-      decoration_manager->RemoveDecorationsFrom(
-          parameter_id, [](const Instruction& inst) {
-            return (inst.opcode() == SpvOpDecorate ||
-                    inst.opcode() == SpvOpMemberDecorate) &&
-                   inst.GetSingleWordInOperand(1u) ==
-                       SpvDecorationFuncParamAttr;
-          });
-    }
-  }
-
   // Remove prototypes of imported functions
   for (const auto& linking_entry : linkings_to_do) {
     for (auto func_iter = linked_context->module()->begin();
@@ -746,24 +726,34 @@
   opt::Pass::Status pass_res = manager.Run(&linked_context);
   if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
 
-  // Phase 7: Rematch import variables/functions to export variables/functions
-  for (const auto& linking_entry : linkings_to_do)
+  // Phase 7: Remove all names and decorations of import variables/functions
+  for (const auto& linking_entry : linkings_to_do) {
+    linked_context.KillNamesAndDecorates(linking_entry.imported_symbol.id);
+    for (const auto parameter_id :
+         linking_entry.imported_symbol.parameter_ids) {
+      linked_context.KillNamesAndDecorates(parameter_id);
+    }
+  }
+
+  // Phase 8: Rematch import variables/functions to export variables/functions
+  for (const auto& linking_entry : linkings_to_do) {
     linked_context.ReplaceAllUsesWith(linking_entry.imported_symbol.id,
                                       linking_entry.exported_symbol.id);
+  }
 
-  // Phase 8: Remove linkage specific instructions, such as import/export
+  // Phase 9: Remove linkage specific instructions, such as import/export
   // attributes, linkage capability, etc. if applicable
   res = RemoveLinkageSpecificInstructions(consumer, options, linkings_to_do,
                                           linked_context.get_decoration_mgr(),
                                           &linked_context);
   if (res != SPV_SUCCESS) return res;
 
-  // Phase 9: Compact the IDs used in the module
+  // Phase 10: Compact the IDs used in the module
   manager.AddPass<opt::CompactIdsPass>();
   pass_res = manager.Run(&linked_context);
   if (pass_res == opt::Pass::Status::Failure) return SPV_ERROR_INVALID_DATA;
 
-  // Phase 10: Output the module
+  // Phase 11: Output the module
   linked_context.module()->ToBinary(linked_binary, true);
 
   return SPV_SUCCESS;
diff --git a/test/link/matching_imports_to_exports_test.cpp b/test/link/matching_imports_to_exports_test.cpp
index 59e62d5..e76c69f 100644
--- a/test/link/matching_imports_to_exports_test.cpp
+++ b/test/link/matching_imports_to_exports_test.cpp
@@ -399,5 +399,78 @@
   EXPECT_EQ(expected_res, res_body);
 }
 
+TEST_F(MatchingImportsToExports, NamesAndDecorations) {
+  const std::string body1 = R"(
+OpCapability Kernel
+OpCapability Linkage
+OpName %1 "foo"
+OpName %3 "param"
+OpDecorate %1 LinkageAttributes "foo" Import
+OpDecorate %2 Restrict
+OpDecorate %4 NonWritable
+%2 = OpDecorationGroup
+OpGroupDecorate %2 %3 %4
+%5 = OpTypeVoid
+%6 = OpTypeInt 32 0
+%9 = OpTypePointer Function %6
+%7 = OpTypeFunction %5 %9
+%1 = OpFunction %5 None %7
+%3 = OpFunctionParameter %9
+OpFunctionEnd
+%8 = OpFunction %5 None %7
+%4 = OpFunctionParameter %9
+OpFunctionEnd
+)";
+  const std::string body2 = R"(
+OpCapability Kernel
+OpCapability Linkage
+OpName %1 "foo"
+OpName %2 "param"
+OpDecorate %1 LinkageAttributes "foo" Export
+OpDecorate %2 Restrict
+%3 = OpTypeVoid
+%4 = OpTypeInt 32 0
+%7 = OpTypePointer Function %4
+%5 = OpTypeFunction %3 %7
+%1 = OpFunction %3 None %5
+%2 = OpFunctionParameter %7
+%6 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+
+  spvtest::Binary linked_binary;
+  EXPECT_EQ(SPV_SUCCESS, AssembleAndLink({body1, body2}, &linked_binary))
+      << GetErrorMessage();
+
+  const std::string expected_res = R"(OpCapability Kernel
+OpName %1 "foo"
+OpName %2 "param"
+OpModuleProcessed "Linked by SPIR-V Tools Linker"
+OpDecorate %3 Restrict
+OpDecorate %4 NonWritable
+%3 = OpDecorationGroup
+OpGroupDecorate %3 %4
+OpDecorate %2 Restrict
+%5 = OpTypeVoid
+%6 = OpTypeInt 32 0
+%7 = OpTypePointer Function %6
+%8 = OpTypeFunction %5 %7
+%9 = OpFunction %5 None %8
+%4 = OpFunctionParameter %7
+OpFunctionEnd
+%1 = OpFunction %5 None %8
+%2 = OpFunctionParameter %7
+%10 = OpLabel
+OpReturn
+OpFunctionEnd
+)";
+  std::string res_body;
+  SetDisassembleOptions(SPV_BINARY_TO_TEXT_OPTION_NO_HEADER);
+  EXPECT_EQ(SPV_SUCCESS, Disassemble(linked_binary, &res_body))
+      << GetErrorMessage();
+  EXPECT_EQ(expected_res, res_body);
+}
+
 }  // namespace
 }  // namespace spvtools