-
Notifications
You must be signed in to change notification settings - Fork 468
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add UseVolatileReadWriteAnalyzer (#7043)
* Add UseVolatileReadWriteAnalyzer * Move analyzer to test project. * Update RulesMissingDocumentation.md * Add copyright comment * Remove analyzer from test project * Add tests for named arguments and trivia * Use IOperation API * Enable reverse order test in VB
- Loading branch information
1 parent
94749ce
commit d98dd32
Showing
19 changed files
with
1,164 additions
and
0 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
src/NetAnalyzers/CSharp/Microsoft.NetCore.Analyzers/Usage/CSharpUseVolatileReadWriteFixer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Composition; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Operations; | ||
using Microsoft.NetCore.Analyzers.Usage; | ||
|
||
namespace Microsoft.NetCore.CSharp.Analyzers.Usage | ||
{ | ||
[ExportCodeFixProvider(LanguageNames.CSharp), Shared] | ||
internal sealed class CSharpUseVolatileReadWriteFixer : UseVolatileReadWriteFixer | ||
{ | ||
protected override SyntaxNode GetArgumentForVolatileReadCall(IArgumentOperation argument, IParameterSymbol volatileReadParameter) | ||
{ | ||
var argumentSyntax = (ArgumentSyntax)argument.Syntax; | ||
if (argumentSyntax.NameColon is null) | ||
{ | ||
return argumentSyntax; | ||
} | ||
|
||
return argumentSyntax.WithNameColon(SyntaxFactory.NameColon(volatileReadParameter.Name)); | ||
} | ||
|
||
protected override IEnumerable<SyntaxNode> GetArgumentForVolatileWriteCall(ImmutableArray<IArgumentOperation> arguments, ImmutableArray<IParameterSymbol> volatileWriteParameters) | ||
{ | ||
foreach (var argument in arguments) | ||
{ | ||
var argumentSyntax = (ArgumentSyntax)argument.Syntax; | ||
if (argumentSyntax.NameColon is null) | ||
{ | ||
yield return argumentSyntax; | ||
} | ||
else | ||
{ | ||
var parameterName = volatileWriteParameters[argument.Parameter!.Ordinal].Name; | ||
yield return argumentSyntax.WithNameColon(SyntaxFactory.NameColon(parameterName)); | ||
} | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
101 changes: 101 additions & 0 deletions
101
src/NetAnalyzers/Core/Microsoft.NetCore.Analyzers/Usage/UseVolatileReadWrite.Fixer.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the MIT license. See License.txt in the project root for license information. | ||
|
||
using System; | ||
using System.Collections.Generic; | ||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Analyzer.Utilities; | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CodeActions; | ||
using Microsoft.CodeAnalysis.CodeFixes; | ||
using Microsoft.CodeAnalysis.Editing; | ||
using Microsoft.CodeAnalysis.Operations; | ||
|
||
namespace Microsoft.NetCore.Analyzers.Usage | ||
{ | ||
public abstract class UseVolatileReadWriteFixer : CodeFixProvider | ||
{ | ||
private const string ThreadVolatileReadMethodName = nameof(Thread.VolatileRead); | ||
private const string ThreadVolatileWriteMethodName = nameof(Thread.VolatileWrite); | ||
private const string VolatileReadMethodName = nameof(Volatile.Read); | ||
private const string VolatileWriteMethodName = nameof(Volatile.Write); | ||
|
||
public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context) | ||
{ | ||
var root = await context.Document.GetRequiredSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false); | ||
var node = root.FindNode(context.Span, getInnermostNodeForTie: true); | ||
var semanticModel = await context.Document.GetRequiredSemanticModelAsync(context.CancellationToken).ConfigureAwait(false); | ||
var typeProvider = WellKnownTypeProvider.GetOrCreate(semanticModel.Compilation); | ||
var operation = semanticModel.GetOperation(node); | ||
if (typeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingThread) is not INamedTypeSymbol threadType | ||
|| typeProvider.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingVolatile) is not INamedTypeSymbol volatileType | ||
|| operation is not IInvocationOperation invocationOperation) | ||
{ | ||
return; | ||
} | ||
|
||
var obsoleteMethodsBuilder = ImmutableArray.CreateBuilder<IMethodSymbol>(); | ||
obsoleteMethodsBuilder.AddRange(threadType.GetMembers(ThreadVolatileReadMethodName).OfType<IMethodSymbol>()); | ||
obsoleteMethodsBuilder.AddRange(threadType.GetMembers(ThreadVolatileWriteMethodName).OfType<IMethodSymbol>()); | ||
var obsoleteMethods = obsoleteMethodsBuilder.ToImmutable(); | ||
|
||
var volatileReadMethod = volatileType.GetMembers(VolatileReadMethodName).OfType<IMethodSymbol>().FirstOrDefault(); | ||
var volatileWriteMethod = volatileType.GetMembers(VolatileWriteMethodName).OfType<IMethodSymbol>().FirstOrDefault(); | ||
|
||
if (!SymbolEqualityComparer.Default.Equals(invocationOperation.TargetMethod.ContainingType, threadType) | ||
|| !obsoleteMethods.Any(SymbolEqualityComparer.Default.Equals, invocationOperation.TargetMethod) | ||
|| volatileReadMethod is null | ||
|| volatileWriteMethod is null) | ||
{ | ||
return; | ||
} | ||
|
||
var codeAction = CodeAction.Create( | ||
MicrosoftNetCoreAnalyzersResources.DoNotUseThreadVolatileReadWriteCodeFixTitle, | ||
ReplaceObsoleteCall, | ||
equivalenceKey: nameof(MicrosoftNetCoreAnalyzersResources.DoNotUseThreadVolatileReadWriteCodeFixTitle)); | ||
|
||
context.RegisterCodeFix(codeAction, context.Diagnostics); | ||
|
||
return; | ||
|
||
async Task<Document> ReplaceObsoleteCall(CancellationToken cancellationToken) | ||
{ | ||
var editor = await DocumentEditor.CreateAsync(context.Document, cancellationToken).ConfigureAwait(false); | ||
var generator = editor.Generator; | ||
|
||
string methodName; | ||
IEnumerable<SyntaxNode> arguments; | ||
if (invocationOperation.TargetMethod.Name.Equals(ThreadVolatileReadMethodName, StringComparison.Ordinal)) | ||
{ | ||
methodName = VolatileReadMethodName; | ||
arguments = [GetArgumentForVolatileReadCall(invocationOperation.Arguments[0], volatileReadMethod.Parameters[0])]; | ||
} | ||
else | ||
{ | ||
methodName = VolatileWriteMethodName; | ||
arguments = GetArgumentForVolatileWriteCall(invocationOperation.Arguments, volatileWriteMethod.Parameters); | ||
} | ||
|
||
var methodExpression = generator.MemberAccessExpression( | ||
generator.TypeExpressionForStaticMemberAccess(volatileType), | ||
methodName); | ||
var methodInvocation = generator.InvocationExpression(methodExpression, arguments); | ||
|
||
editor.ReplaceNode(invocationOperation.Syntax, methodInvocation.WithTriviaFrom(invocationOperation.Syntax)); | ||
|
||
return context.Document.WithSyntaxRoot(editor.GetChangedRoot()); | ||
} | ||
} | ||
|
||
protected abstract SyntaxNode GetArgumentForVolatileReadCall(IArgumentOperation argument, IParameterSymbol volatileReadParameter); | ||
|
||
protected abstract IEnumerable<SyntaxNode> GetArgumentForVolatileWriteCall(ImmutableArray<IArgumentOperation> arguments, ImmutableArray<IParameterSymbol> volatileWriteParameters); | ||
|
||
public sealed override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer; | ||
|
||
public sealed override ImmutableArray<string> FixableDiagnosticIds { get; } = ImmutableArray.Create("SYSLIB0054"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.