1
- // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
1
+ // Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
2
2
3
3
using System . Collections . Generic ;
4
4
using System . Collections . Immutable ;
@@ -46,29 +46,23 @@ public override void Initialize(AnalysisContext context)
46
46
47
47
private static void OnCompilationStart ( CompilationStartAnalysisContext context )
48
48
{
49
- var listType = context . Compilation . GetOrCreateTypeByMetadataName ( WellKnownTypeNames . SystemCollectionsGenericIList1 ) ;
50
- var readonlyListType = context . Compilation . GetOrCreateTypeByMetadataName ( WellKnownTypeNames . SystemCollectionsGenericIReadOnlyList1 ) ;
51
49
var enumerableType = context . Compilation . GetOrCreateTypeByMetadataName ( WellKnownTypeNames . SystemLinqEnumerable ) ;
52
- if ( readonlyListType == null || enumerableType == null || listType == null )
50
+ if ( enumerableType == null )
53
51
{
54
52
return ;
55
53
}
56
54
57
- context . RegisterOperationAction ( operationContext =>
55
+ context . RegisterOperationAction ( context =>
58
56
{
59
- var invocation = ( IInvocationOperation ) operationContext . Operation ;
57
+ var invocation = ( IInvocationOperation ) context . Operation ;
60
58
61
- var excludeOrDefaultMethods = operationContext . Options . GetBoolOptionValue (
62
- EditorConfigOptionNames . ExcludeOrDefaultMethods , Rule , invocation . Syntax . SyntaxTree ,
63
- operationContext . Compilation , defaultValue : false ) ;
64
-
65
- if ( ! IsPossibleLinqInvocation ( invocation , excludeOrDefaultMethods ) )
59
+ if ( ! IsPossibleLinqInvocation ( invocation , context ) )
66
60
{
67
61
return ;
68
62
}
69
63
70
64
var methodSymbol = invocation . TargetMethod . ReducedFrom ?? invocation . TargetMethod ;
71
- var targetType = invocation . GetReceiverType ( operationContext . Compilation , beforeConversion : true , cancellationToken : operationContext . CancellationToken ) ;
65
+ var targetType = invocation . GetReceiverType ( context . Compilation , beforeConversion : true , cancellationToken : context . CancellationToken ) ;
72
66
if ( methodSymbol == null || targetType == null )
73
67
{
74
68
return ;
@@ -79,13 +73,13 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context)
79
73
return ;
80
74
}
81
75
82
- if ( ! IsTypeWithInefficientLinqMethods ( targetType , readonlyListType , listType ) )
76
+ if ( ! IsTypeWithInefficientLinqMethods ( targetType ) )
83
77
{
84
78
return ;
85
79
}
86
80
87
81
var properties = new Dictionary < string , string ? > { [ MethodPropertyKey ] = invocation . TargetMethod . Name } . ToImmutableDictionary ( ) ;
88
- operationContext . ReportDiagnostic ( invocation . CreateDiagnostic ( Rule , properties ) ) ;
82
+ context . ReportDiagnostic ( invocation . CreateDiagnostic ( Rule , properties ) ) ;
89
83
} , OperationKind . Invocation ) ;
90
84
}
91
85
@@ -97,10 +91,10 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context)
97
91
/// At this point it only identifies <see cref="IReadOnlyList{T}"/> directly but could easily be extended to support
98
92
/// any type which has an index and count property.
99
93
/// </summary>
100
- private static bool IsTypeWithInefficientLinqMethods ( ITypeSymbol targetType , ITypeSymbol readonlyListType , ITypeSymbol listType )
94
+ private static bool IsTypeWithInefficientLinqMethods ( ITypeSymbol targetType )
101
95
{
102
96
// If this type is simply IReadOnlyList<T> then no further checking is needed.
103
- if ( targetType . TypeKind == TypeKind . Interface && targetType . OriginalDefinition . Equals ( readonlyListType ) )
97
+ if ( targetType . TypeKind == TypeKind . Interface && targetType . OriginalDefinition . SpecialType == SpecialType . System_Collections_Generic_IReadOnlyList_T )
104
98
{
105
99
return true ;
106
100
}
@@ -109,12 +103,12 @@ private static bool IsTypeWithInefficientLinqMethods(ITypeSymbol targetType, ITy
109
103
bool implementsList = false ;
110
104
foreach ( var current in targetType . AllInterfaces )
111
105
{
112
- if ( current . OriginalDefinition . Equals ( readonlyListType ) )
106
+ if ( current . OriginalDefinition . SpecialType == SpecialType . System_Collections_Generic_IReadOnlyList_T )
113
107
{
114
108
implementsReadOnlyList = true ;
115
109
}
116
110
117
- if ( current . OriginalDefinition . Equals ( listType ) )
111
+ if ( current . OriginalDefinition . SpecialType == SpecialType . System_Collections_Generic_IList_T )
118
112
{
119
113
implementsList = true ;
120
114
}
@@ -139,14 +133,21 @@ private static bool IsSingleParameterLinqMethod(IMethodSymbol methodSymbol, ITyp
139
133
methodSymbol . Parameters . Length == 1 ;
140
134
}
141
135
142
- private static bool IsPossibleLinqInvocation ( IInvocationOperation invocation , bool excludeOrDefaultMethods )
136
+ private static bool IsPossibleLinqInvocation ( IInvocationOperation invocation , OperationAnalysisContext context )
143
137
{
144
138
return invocation . TargetMethod . Name switch
145
139
{
146
140
"Last" or "First" or "Count" => true ,
147
- "LastOrDefault" or "FirstOrDefault" => ! excludeOrDefaultMethods ,
141
+ "LastOrDefault" or "FirstOrDefault" => ! ShouldExcludeOrDefaultMethods ( context ) ,
148
142
_ => false ,
149
143
} ;
150
144
}
145
+
146
+ private static bool ShouldExcludeOrDefaultMethods ( OperationAnalysisContext context )
147
+ {
148
+ return context . Options . GetBoolOptionValue (
149
+ EditorConfigOptionNames . ExcludeOrDefaultMethods , Rule , context . Operation . Syntax . SyntaxTree ,
150
+ context . Compilation , defaultValue : false ) ;
151
+ }
151
152
}
152
153
}
0 commit comments