Skip to content

Commit 0a331c1

Browse files
committed
Defer UnsupportedCSharpLanguageVersionAnalyzer symbol action registration
1 parent 57055d7 commit 0a331c1

File tree

1 file changed

+31
-26
lines changed

1 file changed

+31
-26
lines changed

CommunityToolkit.Mvvm.SourceGenerators/Diagnostics/Analyzers/UnsupportedCSharpLanguageVersionAnalyzer.cs

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -44,42 +44,47 @@ public override void Initialize(AnalysisContext context)
4444
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
4545
context.EnableConcurrentExecution();
4646

47-
context.RegisterSymbolAction(static context =>
47+
// Defer the callback registration to when the compilation starts, so we can execute more
48+
// preliminary checks and skip registering any kind of symbol analysis at all if not needed.
49+
context.RegisterCompilationStartAction(static context =>
4850
{
49-
// The possible attribute targets are only fields, classes and methods
50-
if (context.Symbol is not (IFieldSymbol or INamedTypeSymbol { TypeKind: TypeKind.Class, IsImplicitlyDeclared: false } or IMethodSymbol))
51+
// Check that the language version is not high enough, otherwise no diagnostic should ever be produced
52+
if (context.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8))
5153
{
5254
return;
5355
}
5456

55-
// Check that the language version is not high enough, otherwise no diagnostic should be produced
56-
if (context.Compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp8))
57+
context.RegisterSymbolAction(static context =>
5758
{
58-
return;
59-
}
59+
// The possible attribute targets are only fields, classes and methods
60+
if (context.Symbol is not (IFieldSymbol or INamedTypeSymbol { TypeKind: TypeKind.Class, IsImplicitlyDeclared: false } or IMethodSymbol))
61+
{
62+
return;
63+
}
6064

61-
ImmutableArray<AttributeData> attributes = context.Symbol.GetAttributes();
65+
ImmutableArray<AttributeData> attributes = context.Symbol.GetAttributes();
6266

63-
// If the symbol has no attributes, there's nothing left to do
64-
if (attributes.IsEmpty)
65-
{
66-
return;
67-
}
67+
// If the symbol has no attributes, there's nothing left to do
68+
if (attributes.IsEmpty)
69+
{
70+
return;
71+
}
6872

69-
foreach (AttributeData attribute in attributes)
70-
{
71-
// Go over each attribute on the target symbol, and check if the attribute type name is a candidate.
72-
// If it is, double check by actually resolving the symbol from the compilation and comparing against it.
73-
// This minimizes the calls to CompilationGetTypeByMetadataName(string) to only cases where it's almost
74-
// guaranteed we'll actually get a match. If we do have one, then we can emit the diagnostic for the symbol.
75-
if (attribute.AttributeClass is { Name: string attributeName } attributeClass &&
76-
GeneratorAttributeNamesToFullyQualifiedNamesMap.TryGetValue(attributeName, out string? fullyQualifiedAttributeName) &&
77-
context.Compilation.GetTypeByMetadataName(fullyQualifiedAttributeName) is INamedTypeSymbol attributeSymbol &&
78-
SymbolEqualityComparer.Default.Equals(attributeClass, attributeSymbol))
73+
foreach (AttributeData attribute in attributes)
7974
{
80-
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.Locations.FirstOrDefault()));
75+
// Go over each attribute on the target symbol, and check if the attribute type name is a candidate.
76+
// If it is, double check by actually resolving the symbol from the compilation and comparing against it.
77+
// This minimizes the calls to CompilationGetTypeByMetadataName(string) to only cases where it's almost
78+
// guaranteed we'll actually get a match. If we do have one, then we can emit the diagnostic for the symbol.
79+
if (attribute.AttributeClass is { Name: string attributeName } attributeClass &&
80+
GeneratorAttributeNamesToFullyQualifiedNamesMap.TryGetValue(attributeName, out string? fullyQualifiedAttributeName) &&
81+
context.Compilation.GetTypeByMetadataName(fullyQualifiedAttributeName) is INamedTypeSymbol attributeSymbol &&
82+
SymbolEqualityComparer.Default.Equals(attributeClass, attributeSymbol))
83+
{
84+
context.ReportDiagnostic(Diagnostic.Create(UnsupportedCSharpLanguageVersionError, context.Symbol.Locations.FirstOrDefault()));
85+
}
8186
}
82-
}
83-
}, SymbolKind.Field, SymbolKind.NamedType, SymbolKind.Method);
87+
}, SymbolKind.Field, SymbolKind.NamedType, SymbolKind.Method);
88+
});
8489
}
8590
}

0 commit comments

Comments
 (0)