Add unsafe modifier migration code fixer#131002
Draft
EgorBo wants to merge 13 commits into
Draft
Conversation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c3ccf7c6-8a32-4c31-9e31-12f0f1d2a026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c3ccf7c6-8a32-4c31-9e31-12f0f1d2a026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c3ccf7c6-8a32-4c31-9e31-12f0f1d2a026
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c3ccf7c6-8a32-4c31-9e31-12f0f1d2a026
- Parse unsafe(...) with explicit preview + updated-memory-safety-rules options - Use SyntaxFactory elastic newline trivia instead of hardcoded CRLF literals - Remove redundant single-arm switch Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 826b613c-e6ee-4cc6-a6a7-b06038520aad
The IL5006 document fixer could emit code that fails to compile:
- unsafe(...) expressions at statement/void/assignment-target positions (only valid as a value sub-expression) now fall back to unsafe { } blocks
- out-var/pattern-var declarations (Foo(out int y);) are forward-declared before the unsafe block so they stay in scope
- out-vars in a local declaration initializer (int x = Foo(out int y);) fall back to the unsafe(...) expression form, keeping the variable in scope
- only interior (not leading/trailing) directives block wrapping a statement
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 826b613c-e6ee-4cc6-a6a7-b06038520aad
- Split multi-variable event field declarations with mixed safe/unsafe contracts so 'unsafe' is applied only to the variables that require it (avoids CS9365 where a safe interface event would be made illegally unsafe)
- Drop the statement-wrap branch that ignored requiresExpression, so using/await/directive statements that need an unsafe(...) expression fall back to whole-body wrapping instead of an unsafe { } block that would change scope
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 826b613c-e6ee-4cc6-a6a7-b06038520aad
When splitting a multi-variable event field, keep each variable node's trivia (e.g. inline comments like 'event Action E1 /* keep */, E2;') instead of stripping it; only the outer declaration trivia is normalized. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 826b613c-e6ee-4cc6-a6a7-b06038520aad
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: ee40608f-4e94-47e1-8763-843d916bab40
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c4ec9d91-2b56-40d3-b938-b386154f464c
|
Azure Pipelines: Successfully started running 3 pipeline(s). 12 pipeline(s) were filtered out due to trigger conditions. There may be pipelines that require an authorized user to comment /azp run to run. |
EgorBo
had a problem deploying
to
copilot-pat-pool
July 17, 2026 22:01 — with
GitHub Actions
Failure
Contributor
|
Tagging subscribers to this area: @agocke, @dotnet/illink |
Contributor
There was a problem hiding this comment.
Pull request overview
Adds initial “unsafe modifier migration” support to the ILLink analyzer/codefix tooling (DEBUG-only), wiring a new IL5005-style diagnostic and a code fix that normalizes unsafe modifiers based on signature/docs, plus build plumbing to enable the feature via EnableUnsafeMigration.
Changes:
- Introduces
UnsafeMigrationAnalyzer(IL5005) andUnsafeModifierMigrationCodeFixProviderto report/fix unsafe modifier normalization whenEnableUnsafeMigrationis enabled. - Adds supporting shared diagnostic IDs/categories/strings and exposes
EnableUnsafeMigrationas a compiler-visible MSBuild property. - Extends the existing analyzer/codefix test suite with targeted tests for the new diagnostic and fixer.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs | Adds verifier helpers and new tests for the unsafe modifier migration diagnostic and code fix. |
| src/tools/illink/src/ILLink.Shared/SharedStrings.resx | Adds title/message resources for the new unsafe migration diagnostic. |
| src/tools/illink/src/ILLink.Shared/DiagnosticId.cs | Adds UnsafeModifierMigration (DEBUG-only) and maps it to a new diagnostic category. |
| src/tools/illink/src/ILLink.Shared/DiagnosticCategory.cs | Adds Unsafe diagnostic category (DEBUG-only). |
| src/tools/illink/src/ILLink.RoslynAnalyzer/UnsafeMigrationAnalyzer.cs | New analyzer that reports a single “file needs unsafe modifier migration” diagnostic when updates are detected. |
| src/tools/illink/src/ILLink.RoslynAnalyzer/UnsafeMigrationAnalysis.cs | New semantic analysis that computes which declarations should/shouldn’t have unsafe based on rules (docs/pointers/interop). |
| src/tools/illink/src/ILLink.RoslynAnalyzer/MSBuildPropertyOptionNames.cs | Adds EnableUnsafeMigration MSBuild property name (DEBUG-only constant). |
| src/tools/illink/src/ILLink.RoslynAnalyzer/build/Microsoft.NET.ILLink.Analyzers.props | Exposes EnableUnsafeMigration as a compiler-visible property. |
| src/tools/illink/src/ILLink.CodeFix/UnsafeModifierMigrationCodeFixProvider.cs | New code fix provider to apply modifier normalization across a document when enabled. |
| src/tools/illink/src/ILLink.CodeFix/Resources.resx | Adds the code fix title resource string. |
| eng/liveILLink.targets | Wires EnableUnsafeMigration into LiveILLink, enabling unsafe analyzer and setting the updated-memory-safety-rules feature flag. |
EgorBo
marked this pull request as draft
July 17, 2026 22:06
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: c4ec9d91-2b56-40d3-b938-b386154f464c
EgorBo
had a problem deploying
to
copilot-pat-pool
July 17, 2026 23:43 — with
GitHub Actions
Failure
Contributor
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 16 out of 16 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/tools/illink/test/ILLink.RoslynAnalyzer.Tests/RequiresUnsafeCodeFixTests.cs:130
DiagnosticDescriptor.HelpLinkUriis a nullable string andDiagnosticDescriptors.GetDiagnosticDescriptor(...)passeshelpLinkUrithrough directly. For these new diagnosticsDiagnosticIdExtensions.GetHelpUrireturnsnull, sodescriptor.HelpLinkUriwill benullandAssert.Empty(descriptor.HelpLinkUri)will fail. Use a null check (orstring.IsNullOrEmpty) instead ofAssert.Empty.
DiagnosticDescriptor descriptor = DiagnosticDescriptors.GetDiagnosticDescriptor(diagnosticId);
Assert.Equal("Unsafe", descriptor.Category);
Assert.Empty(descriptor.HelpLinkUri);
}
Comment on lines
+1272
to
+1280
| <data name="UnsafeMemberMissingSafetyDocumentationTitle" xml:space="preserve"> | ||
| <value>Unsafe member is missing safety documentation</value> | ||
| </data> | ||
| <data name="UnsafeMemberMissingSafetyDocumentationMessage" xml:space="preserve"> | ||
| <value>Remove the 'unsafe' modifier or document the caller's safety requirements with a <safety> XML comment.</value> | ||
| </data> | ||
| <data name="PointerSignatureRequiresUnsafeTitle" xml:space="preserve"> | ||
| <value>Pointer signature requires an unsafe modifier</value> | ||
| </data> |
This was referenced Jul 18, 2026
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This PR adds new analyzers and codefixer (not yet shipping) that assists in migrating to the new unsafe-v2 rules ("unsafe evolution") and are supposed to be idempotent. This PR doesn't add a code-fixer that introduces new
unsafescopes/or unsafe-expressions as that ons is quite complex and will be added separately. So I tried to just rely on Roslyn's existing diagnostics and only introducedIL5005andIL5006(see below).New analyzers/code-fixers
AddUnsafeToExternCodeFixProviderfixesCS9389by marking anexternmemberunsafeby default. Developers can replace it withsafeafter auditing the interop boundary.RemoveInvalidUnsafeCodeFixProviderfixesCS9377and unsafe-specificCS0106diagnostics by removing the compiler-reported meaningless or invalidunsafemodifier. (e.g. from class level)UnsafeMemberMissingSafetyDocumentationAnalyzer(IL5005) reports unsafe members without a<safety>XML comment. Members with pointer or function-pointer signatures are excluded because they were already effectively caller-unsafe under the legacy rules.unsafe void Foo()is coming from legacy rules where it used that unsafe to open a global unsafe scope if there is no<safety>comment.RemoveUndocumentedUnsafeCodeFixProvidera companion code-fixer forIL5005defined above ^ by removing the undocumentedunsafemodifier (we assume it's the unsafe-v1's global unsafe scopeunsafeand not caller-unsafe).PointerSignatureRequiresUnsafeAnalyzer(IL5006) reports members with pointer or function-pointer signatures that are missingunsafe. A<safety>XML comment suppresses the diagnostic when the signature is intentionally safe, e.g. an API that never dereferences the pointer -ArgumentNullException.ThrowIfNull(void*).AddUnsafeToPointerSignatureCodeFixProviderfixesIL5006^ by adding the missingunsafemodifier.UnsafeMemberAnalysisandUnsafeModifierCodeFixHelperscontain the shared declaration, pointer-signature, documentation, and modifier-editing logic used by the focused components above.Codes
CS9389[Roslyn] - An extern member must be explicitly markedunsafeorsafe.CS9377[Roslyn] - Theunsafemodifier has no effect at this location under the updated memory safety rules.CS0106[Roslyn] - Theunsafemodifier is not valid for this item. This PR's fixer only activates whenunsafeis the invalid modifier.IL5005[This PR] - An unsafe member has no<safety>XML documentation. Pointer and function-pointer signatures are excluded for legacy compatibility.IL5006[This PR] - A member with a pointer or function-pointer signature is missingunsafe, unless a<safety>comment documents why it is safe. (e.g. when in unsafe-v1 such methods relied onunsafeon the class level).For follow ups
Implement a code fixer for unsafe-context diagnostics
CS9360,CS9361,CS9362,CS9363, andCS9376. It should introduceunsafe { /* SAFETY: Audit */ }blocks orunsafe(/* SAFETY: Audit */ ...)expressionsSynchronize intentional caller-unsafe contracts across overrides, interface implementations, and partial declarations. This includes Roslyn's unsafe-to-safe mismatch diagnostics
CS9364,CS9365, andCS9366, partial modifier mismatchesCS0764andCS9390, and the opposite migration case where an unsafe interface/base contract should be propagated to an implementation that is currently unannotated.Handle explicit/extended-layout fields and compiler-generated backing fields.
CS9392requires an explicitunsafeorsafemarker, whileCS9388reports invalidsafeusage. Migration should default tounsafeunless the developer has explicitly audited the field assafe.Figure out what to do with
LibraryImport. Roslyn currently does not treat it asextern,safecannot be applied to it, and its generated implementation is not compiled under the updated memory-safety rules. See safe keyword on LibraryImport roslyn#84555