private void AddFix(string codeFixTitle, CodeFixContext context, SyntaxNode root, SyntaxNode classDecl, SyntaxGenerator generator, params string[] languages)
 {
     var fix = new MyCodeAction(
         codeFixTitle,
         c => GetFix(context.Document, root, classDecl, generator, languages));
     context.RegisterCodeFix(fix, context.Diagnostics);
 }
 public override async Task AddDocumentFixesAsync(Document document, ImmutableArray<Diagnostic> diagnostics, Action<CodeAction> addFix, FixAllContext fixAllContext)
 {
     var changedDocument = await AddSimplifierAnnotationsAsync(document, diagnostics, fixAllContext).ConfigureAwait(false);
     var title = GetFixAllTitle(fixAllContext);
     var codeAction = new MyCodeAction(title, (c) => Task.FromResult(changedDocument));
     addFix(codeAction);
 }
        private async Task<Tuple<CodeAction, string>> GetCodeActionAsync(
            Document document,
            TextSpan textSpan,
            CancellationToken cancellationToken)
        {
            var result = await ExtractMethodService.ExtractMethodAsync(
                document,
                textSpan,
                cancellationToken: cancellationToken).ConfigureAwait(false);
            Contract.ThrowIfNull(result);

            if (result.Succeeded || result.SucceededWithSuggestion)
            {
                var documentOptions = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
                var description = documentOptions.GetOption(ExtractMethodOptions.AllowMovingDeclaration) ?
                                      FeaturesResources.Extract_Method_plus_Local : FeaturesResources.Extract_Method;

                var codeAction = new MyCodeAction(description, (c) => AddRenameAnnotationAsync(result.Document, result.InvocationNameToken, c));
                var methodBlock = result.MethodDeclarationNode;

                return Tuple.Create<CodeAction, string>(codeAction, methodBlock.ToString());
            }

            return null;
        }
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var root = await document.GetSyntaxRootAsync(context.CancellationToken).ConfigureAwait(false);
            var node = root.FindNode(span, getInnermostNodeForTie: true);

            var codeAction = new MyCodeAction(
                CSharpFeaturesResources.UseExplicitType,
                c => HandleDeclarationAsync(document, root, node, context.CancellationToken));

            context.RegisterCodeFix(codeAction, context.Diagnostics.First());
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var cancellationToken = context.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();
            var root = await document.GetSyntaxRootAsync(cancellationToken);
            var classDeclaration = root.FindToken(span.Start).Parent?.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclaration != null)
            {
                var title = string.Format(FxCopRulesResources.StaticHolderTypeIsNotStatic, classDeclaration.Identifier.Text);
                var codeAction = new MyCodeAction(title, ct => AddStaticKeyword(document, root, classDeclaration));
                context.RegisterCodeFix(codeAction, context.Diagnostics);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var cancellationToken = context.CancellationToken;

            cancellationToken.ThrowIfCancellationRequested();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var classDeclaration = root.FindToken(span.Start).Parent?.FirstAncestorOrSelf<ClassDeclarationSyntax>();
            if (classDeclaration != null)
            {
                var codeAction = new MyCodeAction(MicrosoftApiDesignGuidelinesAnalyzersResources.MakeClassStatic, 
                                                  async ct => await MakeClassStatic(document, root, classDeclaration, ct).ConfigureAwait(false));
                context.RegisterCodeFix(codeAction, context.Diagnostics);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project = document.Project;
            var diagnostic = diagnostics.First();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var node = root.FindToken(span.Start).GetAncestors<SyntaxNode>().First(n => n.Span.Contains(span));

            using (Logger.LogBlock(FunctionId.Refactoring_FullyQualify, cancellationToken))
            {
                // Has to be a simple identifier or generic name.
                if (node != null && CanFullyQualify(diagnostic, ref node))
                {
                    var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    var matchingTypes = await this.GetMatchingTypesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);
                    var matchingNamespaces = await this.GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    if (matchingTypes != null || matchingNamespaces != null)
                    {
                        matchingTypes = matchingTypes ?? SpecializedCollections.EmptyEnumerable<ISymbol>();
                        matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyEnumerable<ISymbol>();

                        var matchingTypeContainers = FilterAndSort(GetContainers(matchingTypes, semanticModel.Compilation));
                        var matchingNamespaceContainers = FilterAndSort(GetContainers(matchingNamespaces, semanticModel.Compilation));

                        var proposedContainers =
                            matchingTypeContainers.Concat(matchingNamespaceContainers)
                                              .Distinct()
                                              .Take(MaxResults);

                        var displayService = project.LanguageServices.GetService<ISymbolDisplayService>();

                        foreach (var container in proposedContainers)
                        {
                            var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                            var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();
                            string name;
                            int arity;
                            syntaxFacts.GetNameAndArityOfSimpleName(node, out name, out arity);

                            // Actual member name might differ by case.
                            string memberName;
                            if (this.IgnoreCase)
                            {
                                var member = container.GetMembers(name).FirstOrDefault();
                                memberName = member != null ? member.Name : name;
                            }
                            else
                            {
                                memberName = name;
                            }

                            var codeAction = new MyCodeAction(
                                $"{containerName}.{memberName}",
                                c => ProcessNode(document, node, containerName, c));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                }
            }
        }
Example #8
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var diagnostics       = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project    = document.Project;
            var diagnostic = diagnostics.First();
            var root       = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var ancestors = root.FindToken(span.Start, findInsideTrivia: true).GetAncestors <SyntaxNode>();

            if (!ancestors.Any())
            {
                return;
            }

            var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root);

            if (node == null)
            {
                return;
            }

            var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption(
                OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language);

            using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken))
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    if (this.CanAddImport(node, cancellationToken))
                    {
                        var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                        var allSymbolReferences = new List <SymbolReference>();

                        var finder = new SymbolReferenceFinder(this, document, semanticModel, diagnostic, node, cancellationToken);

                        // Caches so we don't produce the same data multiple times while searching
                        // all over the solution.
                        var projectToAssembly      = new ConcurrentDictionary <Project, AsyncLazy <IAssemblySymbol> >(concurrencyLevel: 2, capacity: project.Solution.ProjectIds.Count);
                        var referenceToCompilation = new ConcurrentDictionary <PortableExecutableReference, Compilation>(concurrencyLevel: 2, capacity: project.Solution.Projects.Sum(p => p.MetadataReferences.Count));

                        // Look for exact matches first:
                        await FindResults(projectToAssembly, referenceToCompilation, project, allSymbolReferences, finder, exact : true, cancellationToken : cancellationToken).ConfigureAwait(false);

                        if (allSymbolReferences.Count == 0)
                        {
                            // No exact matches found.  Fall back to fuzzy searching.
                            await FindResults(projectToAssembly, referenceToCompilation, project, allSymbolReferences, finder, exact : false, cancellationToken : cancellationToken).ConfigureAwait(false);
                        }

                        // Nothing found at all. No need to proceed.
                        if (allSymbolReferences.Count == 0)
                        {
                            return;
                        }

                        cancellationToken.ThrowIfCancellationRequested();

                        foreach (var reference in allSymbolReferences)
                        {
                            var description = this.GetDescription(reference.SearchResult.Symbol, semanticModel, node);
                            if (description != null)
                            {
                                var action = new MyCodeAction(description, c =>
                                                              this.AddImportAndReferenceAsync(node, reference, document, placeSystemNamespaceFirst, c));
                                context.RegisterCodeFix(action, diagnostic);
                            }
                        }
                    }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var diagnostics       = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project    = document.Project;
            var diagnostic = diagnostics.First();
            var root       = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var ancestors = root.FindToken(span.Start, findInsideTrivia: true).GetAncestors <SyntaxNode>();

            if (!ancestors.Any())
            {
                return;
            }

            var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root);

            if (node == null)
            {
                return;
            }

            var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Shared.Options.OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language);

            using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken))
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    if (this.CanAddImport(node, cancellationToken))
                    {
                        var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                        var containingType           = semanticModel.GetEnclosingNamedType(node.SpanStart, cancellationToken);
                        var containingTypeOrAssembly = containingType ?? (ISymbol)semanticModel.Compilation.Assembly;
                        var namespacesInScope        = this.GetNamespacesInScope(semanticModel, node, cancellationToken);
                        var syntaxFacts = document.Project.LanguageServices.GetService <ISyntaxFactsService>();

                        var matchingTypesNamespaces = await this.GetNamespacesForMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);

                        var matchingTypes = await this.GetMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);

                        var matchingNamespaces = await this.GetNamespacesForMatchingNamespacesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);

                        var matchingExtensionMethodsNamespaces = await this.GetNamespacesForMatchingExtensionMethodsAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);

                        var matchingFieldsAndPropertiesAsync = await this.GetNamespacesForMatchingFieldsAndPropertiesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);

                        var queryPatternsNamespaces = await this.GetNamespacesForQueryPatternsAsync(project, diagnostic, node, semanticModel, namespacesInScope, cancellationToken).ConfigureAwait(false);

                        if (matchingTypesNamespaces != null || matchingNamespaces != null || matchingExtensionMethodsNamespaces != null || matchingFieldsAndPropertiesAsync != null || queryPatternsNamespaces != null || matchingTypes != null)
                        {
                            matchingTypesNamespaces            = matchingTypesNamespaces ?? SpecializedCollections.EmptyList <INamespaceSymbol>();
                            matchingNamespaces                 = matchingNamespaces ?? SpecializedCollections.EmptyList <INamespaceSymbol>();
                            matchingExtensionMethodsNamespaces = matchingExtensionMethodsNamespaces ?? SpecializedCollections.EmptyList <INamespaceSymbol>();
                            matchingFieldsAndPropertiesAsync   = matchingFieldsAndPropertiesAsync ?? SpecializedCollections.EmptyList <INamespaceSymbol>();
                            queryPatternsNamespaces            = queryPatternsNamespaces ?? SpecializedCollections.EmptyList <INamespaceSymbol>();
                            matchingTypes = matchingTypes ?? SpecializedCollections.EmptyList <ITypeSymbol>();

                            var proposedImports =
                                matchingTypesNamespaces.Cast <INamespaceOrTypeSymbol>()
                                .Concat(matchingNamespaces.Cast <INamespaceOrTypeSymbol>())
                                .Concat(matchingExtensionMethodsNamespaces.Cast <INamespaceOrTypeSymbol>())
                                .Concat(matchingFieldsAndPropertiesAsync.Cast <INamespaceOrTypeSymbol>())
                                .Concat(queryPatternsNamespaces.Cast <INamespaceOrTypeSymbol>())
                                .Concat(matchingTypes.Cast <INamespaceOrTypeSymbol>())
                                .Distinct()
                                .Where(NotNull)
                                .Where(NotGlobalNamespace)
                                .OrderBy(INamespaceOrTypeSymbolExtensions.CompareNamespaceOrTypeSymbols)
                                .Take(8)
                                .ToList();

                            if (proposedImports.Count > 0)
                            {
                                cancellationToken.ThrowIfCancellationRequested();

                                foreach (var import in proposedImports)
                                {
                                    var description = this.GetDescription(import, semanticModel, node);
                                    if (description != null)
                                    {
                                        var action = new MyCodeAction(description, (c) =>
                                                                      this.AddImportAsync(node, import, document, placeSystemNamespaceFirst, cancellationToken));
                                        context.RegisterCodeFix(action, diagnostic);
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
Example #10
0
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document          = context.Document;
            var span              = context.Span;
            var diagnostics       = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project    = document.Project;
            var diagnostic = diagnostics.First();
            var root       = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);

            var node = root.FindToken(span.Start).GetAncestors <SyntaxNode>().First(n => n.Span.Contains(span));

            using (Logger.LogBlock(FunctionId.Refactoring_FullyQualify, cancellationToken))
            {
                // Has to be a simple identifier or generic name.
                if (node != null && CanFullyQualify(diagnostic, ref node))
                {
                    var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

                    var matchingTypes = await this.GetMatchingTypesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    var matchingNamespaces = await this.GetMatchingNamespacesAsync(project, semanticModel, node, cancellationToken).ConfigureAwait(false);

                    if (matchingTypes != null || matchingNamespaces != null)
                    {
                        matchingTypes      = matchingTypes ?? SpecializedCollections.EmptyEnumerable <SymbolResult <ISymbol> >();
                        matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyEnumerable <SymbolResult <ISymbol> >();

                        var matchingTypeContainers      = FilterAndSort(GetContainers(matchingTypes, semanticModel.Compilation));
                        var matchingNamespaceContainers = FilterAndSort(GetContainers(matchingNamespaces, semanticModel.Compilation));

                        var proposedContainers =
                            matchingTypeContainers.Concat(matchingNamespaceContainers)
                            .Distinct()
                            .Take(MaxResults);

                        var displayService = project.LanguageServices.GetService <ISymbolDisplayService>();

                        foreach (var container in proposedContainers)
                        {
                            var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                            var    syntaxFacts = document.Project.LanguageServices.GetService <ISyntaxFactsService>();
                            string name;
                            int    arity;
                            syntaxFacts.GetNameAndArityOfSimpleName(node, out name, out arity);

                            // Actual member name might differ by case.
                            string memberName;
                            if (this.IgnoreCase)
                            {
                                var member = container.GetMembers(name).FirstOrDefault();
                                memberName = member != null ? member.Name : name;
                            }
                            else
                            {
                                memberName = name;
                            }

                            var codeAction = new MyCodeAction(
                                $"{containerName}.{memberName}",
                                c => ProcessNode(document, node, containerName, c));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                    }
                }
            }
        }
        public sealed override async Task ComputeRefactoringsAsync(CodeRefactoringContext context)
        {
            var(container, explicitName, name) = await GetContainerAsync(context).ConfigureAwait(false);

            if (container == null)
            {
                return;
            }

            if (!CheckExplicitNameAllowsConversion(explicitName))
            {
                return;
            }

            var(document, _, cancellationToken) = context;
            var semanticModel = await document.GetRequiredSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            var member = semanticModel.GetDeclaredSymbol(container, cancellationToken);

            Contract.ThrowIfNull(member);

            if (!CheckMemberCanBeConverted(member))
            {
                return;
            }

            var project = document.Project;

            var directlyImplementedMembers = new MemberImplementationMap();

            // Grab the name off of the *interface* member being implemented, not the implementation
            // member.  Interface member names are the expected names that people expect to see
            // (like "GetEnumerator"), instead of the auto-generated names that the compiler makes
            // like: "System.IEnumerable.GetEnumerator"
            directlyImplementedMembers.AddRange(member, member.ExplicitOrImplicitInterfaceImplementations());

            var codeAction = new MyCodeAction(
                string.Format(Implement_0, member.ExplicitOrImplicitInterfaceImplementations().First().Name),
                c => ChangeImplementationAsync(project, directlyImplementedMembers, c));

            var containingType = member.ContainingType;
            var interfaceTypes = directlyImplementedMembers.SelectMany(kvp => kvp.Value).Select(
                s => s.ContainingType).Distinct().ToImmutableArray();

            var implementedMembersFromSameInterfaces = GetImplementedMembers(containingType, interfaceTypes);
            var implementedMembersFromAllInterfaces  = GetImplementedMembers(containingType, containingType.AllInterfaces);

            var offerForSameInterface = TotalCount(implementedMembersFromSameInterfaces) > TotalCount(directlyImplementedMembers);
            var offerForAllInterfaces = TotalCount(implementedMembersFromAllInterfaces) > TotalCount(implementedMembersFromSameInterfaces);

            // If there's only one member in the interface we implement, and there are no other
            // interfaces, then just offer to switch the implementation for this single member
            if (!offerForSameInterface && !offerForAllInterfaces)
            {
                context.RegisterRefactoring(codeAction);
                return;
            }

            // Otherwise, create a top level action to change the implementation, and offer this
            // action, along with either/both of the other two.

            var nestedActions = ArrayBuilder <CodeAction> .GetInstance();

            nestedActions.Add(codeAction);

            if (offerForSameInterface)
            {
                var interfaceNames = interfaceTypes.Select(i => i.ToDisplayString(NameAndTypeParametersFormat));
                nestedActions.Add(new MyCodeAction(
                                      string.Format(Implement_0, string.Join(", ", interfaceNames)),
                                      c => ChangeImplementationAsync(project, implementedMembersFromSameInterfaces, c)));
            }

            if (offerForAllInterfaces)
            {
                nestedActions.Add(new MyCodeAction(
                                      Implement_all_interfaces,
                                      c => ChangeImplementationAsync(project, implementedMembersFromAllInterfaces, c)));
            }

            context.RegisterRefactoring(new CodeAction.CodeActionWithNestedActions(
                                            Implement, nestedActions.ToImmutableAndFree(), isInlinable: true));
        }
        private static void RegisterFixForMethodOverloads(
            CodeFixContext context,
            SeparatedSyntaxList <TArgumentSyntax> arguments,
            ImmutableArray <ArgumentInsertPositionData <TArgumentSyntax> > methodsAndArgumentsToAdd)
        {
            var codeFixData = PrepareCreationOfCodeActions(context.Document, arguments, methodsAndArgumentsToAdd);

            // To keep the list of offered fixes short we create one menu entry per overload only
            // as long as there are two or less overloads present. If there are more overloads we
            // create two menu entries. One entry for non-cascading fixes and one with cascading fixes.
            var fixes = codeFixData.Length <= 2
                ? NestByOverload()
                : NestByCascading();

            context.RegisterFixes(fixes, context.Diagnostics);
            return;

            ImmutableArray <CodeAction> NestByOverload()
            {
                using var builderDisposer = ArrayBuilder <CodeAction> .GetInstance(codeFixData.Length, out var builder);

                foreach (var data in codeFixData)
                {
                    // We create the mandatory data.CreateChangedSolutionNonCascading fix first.
                    var        title      = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true);
                    CodeAction codeAction = new MyCodeAction(
                        title: title,
                        data.CreateChangedSolutionNonCascading);
                    if (data.CreateChangedSolutionCascading != null)
                    {
                        // We have two fixes to offer. We nest the two fixes in an inlinable CodeAction
                        // so the IDE is free to either show both at once or to create a sub-menu.
                        var titleForNesting = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true);
                        var titleCascading  = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0_and_overrides_implementations, data.Method,
                                                              includeParameters: true);
                        codeAction = new CodeAction.CodeActionWithNestedActions(
                            title: titleForNesting,
                            ImmutableArray.Create(
                                codeAction,
                                new MyCodeAction(
                                    title: titleCascading,
                                    data.CreateChangedSolutionCascading)),
                            isInlinable: true);
                    }

                    // codeAction is now either a single fix or two fixes wrapped in a CodeActionWithNestedActions
                    builder.Add(codeAction);
                }

                return(builder.ToImmutable());
            }

            ImmutableArray <CodeAction> NestByCascading()
            {
                using var builderDisposer = ArrayBuilder <CodeAction> .GetInstance(capacity : 2, out var builder);

                var nonCascadingActions = codeFixData.SelectAsArray(data =>
                {
                    var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true);
                    return((CodeAction) new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading));
                });

                var cascadingActions = codeFixData.SelectAsArray(
                    data => data.CreateChangedSolutionCascading != null,
                    data =>
                {
                    var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true);
                    return((CodeAction) new MyCodeAction(title: title, data.CreateChangedSolutionCascading !));
                });
        private IEnumerable<CodeAction> CreateActions(
            CodeFixContext context, Document document, Diagnostic diagnostic, 
            SyntaxNode node, SemanticModel semanticModel, 
            IEnumerable<INamespaceOrTypeSymbol> proposedContainers, 
            ISymbolDisplayService displayService)
        {
            foreach (var container in proposedContainers)
            {
                var containerName = displayService.ToMinimalDisplayString(semanticModel, node.SpanStart, container);

                var name = GetNodeName(document, node);

                // Actual member name might differ by case.
                string memberName;
                if (this.IgnoreCase)
                {
                    var member = container.GetMembers(name).FirstOrDefault();
                    memberName = member != null ? member.Name : name;
                }
                else
                {
                    memberName = name;
                }

                var codeAction = new MyCodeAction(
                    $"{containerName}.{memberName}",
                    c => ProcessNode(document, node, containerName, c));

                yield return codeAction;
            }
        }
        private void RegisterFixForMethodOverloads(
            CodeFixContext context,
            SeparatedSyntaxList <TArgumentSyntax> arguments,
            ImmutableArray <ArgumentInsertPositionData <TArgumentSyntax> > methodsAndArgumentsToAdd)
        {
            var codeFixData = PrepareCreationOfCodeActions(context.Document, arguments, methodsAndArgumentsToAdd);

            // To keep the list of offered fixes short we create one menu entry per overload only
            // as long as there are two or less overloads present. If there are more overloads we
            // create two menu entries. One entry for non-cascading fixes and one with cascading fixes.
            var fixes = codeFixData.Length <= 2
                ? NestByOverload()
                : NestByCascading();

            context.RegisterFixes(fixes, context.Diagnostics);
            return;

            ImmutableArray <CodeAction> NestByOverload()
            {
                var builder = ArrayBuilder <CodeAction> .GetInstance(codeFixData.Length);

                foreach (var data in codeFixData)
                {
                    // We create the mandatory data.CreateChangedSolutionNonCascading fix first.
                    var        title      = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true);
                    CodeAction codeAction = new MyCodeAction(
                        title: title,
                        data.CreateChangedSolutionNonCascading);
                    if (data.CreateChangedSolutionCascading != null)
                    {
                        // We have two fixes to offer. We nest the two fixes in an inlinable CodeAction
                        // so the IDE is free to either show both at once or to create a sub-menu.
                        var titleForNesting = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, data.Method, includeParameters: true);
                        var titleCascading  = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0_and_overrides_implementations, data.Method,
                                                              includeParameters: true);
                        codeAction = new CodeAction.CodeActionWithNestedActions(
                            title: titleForNesting,
                            ImmutableArray.Create(
                                codeAction,
                                new MyCodeAction(
                                    title: titleCascading,
                                    data.CreateChangedSolutionCascading)),
                            isInlinable: true);
                    }

                    // codeAction is now either a single fix or two fixes wrapped in a CodeActionWithNestedActions
                    builder.Add(codeAction);
                }

                return(builder.ToImmutableAndFree());
            }

            ImmutableArray <CodeAction> NestByCascading()
            {
                var builder = ArrayBuilder <CodeAction> .GetInstance(2);

                var nonCascadingActions = ImmutableArray.CreateRange <CodeFixData, CodeAction>(codeFixData, data =>
                {
                    var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true);
                    return(new MyCodeAction(title: title, data.CreateChangedSolutionNonCascading));
                });

                var cascading        = codeFixData.Where(data => data.CreateChangedSolutionCascading != null);
                var cascadingActions = ImmutableArray.CreateRange <CodeAction>(cascading.Select(data =>
                {
                    var title = GetCodeFixTitle(FeaturesResources.Add_to_0, data.Method, includeParameters: true);
                    return(new MyCodeAction(title: title, data.CreateChangedSolutionCascading));
                }));

                var aMethod = codeFixData.First().Method; // We need to term the MethodGroup and need an arbitrary IMethodSymbol to do so.
                var nestedNonCascadingTitle = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0, aMethod, includeParameters: false);

                // Create a sub-menu entry with all the non-cascading CodeActions.
                // We make sure the IDE does not inline. Otherwise the context menu gets flooded with our fixes.
                builder.Add(new CodeAction.CodeActionWithNestedActions(nestedNonCascadingTitle, nonCascadingActions, isInlinable: false));

                if (cascadingActions.Length > 0)
                {
                    // if there are cascading CodeActions create a second sub-menu.
                    var nestedCascadingTitle = GetCodeFixTitle(FeaturesResources.Add_parameter_to_0_and_overrides_implementations,
                                                               aMethod, includeParameters: false);
                    builder.Add(new CodeAction.CodeActionWithNestedActions(nestedCascadingTitle, cascadingActions, isInlinable: false));
                }

                return(builder.ToImmutableAndFree());
            }
        }
