未验证 提交 10961943 编写于 作者: S Sam Harwell 提交者: GitHub

Merge pull request #17857 from CyrusNajmabadi/codeStyleOption

Provider a user option to enable/disable the 'Use auto property' analyzer
......@@ -45,15 +45,32 @@ protected sealed override void InitializeWorker(AnalysisContext context)
private void AnalyzeSemanticModel(SemanticModelAnalysisContext context)
{
var cancellationToken = context.CancellationToken;
var semanticModel = context.SemanticModel;
// Don't even bother doing the analysis if the user doesn't even want auto-props.
var optionSet = context.Options.GetDocumentOptionSetAsync(
semanticModel.SyntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
}
var option = optionSet.GetOption(CodeStyleOptions.PreferAutoProperties, semanticModel.Language);
if (!option.Value)
{
return;
}
var analysisResults = new List<AnalysisResult>();
var ineligibleFields = new HashSet<IFieldSymbol>();
var root = context.SemanticModel.SyntaxTree.GetRoot(context.CancellationToken);
var root = semanticModel.SyntaxTree.GetRoot(cancellationToken);
AnalyzeCompilationUnit(context, root, analysisResults);
RegisterIneligibleFieldsAction(
analysisResults, ineligibleFields,
context.SemanticModel.Compilation, context.CancellationToken);
semanticModel.Compilation, cancellationToken);
Process(analysisResults, ineligibleFields, context);
}
......@@ -268,20 +285,49 @@ private void Process(AnalysisResult result, SemanticModelAnalysisContext context
var variableDeclarator = result.VariableDeclarator;
var nodeToFade = GetNodeToFade(result.FieldDeclaration, variableDeclarator);
// Fade out the field/variable we are going to remove.
var diagnostic1 = Diagnostic.Create(UnnecessaryWithoutSuggestionDescriptor, nodeToFade.GetLocation());
context.ReportDiagnostic(diagnostic1);
var optionSet = context.Options.GetDocumentOptionSetAsync(
result.FieldDeclaration.SyntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
}
// Now add diagnostics to both the field and the property saying we can convert it to
// an auto property. For each diagnostic store both location so we can easily retrieve
// them when performing the code fix.
IEnumerable<Location> additionalLocations = new Location[] { propertyDeclaration.GetLocation(), variableDeclarator.GetLocation() };
var additionalLocations = ImmutableArray.Create(
propertyDeclaration.GetLocation(), variableDeclarator.GetLocation());
var option = optionSet.GetOption(CodeStyleOptions.PreferAutoProperties, propertyDeclaration.Language);
// Place the appropriate marker on the field depending on the user option.
var diagnostic1 = Diagnostic.Create(
GetFieldDescriptor(option), nodeToFade.GetLocation(),
additionalLocations: additionalLocations);
var diagnostic2 = Diagnostic.Create(HiddenDescriptor, propertyDeclaration.GetLocation(), additionalLocations);
// Also, place a hidden marker on the property. If they bring up a lightbulb
// there, they'll be able to see that they can convert it to an auto-prop.
var diagnostic2 = Diagnostic.Create(
HiddenDescriptor, propertyDeclaration.GetLocation(),
additionalLocations: additionalLocations);
context.ReportDiagnostic(diagnostic1);
context.ReportDiagnostic(diagnostic2);
}
private DiagnosticDescriptor GetFieldDescriptor(CodeStyleOption<bool> styleOption)
{
if (styleOption.Value)
{
switch (styleOption.Notification.Value)
{
case DiagnosticSeverity.Error: return ErrorDescriptor;
case DiagnosticSeverity.Warning: return WarningDescriptor;
case DiagnosticSeverity.Info: return InfoDescriptor;
}
}
var diagnostic3 = Diagnostic.Create(HiddenDescriptor, nodeToFade.GetLocation(), additionalLocations);
context.ReportDiagnostic(diagnostic3);
return UnnecessaryWithSuggestionDescriptor;
}
protected virtual bool IsEligibleHeuristic(IFieldSymbol field, TPropertyDeclaration propertyDeclaration, Compilation compilation, CancellationToken cancellationToken)
......
......@@ -46,10 +46,15 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context)
{
foreach (var diagnostic in context.Diagnostics)
{
var priority = diagnostic.Severity == DiagnosticSeverity.Hidden
? CodeActionPriority.Low
: CodeActionPriority.Medium;
context.RegisterCodeFix(
new UseAutoPropertyCodeAction(
FeaturesResources.Use_auto_property,
c => ProcessResultAsync(context, diagnostic, c)),
c => ProcessResultAsync(context, diagnostic, c),
priority),
diagnostic);
}
......@@ -273,10 +278,13 @@ private async Task<SyntaxNode> FormatAsync(SyntaxNode newRoot, Document document
private class UseAutoPropertyCodeAction : CodeAction.SolutionChangeAction
{
public UseAutoPropertyCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution)
public UseAutoPropertyCodeAction(string title, Func<CancellationToken, Task<Solution>> createChangedSolution, CodeActionPriority priority)
: base(title, createChangedSolution, title)
{
this.Priority = priority;
}
internal override CodeActionPriority Priority { get; }
}
}
}
......@@ -43,8 +43,8 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var conditionalExpression = (TConditionalExpressionSyntax)context.Node;
var syntaxTree = context.Node.SyntaxTree;
var cancellationTokan = context.CancellationToken;
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationTokan).GetAwaiter().GetResult();
var cancellationToken = context.CancellationToken;
var optionSet = context.Options.GetDocumentOptionSetAsync(syntaxTree, cancellationToken).GetAwaiter().GetResult();
if (optionSet == null)
{
return;
......@@ -105,7 +105,7 @@ private void AnalyzeSyntax(SyntaxNodeAnalysisContext context)
var semanticModel = context.SemanticModel;
var conditionType = semanticModel.GetTypeInfo(
conditionLeftIsNull ? conditionRightLow : conditionLeftLow, cancellationTokan).Type;
conditionLeftIsNull ? conditionRightLow : conditionLeftLow, cancellationToken).Type;
if (conditionType != null &&
!conditionType.IsReferenceType)
{
......
......@@ -70,7 +70,7 @@ public static string Option_When_generating_properties
=> ServicesVSResources.When_generating_properties;
public static string Option_prefer_auto_properties
=> ServicesVSResources.prefer_auto_properties;
=> ServicesVSResources.codegen_prefer_auto_properties;
public static string Option_prefer_throwing_properties
=> ServicesVSResources.prefer_throwing_properties;
......
......@@ -549,6 +549,29 @@ public int GetAge()
//]
}}
}}
";
private static readonly string s_preferAutoProperties = $@"
using System;
class Customer
{{
//[
// {ServicesVSResources.Prefer_colon}
public int Age {{ get; }}
// {ServicesVSResources.Over_colon}
private int age;
public int Age
{{
get
{{
return age;
}}
}}
//]
}}
";
private static readonly string s_preferLocalFunctionOverAnonymousFunction = $@"
......@@ -808,6 +831,7 @@ internal StyleViewModel(OptionSet optionSet, IServiceProvider serviceProvider) :
// Code block
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CSharpCodeStyleOptions.PreferBraces, ServicesVSResources.Prefer_braces, s_preferBraces, s_preferBraces, this, optionSet, codeBlockPreferencesGroupTitle));
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferAutoProperties, ServicesVSResources.analyzer_Prefer_auto_properties, s_preferAutoProperties, s_preferAutoProperties, this, optionSet, codeBlockPreferencesGroupTitle));
// Expression preferences
CodeStyleItems.Add(new BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferObjectInitializer, ServicesVSResources.Prefer_object_initializer, s_preferObjectInitializer, s_preferObjectInitializer, this, optionSet, expressionPreferencesGroupTitle));
......
......@@ -226,6 +226,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to Prefer auto properties.
/// </summary>
internal static string analyzer_Prefer_auto_properties {
get {
return ResourceManager.GetString("analyzer_Prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Analyzer reference to &apos;{0}&apos; in project &apos;{1}&apos;.
/// </summary>
......@@ -462,6 +471,15 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer auto properties.
/// </summary>
internal static string codegen_prefer_auto_properties {
get {
return ResourceManager.GetString("codegen_prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Collapse #regions when collapsing to definitions.
/// </summary>
......@@ -1567,15 +1585,6 @@ internal class ServicesVSResources {
}
}
/// <summary>
/// Looks up a localized string similar to prefer auto properties.
/// </summary>
internal static string prefer_auto_properties {
get {
return ResourceManager.GetString("prefer_auto_properties", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Prefer braces.
/// </summary>
......
......@@ -876,6 +876,9 @@ Additional information: {1}</value>
<data name="Unfortunately_a_process_used_by_Visual_Studio_has_encountered_an_unrecoverable_error_We_recommend_saving_your_work_and_then_closing_and_restarting_Visual_Studio" xml:space="preserve">
<value>Unfortunately, a process used by Visual Studio has encountered an unrecoverable error. We recommend saving your work, and then closing and restarting Visual Studio.</value>
</data>
<data name="analyzer_Prefer_auto_properties" xml:space="preserve">
<value>Prefer auto properties</value>
</data>
<data name="Add_a_symbol_specification" xml:space="preserve">
<value>Add a symbol specification</value>
</data>
......@@ -900,7 +903,7 @@ Additional information: {1}</value>
<data name="VisualStudioWorkspace_TryApplyChanges_cannot_be_called_from_a_background_thread" xml:space="preserve">
<value>VisualStudioWorkspace.TryApplyChanges cannot be called from a background thread.</value>
</data>
<data name="prefer_auto_properties" xml:space="preserve">
<data name="codegen_prefer_auto_properties" xml:space="preserve">
<value>prefer auto properties</value>
</data>
<data name="prefer_throwing_properties" xml:space="preserve">
......
......@@ -91,7 +91,7 @@ Namespace Microsoft.VisualStudio.LanguageServices.VisualBasic.Options
ServicesVSResources.When_generating_properties
Public ReadOnly Property Option_prefer_auto_properties As String =
ServicesVSResources.prefer_auto_properties
ServicesVSResources.codegen_prefer_auto_properties
Public ReadOnly Property Option_prefer_throwing_properties As String =
ServicesVSResources.prefer_throwing_properties
......
......@@ -271,6 +271,26 @@ Class Customer
End Sub
End Class"
Private Shared ReadOnly s_preferAutoProperties As String = $"
Imports System
Class Customer
//[
' {ServicesVSResources.Prefer_colon}
Public ReadOnly Property Age As Integer
' {ServicesVSResources.Over_colon}
Private _age As Integer
Public ReadOnly Property Age As Integer
Get
return _age
End Get
End Property
//]
End Class
"
Private Shared ReadOnly s_preferIsNothingCheckOverReferenceEquals As String = $"
Imports System
......@@ -312,6 +332,7 @@ End Class"
New CodeStylePreference(ServicesVSResources.Prefer_framework_type, isChecked:=False)
}
Dim codeBlockPreferencesGroupTitle = ServicesVSResources.Code_block_preferences_colon
Dim expressionPreferencesGroupTitle = ServicesVSResources.Expression_preferences_colon
Dim nothingPreferencesGroupTitle = BasicVSResources.nothing_checking_colon
......@@ -325,6 +346,9 @@ End Class"
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, ServicesVSResources.For_locals_parameters_and_members, _intrinsicDeclarationPreviewTrue, _intrinsicDeclarationPreviewFalse, Me, optionSet, predefinedTypesGroupTitle, predefinedTypesPreferences))
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, ServicesVSResources.For_member_access_expressions, _intrinsicMemberAccessPreviewTrue, _intrinsicMemberAccessPreviewFalse, Me, optionSet, predefinedTypesGroupTitle, predefinedTypesPreferences))
' Code block
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferAutoProperties, ServicesVSResources.analyzer_Prefer_auto_properties, s_preferAutoProperties, s_preferAutoProperties, Me, optionSet, codeBlockPreferencesGroupTitle))
' expression preferences
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferObjectInitializer, ServicesVSResources.Prefer_object_initializer, s_preferObjectInitializer, s_preferObjectInitializer, Me, optionSet, expressionPreferencesGroupTitle))
Me.CodeStyleItems.Add(New BooleanCodeStyleOptionViewModel(CodeStyleOptions.PreferCollectionInitializer, ServicesVSResources.Prefer_collection_initializer, s_preferCollectionInitializer, s_preferCollectionInitializer, Me, optionSet, expressionPreferencesGroupTitle))
......
......@@ -142,6 +142,14 @@ public class CodeStyleOptions
EditorConfigStorageLocation.ForBoolCodeStyleOption("dotnet_style_explicit_tuple_names"),
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferExplicitTupleNames") });
internal static readonly PerLanguageOption<CodeStyleOption<bool>> PreferAutoProperties = new PerLanguageOption<CodeStyleOption<bool>>(
nameof(CodeStyleOptions),
nameof(PreferAutoProperties),
defaultValue: TrueWithNoneEnforcement,
storageLocations: new OptionStorageLocation[] {
EditorConfigStorageLocation.ForBoolCodeStyleOption("dotnet_style_prefer_auto_properties"),
new RoamingProfileStorageLocation("TextEditor.%LANGUAGE%.Specific.PreferAutoProperties") });
internal static readonly PerLanguageOption<CodeStyleOption<bool>> PreferIsNullCheckOverReferenceEqualityMethod = new PerLanguageOption<CodeStyleOption<bool>>(
nameof(CodeStyleOptions),
nameof(PreferIsNullCheckOverReferenceEqualityMethod),
......
......@@ -222,6 +222,7 @@ protected void WriteOptionSetTo(OptionSet options, string language, ObjectWriter
WriteOptionTo(options, language, CodeStyleOptions.QualifyPropertyAccess, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.QualifyMethodAccess, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.QualifyEventAccess, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferAutoProperties, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, writer, cancellationToken);
WriteOptionTo(options, language, CodeStyleOptions.PreferCoalesceExpression, writer, cancellationToken);
......@@ -244,6 +245,7 @@ protected OptionSet ReadOptionSetFrom(OptionSet options, string language, Object
options = ReadOptionFrom(options, language, CodeStyleOptions.QualifyPropertyAccess, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.QualifyMethodAccess, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.QualifyEventAccess, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferAutoProperties, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInDeclaration, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferIntrinsicPredefinedTypeKeywordInMemberAccess, reader, cancellationToken);
options = ReadOptionFrom(options, language, CodeStyleOptions.PreferCoalesceExpression, reader, cancellationToken);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册