diff --git a/docs/tools/illink/error-codes.md b/docs/tools/illink/error-codes.md index 4850f92152b..282ff575a94 100644 --- a/docs/tools/illink/error-codes.md +++ b/docs/tools/illink/error-codes.md @@ -1870,6 +1870,22 @@ void TestMethod() } ``` +#### `IL2122`: Type 'typeName' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified. + +- The type name string passed to a location with `DynamicallyAccessedMembers` requirements was not assembly-qualified, so the trimmer cannot guarantee that the type is preserved. Consider using an assembly-qualified name instead. + + ```C# + // warning IL2122: Type 'MyClass' is not assembly qualified. Type name strings used for dynamically accessing a type should be assembly qualified. + GetTypeWrapper("MyClass"); + + class MyClass { } + + // May be defined in another assembly, so at runtime Type.GetType will look in that assembly for "MyClass". + void GetTypeWrapper([DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicParameterlessConstructor)] string typeName) + { + var type = Type.GetType(typeName); + } + ``` ## Single-File Warning Codes diff --git a/eng/testing/tests.mobile.targets b/eng/testing/tests.mobile.targets index e87458abd06..b599da5d228 100644 --- a/eng/testing/tests.mobile.targets +++ b/eng/testing/tests.mobile.targets @@ -29,7 +29,7 @@ true true - $(NoWarn);IL2103;IL2105;IL2025;IL2111 + $(NoWarn);IL2103;IL2025;IL2111;IL2122 false diff --git a/eng/testing/tests.singlefile.targets b/eng/testing/tests.singlefile.targets index 9e6e4d0b358..f40703bac41 100644 --- a/eng/testing/tests.singlefile.targets +++ b/eng/testing/tests.singlefile.targets @@ -29,7 +29,7 @@ $(CoreCLRAotSdkDir) $(NetCoreAppCurrentTestHostSharedFrameworkPath) $(NetCoreAppCurrentTestHostSharedFrameworkPath) - $(NoWarn);IL1005;IL2105;IL3000;IL3001;IL3002;IL3003;IL3050;IL3051;IL3052;IL3053 + $(NoWarn);IL1005;IL2122;IL3000;IL3001;IL3002;IL3003;IL3050;IL3051;IL3052;IL3053 partial true false diff --git a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs index 7f19644ad10..83e74b02dd9 100644 --- a/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs +++ b/src/coreclr/tools/Common/TypeSystem/Common/Utilities/CustomAttributeTypeNameParser.cs @@ -36,13 +36,18 @@ namespace Internal.TypeSystem } public static TypeDesc GetTypeByCustomAttributeTypeNameForDataFlow(string name, ModuleDesc callingModule, - TypeSystemContext context, List referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary) + TypeSystemContext context, List referencedModules, bool needsAssemblyName, out bool failedBecauseNotFullyQualified) { - typeWasNotFoundInAssemblyNorBaseLibrary = false; - + failedBecauseNotFullyQualified = false; if (!TypeName.TryParse(name.AsSpan(), out TypeName parsed, s_typeNameParseOptions)) return null; + if (needsAssemblyName && !IsFullyQualified(parsed)) + { + failedBecauseNotFullyQualified = true; + return null; + } + TypeNameResolver resolver = new() { _context = context, @@ -52,8 +57,33 @@ namespace Internal.TypeSystem TypeDesc type = resolver.Resolve(parsed); - typeWasNotFoundInAssemblyNorBaseLibrary = resolver._typeWasNotFoundInAssemblyNorBaseLibrary; return type; + + static bool IsFullyQualified(TypeName typeName) + { + if (typeName.AssemblyName is null) + { + return false; + } + + if (typeName.IsArray || typeName.IsPointer || typeName.IsByRef) + { + return IsFullyQualified(typeName.GetElementType()); + } + + if (typeName.IsConstructedGenericType) + { + foreach (var typeArgument in typeName.GetGenericArguments()) + { + if (!IsFullyQualified(typeArgument)) + { + return false; + } + } + } + + return true; + } } private struct TypeNameResolver @@ -64,7 +94,6 @@ namespace Internal.TypeSystem internal Func _canonResolver; internal List _referencedModules; - internal bool _typeWasNotFoundInAssemblyNorBaseLibrary; internal TypeDesc Resolve(TypeName typeName) { @@ -136,8 +165,6 @@ namespace Internal.TypeSystem return type; } } - - _typeWasNotFoundInAssemblyNorBaseLibrary = true; } if (_throwIfNotFound) diff --git a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs index d4e81f23b0c..bf966393c0f 100644 --- a/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/ReflectionMarker.cs @@ -89,12 +89,13 @@ namespace ILCompiler.Dataflow List referencedModules = new(); TypeDesc foundType = CustomAttributeTypeNameParser.GetTypeByCustomAttributeTypeNameForDataFlow(typeName, callingModule, diagnosticContext.Origin.MemberDefinition!.Context, - referencedModules, out bool typeWasNotFoundInAssemblyNorBaseLibrary); + referencedModules, needsAssemblyName, out bool failedBecauseNotFullyQualified); if (foundType == null) { - if (needsAssemblyName && typeWasNotFoundInAssemblyNorBaseLibrary) - diagnosticContext.AddDiagnostic(DiagnosticId.TypeWasNotFoundInAssemblyNorBaseLibrary, typeName); - + if (failedBecauseNotFullyQualified) + { + diagnosticContext.AddDiagnostic(DiagnosticId.TypeNameIsNotAssemblyQualified, typeName); + } type = default; return false; } diff --git a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs index b2a6ea4cee9..bbe9184c4d7 100644 --- a/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs +++ b/src/coreclr/tools/aot/ILCompiler.Trimming.Tests/TestCasesRunner/AssemblyChecker.cs @@ -12,6 +12,7 @@ using Internal.TypeSystem.Ecma; using Mono.Cecil; using Mono.Cecil.Cil; using Mono.Linker.Tests.Cases.Expectations.Assertions; +using Mono.Linker.Tests.Cases.Expectations.Helpers; using Mono.Linker.Tests.Extensions; using Xunit; using MetadataType = Internal.TypeSystem.MetadataType; diff --git a/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeDescriptionProviderAttributeCtorTest.cs b/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeDescriptionProviderAttributeCtorTest.cs index cfdb6635875..1d46eb8e401 100644 --- a/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeDescriptionProviderAttributeCtorTest.cs +++ b/src/libraries/System.ObjectModel/tests/TrimmingTests/TypeDescriptionProviderAttributeCtorTest.cs @@ -14,7 +14,7 @@ class Program /// static int Main(string[] args) { - TypeDescriptionProviderAttribute attr = new TypeDescriptionProviderAttribute("Program+MyTypeDescriptionProvider"); + TypeDescriptionProviderAttribute attr = new TypeDescriptionProviderAttribute("Program+MyTypeDescriptionProvider, project"); if (!RunTest(attr)) { return -1; diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs index b80f4a1d61b..382d8edbfd8 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerTypeProxyAttributeTests.cs @@ -53,7 +53,7 @@ class Program } } - [DebuggerTypeProxy("Program+MyClassWithProxyStringProxy")] + [DebuggerTypeProxy("Program+MyClassWithProxyStringProxy, project")] public class MyClassWithProxyString { public string Name { get; set; } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerVisualizerAttributeTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerVisualizerAttributeTests.cs index dccaf03b4dd..51ace3fa295 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerVisualizerAttributeTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/TrimmingTests/DebuggerVisualizerAttributeTests.cs @@ -113,8 +113,8 @@ class Program } } - [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer")] - [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer2", "Program+MyClassWithVisualizerStringVisualizerObjectSource")] + [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer, project")] + [DebuggerVisualizer("Program+MyClassWithVisualizerStringVisualizer2, project", "Program+MyClassWithVisualizerStringVisualizerObjectSource, project")] public class MyClassWithVisualizerString { public string Name { get; set; } diff --git a/src/mono/msbuild/apple/build/AppleBuild.LocalBuild.targets b/src/mono/msbuild/apple/build/AppleBuild.LocalBuild.targets index a28bff240a6..14df939e12f 100644 --- a/src/mono/msbuild/apple/build/AppleBuild.LocalBuild.targets +++ b/src/mono/msbuild/apple/build/AppleBuild.LocalBuild.targets @@ -37,7 +37,7 @@ true - $(NoWarn);IL2103;IL2105;IL2025;IL2111 + $(NoWarn);IL2103;IL2025;IL2111;IL2122