-
-
Notifications
You must be signed in to change notification settings - Fork 255
/
CallCastInsteadOfSelectAnalysis.cs
94 lines (69 loc) · 3.27 KB
/
CallCastInsteadOfSelectAnalysis.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Copyright (c) .NET Foundation and Contributors. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Text;
using Roslynator.CSharp.Syntax;
namespace Roslynator.CSharp.Analysis;
internal static class CallCastInsteadOfSelectAnalysis
{
public static void Analyze(
SyntaxNodeAnalysisContext context,
in SimpleMemberInvocationExpressionInfo invocationInfo)
{
InvocationExpressionSyntax invocationExpression = invocationInfo.InvocationExpression;
if (invocationInfo.Name.SpanOrTrailingTriviaContainsDirectives())
return;
if (invocationInfo.ArgumentList.SpanOrLeadingTriviaContainsDirectives())
return;
SemanticModel semanticModel = context.SemanticModel;
CancellationToken cancellationToken = context.CancellationToken;
ExtensionMethodSymbolInfo extensionInfo = semanticModel.GetExtensionMethodInfo(invocationExpression, cancellationToken);
if (extensionInfo.Symbol is null)
return;
if (!SymbolUtility.IsLinqSelect(extensionInfo.Symbol, allowImmutableArrayExtension: true))
return;
ITypeSymbol typeArgument = extensionInfo.ReducedSymbolOrSymbol.TypeArguments[0];
if (!typeArgument.IsReferenceType)
return;
if (typeArgument.SpecialType == SpecialType.System_Object)
return;
ExpressionSyntax expression = invocationExpression.ArgumentList?.Arguments.Last().Expression;
SingleParameterLambdaExpressionInfo lambdaInfo = SyntaxInfo.SingleParameterLambdaExpressionInfo(expression);
if (!lambdaInfo.Success)
return;
CastExpressionSyntax castExpression = GetCastExpression(lambdaInfo.Body);
if (castExpression is null)
return;
if (castExpression.Expression is not IdentifierNameSyntax identifierName)
return;
if (!string.Equals(lambdaInfo.Parameter.Identifier.ValueText, identifierName.Identifier.ValueText, StringComparison.Ordinal))
return;
if (semanticModel.GetMethodSymbol(castExpression, cancellationToken)?.MethodKind == MethodKind.Conversion)
return;
DiagnosticHelpers.ReportDiagnostic(
context,
DiagnosticRules.OptimizeLinqMethodCall,
Location.Create(invocationExpression.SyntaxTree, TextSpan.FromBounds(invocationInfo.Name.SpanStart, invocationExpression.Span.End)));
}
internal static CastExpressionSyntax GetCastExpression(CSharpSyntaxNode node)
{
switch (node.Kind())
{
case SyntaxKind.CastExpression:
{
return (CastExpressionSyntax)node;
}
case SyntaxKind.Block:
{
var block = (BlockSyntax)node;
var returnStatement = block.Statements.SingleOrDefault(shouldThrow: false) as ReturnStatementSyntax;
return returnStatement?.Expression as CastExpressionSyntax;
}
}
return null;
}
}