未验证 提交 5d671959 编写于 作者: M Manish Vasani 提交者: GitHub

Merge pull request #32063 from KristianJakubik/assigment_to_this_with_readonly_fields

Diagnostic for assignment to this with readonly fields
// 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.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.MakeStructFieldsWritable;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.Diagnostics;
using Microsoft.CodeAnalysis.Test.Utilities;
using Xunit;
using static Roslyn.Test.Utilities.TestHelpers;
namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.MakeStructFieldsWritable
{
public class MakeStructFieldsWritableTests : AbstractCSharpDiagnosticProviderBasedUserDiagnosticTest
{
internal override (DiagnosticAnalyzer, CodeFixProvider) CreateDiagnosticProviderAndFixer(Workspace workspace)
=> (new CSharpMakeStructFieldsWritableDiagnosticAnalyzer(), new CSharpMakeStructFieldsWritableCodeFixProvider());
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_ThisAssigmentInMethod()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}",
@"struct MyStruct
{
public int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_ThisAssigmentInMultipleMethods()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
public void Test2()
{
this = new MyStruct(10);
}
}",
@"struct MyStruct
{
public int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
public void Test2()
{
this = new MyStruct(10);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleNonReadonlyField_ThisAssigmentInMethod()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task MultipleMixedFields_ThisAssigmentInMethod()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int First;
public readonly int Second;
public int Third;
public MyStruct(int first, int second, int third)
{
First = first;
Second = second;
Third = third;
}
public void Test()
{
this = new MyStruct(5, 3, 1);
}
}",
@"struct MyStruct
{
public int First;
public int Second;
public int Third;
public MyStruct(int first, int second, int third)
{
First = first;
Second = second;
Third = third;
}
public void Test()
{
this = new MyStruct(5, 3, 1);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_ThisAssigmentInCtor()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
this = new MyStruct(value, 0);
}
public MyStruct(int first, int second)
{
Value = first;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_NoThisAssigment()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_ThisAssigmentInMethod_ReportDiagnostic()
{
await TestDiagnosticsAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}",
expected: Diagnostic(IDEDiagnosticIds.MakeStructFieldsWritable));
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleReadonlyField_InClass()
{
await TestDiagnosticMissingAsync(
@"class [|MyClass|]
{
public readonly int Value;
public MyClass(int value)
{
Value = value;
}
public void Test()
{
this = new MyClass(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task StructWithoutField()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public void Test()
{
this = new MyStruct();
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleProperty_ThisAssigmentInMethod()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public int Value { get; set; }
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task SingleGetterProperty_ThisAssigmentInMethod()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public int Value { get; }
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task MultipleStructDeclaration_SingleReadonlyField_ThisAssigmentInMethod()
{
await TestInRegularAndScriptAsync(
@"struct MyStruct
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}
struct [|MyStruct2|]
{
public readonly int Value;
public MyStruct2(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct2(5);
}
}",
@"struct MyStruct
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}
struct MyStruct2
{
public int Value;
public MyStruct2(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct2(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task MultipleStructDeclaration_SingleReadonlyField_ThisAssigmentInMethod_ShouldNotReportDiagnostic()
{
await TestDiagnosticMissingAsync(
@"struct [|MyStruct|]
{
public int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
}
struct MyStruct2
{
public readonly int Value;
public MyStruct2(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct2(5);
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task NestedStructDeclaration_SingleNestedReadonlyField_ThisAssigmentInMethod()
{
await TestInRegularAndScriptAsync(
@"struct MyStruct
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
struct [|NestedStruct|]
{
public readonly int NestedValue;
public NestedStruct(int nestedValue)
{
NestedValue = nestedValue;
}
public void Test()
{
this = new NestedStruct(5);
}
}
}",
@"struct MyStruct
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
struct NestedStruct
{
public int NestedValue;
public NestedStruct(int nestedValue)
{
NestedValue = nestedValue;
}
public void Test()
{
this = new NestedStruct(5);
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task NestedStructDeclaration_SingleReadonlyField_ThisAssigmentInMethod()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
struct NestedStruct
{
public readonly int NestedValue;
public NestedStruct(int nestedValue)
{
NestedValue = nestedValue;
}
public void Test()
{
this = new NestedStruct(5);
}
}
}",
@"struct MyStruct
{
public int Value;
public MyStruct(int value)
{
Value = value;
}
public void Test()
{
this = new MyStruct(5);
}
struct NestedStruct
{
public readonly int NestedValue;
public NestedStruct(int nestedValue)
{
NestedValue = nestedValue;
}
public void Test()
{
this = new NestedStruct(5);
}
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task StructDeclaration_MixedFields_MixedAssigmentsInMethods()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public int TestValue;
public MyStruct(int value)
{
Value = value;
TestValue = 100;
}
public void Test()
{
this = new MyStruct(5);
}
public void Test2()
{
TestValue = 0;
}
}",
@"struct MyStruct
{
public int Value;
public int TestValue;
public MyStruct(int value)
{
Value = value;
TestValue = 100;
}
public void Test()
{
this = new MyStruct(5);
}
public void Test2()
{
TestValue = 0;
}
}");
}
[Fact, Trait(Traits.Feature, Traits.Features.CodeActionsMakeStructFieldsWritable)]
public async Task StructDeclaration_ChangedOrderOfConstructorDeclaration()
{
await TestInRegularAndScriptAsync(
@"struct [|MyStruct|]
{
public readonly int Value;
public void Test()
{
this = new MyStruct(5);
}
public MyStruct(int value)
{
Value = value;
}
}",
@"struct MyStruct
{
public int Value;
public void Test()
{
this = new MyStruct(5);
}
public MyStruct(int value)
{
Value = value;
}
}");
}
}
}
// 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;
using System.Collections.Immutable;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.CodeActions;
using Microsoft.CodeAnalysis.CodeFixes;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Editing;
using Microsoft.CodeAnalysis.Shared.Extensions;
namespace Microsoft.CodeAnalysis.CSharp.MakeStructFieldsWritable
{
[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.MakeStructFieldsWritable), Shared]
internal class CSharpMakeStructFieldsWritableCodeFixProvider : SyntaxEditorBasedCodeFixProvider
{
public override ImmutableArray<string> FixableDiagnosticIds
=> ImmutableArray.Create(IDEDiagnosticIds.MakeStructFieldsWritable);
public override Task RegisterCodeFixesAsync(CodeFixContext context)
{
context.RegisterCodeFix(new MyCodeAction(
c => FixAsync(context.Document, context.Diagnostics[0], c)),
context.Diagnostics);
return Task.CompletedTask;
}
protected override Task FixAllAsync(
Document document,
ImmutableArray<Diagnostic> diagnostics,
SyntaxEditor editor,
CancellationToken cancellationToken)
{
foreach (var diagnostic in diagnostics)
{
var diagnosticNode = diagnostic.Location.FindNode(cancellationToken);
if (!(diagnosticNode is StructDeclarationSyntax structDeclaration))
{
continue;
}
var fieldDeclarations = structDeclaration.Members
.OfType<FieldDeclarationSyntax>();
foreach (var fieldDeclaration in fieldDeclarations)
{
var fieldDeclarationModifiers = editor.Generator.GetModifiers(fieldDeclaration);
var containsReadonlyModifier =
(fieldDeclarationModifiers & DeclarationModifiers.ReadOnly) == DeclarationModifiers.ReadOnly;
if (containsReadonlyModifier)
{
editor.SetModifiers(fieldDeclaration, fieldDeclarationModifiers.WithIsReadOnly(false));
}
}
}
return Task.CompletedTask;
}
private class MyCodeAction : CodeAction.DocumentChangeAction
{
public MyCodeAction(Func<CancellationToken, Task<Document>> createChangedDocument) :
base(FeaturesResources.Make_readonly_fields_writable, createChangedDocument)
{
}
}
}
}
// 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 System.Linq;
using Microsoft.CodeAnalysis.CodeQuality;
using Microsoft.CodeAnalysis.Diagnostics;
using Microsoft.CodeAnalysis.Operations;
namespace Microsoft.CodeAnalysis.CSharp.MakeStructFieldsWritable
{
[DiagnosticAnalyzer(LanguageNames.CSharp)]
internal sealed class CSharpMakeStructFieldsWritableDiagnosticAnalyzer : AbstractCodeQualityDiagnosticAnalyzer
{
private static readonly DiagnosticDescriptor s_diagnosticDescriptor = CreateDescriptor(
IDEDiagnosticIds.MakeStructFieldsWritable,
new LocalizableResourceString(nameof(FeaturesResources.Make_readonly_fields_writable), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
new LocalizableResourceString(nameof(FeaturesResources.Make_readonly_fields_writable), FeaturesResources.ResourceManager, typeof(FeaturesResources)),
isUnneccessary: false);
public CSharpMakeStructFieldsWritableDiagnosticAnalyzer()
: base(ImmutableArray.Create(s_diagnosticDescriptor), GeneratedCodeAnalysisFlags.ReportDiagnostics)
{
}
public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
=> DiagnosticAnalyzerCategory.SemanticDocumentAnalysis;
public override bool OpenFileOnly(Workspace workspace) => false;
protected override void InitializeWorker(AnalysisContext context)
{
context.RegisterCompilationStartAction(compilationStartContext
=> SymbolAnalyzer.CreateAndRegisterActions(compilationStartContext));
}
private sealed class SymbolAnalyzer
{
private readonly INamedTypeSymbol _namedTypeSymbol;
private bool _hasTypeInstanceAssigment;
private SymbolAnalyzer(INamedTypeSymbol namedTypeSymbol)
{
_namedTypeSymbol = namedTypeSymbol;
}
public static void CreateAndRegisterActions(CompilationStartAnalysisContext compilationStartContext)
{
compilationStartContext.RegisterSymbolStartAction(symbolStartContext =>
{
// We report diagnostic only if these requirements are met:
// 1. The type is struct
// 2. Struct contains at least one 'readonly' field
// 3. Struct contains assignment to 'this' outside the scope of constructor
var namedTypeSymbol = (INamedTypeSymbol)symbolStartContext.Symbol;
// We are only interested in struct declarations
if (namedTypeSymbol.TypeKind != TypeKind.Struct)
{
return;
}
//We check if struct contains any 'readonly' fields
if (!HasReadonlyField(namedTypeSymbol))
{
return;
}
var symbolAnalyzer = new SymbolAnalyzer(namedTypeSymbol);
symbolAnalyzer.RegisterActions(symbolStartContext);
}, SymbolKind.NamedType);
}
private static bool HasReadonlyField(INamedTypeSymbol namedTypeSymbol)
{
return namedTypeSymbol
.GetMembers()
.OfType<IFieldSymbol>()
.Where(field => field.AssociatedSymbol == null)
.Any(field => field.IsReadOnly);
}
private void RegisterActions(SymbolStartAnalysisContext symbolStartContext)
{
symbolStartContext.RegisterOperationBlockStartAction(blockAction =>
{
var isConstructor = blockAction.OwningSymbol is IMethodSymbol method &&
method.MethodKind == MethodKind.Constructor;
blockAction.RegisterOperationAction(
operationAction => AnalyzeAssignment(operationAction, isConstructor), OperationKind.SimpleAssignment);
});
symbolStartContext.RegisterSymbolEndAction(SymbolEndAction);
}
private void AnalyzeAssignment(OperationAnalysisContext operationContext, bool isConstructor)
{
// We are looking for assignment to 'this' outside the constructor scope
if (isConstructor)
{
return;
}
var operationAssigmnent = (IAssignmentOperation)operationContext.Operation;
_hasTypeInstanceAssigment |= operationAssigmnent.Target is IInstanceReferenceOperation instance &&
instance.ReferenceKind == InstanceReferenceKind.ContainingTypeInstance;
}
private void SymbolEndAction(SymbolAnalysisContext symbolEndContext)
{
if (_hasTypeInstanceAssigment)
{
var diagnostic = Diagnostic.Create(
s_diagnosticDescriptor,
_namedTypeSymbol.Locations[0]);
symbolEndContext.ReportDiagnostic(diagnostic);
}
}
}
}
}
......@@ -65,5 +65,6 @@ internal static class PredefinedCodeFixProviderNames
public const string UseObjectInitializer = nameof(UseObjectInitializer);
public const string UseThrowExpression = nameof(UseThrowExpression);
public const string PreferFrameworkType = nameof(PreferFrameworkType);
public const string MakeStructFieldsWritable = nameof(MakeStructFieldsWritable);
}
}
......@@ -105,6 +105,9 @@ internal static class IDEDiagnosticIds
public const string MakeLocalFunctionStaticDiagnosticId = "IDE0062";
public const string UseSimpleUsingStatementDiagnosticId = "IDE0063";
public const string MakeStructFieldsWritable = "IDE0064";
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
......
......@@ -2349,6 +2349,15 @@ internal class FeaturesResources {
}
}
/// <summary>
/// Looks up a localized string similar to Make readonly fields writable.
/// </summary>
internal static string Make_readonly_fields_writable {
get {
return ResourceManager.GetString("Make_readonly_fields_writable", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Member name can be simplified.
/// </summary>
......
......@@ -1637,4 +1637,8 @@ This version used in: {2}</value>
<data name="using_statement_can_be_simplified" xml:space="preserve">
<value>'using' statement can be simplified</value>
</data>
<data name="Make_readonly_fields_writable" xml:space="preserve">
<value>Make readonly fields writable</value>
<comment>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</comment>
</data>
</root>
\ No newline at end of file
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -202,6 +202,11 @@
<target state="new">Introduce query variable</target>
<note />
</trans-unit>
<trans-unit id="Make_readonly_fields_writable">
<source>Make readonly fields writable</source>
<target state="new">Make readonly fields writable</target>
<note>{Locked="readonly"} "readonly" is C# keyword and should not be localized.</note>
</trans-unit>
<trans-unit id="Invert_conditional">
<source>Invert conditional</source>
<target state="new">Invert conditional</target>
......
......@@ -102,6 +102,7 @@ public static class Features
public const string CodeActionsInvokeDelegateWithConditionalAccess = "CodeActions.InvokeDelegateWithConditionalAccess";
public const string CodeActionsLambdaSimplifier = "CodeActions.LambdaSimplifier";
public const string CodeActionsMakeFieldReadonly = "CodeActions.MakeFieldReadonly";
public const string CodeActionsMakeStructFieldsWritable = "CodeActions.MakeStructFieldsWritable";
public const string CodeActionsMakeLocalFunctionStatic = "CodeActions.MakeLocalFunctionStatic";
public const string CodeActionsMakeMethodAsynchronous = "CodeActions.MakeMethodAsynchronous";
public const string CodeActionsMakeMethodSynchronous = "CodeActions.MakeMethodSynchronous";
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册