private static Accessibility GetAccessibility(SyntaxNodeAnalysisContext context, MemberDeclarationSyntax declaration, SyntaxTokenList modifiers)
        {
            if (!modifiers.Any(f => SyntaxFacts.IsAccessibilityModifier(f.Kind())))
            {
                if (modifiers.Any(SyntaxKind.PartialKeyword))
                {
                    if (!declaration.IsKind(SyntaxKind.MethodDeclaration))
                    {
                        Accessibility?accessibility = GetPartialAccessModifier(context, declaration);

                        if (accessibility != null)
                        {
                            if (accessibility == Accessibility.NotApplicable)
                            {
                                return(SyntaxAccessibility.GetDefaultExplicitAccessibility(declaration));
                            }
                            else
                            {
                                return(accessibility.Value);
                            }
                        }
                    }
                }
                else
                {
                    return(SyntaxAccessibility.GetDefaultExplicitAccessibility(declaration));
                }
            }

            return(Accessibility.NotApplicable);
        }
        private static TNode AddModifier<TNode>(
            TNode node,
            SyntaxKind modifierKind,
            IComparer<SyntaxKind> comparer = null) where TNode : SyntaxNode
        {
            switch (modifierKind)
            {
                case SyntaxKind.AbstractKeyword:
                    {
                        node = node.RemoveModifiers(SyntaxKind.VirtualKeyword, SyntaxKind.OverrideKeyword);
                        break;
                    }
                case SyntaxKind.VirtualKeyword:
                    {
                        node = node.RemoveModifiers(SyntaxKind.AbstractKeyword, SyntaxKind.OverrideKeyword);
                        break;
                    }
                case SyntaxKind.OverrideKeyword:
                    {
                        node = node.RemoveModifiers(SyntaxKind.AbstractKeyword, SyntaxKind.VirtualKeyword);
                        break;
                    }
                case SyntaxKind.StaticKeyword:
                    {
                        if (node.IsKind(SyntaxKind.ConstructorDeclaration))
                            node = SyntaxAccessibility.WithoutExplicitAccessibility(node);

                        node = node.RemoveModifier(SyntaxKind.SealedKeyword);

                        break;
                    }
            }

            return node.InsertModifier(modifierKind, comparer);
        }
Beispiel #3
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

            if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.MarkOperatorAsPublicAndStatic))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            ModifierListInfo info = SyntaxInfo.ModifierListInfo(memberDeclaration);

            var title = "Add ";

            if (info.ExplicitAccessibility == Accessibility.Public)
            {
                title += "modifier 'static'";
            }
            else if (info.IsStatic)
            {
                title += "modifier 'public'";
            }
            else
            {
                title += "modifiers 'public static'";
            }

            CodeAction codeAction = CodeAction.Create(
                title,
                cancellationToken =>
            {
                SyntaxNode newNode = memberDeclaration;

                if (info.Modifiers.ContainsAny(SyntaxKind.InternalKeyword, SyntaxKind.ProtectedKeyword, SyntaxKind.PrivateKeyword))
                {
                    newNode = SyntaxAccessibility.WithoutExplicitAccessibility(newNode);
                }

                if (!info.Modifiers.Contains(SyntaxKind.PublicKeyword))
                {
                    newNode = ModifierList.Insert(newNode, SyntaxKind.PublicKeyword);
                }

                if (!info.IsStatic)
                {
                    newNode = ModifierList.Insert(newNode, SyntaxKind.StaticKeyword);
                }

                return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, cancellationToken));
            },
                base.GetEquivalenceKey(diagnostic));

            context.RegisterCodeFix(codeAction, diagnostic);
        }
        private static Accessibility?GetPartialAccessModifier(
            SyntaxNodeAnalysisContext context,
            MemberDeclarationSyntax declaration)
        {
            var accessibility = Accessibility.NotApplicable;

            ISymbol symbol = context.SemanticModel.GetDeclaredSymbol(declaration, context.CancellationToken);

            if (symbol != null)
            {
                foreach (SyntaxReference syntaxReference in symbol.DeclaringSyntaxReferences)
                {
                    if (syntaxReference.GetSyntax(context.CancellationToken) is MemberDeclarationSyntax declaration2)
                    {
                        Accessibility accessibility2 = SyntaxAccessibility.GetExplicitAccessibility(declaration2);

                        if (accessibility2 != Accessibility.NotApplicable)
                        {
                            if (accessibility == Accessibility.NotApplicable || accessibility == accessibility2)
                            {
                                accessibility = accessibility2;
                            }
                            else
                            {
                                return(null);
                            }
                        }
                    }
                }
            }

            return(accessibility);
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

            if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.ChangeAccessibility))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: CSharpOverriddenSymbolInfo.CanCreate))
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            OverriddenSymbolInfo overrideInfo = CSharpOverriddenSymbolInfo.Create(node, semanticModel, context.CancellationToken);

            if (!overrideInfo.Success)
            {
                return;
            }

            Accessibility newAccessibility = overrideInfo.OverriddenSymbol.DeclaredAccessibility;

            CodeAction codeAction = CodeAction.Create(
                $"Change accessibility to '{SyntaxFacts.GetText(newAccessibility)}'",
                cancellationToken =>
            {
                if (node.Kind() == SyntaxKind.VariableDeclarator)
                {
                    node = node.Parent.Parent;
                }

                SyntaxNode newNode;

                if (newAccessibility == Accessibility.Public &&
                    node is AccessorDeclarationSyntax)
                {
                    newNode = SyntaxAccessibility.WithoutExplicitAccessibility(node);
                }
                else
                {
                    newNode = SyntaxAccessibility.WithExplicitAccessibility(node, newAccessibility);
                }

                return(context.Document.ReplaceNodeAsync(node, newNode, cancellationToken));
            },
                GetEquivalenceKey(diagnostic));

            context.RegisterCodeFix(codeAction, diagnostic);
        }
