diff --git a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs index a8b6714fb8a282..8de6f1327dfd3c 100644 --- a/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs +++ b/src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs @@ -98,6 +98,18 @@ internal override bool IsIntrinsicallyHandled(IMethodSymbol calledMethod, MultiV } return true; } + case IntrinsicId.Enum_GetValues: + { + foreach (var value in arguments[0].AsEnumerable()) + { + if (value is not SystemTypeValue) + { + return false; + } + } + + return true; + } } return false; diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs index 3c3287cabab981..5176759021de4e 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/DataFlowTests.cs @@ -252,7 +252,7 @@ public Task MakeGenericDataFlow() } [Fact] - public Task MakeGenericDataflowIntrinsics() + public Task RequiresDynamicCodeAnalyzerIntrinsics() { return RunTest(); } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs index ac3706f82e00ee..08bef6e2bfa53d 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs @@ -549,5 +549,37 @@ public void N() { } // (4,24): warning IL3050: Using member 'System.Reflection.MethodInfo.MakeGenericMethod(params Type[])' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. The native code for this instantiation might not be available at runtime. VerifyCS.Diagnostic(DiagnosticId.RequiresDynamicCode).WithSpan(4, 24, 4, 72).WithArguments("System.Reflection.MethodInfo.MakeGenericMethod(params Type[])", " The native code for this instantiation might not be available at runtime.", "")); } + + [Fact] + public Task EnumGetValuesWithKnownType() + { + const string src = $$""" + using System; + class C + { + public void M() => Enum.GetValues(typeof(MyEnum)); + } + enum MyEnum { One, Two } + """; + + return VerifyRequiresDynamicCodeAnalyzer(src); + } + + [Fact] + public Task EnumGetValuesWithUnknownType() + { + const string src = $$""" + using System; + class C + { + public void M() => Enum.GetValues(GetUnknownType()); + static Type GetUnknownType() => typeof(MyEnum); + } + enum MyEnum { One, Two } + """; + + return VerifyRequiresDynamicCodeAnalyzer(src, + VerifyCS.Diagnostic(DiagnosticId.RequiresDynamicCode).WithSpan(4, 24, 4, 38).WithArguments("System.Enum.GetValues(Type)", " It might not be possible to create an array of the enum type at runtime. Use the GetValues overload or the GetValuesAsUnderlyingType method instead.", "")); + } } } diff --git a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TypeForwardingTests.g.cs b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TypeForwardingTests.g.cs index fe1f556a88fcb3..2bba796cf1ad31 100644 --- a/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TypeForwardingTests.g.cs +++ b/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TypeForwardingTests.g.cs @@ -63,6 +63,12 @@ public Task NestedTypeForwarder() return RunTest(allowMissingWarnings: true); } + [Fact] + public Task RootedForwarderWithExportedTypesIsHandled() + { + return RunTest(allowMissingWarnings: true); + } + [Fact] public Task SecurityAttributeScope() { @@ -207,6 +213,12 @@ public Task UsedForwarderIsRemovedWhenLink() return RunTest(allowMissingWarnings: true); } + [Fact] + public Task UsedForwarderIsRemovedWhenReferencedByRootedAssembly() + { + return RunTest(allowMissingWarnings: true); + } + [Fact] public Task UsedForwarderWithAssemblyCopy() { diff --git a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RequiresDynamicCodeAnalyzerIntrinsics.cs similarity index 85% rename from src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs rename to src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RequiresDynamicCodeAnalyzerIntrinsics.cs index c92bfe65f59eea..6aa6cec041e87d 100644 --- a/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs +++ b/src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/RequiresDynamicCodeAnalyzerIntrinsics.cs @@ -7,12 +7,13 @@ namespace Mono.Linker.Tests.Cases.DataFlow { [SkipKeptItemsValidation] [ExpectedNoWarnings] - class MakeGenericDataflowIntrinsics + class RequiresDynamicCodeAnalyzerIntrinsics { public static void Main() { MakeGenericType.Test(); MakeGenericMethod.Test(); + EnumGetValues.Test(); } class MakeGenericType @@ -88,5 +89,28 @@ public static void Test() [ExpectedWarning("IL3050", nameof(MethodInfo.MakeGenericMethod), Tool.Analyzer | Tool.NativeAot, "NativeAOT-specific warning")] public static void TestUnknownArgument() => typeof(MakeGenericMethod).GetMethod(nameof(Gen)).MakeGenericMethod(GrabUnknownType()); } + + class EnumGetValues + { + enum SomeEnum + { + A, + B + } + + static Type GrabUnknownType() => null; + + public static void Test() + { + TestKnownType(); + TestUnknownType(); + } + + [ExpectedNoWarnings] + public static void TestKnownType() => Enum.GetValues(typeof(SomeEnum)); + + [ExpectedWarning("IL3050", nameof(Enum.GetValues), Tool.Analyzer | Tool.NativeAot, "NativeAOT-specific warning")] + public static void TestUnknownType() => Enum.GetValues(GrabUnknownType()); + } } }