Skip to content

Commit 5682065

Browse files
committed
Refactor CA1826 to read option only when needed and use SpecialType checks
1 parent 3587540 commit 5682065

File tree

1 file changed

+21
-20
lines changed

1 file changed

+21
-20
lines changed

src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/DoNotUseEnumerableMethodsOnIndexableCollectionsInsteadUseTheCollectionDirectly.cs

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
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.
22

33
using System.Collections.Generic;
44
using System.Collections.Immutable;
@@ -46,29 +46,23 @@ public override void Initialize(AnalysisContext context)
4646

4747
private static void OnCompilationStart(CompilationStartAnalysisContext context)
4848
{
49-
var listType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsGenericIList1);
50-
var readonlyListType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemCollectionsGenericIReadOnlyList1);
5149
var enumerableType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemLinqEnumerable);
52-
if (readonlyListType == null || enumerableType == null || listType == null)
50+
if (enumerableType == null)
5351
{
5452
return;
5553
}
5654

57-
context.RegisterOperationAction(operationContext =>
55+
context.RegisterOperationAction(context =>
5856
{
59-
var invocation = (IInvocationOperation)operationContext.Operation;
57+
var invocation = (IInvocationOperation)context.Operation;
6058

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))
6660
{
6761
return;
6862
}
6963

7064
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);
7266
if (methodSymbol == null || targetType == null)
7367
{
7468
return;
@@ -79,13 +73,13 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context)
7973
return;
8074
}
8175

82-
if (!IsTypeWithInefficientLinqMethods(targetType, readonlyListType, listType))
76+
if (!IsTypeWithInefficientLinqMethods(targetType))
8377
{
8478
return;
8579
}
8680

8781
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));
8983
}, OperationKind.Invocation);
9084
}
9185

@@ -97,10 +91,10 @@ private static void OnCompilationStart(CompilationStartAnalysisContext context)
9791
/// At this point it only identifies <see cref="IReadOnlyList{T}"/> directly but could easily be extended to support
9892
/// any type which has an index and count property.
9993
/// </summary>
100-
private static bool IsTypeWithInefficientLinqMethods(ITypeSymbol targetType, ITypeSymbol readonlyListType, ITypeSymbol listType)
94+
private static bool IsTypeWithInefficientLinqMethods(ITypeSymbol targetType)
10195
{
10296
// 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)
10498
{
10599
return true;
106100
}
@@ -109,12 +103,12 @@ private static bool IsTypeWithInefficientLinqMethods(ITypeSymbol targetType, ITy
109103
bool implementsList = false;
110104
foreach (var current in targetType.AllInterfaces)
111105
{
112-
if (current.OriginalDefinition.Equals(readonlyListType))
106+
if (current.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IReadOnlyList_T)
113107
{
114108
implementsReadOnlyList = true;
115109
}
116110

117-
if (current.OriginalDefinition.Equals(listType))
111+
if (current.OriginalDefinition.SpecialType == SpecialType.System_Collections_Generic_IList_T)
118112
{
119113
implementsList = true;
120114
}
@@ -139,14 +133,21 @@ private static bool IsSingleParameterLinqMethod(IMethodSymbol methodSymbol, ITyp
139133
methodSymbol.Parameters.Length == 1;
140134
}
141135

142-
private static bool IsPossibleLinqInvocation(IInvocationOperation invocation, bool excludeOrDefaultMethods)
136+
private static bool IsPossibleLinqInvocation(IInvocationOperation invocation, OperationAnalysisContext context)
143137
{
144138
return invocation.TargetMethod.Name switch
145139
{
146140
"Last" or "First" or "Count" => true,
147-
"LastOrDefault" or "FirstOrDefault" => !excludeOrDefaultMethods,
141+
"LastOrDefault" or "FirstOrDefault" => !ShouldExcludeOrDefaultMethods(context),
148142
_ => false,
149143
};
150144
}
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+
}
151152
}
152153
}

0 commit comments

Comments
 (0)