Beispiel #6
0
        public static Task <Document> RefactorAsync(
            Document document,
            ConstructorDeclarationSyntax constructorDeclaration,
            CancellationToken cancellationToken)
        {
            ConstructorDeclarationSyntax newNode = SyntaxAccessibility.WithExplicitAccessibility(constructorDeclaration, Accessibility.Protected);

            return(document.ReplaceNodeAsync(constructorDeclaration, newNode, cancellationToken));
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(
                    root,
                    context.Span,
                    out SyntaxNode node,
                    predicate: f => OverriddenSymbolInfo.CanCreate(f)))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.CannotChangeAccessModifiersWhenOverridingInheritedMember:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    OverriddenSymbolInfo overrideInfo = OverriddenSymbolInfo.Create(node, semanticModel, context.CancellationToken);

                    if (!overrideInfo.Success)
                    {
                        break;
                    }

                    Accessibility newAccessibility = overrideInfo.OverriddenSymbol.DeclaredAccessibility;

                    CodeAction codeAction = CodeAction.Create(
                        $"Change accessibility to '{SyntaxFacts.GetText(newAccessibility)}'",
                        cancellationToken =>
                        {
                            if (node.Kind() == SyntaxKind.VariableDeclarator)
                            {
                                node = node.Parent.Parent;
                            }

                            SyntaxNode newNode = SyntaxAccessibility.WithExplicitAccessibility(node, newAccessibility);

                            return(context.Document.ReplaceNodeAsync(node, newNode, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Beispiel #8
0
        public static Task <Document> RefactorAsync(
            Document document,
            SyntaxNode node,
            Accessibility newAccessibility,
            CancellationToken cancellationToken)
        {
            SyntaxNode newNode = SyntaxAccessibility.WithExplicitAccessibility(node, newAccessibility);

            return(document.ReplaceNodeAsync(node, newNode, cancellationToken));
        }
        public static Task <Document> RefactorAsync(
            Document document,
            MemberDeclarationSyntax memberDeclaration,
            Accessibility accessibility,
            CancellationToken cancellationToken)
        {
            MemberDeclarationSyntax newNode = SyntaxAccessibility.WithExplicitAccessibility(memberDeclaration, accessibility);

            return(document.ReplaceNodeAsync(memberDeclaration, newNode, cancellationToken));
        }
Beispiel #10
0
        public static async Task <Solution> RefactorAsync(
            Solution solution,
            MemberDeclarationListSelection selectedMembers,
            Accessibility newAccessibility,
            SemanticModel semanticModel,
            CancellationToken cancellationToken)
        {
            var members = new HashSet <MemberDeclarationSyntax>();

            foreach (MemberDeclarationSyntax member in selectedMembers)
            {
                ModifierFilter filter = SyntaxInfo.ModifierListInfo(member).GetFilter();

                if (filter.HasAnyFlag(ModifierFilter.Partial))
                {
                    ISymbol symbol = semanticModel.GetDeclaredSymbol(member, cancellationToken);

                    foreach (SyntaxReference reference in symbol.DeclaringSyntaxReferences)
                    {
                        members.Add((MemberDeclarationSyntax)reference.GetSyntax(cancellationToken));
                    }
                }
                else if (filter.HasAnyFlag(ModifierFilter.AbstractVirtualOverride))
                {
                    ISymbol symbol = GetBaseSymbolOrDefault(member, semanticModel, cancellationToken);

                    if (symbol != null)
                    {
                        foreach (MemberDeclarationSyntax member2 in GetMemberDeclarations(symbol, cancellationToken))
                        {
                            members.Add(member2);
                        }

                        foreach (MemberDeclarationSyntax member2 in await FindOverridingMemberDeclarationsAsync(symbol, solution, cancellationToken).ConfigureAwait(false))
                        {
                            members.Add(member2);
                        }
                    }
                    else
                    {
                        members.Add(member);
                    }
                }
                else
                {
                    members.Add(member);
                }
            }

            return(await solution.ReplaceNodesAsync(
                       members,
                       (node, _) => SyntaxAccessibility.WithExplicitAccessibility(node, newAccessibility),
                       cancellationToken)
                   .ConfigureAwait(false));
        }
Beispiel #11
0
        public static Task <Document> RefactorAsync(
            Document document,
            PropertyDeclarationSyntax propertyDeclaration,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            AccessorListSyntax accessorList = AccessorList();

            if (propertyDeclaration.ExpressionBody != null)
            {
                accessorList = accessorList
                               .AddAccessors(AutoGetAccessorDeclaration());
            }
            else
            {
                AccessorDeclarationSyntax getter = propertyDeclaration.Getter();
                if (getter != null)
                {
                    if (SyntaxAccessibility.GetExplicitAccessibility(getter) == Accessibility.Private)
                    {
                        getter = SyntaxAccessibility.WithExplicitAccessibility(getter, Accessibility.Protected);
                    }

                    accessorList = accessorList.AddAccessors(getter
                                                             .WithBody(null)
                                                             .WithSemicolonToken(SemicolonToken()));
                }

                AccessorDeclarationSyntax setter = propertyDeclaration.Setter();
                if (setter != null)
                {
                    if (SyntaxAccessibility.GetExplicitAccessibility(setter) == Accessibility.Private)
                    {
                        setter = SyntaxAccessibility.WithExplicitAccessibility(setter, Accessibility.Protected);
                    }

                    accessorList = accessorList.AddAccessors(setter
                                                             .WithBody(null)
                                                             .WithSemicolonToken(SemicolonToken()));
                }
            }

            PropertyDeclarationSyntax newNode = propertyDeclaration
                                                .WithExpressionBody(null)
                                                .WithSemicolonToken(default(SyntaxToken))
                                                .WithAccessorList(accessorList)
                                                .InsertModifier(SyntaxKind.AbstractKeyword)
                                                .RemoveModifier(SyntaxKind.VirtualKeyword)
                                                .WithTriviaFrom(propertyDeclaration)
                                                .WithFormatterAnnotation();

            return(document.ReplaceNodeAsync(propertyDeclaration, newNode, cancellationToken));
        }
        public static void ChangeAccessibility(
            CodeFixContext context,
            Diagnostic diagnostic,
            SyntaxNode node,
            Accessibility accessibility)
        {
            if (!SyntaxAccessibility.IsValidAccessibility(node, accessibility))
                return;

            CodeAction codeAction = CodeAction.Create(
                $"Change accessibility to '{GetText(accessibility)}'",
                ct => ChangeAccessibilityRefactoring.RefactorAsync(context.Document, node, accessibility, ct),
                GetEquivalenceKey(diagnostic, accessibility.ToString()));

            context.RegisterCodeFix(codeAction, diagnostic);
        }
Beispiel #13
0
        public static void RemoveAccessibility(
            CodeFixContext context,
            Diagnostic diagnostic,
            SyntaxNode node,
            string additionalKey = null)
        {
            var accessModifier = default(SyntaxToken);

            foreach (SyntaxToken modifier in SyntaxInfo.ModifierListInfo(node).Modifiers)
            {
                if (IsAccessibilityModifier(modifier.Kind()))
                {
                    if (IsAccessibilityModifier(accessModifier.Kind()))
                    {
                        accessModifier = default;
                        break;
                    }
                    else
                    {
                        accessModifier = modifier;
                    }
                }
            }

            if (IsAccessibilityModifier(accessModifier.Kind()))
            {
                RemoveModifier(context, diagnostic, node, accessModifier, additionalKey: additionalKey);
            }
            else
            {
                CodeAction codeAction = CodeAction.Create(
                    "Remove access modifiers",
                    cancellationToken =>
                {
                    SyntaxNode newNode = SyntaxAccessibility.WithoutExplicitAccessibility(node);

                    return(context.Document.ReplaceNodeAsync(node, newNode, cancellationToken));
                },
                    GetEquivalenceKey(diagnostic, additionalKey));

                context.RegisterCodeFix(codeAction, diagnostic);
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

            if (!Settings.IsEnabled(diagnostic.Id, CodeFixIdentifiers.SynchronizeAccessibility))
            {
                return;
            }

            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

            var symbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

            ImmutableArray <MemberDeclarationSyntax> memberDeclarations = ImmutableArray.CreateRange(
                symbol.DeclaringSyntaxReferences,
                f => (MemberDeclarationSyntax)f.GetSyntax(context.CancellationToken));

            foreach (Accessibility accessibility in memberDeclarations
                     .Select(f => SyntaxAccessibility.GetExplicitAccessibility(f))
                     .Where(f => f != Accessibility.NotApplicable))
            {
                if (SyntaxAccessibility.IsValidAccessibility(memberDeclaration, accessibility))
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Change accessibility to '{SyntaxFacts.GetText(accessibility)}'",
                        cancellationToken => ChangeAccessibilityRefactoring.RefactorAsync(context.Solution(), memberDeclarations, accessibility, cancellationToken),
                        GetEquivalenceKey(CompilerDiagnosticIdentifiers.PartialDeclarationsHaveConfictingAccessibilityModifiers, accessibility.ToString()));

                    context.RegisterCodeFix(codeAction, diagnostic);
                }
            }
        }
        public static void AnalyzeConstructorDeclaration(SyntaxNodeAnalysisContext context)
        {
            var constructorDeclaration = (ConstructorDeclarationSyntax)context.Node;

            if (!SyntaxAccessibility.GetExplicitAccessibility(constructorDeclaration).Is(Accessibility.Public, Accessibility.ProtectedOrInternal))
            {
                return;
            }

            if (!constructorDeclaration.IsParentKind(SyntaxKind.ClassDeclaration))
            {
                return;
            }

            var classDeclaration = (ClassDeclarationSyntax)constructorDeclaration.Parent;

            SyntaxTokenList modifiers = classDeclaration.Modifiers;

            bool isAbstract = modifiers.Contains(SyntaxKind.AbstractKeyword);

            if (!isAbstract &&
                modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                INamedTypeSymbol classSymbol = context.SemanticModel.GetDeclaredSymbol(classDeclaration, context.CancellationToken);

                if (classSymbol != null)
                {
                    isAbstract = classSymbol.IsAbstract;
                }
            }

            if (!isAbstract)
            {
                return;
            }

            context.ReportDiagnostic(DiagnosticDescriptors.AbstractTypeShouldNotHavePublicConstructors, constructorDeclaration.Identifier);
        }
Beispiel #16
0
        public static Accessibilities GetValidAccessibilities(MemberDeclarationListSelection selectedMembers, bool allowOverride = false)
        {
            if (selectedMembers.Count < 2)
            {
                return(Accessibilities.None);
            }

            var all = Accessibilities.None;

            Accessibilities valid = Accessibilities.Public
                                    | Accessibilities.Internal
                                    | Accessibilities.Protected
                                    | Accessibilities.Private;

            foreach (MemberDeclarationSyntax member in selectedMembers)
            {
                Accessibility accessibility = SyntaxAccessibility.GetExplicitAccessibility(member);

                if (accessibility == Accessibility.NotApplicable)
                {
                    accessibility = SyntaxAccessibility.GetDefaultExplicitAccessibility(member);

                    if (accessibility == Accessibility.NotApplicable)
                    {
                        return(Accessibilities.None);
                    }
                }

                Accessibilities accessibilities = accessibility.GetAccessibilities();

                switch (accessibility)
                {
                case Accessibility.Private:
                case Accessibility.Protected:
                case Accessibility.ProtectedAndInternal:
                case Accessibility.ProtectedOrInternal:
                case Accessibility.Internal:
                case Accessibility.Public:
                {
                    all |= accessibilities;
                    break;
                }

                default:
                {
                    Debug.Fail(accessibility.ToString());
                    return(Accessibilities.None);
                }
                }

                foreach (Accessibility accessibility2 in AvailableAccessibilities)
                {
                    if (accessibility != accessibility2 &&
                        !SyntaxAccessibility.IsValidAccessibility(member, accessibility2, ignoreOverride: allowOverride))
                    {
                        valid &= ~accessibility2.GetAccessibilities();
                    }
                }
            }

            switch (all)
            {
            case Accessibilities.Private:
            case Accessibilities.Protected:
            case Accessibilities.Internal:
            case Accessibilities.Public:
            {
                valid &= ~all;
                break;
            }
            }

            return(valid);
        }
        public static AccessibilityFilter GetValidAccessibilityFilter(
            MemberDeclarationListSelection selectedMembers,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            if (selectedMembers.Count < 2)
            {
                return(AccessibilityFilter.None);
            }

            ImmutableArray <Accessibility> avaiableAccessibilities = AvailableAccessibilities;

            var all = AccessibilityFilter.None;

            AccessibilityFilter valid = AccessibilityFilter.Public
                                        | AccessibilityFilter.Internal
                                        | AccessibilityFilter.Protected
                                        | AccessibilityFilter.Private;

            foreach (MemberDeclarationSyntax member in selectedMembers)
            {
                Accessibility accessibility = SyntaxAccessibility.GetExplicitAccessibility(member);

                if (accessibility == Accessibility.NotApplicable)
                {
                    accessibility = SyntaxAccessibility.GetDefaultExplicitAccessibility(member);

                    if (accessibility == Accessibility.NotApplicable)
                    {
                        return(AccessibilityFilter.None);
                    }
                }

                switch (accessibility)
                {
                case Accessibility.Private:
                case Accessibility.Protected:
                case Accessibility.ProtectedAndInternal:
                case Accessibility.ProtectedOrInternal:
                case Accessibility.Internal:
                case Accessibility.Public:
                {
                    all |= accessibility.GetAccessibilityFilter();
                    break;
                }

                default:
                {
                    Debug.Fail(accessibility.ToString());
                    return(AccessibilityFilter.None);
                }
                }

                ModifierListInfo modifiersInfo = SyntaxInfo.ModifierListInfo(member);

                if (modifiersInfo.Modifiers.ContainsAny(
                        SyntaxKind.AbstractKeyword,
                        SyntaxKind.VirtualKeyword,
                        SyntaxKind.OverrideKeyword))
                {
                    valid &= ~AccessibilityFilter.Private;
                }

                if (modifiersInfo.IsOverride &&
                    IsBaseDeclarationWithoutSource(member, semanticModel, cancellationToken))
                {
                    switch (accessibility)
                    {
                    case Accessibility.Private:
                    case Accessibility.Protected:
                    case Accessibility.Internal:
                    case Accessibility.Public:
                    {
                        valid &= accessibility.GetAccessibilityFilter();

                        if (valid == AccessibilityFilter.None)
                        {
                            return(AccessibilityFilter.None);
                        }

                        avaiableAccessibilities = _accessibilityArrayMap[accessibility];
                        continue;
                    }

                    default:
                    {
                        return(AccessibilityFilter.None);
                    }
                    }
                }

                foreach (Accessibility accessibility2 in avaiableAccessibilities)
                {
                    if (accessibility != accessibility2 &&
                        !SyntaxAccessibility.IsValidAccessibility(member, accessibility2, ignoreOverride: true))
                    {
                        valid &= ~accessibility2.GetAccessibilityFilter();

                        if (valid == AccessibilityFilter.None)
                        {
                            return(AccessibilityFilter.None);
                        }
                    }
                }
            }

            switch (all)
            {
            case AccessibilityFilter.Private:
            case AccessibilityFilter.Protected:
            case AccessibilityFilter.Internal:
            case AccessibilityFilter.Public:
            {
                valid &= ~all;
                break;
            }
            }

            return(valid);
        }
Beispiel #18
0
        private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context, TypeDeclarationSyntax typeDeclaration)
        {
            if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                return;
            }

            SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members;

            UnusedMemberWalker walker = null;

            foreach (MemberDeclarationSyntax member in members)
            {
                if (member.ContainsDiagnostics)
                {
                    continue;
                }

                if (member.ContainsDirectives)
                {
                    continue;
                }

                switch (member.Kind())
                {
                case SyntaxKind.DelegateDeclaration:
                {
                    var declaration = (DelegateDeclarationSyntax)member;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNode(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }

                case SyntaxKind.EventDeclaration:
                {
                    var declaration = (EventDeclarationSyntax)member;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNode(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }

                case SyntaxKind.EventFieldDeclaration:
                {
                    var declaration = (EventFieldDeclarationSyntax)member;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNodes(declaration.Declaration);
                    }

                    break;
                }

                case SyntaxKind.FieldDeclaration:
                {
                    var             declaration = (FieldDeclarationSyntax)member;
                    SyntaxTokenList modifiers   = declaration.Modifiers;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNodes(declaration.Declaration, isConst: modifiers.Contains(SyntaxKind.ConstKeyword));
                    }

                    break;
                }

                case SyntaxKind.MethodDeclaration:
                {
                    var declaration = (MethodDeclarationSyntax)member;

                    SyntaxTokenList modifiers = declaration.Modifiers;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        !declaration.AttributeLists.Any() &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        string methodName = declaration.Identifier.ValueText;

                        if (!IsMainMethod(declaration, modifiers, methodName))
                        {
                            if (walker == null)
                            {
                                walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                            }

                            walker.AddNode(methodName, declaration);
                        }
                    }

                    break;
                }

                case SyntaxKind.PropertyDeclaration:
                {
                    var declaration = (PropertyDeclarationSyntax)member;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNode(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }
                }
            }

            if (walker == null)
            {
                return;
            }

            walker.Visit(typeDeclaration);

            foreach (NodeSymbolInfo info in UnusedMemberWalkerCache.GetNodesAndFree(walker))
            {
                SyntaxNode node = info.Node;

                if (node is VariableDeclaratorSyntax variableDeclarator)
                {
                    var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent;

                    if (variableDeclaration.Variables.Count == 1)
                    {
                        ReportDiagnostic(context, variableDeclaration.Parent, CSharpFacts.GetTitle(variableDeclaration.Parent));
                    }
                    else
                    {
                        ReportDiagnostic(context, variableDeclarator, CSharpFacts.GetTitle(variableDeclaration.Parent));
                    }
                }
                else
                {
                    ReportDiagnostic(context, node, CSharpFacts.GetTitle(node));
                }
            }
        }
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, SyntaxToken modifier)
        {
            SyntaxNode node = modifier.Parent;

            if (node.IsKind(SyntaxKind.DestructorDeclaration))
            {
                return;
            }

            ModifierListInfo modifiersInfo = SyntaxInfo.ModifierListInfo(node);

            if (node.IsKind(
                    SyntaxKind.ClassDeclaration,
                    SyntaxKind.InterfaceDeclaration,
                    SyntaxKind.StructDeclaration,
                    SyntaxKind.RecordStructDeclaration))
            {
                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                var symbol = (INamedTypeSymbol)semanticModel.GetDeclaredSymbol(node, context.CancellationToken);

                ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                if (syntaxReferences.Length > 1)
                {
                    ImmutableArray <MemberDeclarationSyntax> memberDeclarations = ImmutableArray.CreateRange(
                        syntaxReferences,
                        f => (MemberDeclarationSyntax)f.GetSyntax(context.CancellationToken));

                    foreach (Accessibility accessibility in AvailableAccessibilities)
                    {
                        if (accessibility != modifiersInfo.ExplicitAccessibility &&
                            SyntaxAccessibility.IsValidAccessibility(node, accessibility))
                        {
                            context.RegisterRefactoring(
                                GetTitle(accessibility),
                                ct => RefactorAsync(context.Solution, memberDeclarations, accessibility, ct),
                                RefactoringDescriptors.ChangeAccessibility,
                                accessibility.ToString());
                        }
                    }

                    return;
                }
            }

            foreach (Accessibility accessibility in AvailableAccessibilities)
            {
                if (accessibility == modifiersInfo.ExplicitAccessibility)
                {
                    continue;
                }

                SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                ISymbol symbol = GetBaseSymbolOrDefault(semanticModel, context.CancellationToken);

                if (symbol != null)
                {
                    if (SyntaxAccessibility.IsValidAccessibility(node, accessibility, ignoreOverride: true))
                    {
                        context.RegisterRefactoring(
                            GetTitle(accessibility),
                            ct => RefactorAsync(context.Solution, symbol, accessibility, ct),
                            RefactoringDescriptors.ChangeAccessibility,
                            accessibility.ToString());
                    }
                }
                else if (SyntaxAccessibility.IsValidAccessibility(node, accessibility))
                {
                    context.RegisterRefactoring(
                        GetTitle(accessibility),
                        ct => RefactorAsync(context.Document, node, accessibility, ct),
                        RefactoringDescriptors.ChangeAccessibility,
                        accessibility.ToString());
                }
            }

            ISymbol GetBaseSymbolOrDefault(SemanticModel semanticModel, CancellationToken cancellationToken)
            {
                if (modifiersInfo.GetFilter().HasAnyFlag(ModifierFilter.AbstractVirtualOverride))
                {
                    return(ChangeAccessibilityRefactoring.GetBaseSymbolOrDefault(node, semanticModel, cancellationToken));
                }

                return(null);
            }
        }
