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

CA1070: Do not use mutable struct in readonly field #3405

Closed
wants to merge 2 commits into from
Closed
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,62 @@
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Immutable;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Diagnostics;
using Analyzer.Utilities;
using Analyzer.Utilities.Extensions;

namespace Microsoft.CodeQuality.Analyzers.ApiDesignGuidelines
{
[DiagnosticAnalyzer(LanguageNames.CSharp, LanguageNames.VisualBasic)]
public sealed class DoNotUseMutableStructInReadonlyField : DiagnosticAnalyzer
{
internal const string RuleId = "CA1070";

private static readonly LocalizableString s_localizableTitle = new LocalizableResourceString(nameof(MicrosoftCodeQualityAnalyzersResources.DoNotUseMutableStructInReadonlyFieldTitle), MicrosoftCodeQualityAnalyzersResources.ResourceManager, typeof(MicrosoftCodeQualityAnalyzersResources));
private static readonly LocalizableString s_localizableMessage = new LocalizableResourceString(nameof(MicrosoftCodeQualityAnalyzersResources.DoNotUseMutableStructInReadonlyFieldMessage), MicrosoftCodeQualityAnalyzersResources.ResourceManager, typeof(MicrosoftCodeQualityAnalyzersResources));
private static readonly LocalizableString s_localizableDescription = new LocalizableResourceString(nameof(MicrosoftCodeQualityAnalyzersResources.DoNotUseMutableStructInReadonlyFieldDescription), MicrosoftCodeQualityAnalyzersResources.ResourceManager, typeof(MicrosoftCodeQualityAnalyzersResources));

internal static DiagnosticDescriptor Rule =
DiagnosticDescriptorHelper.Create(
RuleId,
s_localizableTitle,
s_localizableMessage,
DiagnosticCategory.Design,
RuleLevel.BuildWarningCandidate,
s_localizableDescription,
isPortedFxCopRule: true,
isDataflowRule: false);

public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics { get; } = ImmutableArray.Create(Rule);

public override void Initialize(AnalysisContext analysisContext)
{
analysisContext.EnableConcurrentExecution();
analysisContext.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);

analysisContext.RegisterCompilationStartAction(context =>
{
var spinLockType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemThreadingSpinLock);
var gcHandleType = context.Compilation.GetOrCreateTypeByMetadataName(WellKnownTypeNames.SystemRuntimeInteropServicesGCHandle);

context.RegisterSymbolAction(context =>
{
var field = (IFieldSymbol)context.Symbol;

if (!field.IsReadOnly ||
field.Type?.TypeKind != TypeKind.Struct)
{
return;
}

if (field.Type.Equals(spinLockType) ||
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only looking at field type as @stephentoub was suggesting. We could make the rule more advanced and look at mutation calls rather than field definition.

field.Type.Equals(gcHandleType))
{
context.ReportDiagnostic(field.CreateDiagnostic(Rule));
}
}, SymbolKind.Field);
});
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1370,4 +1370,13 @@
<data name="EnumShouldNotHaveDuplicatedValuesTitle" xml:space="preserve">
<value>Enums values should not be duplicated</value>
</data>
<data name="DoNotUseMutableStructInReadonlyFieldDescription" xml:space="preserve">
<value>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</value>
</data>
<data name="DoNotUseMutableStructInReadonlyFieldMessage" xml:space="preserve">
<value>Do not use mutable struct in readonly field</value>
</data>
<data name="DoNotUseMutableStructInReadonlyFieldTitle" xml:space="preserve">
<value>Do not use mutable struct in readonly field</value>
</data>
</root>
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Neukládejte asynchronní výrazy lambda jako typy delegátů vracející hodnotu Void.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">Odkaz na pole {0} je v této bitové inicializaci duplicitní.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Async-Lambdas nicht als "Void" zurückgebende Delegattypen speichern</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">Der Feldverweis "{0}" wird in dieser bitweisen Initialisierung dupliziert.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">No almacenar expresiones lambda asincrónicas como void que devuelve tipos de delegado</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">La referencia de campo "{0}" está duplicada en esta inicialización bit a bit.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Ne pas stocker de lambdas asynchrones en tant que types délégués retournant void</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">La référence de champ '{0}' est dupliquée dans cette initialisation au niveau du bit.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Non archiviare espressioni lambda asincrone come tipi delegati che restituiscono void</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">Il riferimento al campo '{0}' è duplicato in questa inizializzazione bit per bit.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">デリゲート型を返す Void として非同期ラムダを格納しないでください</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">フィールド参照 '{0}' は、このビット単位の初期化で重複しています。</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">비동기 람다를 Void 반환 대리자 형식으로 저장하지 마세요.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">이 비트 초기화에서 필드 참조 '{0}'이(가) 중복되었습니다.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Nie przechowuj asynchronicznych wyrażeń lambda jako typów delegatów zwracających typ void</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">Odwołanie do pola „{0}” jest zduplikowane w tym inicjowaniu bitowym.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Não armazenar lambdas assíncronas como tipos delegados que retornam void</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">A referência de campo '{0}' está duplicada nesta inicialização bit a bit.</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,21 @@
<target state="translated">Не храните асинхронные лямбда-выражения как Void, возвращающие типы делегатов</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldDescription">
<source>Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</source>
<target state="new">Making a mutable struct a readonly field can result in silent but significant problems as any mutatin to the instance will be done on a compiler-generated copy and thus ignored.</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldMessage">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="DoNotUseMutableStructInReadonlyFieldTitle">
<source>Do not use mutable struct in readonly field</source>
<target state="new">Do not use mutable struct in readonly field</target>
<note />
</trans-unit>
<trans-unit id="EnumShouldNotHaveDuplicatedValuesMessageDuplicatedBitwiseValuePart">
<source>The field reference '{0}' is duplicated in this bitwise initialization.</source>
<target state="translated">Ссылка на поле "{0}" дублируется в этой побитовой инициализации.</target>
Expand Down
Loading