6
6
using System . Linq ;
7
7
using Analyzer . Utilities ;
8
8
using Analyzer . Utilities . Extensions ;
9
- using Analyzer . Utilities . PooledObjects ;
10
9
using Microsoft . CodeAnalysis ;
11
10
using Microsoft . CodeAnalysis . Diagnostics ;
12
11
using Microsoft . CodeAnalysis . Operations ;
@@ -32,11 +31,9 @@ public abstract class UseSpanBasedStringConcat : DiagnosticAnalyzer
32
31
isDataflowRule : false ) ;
33
32
34
33
/// <summary>
35
- /// If the specified binary operation is a string concatenation operation, we try to walk up to the top-most
36
- /// string-concatenation operation that it is part of. If it is not a string-concatenation operation, we simply
37
- /// return false.
34
+ /// Returns true if the specified binary operation is a top-most string concatenation operation
38
35
/// </summary>
39
- private protected abstract bool TryGetTopMostConcatOperation ( IBinaryOperation binaryOperation , [ NotNullWhen ( true ) ] out IBinaryOperation ? rootBinaryOperation ) ;
36
+ private protected abstract bool IsTopMostConcatOperation ( IBinaryOperation binaryOperation ) ;
40
37
41
38
/// <summary>
42
39
/// Remove the built in implicit conversion on operands to concat.
@@ -59,49 +56,19 @@ private void OnCompilationStart(CompilationStartAnalysisContext context)
59
56
if ( ! RequiredSymbols . TryGetSymbols ( context . Compilation , out RequiredSymbols symbols ) )
60
57
return ;
61
58
62
- context . RegisterOperationBlockStartAction ( OnOperationBlockStart ) ;
63
- return ;
64
-
65
- // Local functions
66
- void OnOperationBlockStart ( OperationBlockStartAnalysisContext context )
59
+ context . RegisterOperationAction ( context =>
67
60
{
68
- // Maintain set of all top-most concat operations so we don't report sub-expressions of an
69
- // already-reported violation.
61
+ // Report diagnostic only if the operation is the top-most concat operation so we don't report sub-expressions of an
62
+ // already-reported violation.
70
63
// We also don't report any diagnostic if the concat operation has too many operands for the span-based
71
64
// Concat overloads to handle.
72
- var topMostConcatOperations = TemporarySet < IBinaryOperation > . Empty ;
73
-
74
- context . RegisterOperationAction ( PopulateTopMostConcatOperations , OperationKind . Binary ) ;
75
- context . RegisterOperationBlockEndAction ( ReportDiagnosticsOnRootConcatOperationsWithSubstringCalls ) ;
76
-
77
- void PopulateTopMostConcatOperations ( OperationAnalysisContext context )
78
- {
79
- // If the current operation is a string-concatenation operation, walk up to the top-most concat
80
- // operation and add it to the set.
81
- var binary = ( IBinaryOperation ) context . Operation ;
82
- if ( ! TryGetTopMostConcatOperation ( binary , out var topMostConcatOperation ) )
83
- return ;
84
-
85
- topMostConcatOperations . Add ( topMostConcatOperation , context . CancellationToken ) ;
86
- }
87
-
88
- void ReportDiagnosticsOnRootConcatOperationsWithSubstringCalls ( OperationBlockAnalysisContext context )
89
- {
90
- // We report diagnostics for all top-most concat operations that contain
91
- // direct or conditional substring invocations when there is an applicable span-based overload of
92
- // the string.Concat method.
93
- // We don't report when the concatenation contains anything other than strings or character literals.
94
- foreach ( var operation in topMostConcatOperations . NonConcurrentEnumerable )
95
- {
96
- if ( ShouldBeReported ( operation ) )
97
- {
98
- context . ReportDiagnostic ( operation . CreateDiagnostic ( Rule ) ) ;
99
- }
100
- }
65
+ var binary = ( IBinaryOperation ) context . Operation ;
66
+ if ( IsTopMostConcatOperation ( binary ) && ShouldBeReported ( binary ) )
67
+ context . ReportDiagnostic ( binary . CreateDiagnostic ( Rule ) ) ;
68
+ } , OperationKind . Binary ) ;
69
+ return ;
101
70
102
- topMostConcatOperations . Free ( context . CancellationToken ) ;
103
- }
104
- }
71
+ // Local functions
105
72
106
73
bool ShouldBeReported ( IBinaryOperation topMostConcatOperation )
107
74
{
@@ -133,8 +100,8 @@ bool ShouldBeReported(IBinaryOperation topMostConcatOperation)
133
100
134
101
bool IsAnyDirectOrConditionalSubstringInvocation ( IOperation operation )
135
102
{
136
- if ( operation is IConditionalAccessOperation conditionallAccessOperation )
137
- operation = conditionallAccessOperation . WhenNotNull ;
103
+ if ( operation is IConditionalAccessOperation conditionalAccessOperation )
104
+ operation = conditionalAccessOperation . WhenNotNull ;
138
105
139
106
return operation is IInvocationOperation invocation && symbols . IsAnySubstringMethod ( invocation . TargetMethod ) ;
140
107
}
0 commit comments