Beispiel #20
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out MemberDeclarationSyntax memberDeclaration))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeActionFactory.RemoveMemberDeclaration(context.Document, memberDeclaration, equivalenceKey: GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.AddAccessibilityModifiersOrViceVersa:
                {
                    if (diagnostic.Properties.TryGetValue(nameof(Accessibility), out string accessibilityText))
                    {
                        var accessibility = (Accessibility)Enum.Parse(typeof(Accessibility), accessibilityText);

                        CodeAction codeAction = CodeAction.Create(
                            "Add accessibility modifiers",
                            ct =>
                            {
                                MemberDeclarationSyntax newNode = SyntaxAccessibility.WithExplicitAccessibility(memberDeclaration, accessibility);

                                return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else
                    {
                        CodeAction codeAction = CodeAction.Create(
                            "Remove accessibility modifiers",
                            ct =>
                            {
                                MemberDeclarationSyntax newNode = SyntaxAccessibility.WithoutExplicitAccessibility(memberDeclaration);

                                return(context.Document.ReplaceNodeAsync(memberDeclaration, newNode, ct));
                            },
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case DiagnosticIdentifiers.RemoveRedundantSealedModifier:
                {
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, memberDeclaration, SyntaxKind.SealedKeyword);
                    break;
                }

                case DiagnosticIdentifiers.AvoidSemicolonAtEndOfDeclaration:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary semicolon",
                        cancellationToken => AvoidSemicolonAtEndOfDeclarationRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.OrderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Order modifiers",
                        ct => OrderModifiersAsync(context.Document, memberDeclaration, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MakeFieldReadOnly:
                {
                    var fieldDeclaration = (FieldDeclarationSyntax)memberDeclaration;

                    SeparatedSyntaxList <VariableDeclaratorSyntax> declarators = fieldDeclaration.Declaration.Variables;

                    string title = (declarators.Count == 1)
                                ? $"Make '{declarators[0].Identifier.ValueText}' read-only"
                                : "Make fields read-only";

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, title: title);
                    break;
                }

                case DiagnosticIdentifiers.UseConstantInsteadOfField:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use constant instead of field",
                        cancellationToken => UseConstantInsteadOfFieldRefactoring.RefactorAsync(context.Document, (FieldDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.UseReadOnlyAutoProperty:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use read-only auto-property",
                        cancellationToken => UseReadOnlyAutoPropertyAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.ConvertCommentToDocumentationComment:
                {
                    CodeAction codeAction = CodeAction.Create(
                        ConvertCommentToDocumentationCommentRefactoring.Title,
                        cancellationToken => ConvertCommentToDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }

                case DiagnosticIdentifiers.MakeMethodExtensionMethod:
                {
                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Make method an extension method",
                        cancellationToken =>
                        {
                            ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters[0];

                            ParameterSyntax newParameter = ModifierList.Insert(parameter, SyntaxKind.ThisKeyword);

                            return(context.Document.ReplaceNodeAsync(parameter, newParameter, cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context, TypeDeclarationSyntax typeDeclaration, INamedTypeSymbol debuggerDisplayAttribute)
        {
            if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
            {
                return;
            }

            SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members;

            UnusedMemberWalker walker = null;

            foreach (MemberDeclarationSyntax member in members)
            {
                if (member.ContainsDiagnostics)
                {
                    continue;
                }

                if (member.ContainsDirectives)
                {
                    continue;
                }

                switch (member.Kind())
                {
                case SyntaxKind.DelegateDeclaration:
                {
                    var declaration = (DelegateDeclarationSyntax)member;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddDelegate(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }

                case SyntaxKind.EventDeclaration:
                {
                    var declaration = (EventDeclarationSyntax)member;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNode(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }

                case SyntaxKind.EventFieldDeclaration:
                {
                    var declaration = (EventFieldDeclarationSyntax)member;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNodes(declaration.Declaration);
                    }

                    break;
                }

                case SyntaxKind.FieldDeclaration:
                {
                    var             declaration = (FieldDeclarationSyntax)member;
                    SyntaxTokenList modifiers   = declaration.Modifiers;

                    if (SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNodes(declaration.Declaration, isConst: modifiers.Contains(SyntaxKind.ConstKeyword));
                    }

                    break;
                }

                case SyntaxKind.MethodDeclaration:
                {
                    var declaration = (MethodDeclarationSyntax)member;

                    SyntaxTokenList modifiers = declaration.Modifiers;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        !declaration.AttributeLists.Any() &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        string methodName = declaration.Identifier.ValueText;

                        if (!IsMainMethod(declaration, modifiers, methodName))
                        {
                            if (walker == null)
                            {
                                walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                            }

                            walker.AddNode(methodName, declaration);
                        }
                    }

                    break;
                }

                case SyntaxKind.PropertyDeclaration:
                {
                    var declaration = (PropertyDeclarationSyntax)member;

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance(context.SemanticModel, context.CancellationToken);
                        }

                        walker.AddNode(declaration.Identifier.ValueText, declaration);
                    }

                    break;
                }
                }
            }

            if (walker == null)
            {
                return;
            }

            if (debuggerDisplayAttribute != null &&
                walker.Nodes.Any(f => f.CanBeInDebuggerDisplayAttribute) &&
                ShouldAnalyzeDebuggerDisplayAttribute())
            {
                string value = context.SemanticModel
                               .GetDeclaredSymbol(typeDeclaration, context.CancellationToken)
                               .GetAttribute(debuggerDisplayAttribute)?
                               .ConstructorArguments
                               .SingleOrDefault(shouldThrow: false)
                               .Value?
                               .ToString();

                if (value != null)
                {
                    RemoveMethodsAndPropertiesThatAreInDebuggerDisplayAttributeValue(walker.Nodes, value);
                }

                if (walker.Nodes.Count == 0)
                {
                    return;
                }
            }

            walker.Visit(typeDeclaration);

            foreach (NodeSymbolInfo info in UnusedMemberWalkerCache.GetNodesAndFree(walker))
            {
                SyntaxNode node = info.Node;

                if (node is VariableDeclaratorSyntax variableDeclarator)
                {
                    var variableDeclaration = (VariableDeclarationSyntax)variableDeclarator.Parent;

                    if (variableDeclaration.Variables.Count == 1)
                    {
                        ReportDiagnostic(context, variableDeclaration.Parent, CSharpFacts.GetTitle(variableDeclaration.Parent));
                    }
                    else
                    {
                        ReportDiagnostic(context, variableDeclarator, CSharpFacts.GetTitle(variableDeclaration.Parent));
                    }
                }
                else
                {
                    ReportDiagnostic(context, node, CSharpFacts.GetTitle(node));
                }
            }

            bool ShouldAnalyzeDebuggerDisplayAttribute()
            {
                if (typeDeclaration.Modifiers.Contains(SyntaxKind.PartialKeyword))
                {
                    return(true);
                }

                foreach (AttributeListSyntax attributeList in typeDeclaration.AttributeLists)
                {
                    foreach (AttributeSyntax attribute in attributeList.Attributes)
                    {
                        if (attribute.ArgumentList?.Arguments.Count(f => f.NameEquals == null) == 1)
                        {
                            return(true);
                        }
                    }
                }

                return(false);
            }
        }
        public static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)
        {
            var classDeclaration = (ClassDeclarationSyntax)context.Node;

            if (!classDeclaration.Identifier.ValueText.EndsWith("Extensions", StringComparison.Ordinal))
            {
                return;
            }

            if (!classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword))
            {
                return;
            }

            if (!classDeclaration.IsParentKind(SyntaxKind.NamespaceDeclaration, SyntaxKind.CompilationUnit))
            {
                return;
            }

            if (!SyntaxAccessibility.GetAccessibility(classDeclaration).Is(Accessibility.Public, Accessibility.Internal))
            {
                return;
            }

            foreach (MemberDeclarationSyntax member in classDeclaration.Members)
            {
                if (!member.IsKind(SyntaxKind.MethodDeclaration))
                {
                    continue;
                }

                var methodDeclaration = (MethodDeclarationSyntax)member;

                if (!methodDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword))
                {
                    continue;
                }

                if (!SyntaxAccessibility.GetAccessibility(methodDeclaration).Is(Accessibility.Public, Accessibility.Internal))
                {
                    continue;
                }

                ParameterSyntax parameter = methodDeclaration.ParameterList?.Parameters.FirstOrDefault();

                if (parameter == null)
                {
                    continue;
                }

                bool isThis = false;
                bool isIn   = false;
                bool isRef  = false;

                foreach (SyntaxToken modifier in parameter.Modifiers)
                {
                    SyntaxKind kind = modifier.Kind();

                    if (kind == SyntaxKind.ThisKeyword)
                    {
                        isThis = true;
                        break;
                    }
                    else if (kind == SyntaxKind.InKeyword)
                    {
                        isIn = true;
                    }
                    else if (kind == SyntaxKind.RefKeyword)
                    {
                        isRef = true;
                    }

                    if (isThis)
                    {
                        break;
                    }
                }

                if (isThis)
                {
                    continue;
                }

                if (isIn)
                {
                    IParameterSymbol parameterSymbol = context.SemanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

                    ITypeSymbol typeSymbol = parameterSymbol.Type;

                    if (!typeSymbol.IsValueType)
                    {
                        continue;
                    }

                    if (typeSymbol.Kind == SymbolKind.TypeParameter)
                    {
                        continue;
                    }
                }
                else if (isRef)
                {
                    IParameterSymbol parameterSymbol = context.SemanticModel.GetDeclaredSymbol(parameter, context.CancellationToken);

                    if (!parameterSymbol.Type.IsValueType)
                    {
                        continue;
                    }
                }

                context.ReportDiagnostic(DiagnosticDescriptors.MakeMethodExtensionMethod, methodDeclaration.Identifier);
            }
        }
Beispiel #23
0
        public static Task <Document> RefactorAsync(
            Document document,
            MemberDeclarationListSelection selectedMembers,
            Accessibility newAccessibility,
            CancellationToken cancellationToken)
        {
            SyntaxList <MemberDeclarationSyntax> newMembers = selectedMembers
                                                              .UnderlyingList
                                                              .ReplaceRange(selectedMembers.FirstIndex, selectedMembers.Count, selectedMembers.Select(f => SyntaxAccessibility.WithExplicitAccessibility(f, newAccessibility)));

            MemberDeclarationListInfo info = SyntaxInfo.MemberDeclarationListInfo(selectedMembers);

            return(document.ReplaceMembersAsync(info, newMembers, cancellationToken));
        }