1- using System . Linq ;
1+ using System ;
2+ using System . Linq ;
23using Microsoft . CodeAnalysis ;
4+ using Microsoft . CodeAnalysis . CSharp . Syntax ;
5+ using Microsoft . CodeAnalysis . Operations ;
36
47namespace Pandatech . Analyzers . Async ;
58
@@ -25,18 +28,160 @@ internal static bool IsContractImplementation(this IMethodSymbol method)
2528
2629 foreach ( var member in containingType . AllInterfaces . SelectMany ( iface => iface . GetMembers ( method . Name ) ) )
2730 {
28- if ( member is not IMethodSymbol ifaceMethod )
31+ if ( member is not IMethodSymbol interfaceMethod )
2932 {
3033 continue ;
3134 }
3235
33- var implementation = containingType . FindImplementationForInterfaceMember ( ifaceMethod ) ;
34- if ( SymbolEqualityComparer . Default . Equals ( implementation , method ) )
36+ var impl = containingType . FindImplementationForInterfaceMember ( interfaceMethod ) ;
37+ if ( SymbolEqualityComparer . Default . Equals ( impl , method ) )
3538 {
3639 return true ;
3740 }
3841 }
3942
4043 return false ;
4144 }
45+
46+ internal static bool HasUsing ( this CompilationUnitSyntax root , string namespaceName )
47+ {
48+ return root . Usings . Any ( u => u . Name ? . ToString ( ) == namespaceName ) ;
49+ }
50+
51+ internal static bool IsMinimalApiMapMethod ( this IMethodSymbol method )
52+ {
53+ if ( ! method . IsExtensionMethod )
54+ {
55+ return false ;
56+ }
57+
58+ var containingType = method . ContainingType ;
59+ if ( containingType is null || containingType . Name != "EndpointRouteBuilderExtensions" )
60+ {
61+ return false ;
62+ }
63+
64+ var ns = containingType . ContainingNamespace . ToDisplayString ( ) ;
65+ if ( ! ns . StartsWith ( "Microsoft.AspNetCore.Builder" , StringComparison . Ordinal ) )
66+ {
67+ return false ;
68+ }
69+
70+ return method . Name is
71+ "MapGet" or
72+ "MapPost" or
73+ "MapPut" or
74+ "MapDelete" or
75+ "MapPatch" or
76+ "MapHead" or
77+ "MapOptions" or
78+ "MapTrace" or
79+ "MapMethods" ;
80+ }
81+
82+ internal static IAnonymousFunctionOperation ? ExtractAnonymousFunction ( IOperation value )
83+ {
84+ while ( true )
85+ {
86+ switch ( value )
87+ {
88+ case IAnonymousFunctionOperation anon :
89+ return anon ;
90+
91+ case IDelegateCreationOperation { Target : IAnonymousFunctionOperation anon } :
92+ return anon ;
93+
94+ case IConversionOperation { Operand : var operand } :
95+ value = operand ;
96+ continue ;
97+
98+ default :
99+ return null ;
100+ }
101+ }
102+ }
103+
104+ extension ( ITypeSymbol type )
105+ {
106+ internal bool IsTaskLike ( )
107+ {
108+ if ( type is not INamedTypeSymbol named )
109+ {
110+ return false ;
111+ }
112+
113+ return named . ContainingNamespace . ToDisplayString ( ) == "System.Threading.Tasks" &&
114+ named . Name is "Task" or "ValueTask" ;
115+ }
116+
117+ internal bool IsCancellationToken ( )
118+ {
119+ if ( type is not INamedTypeSymbol named )
120+ {
121+ return false ;
122+ }
123+
124+ return named . ContainingNamespace . ToDisplayString ( ) == "System.Threading" &&
125+ named . Name == "CancellationToken" ;
126+ }
127+ }
128+
129+ extension ( IMethodSymbol method )
130+ {
131+ internal bool IsTestMethod ( )
132+ {
133+ foreach ( var attr in method . GetAttributes ( ) )
134+ {
135+ var attrClass = attr . AttributeClass ;
136+ if ( attrClass is null )
137+ {
138+ continue ;
139+ }
140+
141+ var name = attrClass . Name ;
142+ if ( name . EndsWith ( "Attribute" , StringComparison . Ordinal ) )
143+ {
144+ name = name . Substring ( 0 , name . Length - "Attribute" . Length ) ;
145+ }
146+
147+ if ( name is "Fact"
148+ or "Theory"
149+ or "Test"
150+ or "TestCase"
151+ or "TestMethod"
152+ or "DataTestMethod" )
153+ {
154+ return true ;
155+ }
156+ }
157+
158+ return false ;
159+ }
160+
161+ internal bool IsMiddleware ( )
162+ {
163+ if ( method . Name is not ( "Invoke" or "InvokeAsync" ) )
164+ {
165+ return false ;
166+ }
167+
168+ if ( method . Parameters . Length == 0 )
169+ {
170+ return false ;
171+ }
172+
173+ if ( method . ReturnType is not INamedTypeSymbol returnType || ! returnType . IsTaskLike ( ) )
174+ {
175+ return false ;
176+ }
177+
178+ if ( method . Parameters [ 0 ] . Type is not INamedTypeSymbol httpContextType )
179+ {
180+ return false ;
181+ }
182+
183+ return httpContextType . Name == "HttpContext" &&
184+ httpContextType . ContainingNamespace . ToDisplayString ( ) == "Microsoft.AspNetCore.Http" ;
185+ }
186+ }
42187}
0 commit comments