Skip to content

ILLink AOT analyzer: recognize statically-known Enum.GetValues(Type) as intrinsically handled#127258

Open
Copilot wants to merge 4 commits intomainfrom
copilot/add-aot-safe-enum-getvalues
Open

ILLink AOT analyzer: recognize statically-known Enum.GetValues(Type) as intrinsically handled#127258
Copilot wants to merge 4 commits intomainfrom
copilot/add-aot-safe-enum-getvalues

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented Apr 22, 2026

RequiresDynamicCodeAnalyzer currently warns on Enum.GetValues(Type) even when the enum type is statically known, while ILC already treats that shape as safe. This change aligns analyzer behavior with the existing ILC IntrinsicId.Enum_GetValues handling.

  • Analyzer intrinsic parity

    • Added IntrinsicId.Enum_GetValues handling in RequiresDynamicCodeAnalyzer.IsIntrinsicallyHandled.
    • Suppresses IL3050 only when arguments[0] contains exclusively SystemTypeValue; otherwise warning behavior is unchanged.
  • Roslyn analyzer coverage

    • Added EnumGetValuesWithKnownType (no IL3050): Enum.GetValues(typeof(MyEnum))
    • Added EnumGetValuesWithUnknownType (expects IL3050): Enum.GetValues(GetUnknownType())
  • Shared dataflow intrinsic coverage

    • Extended MakeGenericDataflowIntrinsics with EnumGetValues test cases:
      • known-type call path with no warning
      • unknown-type call path with expected IL3050
case IntrinsicId.Enum_GetValues:
{
    foreach (var value in arguments[0].AsEnumerable())
    {
        if (value is not SystemTypeValue)
            return false;
    }

    return true;
}
Original prompt

The AOT analysis Roslyn analyzer (RequiresDynamicCodeAnalyzer) currently doesn't understand that Enum.GetValues(System.Type) can be made AOT safe if the type is statically known at the callsite.

The ILC compiler already handles this in src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs (the IntrinsicId.Enum_GetValues case around line 252). When the argument is a SystemTypeValue that is not a generic definition and doesn't contain signature variables, ILC doesn't emit a RequiresDynamicCode warning. The analyzer should mirror this behavior.

What needs to change:

  1. src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs: In the IsIntrinsicallyHandled method, add a new case IntrinsicId.Enum_GetValues: block. The logic should be: if arguments[0] contains only SystemTypeValue values (i.e., the type is statically known), return true (suppress the warning). Otherwise return false (emit the warning). This mirrors how ILC checks: if the value is a SystemTypeValue and is not a generic definition and doesn't contain signature variables, the call is safe. In the analyzer, we can simplify this to: if every value in arguments[0] is a SystemTypeValue, the call is intrinsically handled.

  2. src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs: Add test cases similar to the existing MakeGenericType* tests:

    • EnumGetValuesWithKnownType: Enum.GetValues(typeof(MyEnum)) — no warning expected
    • EnumGetValuesWithUnknownType: Enum.GetValues(GetUnknownType()) — IL3050 warning expected
  3. src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs: Add test cases for Enum.GetValues in this shared test case file:

    • A method calling Enum.GetValues(typeof(SomeEnum)) with [ExpectedNoWarnings] behavior (no IL3050)
    • A method calling Enum.GetValues(unknownType) with [ExpectedWarning("IL3050", ...)]

This is the same pattern as PR #100858 did for MakeGenericType/MakeGenericMethod.

To run analyzer tests: ./build.sh libs.sfx+tools.illinktests -test

The following is the prior conversation context from the user's chat exploration (may be truncated):

User: the AOT analysis Roslyn analyzer currently doesn't understand that the Enum.GetValues(System.Type) API can be made AOT safe if the type is statically known at the callsite. we should mirror handling of IntrinsicId.Enum_GetValues in src/coreclr/tools/aot/ILCompiler.Compiler/Compiler/Dataflow/HandleCallAction.cs to RequiresDynamicCodeAnalyzer, similar to how @dotnet/runtime/pull/100858 did it for a different API. to run the analyzer tests you might need to execute ./build.sh libs.sfx+tools.illinktests -test

