From a1208e7e101c0e8e2ed306c8dca605e4d77a229f Mon Sep 17 00:00:00 2001 From: Martin Strecker Date: Mon, 12 Mar 2018 14:31:24 +0100 Subject: [PATCH] Change code fix registration to limit the number of menu entries to two. --- .../AbstractAddParameterCodeFixProvider.cs | 108 ++++++++++++++---- .../Core/Portable/AddParameter/CodeFixData.cs | 36 ++++++ 2 files changed, 119 insertions(+), 25 deletions(-) create mode 100644 src/Features/Core/Portable/AddParameter/CodeFixData.cs diff --git a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs index 41b814ac86c..e84d3e4c4a2 100644 --- a/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs +++ b/src/Features/Core/Portable/AddParameter/AbstractAddParameterCodeFixProvider.cs @@ -194,41 +194,96 @@ private int NonParamsParameterCount(IMethodSymbol method) SeparatedSyntaxList arguments, ImmutableArray> methodsAndArgumentsToAdd) { - var codeActions = CreateCodeActions(context.Document, arguments, methodsAndArgumentsToAdd); - context.RegisterFixes(codeActions, context.Diagnostics); + var codeFixData = PrepareCreationOfCodeActions(context.Document, arguments, methodsAndArgumentsToAdd); + var fixes = codeFixData.Length <= 2 + ? NestByOverload() + : NestByCascading(); + + context.RegisterFixes(fixes, context.Diagnostics); + + ImmutableArray NestByOverload() + { + var builder = ImmutableArray.CreateBuilder(codeFixData.Length); + foreach (var data in codeFixData) + { + var title = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true); + CodeAction codeAction = new MyCodeAction( + title: title, + data.CreateChangedSolutionNonCascading); + if (data.CreateChangedSolutionCascading != null) + { + var titleForNesting = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true); + var titleCascading = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0_including_overrides_implementations, data.Method, includeParameters: true); + codeAction = new CodeAction.CodeActionWithNestedActions( + title: titleForNesting, + ImmutableArray.Create( + codeAction, + new MyCodeAction( + title: titleCascading, + data.CreateChangedSolutionCascading)), + isInlinable: true); + } + + builder.Add(codeAction); + } + + return builder.ToImmutable(); + } + + ImmutableArray NestByCascading() + { + var builder = ImmutableArray.CreateBuilder(2); + + var nonCascadingActions = ImmutableArray.CreateRange(codeFixData.Select(data => + { + var title = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, true); + return new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading); + })); + + var cascading = codeFixData.Where(data => data.CreateChangedSolutionCascading != null); + var cascadingActions = ImmutableArray.CreateRange(cascading.Select(data => + { + var title = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, true); + return new MyCodeAction(title: title, data.CreateChangedSolutionCascading); + })); + + var aMethod = codeFixData.First().Method; + var nestedNonCascadingTitle = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, aMethod, false); + + builder.Add(new CodeAction.CodeActionWithNestedActions(nestedNonCascadingTitle, nonCascadingActions, isInlinable: false)); + + if (cascadingActions.Length > 0) + { + var nestedCascadingTitle = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0_including_overrides_implementations, aMethod, false); + builder.Add(new CodeAction.CodeActionWithNestedActions(nestedCascadingTitle, cascadingActions, isInlinable: false)); + } + + return builder.ToImmutable(); + } } - private ImmutableArray CreateCodeActions(Document document, SeparatedSyntaxList arguments, ImmutableArray> methodsAndArgumentsToAdd) + private ImmutableArray PrepareCreationOfCodeActions(Document document, SeparatedSyntaxList arguments, ImmutableArray> methodsAndArgumentsToAdd) { + var builder = ImmutableArray.CreateBuilder(methodsAndArgumentsToAdd.Length); + // Order by the furthest argument index to the nearest argument index. The ones with // larger argument indexes mean that we matched more earlier arguments (and thus are // likely to be the correct match). - var builder = ImmutableArray.CreateBuilder(methodsAndArgumentsToAdd.Length); foreach (var argumentInsertPositionData in methodsAndArgumentsToAdd.OrderByDescending(t => t.ArgumentInsertionIndex)) { var methodToUpdate = argumentInsertPositionData.MethodToUpdate; var argumentToInsert = argumentInsertPositionData.ArgumentToInsert; - var parameters = methodToUpdate.Parameters.Select(p => p.ToDisplayString(SimpleFormat)); - var title = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, methodToUpdate, parameters); - var hasCascadingDeclarations = HasCascadingDeclarations(methodToUpdate); - CodeAction codeAction = new MyCodeAction(title, - c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: false, c)); - if (hasCascadingDeclarations) - { - // Offer another alternative code action. Wrap both options so the IDE can collapse them. - var titleForCascadingFix = GetCodeFixTitle( - FeaturesResources.Add_parameter_to_0_including_overrides_implementations, methodToUpdate, parameters); - codeAction = new CodeAction.CodeActionWithNestedActions( - title: title, - isInlinable: true, - nestedActions: ImmutableArray.Create( - codeAction, - new MyCodeAction(titleForCascadingFix, - c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: true, c)))); - } + var cascadingFix = HasCascadingDeclarations(methodToUpdate) + ? new Func>(c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: true, c)) + : null; + + var codeFixData = new CodeFixData( + methodToUpdate, + c => FixAsync(document, methodToUpdate, argumentToInsert, arguments, fixAllReferences: false, c), + cascadingFix); - builder.Add(codeAction); + builder.Add(codeFixData); } return builder.ToImmutable(); @@ -280,7 +335,7 @@ private bool HasCascadingDeclarations(IMethodSymbol method) return false; } - private static string GetCodeFixTitle(string resourceString, IMethodSymbol methodToUpdate, IEnumerable parameters) + private static string GetCodeFixTitle(string resourceString, IMethodSymbol methodToUpdate, bool includeParameters) { var methodDisplay = methodToUpdate.ToDisplayString(new SymbolDisplayFormat( typeQualificationStyle: SymbolDisplayTypeQualificationStyle.NameAndContainingTypes, @@ -290,7 +345,10 @@ private static string GetCodeFixTitle(string resourceString, IMethodSymbol metho ? SymbolDisplayMemberOptions.None : SymbolDisplayMemberOptions.IncludeContainingType)); - var signature = $"{methodDisplay}({string.Join(", ", parameters)})"; + var parameters = methodToUpdate.Parameters.Select(p => p.ToDisplayString(SimpleFormat)); + var signature = includeParameters + ? $"{methodDisplay}({string.Join(", ", parameters)})" + : methodDisplay; var title = string.Format(resourceString, signature); return title; } diff --git a/src/Features/Core/Portable/AddParameter/CodeFixData.cs b/src/Features/Core/Portable/AddParameter/CodeFixData.cs new file mode 100644 index 00000000000..e23046481f5 --- /dev/null +++ b/src/Features/Core/Portable/AddParameter/CodeFixData.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Text; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.CodeAnalysis.AddParameter +{ + internal struct CodeFixData + { + public CodeFixData( + IMethodSymbol method, + Func> createChangedSolutionNonCascading, + Func> createChangedSolutionCascading) + { + Method = method ?? throw new ArgumentNullException(nameof(method)); + CreateChangedSolutionNonCascading = createChangedSolutionNonCascading ?? throw new ArgumentNullException(nameof(createChangedSolutionNonCascading)); + CreateChangedSolutionCascading = createChangedSolutionCascading; + } + + /// + /// The overload to fix. + /// + public IMethodSymbol Method { get; } + + /// + /// A mandatory fix for the overload without cascading. + /// + public Func> CreateChangedSolutionNonCascading { get; } + + /// + /// An optional fix for the overload with cascading. + /// + public Func> CreateChangedSolutionCascading { get; } + } +} -- GitLab