@@ -14,6 +14,7 @@ internal class GetInterfaceAnalyzer : DiagnosticAnalyzer
1414 /// <inheritdoc/>
1515 public override ImmutableArray < DiagnosticDescriptor > SupportedDiagnostics { get ; } = ImmutableArray . Create (
1616 REFL020AmbiguousMatchInterface . Descriptor ,
17+ REFL022UseFullyQualifiedName . Descriptor ,
1718 REFL023TypeDoesNotImplementInterface . Descriptor ) ;
1819
1920 /// <inheritdoc/>
@@ -31,20 +32,71 @@ context.Node is InvocationExpressionSyntax invocation &&
3132 invocation . TryGetTarget ( KnownSymbol . Type . GetInterface , context . SemanticModel , context . CancellationToken , out var getInterface ) &&
3233 getInterface . TryFindParameter ( KnownSymbol . String , out var nameParameter ) &&
3334 invocation . TryFindArgument ( nameParameter , out var nameArg ) &&
34- TryGetName ( nameArg , context , out var name ) &&
35+ TryGetName ( nameArg , context , out var maybeNameSyntax , out var name ) &&
3536 GetX . TryGetType ( invocation , context , out var type , out _ ) )
3637 {
37- var count = type . AllInterfaces . Count ( x => IsMatch ( x ) ) ;
38+ var count = CountInterfaces ( type , name , out var match ) ;
39+
3840 if ( count > 1 )
3941 {
4042 context . ReportDiagnostic ( Diagnostic . Create ( REFL020AmbiguousMatchInterface . Descriptor , nameArg . GetLocation ( ) ) ) ;
4143 }
4244
45+ if ( count == 1 && match . MetadataName == name )
46+ {
47+ switch ( nameArg . Expression )
48+ {
49+ case LiteralExpressionSyntax literal when literal . IsKind ( SyntaxKind . StringLiteralExpression ) :
50+ context . ReportDiagnostic (
51+ Diagnostic . Create (
52+ REFL022UseFullyQualifiedName . Descriptor ,
53+ literal . GetLocation ( ) ,
54+ ImmutableDictionary < string , string > . Empty . Add (
55+ nameof ( SyntaxKind . StringLiteralExpression ) ,
56+ $ "{ match . ContainingNamespace } .{ match . MetadataName } ") ) ) ;
57+ break ;
58+ default :
59+ if ( maybeNameSyntax . HasValue &&
60+ maybeNameSyntax . Value . Identifier . ValueText == "Name" )
61+ {
62+ context . ReportDiagnostic (
63+ Diagnostic . Create (
64+ REFL022UseFullyQualifiedName . Descriptor ,
65+ maybeNameSyntax . Value . Identifier . GetLocation ( ) ,
66+ ImmutableDictionary < string , string > . Empty . Add (
67+ nameof ( SimpleNameSyntax ) ,
68+ "FullName" ) ) ) ;
69+ }
70+ else
71+ {
72+ context . ReportDiagnostic ( Diagnostic . Create ( REFL022UseFullyQualifiedName . Descriptor , nameArg . GetLocation ( ) ) ) ;
73+ }
74+
75+ break ;
76+ }
77+ }
78+
4379 if ( count == 0 )
4480 {
4581 context . ReportDiagnostic ( Diagnostic . Create ( REFL023TypeDoesNotImplementInterface . Descriptor , nameArg . GetLocation ( ) ) ) ;
4682 }
4783 }
84+ }
85+
86+ private static int CountInterfaces ( ITypeSymbol type , string name , out ITypeSymbol match )
87+ {
88+ var count = 0 ;
89+ match = null ;
90+ foreach ( var candidate in type . AllInterfaces )
91+ {
92+ if ( IsMatch ( candidate ) )
93+ {
94+ count ++ ;
95+ match = candidate ;
96+ }
97+ }
98+
99+ return count ;
48100
49101 bool IsMatch ( ITypeSymbol candidate )
50102 {
@@ -57,8 +109,9 @@ bool IsMatch(ITypeSymbol candidate)
57109 }
58110 }
59111
60- private static bool TryGetName ( ArgumentSyntax nameArg , SyntaxNodeAnalysisContext context , out string name )
112+ private static bool TryGetName ( ArgumentSyntax nameArg , SyntaxNodeAnalysisContext context , out Optional < SimpleNameSyntax > nameSyntax , out string name )
61113 {
114+ nameSyntax = default ( Optional < SimpleNameSyntax > ) ;
62115 switch ( nameArg . Expression )
63116 {
64117 case MemberAccessExpressionSyntax memberAccess :
@@ -67,12 +120,14 @@ private static bool TryGetName(ArgumentSyntax nameArg, SyntaxNodeAnalysisContext
67120 {
68121 if ( memberAccess . Name . Identifier . ValueText == "Name" )
69122 {
123+ nameSyntax = memberAccess . Name ;
70124 name = type . MetadataName ;
71125 return true ;
72126 }
73127
74128 if ( memberAccess . Name . Identifier . ValueText == "FullName" )
75129 {
130+ nameSyntax = memberAccess . Name ;
76131 name = $ "{ type . ContainingNamespace } .{ type . MetadataName } ";
77132 return true ;
78133 }
0 commit comments