diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs index a7987be2ca3b5..3acb99c254651 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyAnalyzer.cs @@ -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(); var ineligibleFields = new HashSet(); - 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); } @@ -275,32 +292,31 @@ private void Process(AnalysisResult result, SemanticModelAnalysisContext context return; } - // Always offer the conversion if possible. But only let the user know (by - // fading/suggestions/squiggles) if their option is set to see this. - - var option = optionSet.GetOption(CodeStyleOptions.PreferAutoProperties, propertyDeclaration.Language); - if (option.Value) - { - // Fade out the field/variable we are going to remove. - var diagnostic1 = Diagnostic.Create(UnnecessaryWithoutSuggestionDescriptor, nodeToFade.GetLocation()); - context.ReportDiagnostic(diagnostic1); - } - // 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. var additionalLocations = ImmutableArray.Create( propertyDeclaration.GetLocation(), variableDeclarator.GetLocation()); - var diagnostic2 = Diagnostic.Create(HiddenDescriptor, propertyDeclaration.GetLocation(), - additionalLocations: additionalLocations); - context.ReportDiagnostic(diagnostic2); + var option = optionSet.GetOption(CodeStyleOptions.PreferAutoProperties, propertyDeclaration.Language); + + var lowPriority = ImmutableDictionary.Empty.Add("LowPriority", ""); // Place the appropriate marker on the field depending on the user option. - var diagnostic3 = Diagnostic.Create( + var diagnostic1 = Diagnostic.Create( GetFieldDescriptor(option), nodeToFade.GetLocation(), - additionalLocations: additionalLocations); - context.ReportDiagnostic(diagnostic3); + additionalLocations: additionalLocations, + properties: option.Notification.Value == DiagnosticSeverity.Hidden ? lowPriority : default); + + // 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, + properties: lowPriority); + + context.ReportDiagnostic(diagnostic1); + context.ReportDiagnostic(diagnostic2); } private DiagnosticDescriptor GetFieldDescriptor(CodeStyleOption styleOption) @@ -315,7 +331,7 @@ private DiagnosticDescriptor GetFieldDescriptor(CodeStyleOption styleOptio } } - return HiddenDescriptor; + return UnnecessaryWithSuggestionDescriptor; } protected virtual bool IsEligibleHeuristic(IFieldSymbol field, TPropertyDeclaration propertyDeclaration, Compilation compilation, CancellationToken cancellationToken) diff --git a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs index 0d89c42e95340..491c8fca775aa 100644 --- a/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs +++ b/src/Features/Core/Portable/UseAutoProperty/AbstractUseAutoPropertyCodeFixProvider.cs @@ -46,10 +46,15 @@ public sealed override Task RegisterCodeFixesAsync(CodeFixContext context) { foreach (var diagnostic in context.Diagnostics) { + var priority = diagnostic.Properties.ContainsKey("LowPriority") + ? 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 static bool IsWrittenToOutsideOfConstructorOrProperty( private class UseAutoPropertyCodeAction : CodeAction.SolutionChangeAction { - public UseAutoPropertyCodeAction(string title, Func> createChangedSolution) + public UseAutoPropertyCodeAction(string title, Func> createChangedSolution, CodeActionPriority priority) : base(title, createChangedSolution, title) { + this.Priority = priority; } + + internal override CodeActionPriority Priority { get; } } } }