Assistant: Now let me look at how Enum_GetValues is handled in HandleCallAction.cs (lines 252-274) and check the current RequiresDynamicCodeAnalyzer.cs to see what needs to be added:

Assistant: Now I have a clear picture. The HandleCallAction.cs in ILC handles Enum_GetValues (lines 252-274) by checking if the type argument is a statically known SystemTypeValue — if so, it doesn't emit a RequiresDynamicCode warning. The RequiresDynamicCodeAnalyzer.cs already handles MakeGenericType and MakeGenericMethod via IsIntrinsicallyHandled, but does not handle Enum_GetValues. I need to add that case.

Assistant: I've started the coding agent to create a PR in dotnet/runtime. It will:

  1. Add IntrinsicId.Enum_GetValues handling to RequiresDynamicCodeAnalyzer.IsIntrinsicallyHandled — suppressing the IL3050 warning when the type argument is statically known (a SystemTypeValue), mirroring the ILC logic in HandleCallAction.cs.
  2. Add unit tests in RequiresDynamicCodeAnalyzerTests.cs for both the known-type (no warning) and unknown-type (warning) cases.
  3. Add shared test cases in MakeGenericDataflowIntrinsics.cs for Enum.GetValues.

You'll receive a pull request once the agent completes the work.

This pull request was created from Copilot chat.

…d tests

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/50b8fa00-f801-423f-8d88-ad7abceb0df6

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 22, 2026 02:34
@dotnet-policy-service dotnet-policy-service Bot added the linkable-framework Issues associated with delivering a linker friendly framework label Apr 22, 2026
Copilot AI changed the title [WIP] Add support for AOT safe Enum.GetValues in RequiresDynamicCodeAnalyzer ILLink AOT analyzer: recognize statically-known Enum.GetValues(Type) as intrinsically handled Apr 22, 2026
Copilot AI requested a review from MichalStrehovsky April 22, 2026 02:36
@MichalStrehovsky
Copy link
Copy Markdown
Member

@copilot the test is failing. next time do not abort running tests. it is expected to run for 40 minutes:

