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);
            }
        }
Esempio n. 2
0
            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());
            }
Esempio n. 3
0
        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());
                }
Esempio n. 5
0
        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));
                    }
                }
            }
        }