public override async Task ComputeRefactoringsAsync(CodeRefactoringContext context) { var document = context.Document; var textSpan = context.Span; var cancellationToken = context.CancellationToken; var state = await State.CreateAsync(this, document, textSpan, cancellationToken).ConfigureAwait(false); if (state == null) { return; } // No move file action if rootnamespace isn't a prefix of current declared namespace if (state.RelativeDeclaredNamespace != null) { context.RegisterRefactorings(MoveFileCodeAction.Create(state)); } // No change namespace action if we can't construct a valid namespace from rootnamespace and folder names. if (state.TargetNamespace != null) { var service = document.GetLanguageService <IChangeNamespaceService>(); var solutionChangeAction = new SolutionChangeAction(ChangeNamespaceActionTitle(state), token => service.ChangeNamespaceAsync(state.Solution, state.DocumentIds, state.DeclaredNamespace, state.TargetNamespace, token)); context.RegisterRefactoring(solutionChangeAction); } }
protected override async Task <IEnumerable <CodeActionOperation> > ComputePreviewOperationsAsync(CancellationToken cancellationToken) { // Make a SolutionChangeAction. This way we can let it generate the diff // preview appropriately. var solutionChangeAction = SolutionChangeAction.Create("", GetUpdatedSolutionAsync, ""); using var _ = ArrayBuilder <CodeActionOperation> .GetInstance(out var result); result.AddRange(await solutionChangeAction.GetPreviewOperationsAsync(cancellationToken).ConfigureAwait(false)); result.Add(_installOperation); return(result.ToImmutable()); }
public static CodeAction Create(string title, Func <CancellationToken, Task <Solution> > createChangedSolution, string?equivalenceKey = null) { if (title == null) { throw new ArgumentNullException(nameof(title)); } if (createChangedSolution == null) { throw new ArgumentNullException(nameof(createChangedSolution)); } return(SolutionChangeAction.Create(title, createChangedSolution, equivalenceKey)); }
/// <summary> /// For preview purposes we return all the operations in a list. This way the /// preview system stiches things together in the UI to make a suitable display. /// i.e. if we have a SolutionChangedOperation and some other operation with a /// Title, then the UI will show that nicely to the user. /// </summary> protected override async Task <IEnumerable <CodeActionOperation> > ComputePreviewOperationsAsync(CancellationToken cancellationToken) { var installData = await _installData.GetValueAsync(cancellationToken).ConfigureAwait(false); // Make a SolutionChangeAction. This way we can let it generate the diff // preview appropriately. var solutionChangeAction = new SolutionChangeAction( "", c => Task.FromResult(installData.NewDocument.Project.Solution)); var result = ArrayBuilder <CodeActionOperation> .GetInstance(); result.AddRange(await solutionChangeAction.GetPreviewOperationsAsync(cancellationToken).ConfigureAwait(false)); result.Add(installData.InstallOperation); return(result.ToImmutableAndFree()); }
private static ImmutableArray <CodeFix> GetConfigurations(Project project, IEnumerable <Diagnostic> diagnostics, CancellationToken cancellationToken) { var result = ArrayBuilder <CodeFix> .GetInstance(); foreach (var diagnostic in diagnostics) { // First get all the relevant code style options for the diagnostic. var codeStyleOptions = ConfigurationUpdater.GetCodeStyleOptionsForDiagnostic(diagnostic, project); if (codeStyleOptions.IsEmpty) { continue; } // For each code style option, create a top level code action with nested code actions for every valid option value. // For example, if the option value is CodeStyleOption<bool>, we will have two nested actions, one for 'true' setting and one // for 'false' setting. If the option value is CodeStyleOption<SomeEnum>, we will have a nested action for each enum field. using var _ = ArrayBuilder <CodeAction> .GetInstance(out var nestedActions); var optionSet = project.Solution.Workspace.Options; var hasMultipleOptions = codeStyleOptions.Length > 1; foreach (var(optionKey, codeStyleOption, editorConfigLocation, perLanguageOption) in codeStyleOptions.OrderBy(t => t.optionKey.Option.Name)) { var topLevelAction = GetCodeActionForCodeStyleOption(optionKey, codeStyleOption, editorConfigLocation, diagnostic, perLanguageOption, optionSet, hasMultipleOptions); if (topLevelAction != null) { nestedActions.Add(topLevelAction); } } if (nestedActions.Count != 0) { // Wrap actions by another level if the diagnostic ID has multiple associated code style options to reduce clutter. var resultCodeAction = nestedActions.Count > 1 ? new TopLevelConfigureCodeStyleOptionCodeAction(diagnostic, nestedActions.ToImmutable()) : nestedActions.Single(); result.Add(new CodeFix(project, resultCodeAction, diagnostic)); } } return(result.ToImmutableAndFree()); // Local functions TopLevelConfigureCodeStyleOptionCodeAction GetCodeActionForCodeStyleOption( OptionKey optionKey, ICodeStyleOption codeStyleOption, IEditorConfigStorageLocation2 editorConfigLocation, Diagnostic diagnostic, bool isPerLanguage, OptionSet optionSet, bool hasMultipleOptions) { // Add a code action for every valid value of the given code style option. // We only support light-bulb configuration of code style options with boolean or enum values. using var _ = ArrayBuilder <CodeAction> .GetInstance(out var nestedActions); string optionName = null; if (codeStyleOption.Value is bool) { foreach (var boolValue in s_boolValues) { AddCodeActionWithOptionValue(codeStyleOption, boolValue); } } else if (codeStyleOption.Value?.GetType() is Type t && t.IsEnum) { foreach (var enumValue in Enum.GetValues(t)) { AddCodeActionWithOptionValue(codeStyleOption, enumValue); } } if (nestedActions.Count > 0) { // If this is not a unique code style option for the diagnostic, use the optionName as the code action title. // In that case, we will already have a containing top level action for the diagnostic. // Otherwise, use the diagnostic information in the title. return(hasMultipleOptions ? new TopLevelConfigureCodeStyleOptionCodeAction(optionName, nestedActions.ToImmutable()) : new TopLevelConfigureCodeStyleOptionCodeAction(diagnostic, nestedActions.ToImmutable())); } return(null); // Local functions void AddCodeActionWithOptionValue(ICodeStyleOption codeStyleOption, object newValue) { // Create a new code style option value with the newValue var configuredCodeStyleOption = codeStyleOption.WithValue(newValue); // Try to get the parsed editorconfig string representation of the new code style option value if (ConfigurationUpdater.TryGetEditorConfigStringParts(configuredCodeStyleOption, editorConfigLocation, optionSet, out var parts)) { // We expect all code style values for same code style option to have the same editorconfig option name. Debug.Assert(optionName == null || optionName == parts.optionName); optionName ??= parts.optionName; // Add code action to configure the optionValue. nestedActions.Add( SolutionChangeAction.Create( parts.optionValue, solution => ConfigurationUpdater.ConfigureCodeStyleOptionAsync(parts.optionName, parts.optionValue, diagnostic, isPerLanguage, project, cancellationToken), parts.optionValue)); } } } }