Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit0c86a45

Browse files
authored
Add CA1872: Prefer 'Convert.ToHexString' over 'BitConverter.ToString' (#6967)
* Add CA1872: Prefer 'Convert.ToHexString' over 'BitConverter.ToString'This analyzer detects the usage of the pattern`BitConverter.ToString(bytes).Replace("-", "")` to convert an array ofbytes to an uppercase hex string (without hyphens in between) andreplaces it with a call to `Convert.ToHexString(bytes)`.The analyzer will also try to preserve chaining `ToLower*` in betweenfor a lowercase hex string.* Use span overload when replacing call with two arguments* Use Convert.ToHexStringLower if available* Improve resource strings* Improve description resource string* Remove redundant helper methods* Change invocation analyze order and remove duplicate work in fixer* Remove temporary Net90 reference assembly
1 parentde3a920 commit0c86a45

File tree

23 files changed

+2272
-1
lines changed

23 files changed

+2272
-1
lines changed

‎src/NetAnalyzers/Core/AnalyzerReleases.Unshipped.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Rule ID | Category | Severity | Notes
77
CA1514 | Maintainability | Info | AvoidLengthCheckWhenSlicingToEndAnalyzer,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1514)
88
CA1515 | Maintainability | Disabled | MakeTypesInternal,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1515)
99
CA1871 | Performance | Info | DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1871)
10+
CA1872 | Performance | Info | PreferConvertToHexStringOverBitConverterAnalyzer,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca1872)
1011
CA2262 | Usage | Info | ProvideHttpClientHandlerMaxResponseHeaderLengthValueCorrectly,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2262)
1112
CA2263 | Usage | Info | PreferGenericOverloadsAnalyzer,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2263)
1213
CA2264 | Usage | Warning | DoNotPassNonNullableValueToArgumentNullExceptionThrowIfNull,[Documentation](https://learn.microsoft.com/dotnet/fundamentals/code-analysis/quality-rules/ca2264)

‎src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/MicrosoftNetCoreAnalyzersResources.resx‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,18 @@
195195
<dataname="DoNotUseCountWhenAnyCanBeUsedTitle"xml:space="preserve">
196196
<value>Do not use Count() or LongCount() when Any() can be used</value>
197197
</data>
198+
<dataname="PreferConvertToHexStringOverBitConverterTitle"xml:space="preserve">
199+
<value>Prefer 'Convert.ToHexString' and 'Convert.ToHexStringLower' over call chains based on 'BitConverter.ToString'</value>
200+
</data>
201+
<dataname="PreferConvertToHexStringOverBitConverterDescription"xml:space="preserve">
202+
<value>Use 'Convert.ToHexString' or 'Convert.ToHexStringLower' when encoding bytes to a hexadecimal string representation. These methods are more efficient and allocation-friendly than using 'BitConverter.ToString' in combination with 'String.Replace' to replace dashes and 'String.ToLower'.</value>
203+
</data>
204+
<dataname="PreferConvertToHexStringOverBitConverterMessage"xml:space="preserve">
205+
<value>Prefer '{0}' over call chains based on '{1}'</value>
206+
</data>
207+
<dataname="PreferConvertToHexStringOverBitConverterCodeFixTitle"xml:space="preserve">
208+
<value>Replace with 'Convert.{0}'</value>
209+
</data>
198210
<dataname="DoNotUseTimersThatPreventPowerStateChangesTitle"xml:space="preserve">
199211
<value>Do not use timers that prevent power state changes</value>
200212
</data>
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information.
2+
3+
usingSystem;
4+
usingSystem.Collections.Immutable;
5+
usingSystem.Composition;
6+
usingSystem.Globalization;
7+
usingSystem.Linq;
8+
usingSystem.Threading;
9+
usingSystem.Threading.Tasks;
10+
usingAnalyzer.Utilities;
11+
usingAnalyzer.Utilities.Extensions;
12+
usingMicrosoft.CodeAnalysis;
13+
usingMicrosoft.CodeAnalysis.CodeActions;
14+
usingMicrosoft.CodeAnalysis.CodeFixes;
15+
usingMicrosoft.CodeAnalysis.Editing;
16+
usingMicrosoft.CodeAnalysis.Operations;
17+
usingMicrosoft.CodeAnalysis.Text;
18+
19+
namespaceMicrosoft.NetCore.Analyzers.Performance
20+
{
21+
usingstaticMicrosoftNetCoreAnalyzersResources;
22+
23+
/// <summary>
24+
/// CA1872: <inheritdoc cref="PreferConvertToHexStringOverBitConverterTitle"/>
25+
/// </summary>
26+
[ExportCodeFixProvider(LanguageNames.CSharp,LanguageNames.VisualBasic),Shared]
27+
publicsealedclassPreferConvertToHexStringOverBitConverterFixer:CodeFixProvider
28+
{
29+
privatestaticreadonlySyntaxAnnotations_asSpanSymbolAnnotation=new("SymbolId",WellKnownTypeNames.SystemMemoryExtensions);
30+
31+
publicsealedoverrideImmutableArray<string>FixableDiagnosticIds{get;}=
32+
ImmutableArray.Create(PreferConvertToHexStringOverBitConverterAnalyzer.RuleId);
33+
34+
publicsealedoverrideFixAllProviderGetFixAllProvider()
35+
{
36+
returnWellKnownFixAllProviders.BatchFixer;
37+
}
38+
39+
publicsealedoverrideasyncTaskRegisterCodeFixesAsync(CodeFixContextcontext)
40+
{
41+
vardiagnostic=context.Diagnostics.FirstOrDefault();
42+
43+
if(diagnosticis not{AdditionalLocations.Count:>0,Properties.Count:1}||
44+
!diagnostic.Properties.TryGetValue(PreferConvertToHexStringOverBitConverterAnalyzer.ReplacementPropertiesKey,outvarconvertToHexStringName)||
45+
convertToHexStringNameisnull)
46+
{
47+
return;
48+
}
49+
50+
varroot=awaitcontext.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
51+
varsemanticModel=awaitcontext.Document.GetRequiredSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);
52+
53+
varbitConverterInvocation=GetInvocationFromTextSpan(diagnostic.AdditionalLocations[0].SourceSpan);
54+
varouterInvocation=GetInvocationFromTextSpan(context.Span);
55+
56+
if(bitConverterInvocationisnull||outerInvocationisnull)
57+
{
58+
return;
59+
}
60+
61+
vartoLowerInvocation=diagnostic.AdditionalLocations.Count==2
62+
?GetInvocationFromTextSpan(diagnostic.AdditionalLocations[1].SourceSpan)
63+
:null;
64+
65+
varcodeAction=CodeAction.Create(
66+
string.Format(CultureInfo.CurrentCulture,PreferConvertToHexStringOverBitConverterCodeFixTitle,convertToHexStringName),
67+
ReplaceWithConvertToHexStringCall,
68+
nameof(PreferConvertToHexStringOverBitConverterCodeFixTitle));
69+
70+
context.RegisterCodeFix(codeAction,context.Diagnostics);
71+
72+
IInvocationOperation?GetInvocationFromTextSpan(TextSpanspan)
73+
{
74+
varnode=root.FindNode(span,getInnermostNodeForTie:true);
75+
76+
if(nodeisnull)
77+
{
78+
returnnull;
79+
}
80+
81+
returnsemanticModel.GetOperation(node,context.CancellationToken)asIInvocationOperation;
82+
}
83+
84+
asyncTask<Document>ReplaceWithConvertToHexStringCall(CancellationTokencancellationToken)
85+
{
86+
vareditor=awaitDocumentEditor.CreateAsync(context.Document,cancellationToken).ConfigureAwait(false);
87+
vargenerator=editor.Generator;
88+
varbitConverterArgumentsInParameterOrder=bitConverterInvocation.Arguments.GetArgumentsInParameterOrder();
89+
90+
vartypeExpression=generator.DottedName(WellKnownTypeNames.SystemConvert);
91+
varmethodExpression=generator.MemberAccessExpression(typeExpression,convertToHexStringName);
92+
varmethodInvocation=bitConverterArgumentsInParameterOrder.Lengthswitch
93+
{
94+
// BitConverter.ToString(data).Replace("-", "") => Convert.ToHexString(data)
95+
1=>generator.InvocationExpression(methodExpression,bitConverterArgumentsInParameterOrder[0].Value.Syntax),
96+
// BitConverter.ToString(data, start).Replace("-", "") => Convert.ToHexString(data.AsSpan().Slice(start))
97+
2=>generator.InvocationExpression(
98+
methodExpression,
99+
generator.InvocationExpression(generator.MemberAccessExpression(
100+
generator.InvocationExpression(generator.MemberAccessExpression(
101+
bitConverterArgumentsInParameterOrder[0].Value.Syntax,
102+
nameof(MemoryExtensions.AsSpan))),
103+
WellKnownMemberNames.SliceMethodName),
104+
bitConverterArgumentsInParameterOrder[1].Value.Syntax))
105+
.WithAddImportsAnnotation()
106+
.WithAdditionalAnnotations(s_asSpanSymbolAnnotation),
107+
// BitConverter.ToString(data, start, length).Replace("-", "") => Convert.ToHexString(data, start, length)
108+
3=>generator.InvocationExpression(methodExpression,bitConverterArgumentsInParameterOrder.Select(a=>a.Value.Syntax).ToArray()),
109+
_=>thrownewNotImplementedException()
110+
};
111+
112+
// This branch is hit when string.ToLower* is used and Convert.ToHexStringLower is not available.
113+
if(toLowerInvocationis notnull)
114+
{
115+
methodInvocation=generator.InvocationExpression(
116+
generator.MemberAccessExpression(methodInvocation,toLowerInvocation.TargetMethod.Name),
117+
toLowerInvocation.Arguments.Select(a=>a.Value.Syntax).ToArray());
118+
}
119+
120+
editor.ReplaceNode(outerInvocation.Syntax,methodInvocation.WithTriviaFrom(outerInvocation.Syntax));
121+
122+
returncontext.Document.WithSyntaxRoot(editor.GetChangedRoot());
123+
}
124+
}
125+
}
126+
}

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp