-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Move diagnostic generation from LibraryImportGenerator to LibraryImportDiagnosticsAnalyzer #123780
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
5ab07b3
87827dd
4e3556e
b0d4d92
deaee03
f8ec08c
6232571
7a1d4df
831d431
f33ac74
9f85c66
eb6466c
cd49aed
ebe5dc3
6fbe38b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,300 @@ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Licensed to the .NET Foundation under one or more agreements. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // The .NET Foundation licenses this file to you under the MIT license. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using System; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Collections.Immutable; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using System.Threading; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.CodeAnalysis; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.CodeAnalysis.CSharp; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.CodeAnalysis.CSharp.Syntax; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.CodeAnalysis.Diagnostics; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.CodeAnalysis.DotnetRuntime.Extensions; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| using Microsoft.Interop; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| namespace Microsoft.Interop.Analyzers | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// <summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// Analyzer that reports diagnostics for LibraryImport methods. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// This analyzer runs the same diagnostic logic as LibraryImportGenerator | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// but reports diagnostics separately from the source generator. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| /// </summary> | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| [DiagnosticAnalyzer(LanguageNames.CSharp)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public class LibraryImportDiagnosticsAnalyzer : DiagnosticAnalyzer | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ImmutableArray.Create( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.InvalidAttributedMethodSignature, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.InvalidStringMarshallingConfiguration, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ParameterTypeNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ReturnTypeNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ParameterTypeNotSupportedWithDetails, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ReturnTypeNotSupportedWithDetails, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ParameterConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ReturnConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.MarshalAsParameterConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.MarshalAsReturnConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.ConfigurationValueNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.MarshallingAttributeConfigurationNotSupported, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.CannotForwardToDllImport, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.RequiresAllowUnsafeBlocks, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.UnnecessaryParameterMarshallingInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.UnnecessaryReturnMarshallingInfo, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallOutParam, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.SizeOfInCollectionMustBeDefinedAtCallReturnValue, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| GeneratorDiagnostics.LibraryImportUsageDoesNotFollowBestPractices); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| public override void Initialize(AnalysisContext context) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.EnableConcurrentExecution(); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.RegisterCompilationStartAction(context => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Nothing to do if the LibraryImportAttribute is not in the compilation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| INamedTypeSymbol? libraryImportAttrType = context.Compilation.GetBestTypeByMetadataName(TypeNames.LibraryImportAttribute); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (libraryImportAttrType is null) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| StubEnvironment env = new StubEnvironment( | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.Compilation, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.Compilation.GetEnvironmentFlags()); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Get generator options once per compilation | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| LibraryImportGeneratorOptions options = new(context.Options.AnalyzerConfigOptionsProvider.GlobalOptions); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Track if we found any LibraryImport methods to report RequiresAllowUnsafeBlocks once | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool foundLibraryImportMethod = false; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool unsafeEnabled = context.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.RegisterSymbolAction(symbolContext => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (AnalyzeMethod(symbolContext, env, libraryImportAttrType, options)) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| foundLibraryImportMethod = true; | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| }, SymbolKind.Method); | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // Report RequiresAllowUnsafeBlocks once per compilation if there are LibraryImport methods and unsafe is not enabled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| context.RegisterCompilationEndAction(endContext => | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if (foundLibraryImportMethod && !unsafeEnabled) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+67
to
+81
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| bool foundLibraryImportMethod = false; | |
| bool unsafeEnabled = context.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; | |
| context.RegisterSymbolAction(symbolContext => | |
| { | |
| if (AnalyzeMethod(symbolContext, env, libraryImportAttrType, options)) | |
| { | |
| foundLibraryImportMethod = true; | |
| } | |
| }, SymbolKind.Method); | |
| // Report RequiresAllowUnsafeBlocks once per compilation if there are LibraryImport methods and unsafe is not enabled | |
| context.RegisterCompilationEndAction(endContext => | |
| { | |
| if (foundLibraryImportMethod && !unsafeEnabled) | |
| int foundLibraryImportMethod = 0; | |
| bool unsafeEnabled = context.Compilation.Options is CSharpCompilationOptions { AllowUnsafe: true }; | |
| context.RegisterSymbolAction(symbolContext => | |
| { | |
| if (AnalyzeMethod(symbolContext, env, libraryImportAttrType, options)) | |
| { | |
| Interlocked.CompareExchange(ref foundLibraryImportMethod, 1, 0); | |
| } | |
| }, SymbolKind.Method); | |
| // Report RequiresAllowUnsafeBlocks once per compilation if there are LibraryImport methods and unsafe is not enabled | |
| context.RegisterCompilationEndAction(endContext => | |
| { | |
| if (Interlocked.CompareExchange(ref foundLibraryImportMethod, 0, 0) == 1 && !unsafeEnabled) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure about how analyzers work in VS, is there any caching / incrementality that we might set this to true, then the LibraryImport is deleted, and we still report the message later?