�[m�[37m      System.InvalidOperationException : Expected diagnostic to end at column "56" was actually at column "38"
�[m�[37m      
�[m�[37m      Expected diagnostic:
�[m�[37m          // ?(4,24,4,56): warning IL3050: Using member 'System.Enum.GetValues(System.Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload or the GetValuesAsUnderlyingType method instead.
�[m�[37m      VerifyCS.Diagnostic(DiagnosticId.RequiresDynamicCode).WithSpan(4, 24, 4, 56).WithArguments("System.Enum.GetValues(System.Type)", " It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload or the GetValuesAsUnderlyingType method instead.", ""),
�[m�[37m      
�[m�[37m      Actual diagnostic:
�[m�[37m          // (4,24): warning IL3050: Using member 'System.Enum.GetValues(Type)' which has 'RequiresDynamicCodeAttribute' can break functionality when AOT compiling. It might not be possible to create an array of the enum type at runtime. Use the GetValues<TEnum> overload or the GetValuesAsUnderlyingType method instead.
�[m�[37m      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<TEnum> overload or the GetValuesAsUnderlyingType method instead.", ""),
�[m�[37m      
�[m�[37m      
�[m�[30;1m      Stack Trace:
�[m�[37m        /_/src/Microsoft.CodeAnalysis.Testing/Microsoft.CodeAnalysis.Analyzer.Testing/DefaultVerifier.cs(79,0): at Microsoft.CodeAnalysis.Testing.DefaultVerifier.Equal[T](T expected, T actual, String message)
�[m�[37m        /__w/1/s/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs(207,0): at ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier`1.VerifyLinePosition(ImmutableArray`1 analyzers, Diagnostic diagnostic, DiagnosticResult expectedDiagnostic, LinePosition actualLinePosition, LinePosition expectedLinePosition, String positionText, IVerifier verifier)
�[m�[37m        /__w/1/s/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs(194,0): at ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier`1.VerifyDiagnosticLocation(ImmutableArray`1 analyzers, Diagnostic diagnostic, DiagnosticResult expectedDiagnostic, Location actual, DiagnosticLocation expected, IVerifier verifier)
�[m�[37m        /__w/1/s/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs(119,0): at ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier`1.VerifyDiagnosticResults(IEnumerable`1 actualResults, ImmutableArray`1 analyzers, DiagnosticResult[] expectedResults, IVerifier verifier)
�[m�[37m        /__w/1/s/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/Verifiers/CSharpAnalyzerVerifier`1.cs(61,0): at ILLink.RoslynAnalyzer.Tests.CSharpAnalyzerVerifier`1.VerifyAnalyzerAsync(String src, Boolean consoleApplication, ValueTuple`2[] analyzerOptions, IEnumerable`1 additionalReferences, Boolean allowUnsafe, DiagnosticResult[] expected)
�[m�[37m        /__w/1/s/src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs(44,0): at ILLink.RoslynAnalyzer.Tests.RequiresDynamicCodeAnalyzerTests.VerifyRequiresDynamicCodeAnalyzer(String source, DiagnosticResult[] expected)
�[m�[37m        --- End of stack trace from previous location ---

…cidental generated file

Agent-Logs-Url: https://github.com/dotnet/runtime/sessions/eb06220d-4ee6-40c5-8e2d-393941d2c4d5

Co-authored-by: MichalStrehovsky <13110571+MichalStrehovsky@users.noreply.github.com>
Copilot AI requested review from Copilot and removed request for Copilot April 22, 2026 03:47
Copy link
Copy Markdown
Contributor Author

Copilot AI commented Apr 22, 2026

@copilot the test is failing. next time do not abort running tests. it is expected to run for 40 minutes:

...

Fixed in 12710a0. The test expectation had incorrect span (4,24,4,56)(4,24,4,38) and method signature System.Enum.GetValues(System.Type)System.Enum.GetValues(Type) to match the actual diagnostic output. Also reverted the accidentally committed TypeForwardingTests.g.cs generated file.

Copilot AI review requested due to automatic review settings April 22, 2026 08:24
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Aligns the ILLink Roslyn AOT analyzer (RequiresDynamicCodeAnalyzer) with NativeAOT/ILC intrinsic handling so Enum.GetValues(Type) does not warn (IL3050) when the enum Type argument is statically known at the callsite.

Changes:

  • Added IntrinsicId.Enum_GetValues handling to RequiresDynamicCodeAnalyzer.IsIntrinsicallyHandled to suppress IL3050 when the argument value-set is exclusively SystemTypeValue.
  • Added Roslyn analyzer unit tests validating known-type (no warning) vs unknown-type (warning) behavior for Enum.GetValues(Type).
  • Added shared dataflow intrinsic test coverage in MakeGenericDataflowIntrinsics for known/unknown enum Type cases.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated no comments.

File Description
src/tools/illink/src/ILLink.RoslynAnalyzer/RequiresDynamicCodeAnalyzer.cs Adds intrinsic handling for Enum.GetValues(Type) when the type argument is statically known.
src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresDynamicCodeAnalyzerTests.cs Adds analyzer tests to ensure IL3050 is suppressed/emitted appropriately for Enum.GetValues.
src/tools/illink/test/Mono.Linker.Tests.Cases/DataFlow/MakeGenericDataflowIntrinsics.cs Extends shared dataflow intrinsic coverage with Enum.GetValues scenarios.
src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/generated/ILLink.RoslynAnalyzer.Tests.Generator/ILLink.RoslynAnalyzer.Tests.TestCaseGenerator/TypeForwardingTests.g.cs Updates generated test wrapper to include additional TypeForwarding test cases.

@MichalStrehovsky MichalStrehovsky marked this pull request as ready for review April 22, 2026 08:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area-NativeAOT-coreclr linkable-framework Issues associated with delivering a linker friendly framework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants