Skip to content

Commit d9eafd0

Browse files
authored
Move diagnostics for invalid GeneratedDllImportAttribute usage to generator instead of analyzer (dotnet#65915)
1 parent b4c746b commit d9eafd0

File tree

9 files changed

+245
-433
lines changed

9 files changed

+245
-433
lines changed

docs/design/libraries/DllImportGenerator/Diagnostics.md

Lines changed: 0 additions & 47 deletions
This file was deleted.

src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/Analyzers/GeneratedDllImportAnalyzer.cs

Lines changed: 0 additions & 104 deletions
This file was deleted.

src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/DllImportGenerator.cs

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,31 @@ public void Initialize(IncrementalGeneratorInitializationContext context)
7575
.CreateSyntaxProvider(
7676
static (node, ct) => ShouldVisitNode(node),
7777
static (context, ct) =>
78-
new
78+
{
79+
MethodDeclarationSyntax syntax = (MethodDeclarationSyntax)context.Node;
80+
if (context.SemanticModel.GetDeclaredSymbol(syntax, ct) is IMethodSymbol methodSymbol
81+
&& methodSymbol.GetAttributes().Any(static attribute => attribute.AttributeClass?.ToDisplayString() == TypeNames.GeneratedDllImportAttribute))
7982
{
80-
Syntax = (MethodDeclarationSyntax)context.Node,
81-
Symbol = (IMethodSymbol)context.SemanticModel.GetDeclaredSymbol(context.Node, ct)!
82-
})
83+
return new { Syntax = syntax, Symbol = methodSymbol };
84+
}
85+
86+
return null;
87+
})
8388
.Where(
84-
static modelData => modelData.Symbol.IsStatic && modelData.Symbol.GetAttributes().Any(
85-
static attribute => attribute.AttributeClass?.ToDisplayString() == TypeNames.GeneratedDllImportAttribute)
86-
);
89+
static modelData => modelData is not null);
8790

88-
var methodsToGenerate = attributedMethods.Where(static data => !data.Symbol.ReturnsByRef && !data.Symbol.ReturnsByRefReadonly);
91+
var methodsWithDiagnostics = attributedMethods.Select(static (data, ct) =>
92+
{
93+
Diagnostic? diagnostic = GetDiagnosticIfInvalidMethodForGeneration(data.Syntax, data.Symbol);
94+
return new { Syntax = data.Syntax, Symbol = data.Symbol, Diagnostic = diagnostic };
95+
});
8996

90-
var refReturnMethods = attributedMethods.Where(static data => data.Symbol.ReturnsByRef || data.Symbol.ReturnsByRefReadonly);
97+
var methodsToGenerate = methodsWithDiagnostics.Where(static data => data.Diagnostic is null);
98+
var invalidMethodDiagnostics = methodsWithDiagnostics.Where(static data => data.Diagnostic is not null);
9199

92-
context.RegisterSourceOutput(refReturnMethods, static (context, refReturnMethod) =>
100+
context.RegisterSourceOutput(invalidMethodDiagnostics, static (context, invalidMethod) =>
93101
{
94-
context.ReportDiagnostic(Diagnostic.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, refReturnMethod.Syntax.GetLocation(), "ref return", refReturnMethod.Symbol.ToDisplayString()));
102+
context.ReportDiagnostic(invalidMethod.Diagnostic);
95103
});
96104

97105
IncrementalValueProvider<(Compilation compilation, TargetFramework targetFramework, Version targetFrameworkVersion)> compilationAndTargetFramework = context.CompilationProvider
@@ -739,34 +747,38 @@ private static bool ShouldVisitNode(SyntaxNode syntaxNode)
739747
return false;
740748
}
741749

742-
var methodSyntax = (MethodDeclarationSyntax)syntaxNode;
750+
// Filter out methods with no attributes early.
751+
return ((MethodDeclarationSyntax)syntaxNode).AttributeLists.Count > 0;
752+
}
743753

754+
private static Diagnostic? GetDiagnosticIfInvalidMethodForGeneration(MethodDeclarationSyntax methodSyntax, IMethodSymbol method)
755+
{
744756
// Verify the method has no generic types or defined implementation
745757
// and is marked static and partial.
746758
if (methodSyntax.TypeParameterList is not null
747759
|| methodSyntax.Body is not null
748760
|| !methodSyntax.Modifiers.Any(SyntaxKind.StaticKeyword)
749761
|| !methodSyntax.Modifiers.Any(SyntaxKind.PartialKeyword))
750762
{
751-
return false;
763+
return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodSignature, methodSyntax.Identifier.GetLocation(), method.Name);
752764
}
753765

754766
// Verify that the types the method is declared in are marked partial.
755767
for (SyntaxNode? parentNode = methodSyntax.Parent; parentNode is TypeDeclarationSyntax typeDecl; parentNode = parentNode.Parent)
756768
{
757769
if (!typeDecl.Modifiers.Any(SyntaxKind.PartialKeyword))
758770
{
759-
return false;
771+
return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingModifiers, methodSyntax.Identifier.GetLocation(), method.Name, typeDecl.Identifier);
760772
}
761773
}
762774

763-
// Filter out methods with no attributes early.
764-
if (methodSyntax.AttributeLists.Count == 0)
775+
// Verify the method does not have a ref return
776+
if (method.ReturnsByRef || method.ReturnsByRefReadonly)
765777
{
766-
return false;
778+
return Diagnostic.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, methodSyntax.Identifier.GetLocation(), "ref return", method.ToDisplayString());
767779
}
768780

769-
return true;
781+
return null;
770782
}
771783
}
772784
}

src/libraries/System.Runtime.InteropServices/gen/DllImportGenerator/GeneratorDiagnostics.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,26 @@ public class Ids
2828

2929
private const string Category = "SourceGeneration";
3030

31+
public static readonly DiagnosticDescriptor InvalidAttributedMethodSignature =
32+
new DiagnosticDescriptor(
33+
Ids.InvalidGeneratedDllImportAttributeUsage,
34+
GetResourceString(nameof(Resources.InvalidLibraryImportAttributeUsageTitle)),
35+
GetResourceString(nameof(Resources.InvalidAttributedMethodSignatureMessage)),
36+
Category,
37+
DiagnosticSeverity.Error,
38+
isEnabledByDefault: true,
39+
description: GetResourceString(nameof(Resources.InvalidAttributedMethodDescription)));
40+
41+
public static readonly DiagnosticDescriptor InvalidAttributedMethodContainingTypeMissingModifiers =
42+
new DiagnosticDescriptor(
43+
Ids.InvalidGeneratedDllImportAttributeUsage,
44+
GetResourceString(nameof(Resources.InvalidLibraryImportAttributeUsageTitle)),
45+
GetResourceString(nameof(Resources.InvalidAttributedMethodContainingTypeMissingModifiersMessage)),
46+
Category,
47+
DiagnosticSeverity.Error,
48+
isEnabledByDefault: true,
49+
description: GetResourceString(nameof(Resources.InvalidAttributedMethodDescription)));
50+
3151
public static readonly DiagnosticDescriptor InvalidStringMarshallingConfiguration =
3252
new DiagnosticDescriptor(
3353
Ids.InvalidGeneratedDllImportAttributeUsage,

0 commit comments

Comments
 (0)