-
Notifications
You must be signed in to change notification settings - Fork 466
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
(3/4) Use Span-Based String Concat Analyzer and Fixer #4764
(3/4) Use Span-Based String Concat Analyzer and Fixer #4764
Conversation
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
Outdated
Show resolved
Hide resolved
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx
Outdated
Show resolved
Hide resolved
…CoreAnalyzersResources.resx Fix title Co-authored-by: Manish Vasani <mavasani@microsoft.com>
…CoreAnalyzersResources.resx Co-authored-by: Manish Vasani <mavasani@microsoft.com>
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.cs
Outdated
Show resolved
Hide resolved
src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcatTests.cs
Outdated
Show resolved
Hide resolved
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.cs
Outdated
Show resolved
Hide resolved
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.Fixer.cs
Outdated
Show resolved
Hide resolved
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.cs
Outdated
Show resolved
Hide resolved
public Task SingleViolationInOneBlock_ReportedAndFixed_CS(string testStatements, string fixedStatements) | ||
{ | ||
var test = new VerifyCS.Test | ||
{ | ||
TestCode = CSUsings + CSWithBody(testStatements), | ||
FixedCode = CSUsings + CSWithBody(fixedStatements), | ||
ReferenceAssemblies = ReferenceAssemblies.Net.Net50, | ||
ExpectedDiagnostics = { VerifyCS.Diagnostic(Rule).WithLocation(0) } | ||
}; | ||
return test.RunAsync(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider making the tests async
, then await test.RunAsync()
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public async Task TestMethod() => await test.RunAsync();
is semantically identical to
public Task TestMethod() => return test.RunAsync();
, but potentially slower. If we needed to await multiple async calls, it would make sense to mark the method as async
, but since we have just that one async
call, it makes sense to simply return the Task
produced by test.RunAsync()
.
Basically, we already have a Task
. May as well just return it.
src/NetAnalyzers/UnitTests/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcatTests.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Consider having tests against null-conditional access operator (?.
).
@Youssef1313 Do you mean for |
Yes. |
What should the fixer do for |
I'm not sure whether the fixer should do something or not. But I think at least the analyzer should flag these. |
That's a reasonable starting position. |
…d made it a static method. - Added tests for conditional substring invocation. We report conditional substring invocations, but do not fix them. - Fixed issue where `Imports System` was unnecessarily being added in projects that had `System` as an implicit global import, and added tests for VB projects with and without an implicit global `System` import. - Added null tests for both string and char type symbols, just in case. - Used exact values for expected iteration counts for nested violations tests. - Other minor style changes.
Some tests didn't explicitly specify net5.0, which caused the tests to fail due to lack of span-based string.Concat.
I've made the requested changes. The fixer will now only add Analyzer detects |
Codecov Report
@@ Coverage Diff @@
## release/6.0.1xx #4764 +/- ##
==================================================
Coverage 95.55% 95.56%
==================================================
Files 1203 1210 +7
Lines 274337 275763 +1426
Branches 16632 16713 +81
==================================================
+ Hits 262137 263526 +1389
- Misses 9988 10005 +17
- Partials 2212 2232 +20 |
How do we want to handle character arguments? I was thinking |
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.cs
Show resolved
Hide resolved
// If the current operation is a string-concatenation operation, walk up to the top-most concat | ||
// operation and add it to the set. | ||
var binary = (IBinaryOperation)context.Operation; | ||
if (!TryGetTopMostConcatOperation(binary, out var topMostConcatOperation)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This approach seems fine, but seems you can do without topMostConcatOperations
and reporting in the end action. Instead you can just have the following in IBinaryOperation
callback:
if (IsTopMostConcatOperation(binary) && ShouldBeReported(binary))
{
context.ReportDiagnostic(binary.CreateDiagnostic(Rule));
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The problem with this approach is that we may end up reporting the same violation multiple times. I remember encountering this issue while writing the analyzer. I'll add a comment clarifying this.
} | ||
} | ||
|
||
internal static ImmutableArray<IOperation> FlattenBinaryOperation(IBinaryOperation root) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be much simpler to just write a specialized OperationWalker here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right. I've done that.
case LanguageNames.CSharp when conversion.Type.SpecialType is SpecialType.System_Object: | ||
case LanguageNames.VisualBasic when conversion.Type.SpecialType is SpecialType.System_Object or SpecialType.System_String: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please move all language specific logic to language specific layers instead of checking language names - you already have similar abstract methods and language specific operation walking code, so please move this out as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed. I did have to add two static methods with the VB and CS implementations, as the method is called from both the analyzer and the fixer, but I've taken care of it.
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.Fixer.cs
Show resolved
Hide resolved
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.Fixer.cs
Show resolved
Hide resolved
if (root.FindNode(context.Span, getInnermostNodeForTie: true) is not SyntaxNode concatExpressionSyntax) | ||
return; | ||
// OperatorKind will be BinaryOperatorKind.Concatenate, even when '+' is used instead of '&' in Visual Basic. | ||
if (model.GetOperation(concatExpressionSyntax, cancellationToken) is not IBinaryOperation concatOperation || concatOperation.OperatorKind is not (BinaryOperatorKind.Add or BinaryOperatorKind.Concatenate)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please break down the expression into separate lines for readability
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Runtime/UseSpanBasedStringConcat.Fixer.cs
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall LGTM. Thanks for extensive tests.
Co-authored-by: Manish Vasani <mavasani@microsoft.com>
- Apply Mavasani's changes - Remove unused method from fixers
if (!IsSystemNamespaceImported(context.Document.Project, generator.GetNamespaceImports(newRoot))) | ||
{ | ||
SyntaxNode systemNamespaceImport = generator.NamespaceImportDeclaration(nameof(System)); | ||
newRoot = generator.AddNamespaceImports(newRoot, systemNamespaceImport); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would you be able to check if calling WithAddImportsAnnotation
on concatMethodInvocationSyntax
eliminate the need of IsSystemNamespaceImported
?
If WithAddImportsAnnotation
didn't work, consider doing a case-insensitive string comparison in the VB override.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
WithAddImportsAnnotation
only works for syntax nodes that represent types (just tested it).
I did change the VB fixer to use a case-insensitive comparison (good catch).
Use case-insensitive string comparison to import System namespace in the VB fixer.
Same request and apologies as #4726 (comment). This needs to be targeted to |
Co-authored-by: Manish Vasani <mavasani@microsoft.com>
Fixes issue #33777.
Issues in dotnet/runtime have been addressed.