Skip to content
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

Add UseVolatileReadWriteAnalyzer #7043

Merged
merged 15 commits into from
Mar 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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