@@ -21,48 +21,67 @@ public override void Initialize(AnalysisContext context)
2121 private static void AnalyzeSyntax ( SyntaxNodeAnalysisContext context )
2222 {
2323 var invocationExpressionSyntax = ( InvocationExpressionSyntax ) context . Node ;
24-
2524 var expression = invocationExpressionSyntax . Expression ;
2625
27- if ( expression == null )
28- return ;
29-
26+
3027 if ( expression . IsKind ( SyntaxKind . SimpleMemberAccessExpression ) == false && expression . IsKind ( SyntaxKind . IdentifierName ) == false )
3128 return ;
3229
33- var methodSymbol = context . SemanticModel . GetSymbolInfo ( expression ) . Symbol as IMethodSymbol ;
34-
35- if ( methodSymbol == null )
30+ if ( TryGetSymbolOrCandidate ( context , expression , out IMethodSymbol methodSymbol ) == false )
3631 return ;
3732
38- if ( methodSymbol . ReceiverType . Name . Equals ( "RavenConfiguration" , StringComparison . Ordinal ) == false || methodSymbol . Name . Equals ( "GetKey" , StringComparison . Ordinal ) == false )
33+ // Using ToDisplayString() is more robust as it includes the full namespace
34+ if ( methodSymbol . ContainingType . ToDisplayString ( ) . Equals ( "Raven.Database.Config.RavenConfiguration" , StringComparison . Ordinal ) == false ||
35+ methodSymbol . Name . Equals ( "GetKey" , StringComparison . Ordinal ) == false )
3936 return ;
4037
4138 var argumentList = invocationExpressionSyntax . ArgumentList ;
4239
4340 if ( argumentList == null || argumentList . Arguments . Count != 1 )
4441 return ;
4542
46- var simpleLambda = argumentList . Arguments [ 0 ] . Expression as SimpleLambdaExpressionSyntax ;
43+ if ( ! ( argumentList . Arguments [ 0 ] . Expression is SimpleLambdaExpressionSyntax simpleLambda ) )
44+ return ;
4745
48- var syntaxToken = simpleLambda ? . Body as MemberAccessExpressionSyntax ;
46+ if ( ! ( simpleLambda . Body is MemberAccessExpressionSyntax propertyAccessExpression ) )
47+ return ;
4948
50- var propertyIdentifier = syntaxToken ? . ChildNodes ( ) . OfType < IdentifierNameSyntax > ( ) . LastOrDefault ( ) ;
49+ var configurationType = methodSymbol . ContainingType ;
50+
51+ var propertyIdentifier = propertyAccessExpression . Name ;
52+ var propertyName = propertyIdentifier . Identifier . ValueText ;
5153
52- if ( propertyIdentifier == null )
53- return ;
54+ var propertySymbol = configurationType . GetMembers ( propertyName ) . OfType < IPropertySymbol > ( ) . FirstOrDefault ( ) ;
5455
55- var propertySymbol = context . SemanticModel . GetSymbolInfo ( propertyIdentifier ) ;
56- if ( propertySymbol . Symbol == null )
56+ // Get the symbol from the entire member access expression (e.g., "x.OrdinaryProperty")
57+ // This is the key change
58+ if ( propertySymbol == null )
5759 return ;
5860
59- var attributes = propertySymbol . Symbol . GetAttributes ( ) ;
60- if ( attributes . Any ( x => x . AttributeClass . ToString ( ) . Contains ( "ConfigurationEntryAttribute" ) ) )
61+ var attributes = propertySymbol . GetAttributes ( ) ;
62+ // A more robust check for the attribute by its name
63+ if ( attributes . Any ( attr => attr . AttributeClass . Name . Equals ( "ConfigurationEntryAttribute" , StringComparison . Ordinal ) ) )
6164 return ;
6265
66+ // The diagnostic should be reported on the name of the property
6367 ReportDiagnostic ( context , propertyIdentifier , propertyIdentifier . Identifier . ValueText ) ;
6468 }
6569
70+ private static bool TryGetSymbolOrCandidate < TSymbol > ( SyntaxNodeAnalysisContext context , ExpressionSyntax expression , out TSymbol result )
71+ where TSymbol : class , ISymbol
72+ {
73+ var info = context . SemanticModel . GetSymbolInfo ( expression ) ;
74+
75+ var symbol = info . Symbol as TSymbol ;
76+ if ( symbol == null && info . CandidateSymbols . Length == 1 )
77+ {
78+ symbol = info . CandidateSymbols [ 0 ] as TSymbol ;
79+ }
80+
81+ result = symbol ;
82+ return symbol != null ;
83+ }
84+
6685 private static void ReportDiagnostic (
6786 SyntaxNodeAnalysisContext context ,
6887 CSharpSyntaxNode syntaxNode ,
0 commit comments