diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
index f248575e467bb..c4a127094f72d 100644
--- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
+++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzers.projitems
@@ -74,6 +74,7 @@
+
diff --git a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx
index 622002791820c..6bc5a997a5b67 100644
--- a/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx
+++ b/src/Analyzers/CSharp/Analyzers/CSharpAnalyzersResources.resx
@@ -434,4 +434,10 @@
Implement with Copilot
+
+ Simplify property accessor
+
+
+ Property accessor can be simplified
+
\ No newline at end of file
diff --git a/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs b/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs
index 0e5b54eb44ac0..15938f5da924f 100644
--- a/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs
+++ b/src/Analyzers/CSharp/Analyzers/CodeStyle/CSharpAnalyzerOptionsProvider.cs
@@ -71,6 +71,7 @@ internal CSharpSimplifierOptions GetSimplifierOptions()
public CodeStyleOption2 PreferPrimaryConstructors => GetOption(CSharpCodeStyleOptions.PreferPrimaryConstructors);
public CodeStyleOption2 PreferSystemThreadingLock => GetOption(CSharpCodeStyleOptions.PreferSystemThreadingLock);
public CodeStyleOption2 PreferUnboundGenericTypeInNameOf => GetOption(CSharpCodeStyleOptions.PreferUnboundGenericTypeInNameOf);
+ public CodeStyleOption2 PreferSimplePropertyAccessors => GetOption(CSharpCodeStyleOptions.PreferSimplePropertyAccessors);
// CodeGenerationOptions
diff --git a/src/Analyzers/CSharp/Analyzers/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorDiagnosticAnalyzer.cs b/src/Analyzers/CSharp/Analyzers/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorDiagnosticAnalyzer.cs
new file mode 100644
index 0000000000000..f104c65de68c8
--- /dev/null
+++ b/src/Analyzers/CSharp/Analyzers/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorDiagnosticAnalyzer.cs
@@ -0,0 +1,101 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Linq;
+using Microsoft.CodeAnalysis.CodeStyle;
+using Microsoft.CodeAnalysis.CSharp.CodeStyle;
+using Microsoft.CodeAnalysis.CSharp.Extensions;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+
+namespace Microsoft.CodeAnalysis.CSharp.SimplifyPropertyAccessor;
+
+[DiagnosticAnalyzer(LanguageNames.CSharp)]
+internal sealed class CSharpSimplifyPropertyAccessorDiagnosticAnalyzer : AbstractBuiltInCodeStyleDiagnosticAnalyzer
+{
+ public CSharpSimplifyPropertyAccessorDiagnosticAnalyzer()
+ : base(IDEDiagnosticIds.SimplifyPropertyAccessorDiagnosticId,
+ EnforceOnBuildValues.SimplifyPropertyAccessor,
+ CSharpCodeStyleOptions.PreferSimplePropertyAccessors,
+ new LocalizableResourceString(nameof(CSharpAnalyzersResources.Simplify_property_accessor), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)),
+ new LocalizableResourceString(nameof(CSharpAnalyzersResources.Property_accessor_can_be_simplified), CSharpAnalyzersResources.ResourceManager, typeof(CSharpAnalyzersResources)))
+ {
+ }
+
+ public override DiagnosticAnalyzerCategory GetAnalyzerCategory()
+ => DiagnosticAnalyzerCategory.SyntaxTreeWithoutSemanticsAnalysis;
+
+ protected override void InitializeWorker(AnalysisContext context)
+ => context.RegisterSyntaxNodeAction(AnalyzePropertyDeclaration, SyntaxKind.PropertyDeclaration);
+
+ private void AnalyzePropertyDeclaration(SyntaxNodeAnalysisContext context)
+ {
+ var option = context.GetCSharpAnalyzerOptions().PreferSimplePropertyAccessors;
+ if (!option.Value || ShouldSkipAnalysis(context, option.Notification))
+ return;
+
+ var propertyDeclaration = (PropertyDeclarationSyntax)context.Node;
+
+ if (propertyDeclaration.AccessorList is not { } accessorList ||
+ accessorList.GetDiagnostics().Any(d => d.Severity == DiagnosticSeverity.Error))
+ {
+ return;
+ }
+
+ foreach (var accessor in accessorList.Accessors)
+ {
+ // get { return field; }
+ // get => field;
+ if (accessor is (SyntaxKind.GetAccessorDeclaration) { Body.Statements: [ReturnStatementSyntax { Expression.RawKind: (int)SyntaxKind.FieldExpression }] }
+ or (SyntaxKind.GetAccessorDeclaration) { ExpressionBody.Expression.RawKind: (int)SyntaxKind.FieldExpression })
+ {
+ ReportIfValid(accessor);
+ }
+
+ // set/init { field = value; }
+ if (accessor is (SyntaxKind.SetAccessorDeclaration or SyntaxKind.InitAccessorDeclaration) { Body.Statements: [ExpressionStatementSyntax { Expression: var innerBlockBodyExpression }] } &&
+ IsFieldValueAssignmentExpression(innerBlockBodyExpression))
+ {
+ ReportIfValid(accessor);
+ }
+
+ // set/init => field = value;
+ if (accessor is (SyntaxKind.SetAccessorDeclaration or SyntaxKind.InitAccessorDeclaration) { ExpressionBody.Expression: var innerExpressionBodyExpression } &&
+ IsFieldValueAssignmentExpression(innerExpressionBodyExpression))
+ {
+ ReportIfValid(accessor);
+ }
+ }
+
+ static bool IsFieldValueAssignmentExpression(ExpressionSyntax expression)
+ {
+ return expression is AssignmentExpressionSyntax(SyntaxKind.SimpleAssignmentExpression)
+ {
+ Left.RawKind: (int)SyntaxKind.FieldExpression,
+ Right: IdentifierNameSyntax { Identifier.ValueText: "value" }
+ };
+ }
+
+ void ReportIfValid(AccessorDeclarationSyntax accessorDeclaration)
+ {
+ // If we are analyzing an accessor of a partial property and all other accessors have no bodies
+ // then if we simplify our current accessor the property will no longer be a valid
+ // implementation part. Thus we block that case
+ if (accessorDeclaration is { Parent: AccessorListSyntax { Parent: BasePropertyDeclarationSyntax containingPropertyDeclaration } containingAccessorList } &&
+ containingPropertyDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) &&
+ containingAccessorList.Accessors.All(a => ReferenceEquals(a, accessorDeclaration) || a is { Body: null, ExpressionBody: null }))
+ {
+ return;
+ }
+
+ context.ReportDiagnostic(DiagnosticHelper.Create(
+ Descriptor,
+ accessorDeclaration.GetLocation(),
+ option.Notification,
+ context.Options,
+ additionalLocations: null,
+ properties: null));
+ }
+ }
+}
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf
index 576a142a0ecc7..814d529007007 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.cs.xlf
@@ -177,6 +177,11 @@
Upřednostňovat kontrolu hodnoty null před kontrolou typu
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Vzor vlastnosti se dá zjednodušit.
@@ -222,6 +227,11 @@
Zjednodušit vyvolání delegáta
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Zjednodušit vzor vlastnosti
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf
index 96dccc829b54f..2d855adab93e4 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.de.xlf
@@ -177,6 +177,11 @@
„NULL“-Überprüfung vor Typüberprüfung bevorzugen
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Das Eigenschaftsmuster kann vereinfacht werden.
@@ -222,6 +227,11 @@
Vereinfachen des Delegatenaufrufs
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Eigenschaftenmuster vereinfachen
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf
index 808bededb715e..d55ce9d83f905 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.es.xlf
@@ -177,6 +177,11 @@
Preferir comprobación "null' sobre comprobación de tipo
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
El patrón de propiedad puede ser simplificado
@@ -222,6 +227,11 @@
Simplificar la invocación del delegado
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Simplificar el patrón de propiedad
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf
index 7125923272b2b..9a10359b62b32 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.fr.xlf
@@ -177,6 +177,11 @@
Préférer la vérification « null » à la vérification de type
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Le modèle de propriété peut être simplifié
@@ -222,6 +227,11 @@
Simplifier l’appel du délégué
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Simplifier le modèle de propriété
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf
index 1c47f131846cf..aaab6c822a1ce 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.it.xlf
@@ -177,6 +177,11 @@
Preferisci il controllo 'null' al controllo del tipo
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Il modello di proprietà può essere semplificato
@@ -222,6 +227,11 @@
Semplifica la chiamata del delegato
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Semplifica il modello di proprietà
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf
index 498434b70baad..82e40a16053c8 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ja.xlf
@@ -177,6 +177,11 @@
型のチェックよりも 'null 値' チェックを優先する
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
プロパティ パターンは簡略化できます
@@ -222,6 +227,11 @@
デリゲートの呼び出しを簡略化する
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
プロパティ パターンを簡略化する
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf
index 38e28ac74b712..cbf7dbabbfb2f 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ko.xlf
@@ -177,6 +177,11 @@
형식 검사보다 'null' 검사 선호
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
속성 패턴을 간소화할 수 있습니다.
@@ -222,6 +227,11 @@
대리자 호출 간소화
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
속성 패턴 간소화
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf
index 6df51c97b6ce0..c7fa53568ddc9 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pl.xlf
@@ -177,6 +177,11 @@
Ustaw preferencje na sprawdzanie wartości „null” zamiast sprawdzania typu
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Wzorzec właściwości można uprościć
@@ -222,6 +227,11 @@
Uprość wywołanie delegata
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Uprość wzorzec właściwości
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf
index 3d1c3ff54e34e..b5b883dad260c 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.pt-BR.xlf
@@ -177,6 +177,11 @@
Preferir a verificação 'nula' à verificação de tipo
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
O padrão da propriedade pode ser simplificado
@@ -222,6 +227,11 @@
Simplificar invocação de delegado
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Simplificar o padrão de propriedade
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf
index f4c2e65836c99..5cca32124a9e3 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.ru.xlf
@@ -177,6 +177,11 @@
Предпочитать проверку "null" проверке типа
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Шаблон свойства можно упростить
@@ -222,6 +227,11 @@
Упростить вызов делегата
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Упростить шаблон свойства
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf
index fd2429f73c4f1..140bb46e3c161 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.tr.xlf
@@ -177,6 +177,11 @@
Tür denetimi yerine 'null' denetimini tercih et
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
Özellik deseni basitleştirilebilir
@@ -222,6 +227,11 @@
Temsilci çağırmayı basitleştir
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
Özellik desenini basitleştir
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf
index e86aa58e241ca..a600214b8837e 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hans.xlf
@@ -177,6 +177,11 @@
与类型检查相比,首选 “Null” 检查
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
可以简化属性模式
@@ -222,6 +227,11 @@
简化委托调用
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
简化属性模式
diff --git a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf
index c2ee335464254..4019df8915df7 100644
--- a/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf
+++ b/src/Analyzers/CSharp/Analyzers/xlf/CSharpAnalyzersResources.zh-Hant.xlf
@@ -177,6 +177,11 @@
建議使用 'null' 檢查而非鍵入檢查
+
+ Property accessor can be simplified
+ Property accessor can be simplified
+
+
Property pattern can be simplified
可簡化屬性模式
@@ -222,6 +227,11 @@
簡化委派引動
+
+ Simplify property accessor
+ Simplify property accessor
+
+
Simplify property pattern
簡化屬性模式
diff --git a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems
index 63971fc537b83..968dd83fb7ec0 100644
--- a/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems
+++ b/src/Analyzers/CSharp/CodeFixes/CSharpCodeFixes.projitems
@@ -93,6 +93,7 @@
+
diff --git a/src/Analyzers/CSharp/CodeFixes/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorCodeFixProvider.cs b/src/Analyzers/CSharp/CodeFixes/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorCodeFixProvider.cs
new file mode 100644
index 0000000000000..e52ed94b96f79
--- /dev/null
+++ b/src/Analyzers/CSharp/CodeFixes/SimplifyPropertyAccessor/CSharpSimplifyPropertyAccessorCodeFixProvider.cs
@@ -0,0 +1,74 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Collections.Immutable;
+using System.Composition;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CodeFixes;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using Microsoft.CodeAnalysis.Diagnostics;
+using Microsoft.CodeAnalysis.Editing;
+using Microsoft.CodeAnalysis.Formatting;
+using Microsoft.CodeAnalysis.Host.Mef;
+using Microsoft.CodeAnalysis.PooledObjects;
+using Microsoft.CodeAnalysis.Shared.Extensions;
+
+namespace Microsoft.CodeAnalysis.CSharp.SimplifyPropertyAccessor;
+
+using static CSharpSyntaxTokens;
+
+[ExportCodeFixProvider(LanguageNames.CSharp, Name = PredefinedCodeFixProviderNames.SimplifyPropertyAccessor), Shared]
+[method: ImportingConstructor]
+[method: Obsolete(MefConstruction.ImportingConstructorMessage, error: true)]
+internal sealed class CSharpSimplifyPropertyAccessorCodeFixProvider() : SyntaxEditorBasedCodeFixProvider
+{
+ public override ImmutableArray FixableDiagnosticIds { get; }
+ = [IDEDiagnosticIds.SimplifyPropertyAccessorDiagnosticId];
+
+ public override Task RegisterCodeFixesAsync(CodeFixContext context)
+ {
+ RegisterCodeFix(context, CSharpAnalyzersResources.Simplify_property_accessor, nameof(CSharpAnalyzersResources.Simplify_property_accessor));
+ return Task.CompletedTask;
+ }
+
+ protected override Task FixAllAsync(Document document, ImmutableArray diagnostics, SyntaxEditor editor, CancellationToken cancellationToken)
+ {
+ using var _ = PooledHashSet.GetInstance(out var seenPartialProperties);
+
+ foreach (var diagnostic in diagnostics)
+ {
+ var accessor = (AccessorDeclarationSyntax)diagnostic.Location.FindNode(cancellationToken);
+
+ // If this accessor belongs to a partial property remember that property.
+ // If we later find another accessor of the same partial property, we reject the fix.
+ // This is a case where both accessors of a partial property implementation part
+ // are potentially simplifiable and we are performing a fix-all.
+ // Analyzer reports both accessors since simplifying each individually won't break anything
+ // but if we "fix" both the property won't be a valid partial implementation part anymore.
+ // Therefore we fix only the first accessor we encounter
+ if (accessor.Parent?.Parent is PropertyDeclarationSyntax containingProperty &&
+ containingProperty.Modifiers.Any(SyntaxKind.PartialKeyword) &&
+ !seenPartialProperties.Add(containingProperty))
+ {
+ continue;
+ }
+
+ var fixedAccessor = accessor
+ .WithBody(null)
+ .WithExpressionBody(null);
+
+ if (fixedAccessor.SemicolonToken == default)
+ {
+ fixedAccessor = fixedAccessor.WithSemicolonToken(
+ SemicolonToken.WithTrailingTrivia(accessor.GetTrailingTrivia()));
+ }
+
+ editor.ReplaceNode(accessor, fixedAccessor.WithAdditionalAnnotations(Formatter.Annotation));
+ }
+
+ return Task.CompletedTask;
+ }
+}
diff --git a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
index 26423cafb96a6..bd9e6cf7e6502 100644
--- a/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
+++ b/src/Analyzers/CSharp/Tests/CSharpAnalyzers.UnitTests.projitems
@@ -99,6 +99,7 @@
+
diff --git a/src/Analyzers/CSharp/Tests/SimplifyPropertyAccessor/SimplifyPropertyAccessorTests.cs b/src/Analyzers/CSharp/Tests/SimplifyPropertyAccessor/SimplifyPropertyAccessorTests.cs
new file mode 100644
index 0000000000000..be0f1644c9f56
--- /dev/null
+++ b/src/Analyzers/CSharp/Tests/SimplifyPropertyAccessor/SimplifyPropertyAccessorTests.cs
@@ -0,0 +1,529 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Threading.Tasks;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.CodeStyle;
+using Microsoft.CodeAnalysis.CSharp.SimplifyPropertyAccessor;
+using Microsoft.CodeAnalysis.Editor.UnitTests.CodeActions;
+using Microsoft.CodeAnalysis.Test.Utilities;
+using Microsoft.CodeAnalysis.Testing;
+using Xunit;
+
+namespace Microsoft.CodeAnalysis.Editor.CSharp.UnitTests.SimplifyPropertyAccessor;
+
+using VerifyCS = CSharpCodeFixVerifier<
+ CSharpSimplifyPropertyAccessorDiagnosticAnalyzer,
+ CSharpSimplifyPropertyAccessorCodeFixProvider>;
+
+[Trait(Traits.Feature, Traits.Features.CodeActionsSimplifyPropertyAccessor)]
+public sealed class SimplifyPropertyAccessorTests
+{
+ private static async Task TestAsync(
+ [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string markup,
+ LanguageVersion languageVersion = LanguageVersion.CSharp14)
+ {
+ await new VerifyCS.Test
+ {
+ TestCode = markup,
+ FixedCode = markup,
+ LanguageVersion = languageVersion,
+ }.RunAsync();
+ }
+
+ private static async Task TestAsync(
+ [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string initialMarkup,
+ [StringSyntax(PredefinedEmbeddedLanguageNames.CSharpTest)] string fixedMarkup)
+ {
+ await new VerifyCS.Test
+ {
+ TestCode = initialMarkup,
+ FixedCode = fixedMarkup,
+ LanguageVersion = LanguageVersion.CSharp14,
+ ReferenceAssemblies = ReferenceAssemblies.Net.Net80, // for 'IsExternalInit' type
+ }.RunAsync();
+ }
+
+ public static IEnumerable SimplifiableGetterBodies => ["{ return field; }", "=> field;"];
+
+ public static IEnumerable TrailingTrivia => ["", " // useful comment"];
+
+ public static IEnumerable SimplifiableSetterBodies => ["{ field = value; }", "=> field = value;"];
+
+ public static IEnumerable SetInitKeywords => ["set", "init"];
+
+ [Fact]
+ public async Task NotInCSharpVersionBefore14()
+ {
+ // 'field' is not even parsed as a keyword before C# 14, but let's test this anyway
+ await TestAsync("""
+ class C
+ {
+ public int Prop
+ {
+ get => {|CS0103:field|};
+ set => {|CS0103:field|} = value;
+ }
+ }
+ """, LanguageVersion.CSharp13);
+ }
+
+ [Fact]
+ public async Task NotWhenOptionIsDisabled()
+ {
+ var code = """
+ class C
+ {
+ public int Prop
+ {
+ get => field;
+ set => field = value;
+ }
+ }
+ """;
+
+ await new VerifyCS.Test
+ {
+ TestCode = code,
+ FixedCode = code,
+ LanguageVersion = LanguageVersion.CSharp14,
+ Options =
+ {
+ { CSharpCodeStyleOptions.PreferSimplePropertyAccessors, false }
+ }
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task NotWhenAccessorHasSyntaxError()
+ {
+ var code = """
+ class C
+ {
+ public int Prop
+ {
+ get => field{|CS1002:|}
+ set { field = value {|CS1002:}|}
+ }
+ }
+ """;
+
+ await new VerifyCS.Test
+ {
+ TestCode = code,
+ FixedCode = code,
+ LanguageVersion = LanguageVersion.CSharp14
+ }.RunAsync();
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public async Task SimpleGetter(
+ [CombinatorialMemberData(nameof(SimplifiableGetterBodies))] string getterBody,
+ [CombinatorialMemberData(nameof(TrailingTrivia))] string trailingTrivia)
+ {
+ await TestAsync($$"""
+ class C
+ {
+ public int Prop
+ {
+ [|get {{getterBody}}|]{{trailingTrivia}}
+ set;
+ }
+ }
+ """, $$"""
+ class C
+ {
+ public int Prop
+ {
+ get;{{trailingTrivia}}
+ set;
+ }
+ }
+ """);
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public async Task SimpleSetter(
+ [CombinatorialMemberData(nameof(SetInitKeywords))] string setterKeyword,
+ [CombinatorialMemberData(nameof(SimplifiableSetterBodies))] string setterBody,
+ [CombinatorialMemberData(nameof(TrailingTrivia))] string trailingTrivia)
+ {
+ await TestAsync($$"""
+ class C
+ {
+ public int Prop
+ {
+ get;
+ [|{{setterKeyword}} {{setterBody}}|]{{trailingTrivia}}
+ }
+ }
+ """, $$"""
+ class C
+ {
+ public int Prop
+ {
+ get;
+ {{setterKeyword}};{{trailingTrivia}}
+ }
+ }
+ """);
+ }
+
+ [Theory]
+ [CombinatorialData]
+ public async Task FixAll(
+ [CombinatorialMemberData(nameof(SimplifiableGetterBodies))] string getterBody,
+ [CombinatorialMemberData(nameof(TrailingTrivia))] string getterTrailingTrivia,
+ [CombinatorialMemberData(nameof(SetInitKeywords))] string setterKeyword,
+ [CombinatorialMemberData(nameof(SimplifiableSetterBodies))] string setterBody,
+ [CombinatorialMemberData(nameof(TrailingTrivia))] string setterTrailingTrivia)
+ {
+ await TestAsync($$"""
+ class C
+ {
+ public int Prop
+ {
+ [|get {{getterBody}}|]{{getterTrailingTrivia}}
+ [|{{setterKeyword}} {{setterBody}}|]{{setterTrailingTrivia}}
+ }
+ }
+ """, $$"""
+ class C
+ {
+ public int Prop
+ {
+ get;{{getterTrailingTrivia}}
+ {{setterKeyword}};{{setterTrailingTrivia}}
+ }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task NotWhenPropertyHasNoAccessors()
+ {
+ // Just to verify we do not crash etc.
+ await TestAsync("""
+ class C
+ {
+ public int {|CS0548:Prop|} { }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task EvenWhenPropertyHasTooManyAccessors()
+ {
+ await new VerifyCS.Test()
+ {
+ TestCode = """
+ class C
+ {
+ public int Prop { [|get { return field; }|] [|set => field = value;|] [|init { field = value; }|] }
+ }
+ """,
+ FixedCode = """
+ class C
+ {
+ public int Prop { get; set; init; }
+ }
+ """,
+ LanguageVersion = LanguageVersion.CSharp14,
+ CompilerDiagnostics = CompilerDiagnostics.None,
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task EvenWhenPropertyHasDuplicateAccessors()
+ {
+ await new VerifyCS.Test()
+ {
+ TestCode = """
+ class C
+ {
+ public int Prop { [|get { return field; }|] [|get => field;|] }
+ }
+ """,
+ FixedCode = """
+ class C
+ {
+ public int Prop { get; get; }
+ }
+ """,
+ LanguageVersion = LanguageVersion.CSharp14,
+ CompilerDiagnostics = CompilerDiagnostics.None,
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task NotOnIndexerAccessor()
+ {
+ // Again 'field' is not even parsed as a keyword
+ await TestAsync("""
+ class C
+ {
+ public int this[int i]
+ {
+ get => {|CS0103:field|};
+ set => {|CS0103:field|} = value;
+ }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task NotOnPropertyLikeEventAccessor()
+ {
+ // 'field' keyword? Never heard of that thing...
+ await TestAsync("""
+ using System;
+
+ class C
+ {
+ public event EventHandler Tested
+ {
+ add => {|CS0201:{|CS0103:field|}|};
+ remove => {|CS0103:field|} = value;
+ }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task NotOnPartialPropertyImplementationWithAnotherAccessorEmpty_Get()
+ {
+ await TestAsync("""
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ public partial int Prop { get => field; set; }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task NotOnPartialPropertyImplementationWithAnotherAccessorEmpty_Set()
+ {
+ await TestAsync("""
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ public partial int Prop { get; set { field = value; } }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task PartialPropertyImplementation_BothAccessors1()
+ {
+ await TestAsync("""
+ partial class C
+ {
+ public partial int Prop { get; set; }
+
+ public partial int Prop
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+
+ public partial int Prop
+ {
+ get;
+ set { field = value; }
+ }
+ }
+ """);
+ }
+
+ [Fact]
+ public async Task PartialPropertyImplementation_BothAccessors1_DifferentFiles()
+ {
+ await new VerifyCS.Test
+ {
+ TestState =
+ {
+ Sources =
+ {
+ """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+ }
+ """
+ }
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop
+ {
+ get;
+ set { field = value; }
+ }
+ }
+ """
+ }
+ },
+ LanguageVersion = LanguageVersion.CSharp14,
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task PartialPropertyImplementation_BothAccessors2()
+ {
+ await new VerifyCS.Test
+ {
+ TestCode = """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+
+ public partial int Prop
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+ }
+ """,
+ FixedCode = """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+
+ public partial int Prop
+ {
+ get => field;
+ set;
+ }
+ }
+ """,
+ LanguageVersion = LanguageVersion.CSharp14,
+ CodeFixTestBehaviors = CodeFixTestBehaviors.SkipFixAllCheck | CodeFixTestBehaviors.FixOne,
+ DiagnosticSelector = diagnostics => diagnostics[1],
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task PartialPropertyImplementation_BothAccessors2_DifferentFiles()
+ {
+ await new VerifyCS.Test
+ {
+ TestState =
+ {
+ Sources =
+ {
+ """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+ }
+ """
+ }
+ },
+ FixedState =
+ {
+ Sources =
+ {
+ """
+ partial class C
+ {
+ public partial int Prop { get; set; }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop
+ {
+ get => field;
+ set;
+ }
+ }
+ """
+ }
+ },
+ LanguageVersion = LanguageVersion.CSharp14,
+ CodeFixTestBehaviors = CodeFixTestBehaviors.SkipFixAllCheck | CodeFixTestBehaviors.FixOne,
+ DiagnosticSelector = diagnostics => diagnostics[1],
+ }.RunAsync();
+ }
+
+ [Fact]
+ public async Task MultiplePartialPropertyImplementationsWithBothAccessors()
+ {
+ await TestAsync("""
+ partial class C
+ {
+ public partial int Prop1 { get; set; }
+ public partial string Prop2 { get; set; }
+
+ public partial int Prop1
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+
+ public partial string Prop2
+ {
+ [|get => field;|]
+ [|set { field = value; }|]
+ }
+ }
+ """, """
+ partial class C
+ {
+ public partial int Prop1 { get; set; }
+ public partial string Prop2 { get; set; }
+
+ public partial int Prop1
+ {
+ get;
+ set { field = value; }
+ }
+
+ public partial string Prop2
+ {
+ get;
+ set { field = value; }
+ }
+ }
+ """);
+ }
+}
diff --git a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs
index 45b60093d331d..52ee6ead8fbf8 100644
--- a/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs
+++ b/src/Analyzers/Core/Analyzers/EnforceOnBuildValues.cs
@@ -101,6 +101,7 @@ internal static class EnforceOnBuildValues
public const EnforceOnBuild UseSystemThreadingLock = /*IDE0330*/ EnforceOnBuild.Recommended;
public const EnforceOnBuild UseUnboundGenericTypeInNameOf = /*IDE0340*/ EnforceOnBuild.Recommended;
public const EnforceOnBuild UseImplicitlyTypedLambdaExpression = /*IDE0350*/ EnforceOnBuild.Recommended;
+ public const EnforceOnBuild SimplifyPropertyAccessor = /*IDE0360*/ EnforceOnBuild.Recommended;
/* EnforceOnBuild.WhenExplicitlyEnabled */
public const EnforceOnBuild RemoveUnnecessaryCast = /*IDE0004*/ EnforceOnBuild.WhenExplicitlyEnabled; // TODO: Move to 'Recommended' OR 'HighlyRecommended' bucket once performance problems are addressed: https://github.com/dotnet/roslyn/issues/43304
diff --git a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
index 5d2a44f2f4121..e3cac691d325d 100644
--- a/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
+++ b/src/Analyzers/Core/Analyzers/IDEDiagnosticIds.cs
@@ -209,6 +209,8 @@ internal static class IDEDiagnosticIds
public const string UseImplicitlyTypedLambdaExpressionDiagnosticId = "IDE0350";
+ public const string SimplifyPropertyAccessorDiagnosticId = "IDE0360";
+
// Analyzer error Ids
public const string AnalyzerChangedId = "IDE1001";
public const string AnalyzerDependencyConflictId = "IDE1002";
diff --git a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs
index 13066ab750497..d1af593b1a51c 100644
--- a/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs
+++ b/src/Analyzers/Core/CodeFixes/PredefinedCodeFixProviderNames.cs
@@ -122,6 +122,7 @@ internal static class PredefinedCodeFixProviderNames
public const string SimplifyLinqTypeCheckAndCast = nameof(SimplifyLinqTypeCheckAndCast);
public const string SimplifyNames = nameof(SimplifyNames);
public const string SimplifyObjectCreation = nameof(SimplifyObjectCreation);
+ public const string SimplifyPropertyAccessor = nameof(SimplifyPropertyAccessor);
public const string SimplifyPropertyPattern = nameof(SimplifyPropertyPattern);
public const string SimplifyThisOrMe = nameof(SimplifyThisOrMe);
public const string SpellCheck = nameof(SpellCheck);
diff --git a/src/Compilers/Test/Core/Traits/Traits.cs b/src/Compilers/Test/Core/Traits/Traits.cs
index 9be99ab4f2769..b4a2e48926f4b 100644
--- a/src/Compilers/Test/Core/Traits/Traits.cs
+++ b/src/Compilers/Test/Core/Traits/Traits.cs
@@ -175,6 +175,7 @@ public static class Features
public const string CodeActionsSimplifyInterpolation = "CodeActions.SimplifyInterpolation";
public const string CodeActionsSimplifyLinqExpression = "CodeActions.SimplifyLinqExpression";
public const string CodeActionsSimplifyLinqTypeCheckAndCast = "CodeActions.SimplifyLinqTypeCheckAndCast";
+ public const string CodeActionsSimplifyPropertyAccessor = "CodeActions.SimplifyPropertyAccessor";
public const string CodeActionsSimplifyPropertyPattern = "CodeActions.SimplifyPropertyPattern";
public const string CodeActionsSimplifyThisOrMe = "CodeActions.SimplifyThisOrMe";
public const string CodeActionsSimplifyTypeNames = "CodeActions.SimplifyTypeNames";
diff --git a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs
index ea55e2675d7f0..2207636e0c816 100644
--- a/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs
+++ b/src/EditorFeatures/Test/Diagnostics/IDEDiagnosticIDConfigurationTests.cs
@@ -499,6 +499,9 @@ public void CSharp_VerifyIDEDiagnosticSeveritiesAreConfigurable()
# IDE0350
dotnet_diagnostic.IDE0350.severity = %value%
+ # IDE0360
+ dotnet_diagnostic.IDE0360.severity = %value%
+
# IDE1005
dotnet_diagnostic.IDE1005.severity = %value%
@@ -912,6 +915,7 @@ public void CSharp_VerifyIDECodeStyleOptionsAreConfigurable()
("IDE0330", "csharp_prefer_system_threading_lock", "true"),
("IDE0340", "csharp_style_prefer_unbound_generic_type_in_nameof", "true"),
("IDE0350", "csharp_style_prefer_implicitly_typed_lambda_expression", "true"),
+ ("IDE0360", "csharp_style_prefer_simple_property_accessors", "true"),
("IDE1005", "csharp_style_conditional_delegate_call", "true"),
("IDE1006", null, null),
("IDE1007", null, null),
diff --git a/src/Features/RulesMissingDocumentation.md b/src/Features/RulesMissingDocumentation.md
index 16fad36e94713..ffc172fbb25b4 100644
--- a/src/Features/RulesMissingDocumentation.md
+++ b/src/Features/RulesMissingDocumentation.md
@@ -17,6 +17,7 @@ IDE0320 | | Use 'System.Threading.Lock' |
IDE0340 | | Use unbound generic type |
IDE0350 | | Use implicitly typed lambda |
+IDE0360 | | Simplify property accessor |
IDE1007 | | |
IDE2000 | | Avoid multiple blank lines |
IDE2001 | | Embedded statements must be on their own line |
diff --git a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs
index 5e539463775bb..61559fa4ec6a4 100644
--- a/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs
+++ b/src/VisualStudio/CSharp/Impl/EditorConfigSettings/DataProvider/CodeStyle/CSharpCodeStyleSettingsProvider.cs
@@ -116,6 +116,7 @@ private static IEnumerable GetCodeBlockCodeStyleOptions(Tiered
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferTopLevelStatements, ServicesVSResources.Prefer_top_level_statements, options, updater);
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferPrimaryConstructors, ServicesVSResources.Prefer_primary_constructors, options, updater);
yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSystemThreadingLock, ServicesVSResources.Prefer_System_Threading_Lock, options, updater);
+ yield return CodeStyleSetting.Create(CSharpCodeStyleOptions.PreferSimplePropertyAccessors, ServicesVSResources.Prefer_simple_property_accessors, options, updater);
}
private static IEnumerable GetExpressionCodeStyleOptions(TieredAnalyzerConfigOptions options, OptionUpdater updater)
diff --git a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs
index f3c391219fd97..6c46347550387 100644
--- a/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs
+++ b/src/VisualStudio/Core/Def/Options/VisualStudioOptionStorage.cs
@@ -218,6 +218,7 @@ public bool TryFetch(LocalUserRegistryOptionPersister persister, OptionKey2 opti
{"csharp_style_prefer_range_operator", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferRangeOperator")},
{"csharp_style_prefer_readonly_struct", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferReadOnlyStruct")},
{"csharp_style_prefer_readonly_struct_member", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferReadOnlyStructMember")},
+ {"csharp_style_prefer_simple_property_accessors", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferSimplePropertyAccessors")},
{"csharp_style_prefer_switch_expression", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferSwitchExpression")},
{"csharp_style_prefer_top_level_statements", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferTopLevelStatements")},
{"csharp_style_prefer_tuple_swap", new RoamingProfileStorage("TextEditor.CSharp.Specific.PreferTupleSwap")},
diff --git a/src/VisualStudio/Core/Def/ServicesVSResources.resx b/src/VisualStudio/Core/Def/ServicesVSResources.resx
index e28500734e3a0..600d3c4725dd2 100644
--- a/src/VisualStudio/Core/Def/ServicesVSResources.resx
+++ b/src/VisualStudio/Core/Def/ServicesVSResources.resx
@@ -1892,4 +1892,7 @@ Additional information: {1}
Experimental feature
This is used by the settings UI to mark experimental features.
+
+ Prefer simple property accessors
+
\ No newline at end of file
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
index 0b26b905f7de8..8b3035f1d58a3 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.cs.xlf
@@ -1122,6 +1122,11 @@
Preferovat pole s modifikátorem readonly
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Preferovat jednoduchý příkaz using
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
index 8035f25b1fc94..5f228fcab89aa 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.de.xlf
@@ -1122,6 +1122,11 @@
readonly-Felder bevorzugen
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Einfache using-Anweisung bevorzugen
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
index 4b41753ca5f3f..430a785d0ea7b 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.es.xlf
@@ -1122,6 +1122,11 @@
Preferir campos de solo lectura
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Preferir la instrucción "using" sencilla
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
index 5749db3e0e1b1..9d8fa2ebcaef5 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.fr.xlf
@@ -1122,6 +1122,11 @@
Préférer les champs readonly
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Préférer une instruction 'using' simple
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
index c7721016e89a5..5763c9972764e 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.it.xlf
@@ -1122,6 +1122,11 @@
Preferisci campi readonly
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Preferisci l'istruzione 'using' semplice
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
index 59e1d97670c06..e5412d6495713 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ja.xlf
@@ -1122,6 +1122,11 @@
readonly フィールドを優先する
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
単純な 'using' ステートメントを優先する
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
index 809d59abf787a..2482cb9cbbb03 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ko.xlf
@@ -1122,6 +1122,11 @@
읽기 전용 필드 선호
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
간단한 'using' 문 선호
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
index 41c55d7aa1c10..6f475dfd3cd55 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pl.xlf
@@ -1122,6 +1122,11 @@
Preferuj pola tylko do odczytu
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Preferuj prostą instrukcję „using”
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
index 59a6017fa1bd6..0e24721f23560 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.pt-BR.xlf
@@ -1122,6 +1122,11 @@
Preferir campos readonly
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Preferir a instrução 'using' simples
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
index 22941317b947c..6cec5615575a9 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.ru.xlf
@@ -1122,6 +1122,11 @@
Предпочитать поля только для чтения
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Предпочитать простой оператор using
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
index 4af2666078f0a..a979a27474001 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.tr.xlf
@@ -1122,6 +1122,11 @@
Saltokunur alanları tercih et
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
Basit 'using' deyimini tercih et
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
index 50bacb6e87956..41ef5c1ab21c7 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hans.xlf
@@ -1122,6 +1122,11 @@
首选只读字段
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
首选简单的 "using" 语句
diff --git a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
index a6c6d25eac1cf..b5e70be274d29 100644
--- a/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
+++ b/src/VisualStudio/Core/Def/xlf/ServicesVSResources.zh-Hant.xlf
@@ -1122,6 +1122,11 @@
優先使用唯讀欄位
+
+ Prefer simple property accessors
+ Prefer simple property accessors
+
+
Prefer simple 'using' statement
優先使用簡單的 'using' 陳述式
diff --git a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb
index 9fa99df3d2858..2f52f5d421949 100644
--- a/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb
+++ b/src/VisualStudio/Core/Test/Options/CSharpEditorConfigGeneratorTests.vb
@@ -146,6 +146,7 @@ csharp_prefer_system_threading_lock = true
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
+csharp_style_prefer_simple_property_accessors = true
csharp_style_prefer_top_level_statements = true
# Expression-level preferences
@@ -267,7 +268,7 @@ dotnet_naming_style.begins_with_i.capitalization = pascal_case
' Use the default options
Dim options = New OptionStore(workspace.GlobalOptions)
Dim groupedOptions = workspace.GetService(Of EditorConfigOptionsEnumerator).GetOptions(LanguageNames.CSharp)
- Dim actualText = EditorConfigFileGenerator.Generate(groupedOptions, Options, LanguageNames.CSharp)
+ Dim actualText = EditorConfigFileGenerator.Generate(groupedOptions, options, LanguageNames.CSharp)
AssertEx.EqualOrDiff(expectedText, actualText)
End Using
End Sub
@@ -407,6 +408,7 @@ csharp_prefer_system_threading_lock = true
csharp_style_namespace_declarations = block_scoped
csharp_style_prefer_method_group_conversion = true
csharp_style_prefer_primary_constructors = true
+csharp_style_prefer_simple_property_accessors = true
csharp_style_prefer_top_level_statements = true
# Expression-level preferences
diff --git a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs
index 1c633ea244817..ac70c33905937 100644
--- a/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs
+++ b/src/Workspaces/SharedUtilitiesAndExtensions/Compiler/CSharp/CodeStyle/CSharpCodeStyleOptions.cs
@@ -297,6 +297,11 @@ private static Option2> CreatePreferE
"csharp_style_prefer_primary_constructors",
defaultValue: CodeStyleOption2.TrueWithSuggestionEnforcement);
+ public static readonly Option2> PreferSimplePropertyAccessors = CreateOption(
+ CSharpCodeStyleOptionGroups.CodeBlockPreferences,
+ "csharp_style_prefer_simple_property_accessors",
+ defaultValue: CodeStyleOption2.TrueWithSuggestionEnforcement);
+
///
/// Options that we expect the user to set in editorconfig.
///