Example #15
0
 public sealed override Task ComputeRefactoringsAsync(CodeRefactoringContext context)
 {
     var codeAction = new MyCodeAction(context.Document);
     context.RegisterRefactoring(codeAction);
     return SpecializedTasks.EmptyTask;
 }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            var document = context.Document;
            var span = context.Span;
            var diagnostics = context.Diagnostics;
            var cancellationToken = context.CancellationToken;

            var project = document.Project;
            var diagnostic = diagnostics.First();
            var root = await document.GetSyntaxRootAsync(cancellationToken).ConfigureAwait(false);
            var ancestors = root.FindToken(span.Start, findInsideTrivia: true).GetAncestors<SyntaxNode>();
            if (!ancestors.Any())
            {
                return;
            }

            var node = ancestors.FirstOrDefault(n => n.Span.Contains(span) && n != root);
            if (node == null)
            {
                return;
            }

            var placeSystemNamespaceFirst = document.Project.Solution.Workspace.Options.GetOption(Microsoft.CodeAnalysis.Shared.Options.OrganizerOptions.PlaceSystemNamespaceFirst, document.Project.Language);

            using (Logger.LogBlock(FunctionId.Refactoring_AddImport, cancellationToken))
            {
                if (!cancellationToken.IsCancellationRequested)
                {
                    if (this.CanAddImport(node, cancellationToken))
                    {
                        var semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);
                        var containingType = semanticModel.GetEnclosingNamedType(node.SpanStart, cancellationToken);
                        var containingTypeOrAssembly = containingType ?? (ISymbol)semanticModel.Compilation.Assembly;
                        var namespacesInScope = this.GetNamespacesInScope(semanticModel, node, cancellationToken);
                        var syntaxFacts = document.Project.LanguageServices.GetService<ISyntaxFactsService>();

                        var matchingTypesNamespaces = await this.GetNamespacesForMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingTypes = await this.GetMatchingTypesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingNamespaces = await this.GetNamespacesForMatchingNamespacesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingExtensionMethodsNamespaces = await this.GetNamespacesForMatchingExtensionMethodsAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var matchingFieldsAndPropertiesAsync = await this.GetNamespacesForMatchingFieldsAndPropertiesAsync(project, diagnostic, node, semanticModel, namespacesInScope, syntaxFacts, cancellationToken).ConfigureAwait(false);
                        var queryPatternsNamespaces = await this.GetNamespacesForQueryPatternsAsync(project, diagnostic, node, semanticModel, namespacesInScope, cancellationToken).ConfigureAwait(false);

                        if (matchingTypesNamespaces != null || matchingNamespaces != null || matchingExtensionMethodsNamespaces != null || matchingFieldsAndPropertiesAsync != null || queryPatternsNamespaces != null || matchingTypes != null)
                        {
                            matchingTypesNamespaces = matchingTypesNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingNamespaces = matchingNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingExtensionMethodsNamespaces = matchingExtensionMethodsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingFieldsAndPropertiesAsync = matchingFieldsAndPropertiesAsync ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            queryPatternsNamespaces = queryPatternsNamespaces ?? SpecializedCollections.EmptyList<INamespaceSymbol>();
                            matchingTypes = matchingTypes ?? SpecializedCollections.EmptyList<ITypeSymbol>();

                            var proposedImports =
                                matchingTypesNamespaces.Cast<INamespaceOrTypeSymbol>()
                                           .Concat(matchingNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingExtensionMethodsNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingFieldsAndPropertiesAsync.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(queryPatternsNamespaces.Cast<INamespaceOrTypeSymbol>())
                                           .Concat(matchingTypes.Cast<INamespaceOrTypeSymbol>())
                                           .Distinct()
                                           .Where(NotNull)
                                           .Where(NotGlobalNamespace)
                                           .OrderBy(INamespaceOrTypeSymbolExtensions.CompareNamespaceOrTypeSymbols)
                                           .Take(8)
                                           .ToList();

                            if (proposedImports.Count > 0)
                            {
                                cancellationToken.ThrowIfCancellationRequested();

                                foreach (var import in proposedImports)
                                {
                                    var action = new MyCodeAction(this.GetDescription(import, semanticModel, node), (c) =>
                                        this.AddImportAsync(node, import, document, placeSystemNamespaceFirst, cancellationToken));

                                    context.RegisterCodeFix(action, diagnostic);
                                }
                            }
                        }
                    }
                }
            }
        }
        protected override async Task<ImmutableArray<CodeAction>> GetRefactoringsForSingleParameterAsync(
            Document document, IParameterSymbol parameter, SyntaxNode functionDeclaration, IMethodSymbol method,
            IBlockOperation? blockStatementOpt, CancellationToken cancellationToken)
        {
            // Only supported for constructor parameters.
            if (method.MethodKind != MethodKind.Constructor)
                return ImmutableArray<CodeAction>.Empty;

            var typeDeclaration = functionDeclaration.GetAncestor<TTypeDeclarationSyntax>();
            if (typeDeclaration == null)
                return ImmutableArray<CodeAction>.Empty;

            var assignmentStatement = TryFindFieldOrPropertyAssignmentStatement(
                parameter, blockStatementOpt);
            if (assignmentStatement != null)
            {
                // We're already assigning this parameter to a field/property in this type.
                // So there's nothing more for us to do.
                return ImmutableArray<CodeAction>.Empty;
            }

            // Haven't initialized any fields/properties with this parameter.  Offer to assign
            // to an existing matching field/prop if we can find one, or add a new field/prop
            // if we can't.

            var rules = await document.GetNamingRulesAsync(cancellationToken).ConfigureAwait(false);
            var parameterNameParts = IdentifierNameParts.CreateIdentifierNameParts(parameter, rules);
            if (parameterNameParts.BaseName == "")
            {
                return ImmutableArray<CodeAction>.Empty;
            }

            var fieldOrProperty = await TryFindMatchingUninitializedFieldOrPropertySymbolAsync(
                document, parameter, blockStatementOpt, rules, parameterNameParts.BaseNameParts, cancellationToken).ConfigureAwait(false);

            if (fieldOrProperty != null)
            {
                // Found a field/property that this parameter should be assigned to.
                // Just offer the simple assignment to it.

                var resource = fieldOrProperty.Kind == SymbolKind.Field
                    ? FeaturesResources.Initialize_field_0
                    : FeaturesResources.Initialize_property_0;

                var title = string.Format(resource, fieldOrProperty.Name);

                return ImmutableArray.Create<CodeAction>(new MyCodeAction(
                    title,
                    c => AddSymbolInitializationAsync(
                        document, parameter, functionDeclaration, blockStatementOpt, fieldOrProperty, c)));
            }
            else
            {
                // Didn't find a field/prop that this parameter could be assigned to.
                // Offer to create new one and assign to that.
                var codeGenService = document.GetLanguageService<ICodeGenerationService>();

                var options = await document.GetOptionsAsync(cancellationToken).ConfigureAwait(false);
                var requireAccessibilityModifiers = options.GetOption(CodeStyleOptions2.RequireAccessibilityModifiers);

                var field = CreateField(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);
                var property = CreateProperty(requireAccessibilityModifiers, parameter, rules, parameterNameParts.BaseNameParts);

                var fieldAction = new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_field_0, field.Name),
                    c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, blockStatementOpt, field, c));
                var propertyAction = new MyCodeAction(string.Format(FeaturesResources.Create_and_initialize_property_0, property.Name),
                    c => AddSymbolInitializationAsync(document, parameter, functionDeclaration, blockStatementOpt, property, c));

                // Check if the surrounding parameters are assigned to another field in this class.  If so, offer to
                // make this parameter into a field as well.  Otherwise, default to generating a property
                var siblingFieldOrProperty = TryFindSiblingFieldOrProperty(parameter, blockStatementOpt);
                return siblingFieldOrProperty is IFieldSymbol
                    ? ImmutableArray.Create<CodeAction>(fieldAction, propertyAction)
                    : ImmutableArray.Create<CodeAction>(propertyAction, fieldAction);
            }
        }