Skip to content

Commit

Permalink
Add UseVolatileReadWriteAnalyzer (#7043)
Browse files Browse the repository at this point in the history
* 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
CollinAlpert authored Mar 12, 2024
1 parent 94749ce commit d98dd32
Show file tree
Hide file tree
Showing 19 changed files with 1,164 additions and 0 deletions.
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));
}
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2147,4 +2147,7 @@ Widening and user defined conversions are not supported with generic types.</val
<data name="DoNotCompareSpanToNullIsEmptyCodeFixTitle" xml:space="preserve">
<value>Use 'IsEmpty'</value>
</data>
<data name="DoNotUseThreadVolatileReadWriteCodeFixTitle" xml:space="preserve">
<value>Replace obsolete call</value>
</data>
</root>
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");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Obecné přetypování (IL unbox.any) používané sekvencí vrácenou metodou E
<target state="translated">Nepoužívat stackalloc ve smyčkách</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Častější pravidelná aktivita bude zatěžovat procesor a ovlivňovat časovače neaktivity, které šetří energii a vypínají displej a pevné disky.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Erweiterungen und benutzerdefinierte Konvertierungen werden bei generischen Type
<target state="translated">stackalloc nicht in Schleifen verwenden</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Regelmäßige Aktivitäten mit einer höheren Frequenz belasten die CPU und beeinflussen energiesparende Leerlauftimer, mit denen die Anzeige sowie die Festplatten ausgeschaltet werden.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ La ampliación y las conversiones definidas por el usuario no se admiten con tip
<target state="translated">No utilizar stackalloc en los bucles</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Una actividad periódica más frecuente ocupará la CPU e interferirá con los temporizadores de inactividad para ahorro de energía que apagan el monitor y los discos duros.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Les conversions étendues et définies par l’utilisateur ne sont pas prises en
<target state="translated">N'utilisez pas stackalloc dans les boucles</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Une activité régulière à plus grande fréquence occupe le processeur et interfère avec les minuteurs d'inactivité qui déclenchent la mise en veille de l'écran et des disques durs pour économiser de l'énergie.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ L'ampliamento e le conversioni definite dall'utente non sono supportate con tipi
<target state="translated">Non usare stackalloc nei cicli</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Un'attività periodica più frequente tiene la CPU occupata e interferisce con i timer di inattività per il risparmio di energia che disattivano lo schermo e i dischi rigidi.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Enumerable.OfType&lt;T&gt; で使用されるジェネリック型チェック (
<target state="translated">stackalloc はループ内で使用不可</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">頻度の高い定期的な動作は CPU のビジー状態を維持し、画面およびハード ディスクの電源を切る節電アイドル タイマーに影響します。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Enumerable.OfType&lt;T&gt;에서 사용하는 제네릭 형식 검사(C# 'is'
<target state="translated">루프에서 stackalloc을 사용하면 안 됨</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">정기적인 작업의 실행 빈도가 높아지면 CPU 사용률도 높아져 디스플레이 및 하드 디스크를 끄는 절전 유휴 타이머에 방해가 됩니다.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Konwersje poszerzane i zdefiniowane przez użytkownika nie są obsługiwane w pr
<target state="translated">Nie używaj słowa kluczowego stackalloc w pętlach</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Działania okresowe wykonywane z dużą częstotliwością utrzymują zajętość procesora CPU i wpływają na czasomierze bezczynności funkcji oszczędzania energii, które powodują wyłączanie ekranu i dysków twardych.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Ampliação e conversões definidas pelo usuário não são compatíveis com tip
<target state="translated">Não use stackalloc em loops</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Atividade periódica de alta frequência manterá a CPU ocupada e interferirá nos medidores de tempo ocioso para economia de energia que desligam o visor e os discos rígidos.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Widening and user defined conversions are not supported with generic types.</sou
<target state="translated">Запрет использования stackalloc в циклах</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Периодическая активность с более высокой частотой заставит ЦП переключаться в активный режим и помешает работе энергосберегающих таймеров простоя, которые отключают дисплей и жесткие диски.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Genel türlerde genişletme ve kullanıcı tanımlı dönüştürmeler desteklen
<target state="translated">Döngüler içinde stackalloc kullanmayın</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">Daha yüksek frekanslı düzenli etkinlik, CPU’nun meşgul kalmasına neden olmasının yanı sıra ekranı ve sabit diskleri kapatarak güç tasarrufu sağlayan boşta süreölçerlerini etkileyebilir.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Enumerable.OfType&lt;T&gt; 使用的泛型类型检查 (C# 'is' operator/IL 'isi
<target state="translated">不要循环使用 stackalloc</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">频率较高的定期活动会使 CPU 处于忙状态并且干扰具有节能功能(关闭显示器和硬盘)的空闲计时器。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1163,6 +1163,11 @@ Enumerable.OfType&lt;T&gt; 使用的一般型別檢查 (C# 'is' operator/IL 'isi
<target state="translated">請勿在迴圈中使用 stackalloc</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseThreadVolatileReadWriteCodeFixTitle">
<source>Replace obsolete call</source>
<target state="new">Replace obsolete call</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseTimersThatPreventPowerStateChangesDescription">
<source>Higher-frequency periodic activity will keep the CPU busy and interfere with power-saving idle timers that turn off the display and hard disks.</source>
<target state="translated">更高頻率的週期性活動,會讓 CPU 一直處於忙碌狀態,且會干擾關閉顯示器與硬碟的省電閒置計時器。</target>
Expand Down
Loading

0 comments on commit d98dd32

Please sign in to comment.