private static void AnalyzeSimpleAssignment(SyntaxNodeAnalysisContext context)
        {
            if (context.Node.ContainsDiagnostics)
            {
                return;
            }

            if (context.Node.SpanOrTrailingTriviaContainsDirectives())
            {
                return;
            }

            var assignment = (AssignmentExpressionSyntax)context.Node;

            SimpleAssignmentStatementInfo assignmentInfo = SyntaxInfo.SimpleAssignmentStatementInfo(assignment);

            if (!assignmentInfo.Success)
            {
                return;
            }

            if (!(assignmentInfo.Left is IdentifierNameSyntax identifierName))
            {
                return;
            }

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(assignmentInfo.Statement);

            if (!statementsInfo.Success)
            {
                return;
            }

            int index = statementsInfo.IndexOf(assignmentInfo.Statement);

            if (index == statementsInfo.Count - 1)
            {
                return;
            }

            if (index > 0)
            {
                StatementSyntax previousStatement = statementsInfo[index - 1];

                SimpleAssignmentStatementInfo assignmentInfo2 = SyntaxInfo.SimpleAssignmentStatementInfo(previousStatement);

                if (assignmentInfo2.Success &&
                    assignmentInfo2.Left is IdentifierNameSyntax identifierName2 &&
                    string.Equals(identifierName.Identifier.ValueText, identifierName2.Identifier.ValueText, StringComparison.Ordinal))
                {
                    return;
                }
            }

            StatementSyntax nextStatement = statementsInfo[index + 1];

            if (nextStatement.SpanOrLeadingTriviaContainsDirectives())
            {
                return;
            }

            if (!(nextStatement is ReturnStatementSyntax returnStatement))
            {
                return;
            }

            if (!(returnStatement.Expression?.WalkDownParentheses() is IdentifierNameSyntax identifierName3))
            {
                return;
            }

            if (!string.Equals(identifierName.Identifier.ValueText, identifierName3.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            ISymbol symbol = context.SemanticModel.GetSymbol(identifierName, context.CancellationToken);

            switch (symbol?.Kind)
            {
            case SymbolKind.Local:
            {
                break;
            }

            case SymbolKind.Parameter:
            {
                if (((IParameterSymbol)symbol).RefKind != RefKind.None)
                {
                    return;
                }

                break;
            }

            default:
            {
                return;
            }
            }

            if (IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt())
            {
                return;
            }

            bool result;
            RemoveRedundantAssignmentWalker walker = null;

            try
            {
                walker = RemoveRedundantAssignmentWalker.GetInstance();

                walker.Symbol            = symbol;
                walker.SemanticModel     = context.SemanticModel;
                walker.CancellationToken = context.CancellationToken;
                walker.Result            = false;

                walker.Visit(assignmentInfo.Right);

                result = walker.Result;
            }
            finally
            {
                if (walker != null)
                {
                    RemoveRedundantAssignmentWalker.Free(walker);
                }
            }

            if (result)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantAssignment, assignment);

            bool IsAssignedInsideAnonymousFunctionButDeclaredOutsideOfIt()
            {
                SyntaxNode declaringSyntax = null;
                SyntaxNode n = assignment.Parent;

                do
                {
                    if (CSharpFacts.IsAnonymousFunctionExpression(n.Kind()))
                    {
                        if (declaringSyntax == null)
                        {
                            declaringSyntax = symbol.GetSyntaxOrDefault();

                            Debug.Assert(declaringSyntax != null, "");

                            if (declaringSyntax == null)
                            {
                                break;
                            }

                            Debug.Assert(declaringSyntax.IsKind(SyntaxKind.VariableDeclarator, SyntaxKind.Parameter), declaringSyntax.Kind().ToString());
                        }

                        SyntaxNode n2 = declaringSyntax.Parent;

                        do
                        {
                            if (CSharpFacts.IsAnonymousFunctionExpression(n2.Kind()))
                            {
                                return(!object.ReferenceEquals(n, n2));
                            }

                            if (n2 is MemberDeclarationSyntax)
                            {
                                break;
                            }

                            n2 = n2.Parent;
                        } while (n2 != null);

                        return(true);
                    }
                    else if (n is MemberDeclarationSyntax)
                    {
                        break;
                    }

                    n = n.Parent;
                } while (n != null);

                return(false);
            }
        }
        protected override void WriteSymbol(
            ISymbol symbol,
            SymbolDisplayFormat format = null,
            bool removeAttributeSuffix = false)
        {
            bool shouldWriteContainingNamespace = false;

            if (symbol.Kind == SymbolKind.Field &&
                symbol.ContainingType.TypeKind == TypeKind.Enum)
            {
                base.WriteSymbol(symbol, format);
            }
            else
            {
                shouldWriteContainingNamespace = ShouldWriteContainingNamespace();

                if (IsExternal(symbol))
                {
                    string url = WellKnownExternalUrlProviders.MicrosoftDocs.CreateUrl(symbol).Url;

                    if (url != null)
                    {
                        if (shouldWriteContainingNamespace)
                        {
                            WriteContainingNamespace(symbol);
                        }

                        WriteStartElement("a");
                        WriteAttributeString("href", url);
                        WriteName();
                        WriteEndElement();
                    }
                    else
                    {
                        WriteName();
                    }
                }
                else
                {
                    if (shouldWriteContainingNamespace)
                    {
                        WriteContainingNamespace(symbol);
                    }

                    WriteStartElement("a");
                    WriteStartAttribute("href");
                    Write("#");
                    WriteLocalLink(symbol);
                    WriteEndAttribute();
                    WriteName();
                    WriteEndElement();
                }
            }

            bool ShouldWriteContainingNamespace()
            {
                return(symbol.IsKind(SymbolKind.NamedType) &&
                       !symbol.ContainingNamespace.IsGlobalNamespace &&
                       Format.Includes(SymbolDefinitionPartFilter.ContainingNamespace) &&
                       !CSharpFacts.IsPredefinedType(((INamedTypeSymbol)symbol).SpecialType) &&
                       (format == null || format.TypeQualificationStyle == SymbolDisplayTypeQualificationStyle.NameAndContainingTypesAndNamespaces));
            }

            void WriteName()
            {
                if (symbol.IsKind(SymbolKind.Namespace))
                {
                    format = TypeSymbolDisplayFormats.Name_ContainingTypes_Namespaces;
                }
                else if (shouldWriteContainingNamespace)
                {
                    format = TypeSymbolDisplayFormats.Name_ContainingTypes_SpecialTypes;
                }

                base.WriteSymbol(symbol, format, removeAttributeSuffix: removeAttributeSuffix);
            }
        }
Пример #3
0
        private static void AnalyzeForStatement(SyntaxNodeAnalysisContext context)
        {
            var forStatement = (ForStatementSyntax)context.Node;

            StatementSyntax statement = forStatement.EmbeddedStatement();

            if (statement == null)
            {
                return;
            }

            if (statement.ContainsDirectives)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticDescriptors.AddBraces, statement, CSharpFacts.GetTitle(forStatement));
        }
Пример #4
0
        private static void AnalyzeMethodDeclaration(SyntaxNodeAnalysisContext context)
        {
            var methodDeclaration = (MethodDeclarationSyntax)context.Node;

            if (methodDeclaration.ContainsDirectives)
            {
                return;
            }

            if (methodDeclaration.ContainsDiagnostics)
            {
                return;
            }

            if (methodDeclaration.AttributeLists.Any())
            {
                return;
            }

            if (!CheckModifiers(methodDeclaration.Modifiers))
            {
                return;
            }

            if (methodDeclaration.HasDocumentationComment())
            {
                return;
            }

            if (!methodDeclaration.DescendantTrivia(methodDeclaration.Span).All(f => f.IsWhitespaceOrEndOfLineTrivia()))
            {
                return;
            }

            ExpressionSyntax expression = GetMethodExpression(methodDeclaration);

            SimpleMemberInvocationExpressionInfo invocationInfo = SyntaxInfo.SimpleMemberInvocationExpressionInfo(expression);

            if (!invocationInfo.Success)
            {
                return;
            }

            if (invocationInfo.Expression.Kind() != SyntaxKind.BaseExpression)
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, cancellationToken);

            if (methodSymbol == null)
            {
                return;
            }

            IMethodSymbol overriddenMethod = methodSymbol.OverriddenMethod;

            if (overriddenMethod == null)
            {
                return;
            }

            ISymbol symbol = semanticModel.GetSymbol(invocationInfo.Name, cancellationToken);

            if (!SymbolEqualityComparer.Default.Equals(overriddenMethod, symbol))
            {
                return;
            }

            if (!CheckParameters(methodDeclaration.ParameterList, invocationInfo.ArgumentList, semanticModel, cancellationToken))
            {
                return;
            }

            if (!CheckDefaultValues(methodSymbol.Parameters, overriddenMethod.Parameters))
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context,
                                               DiagnosticDescriptors.RemoveRedundantOverridingMember,
                                               methodDeclaration,
                                               CSharpFacts.GetTitle(methodDeclaration));
        }
Пример #5
0
        public static void AnalyzeSimpleMemberAccessExpression(SyntaxNodeAnalysisContext context)
        {
            var memberAccess = (MemberAccessExpressionSyntax)context.Node;

            if (memberAccess.IsParentKind(SyntaxKind.SimpleMemberAccessExpression))
            {
                return;
            }

            ExpressionSyntax expression = memberAccess.Expression;

            if (expression == null)
            {
                return;
            }

            SyntaxKind kind = expression.Kind();

            if (kind == SyntaxKind.IdentifierName)
            {
                if (!SupportsPredefinedType((IdentifierNameSyntax)expression))
                {
                    return;
                }
            }
            else if (kind == SyntaxKind.SimpleMemberAccessExpression)
            {
                memberAccess = (MemberAccessExpressionSyntax)expression;

                if (!(memberAccess.Name is IdentifierNameSyntax identifierName))
                {
                    return;
                }

                if (!SupportsPredefinedType(identifierName))
                {
                    return;
                }
            }
            else
            {
                return;
            }

            if (!(context.SemanticModel.GetSymbol(expression, context.CancellationToken) is ITypeSymbol typeSymbol))
            {
                return;
            }

            if (!CSharpFacts.IsPredefinedType(typeSymbol.SpecialType))
            {
                return;
            }

            IAliasSymbol aliasSymbol = context.SemanticModel.GetAliasInfo(expression, context.CancellationToken);

            if (aliasSymbol != null)
            {
                return;
            }

            ReportDiagnostic(context, expression);
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsAnyCodeFixEnabled(
                    CodeFixIdentifiers.WrapInUnsafeStatement,
                    CodeFixIdentifiers.MakeContainingDeclarationUnsafe))
            {
                return;
            }

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

            if (!TryFindNode(root, context.Span, out SyntaxNode node))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.PointersAndFixedSizeBuffersMayOnlyBeUsedInUnsafeContext:
                {
                    bool fStatement         = false;
                    bool fMemberDeclaration = false;

                    foreach (SyntaxNode ancestor in node.AncestorsAndSelf())
                    {
                        if (fStatement &&
                            fMemberDeclaration)
                        {
                            break;
                        }

                        if (!fStatement &&
                            ancestor is StatementSyntax)
                        {
                            fStatement = true;

                            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.WrapInUnsafeStatement))
                            {
                                continue;
                            }

                            var statement = (StatementSyntax)ancestor;

                            if (statement.IsKind(SyntaxKind.Block) &&
                                statement.Parent is StatementSyntax)
                            {
                                statement = (StatementSyntax)statement.Parent;
                            }

                            if (statement.IsKind(SyntaxKind.UnsafeStatement))
                            {
                                break;
                            }

                            CodeAction codeAction = CodeAction.Create(
                                "Wrap in unsafe block",
                                cancellationToken =>
                                {
                                    BlockSyntax block = (statement.IsKind(SyntaxKind.Block))
                                                ? (BlockSyntax)statement
                                                : SyntaxFactory.Block(statement);

                                    UnsafeStatementSyntax unsafeStatement = SyntaxFactory.UnsafeStatement(block).WithFormatterAnnotation();

                                    return(context.Document.ReplaceNodeAsync(statement, unsafeStatement, cancellationToken));
                                },
                                GetEquivalenceKey(diagnostic, CodeFixIdentifiers.WrapInUnsafeStatement));

                            context.RegisterCodeFix(codeAction, diagnostic);
                        }
                        else if (!fMemberDeclaration &&
                                 ancestor is MemberDeclarationSyntax)
                        {
                            fMemberDeclaration = true;

                            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingDeclarationUnsafe))
                            {
                                continue;
                            }

                            if (!CSharpFacts.CanHaveModifiers(ancestor.Kind()))
                            {
                                continue;
                            }

                            ModifiersCodeFixRegistrator.AddModifier(
                                context,
                                diagnostic,
                                ancestor,
                                SyntaxKind.UnsafeKeyword,
                                title: "Make containing declaration unsafe",
                                additionalKey: CodeFixIdentifiers.MakeContainingDeclarationUnsafe);
                        }
                    }

                    break;
                }
                }
            }
        }
Пример #7
0
        private static void AnalyzeIfStatement(SyntaxNodeAnalysisContext context)
        {
            var ifStatement = (IfStatementSyntax)context.Node;

            if (ifStatement.IsSimpleIf())
            {
                return;
            }

            StatementSyntax statement = ifStatement.EmbeddedStatement();

            if (statement == null)
            {
                return;
            }

            if (statement.ContainsDirectives)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.AddBracesToIfElse, statement, CSharpFacts.GetTitle(ifStatement));
        }
        private static void AnalyzeTypeDeclaration(SyntaxNodeAnalysisContext context)
        {
            var typeDeclaration = (TypeDeclarationSyntax)context.Node;

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

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            ImmutableArray <AttributeData> attributes = default;

            if (typeDeclaration.IsKind(SyntaxKind.StructDeclaration))
            {
                INamedTypeSymbol declarationSymbol = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken);

                attributes = declarationSymbol.GetAttributes();

                if (attributes.Any(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Runtime_InteropServices_StructLayoutAttribute)))
                {
                    return;
                }
            }

            SyntaxList <MemberDeclarationSyntax> members = typeDeclaration.Members;

            UnusedMemberWalker walker = null;

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

                if (member.ContainsUnbalancedIfElseDirectives(member.Span))
                {
                    continue;
                }

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

                    if (SyntaxAccessibility <DelegateDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance();
                        }

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

                    break;
                }

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

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility <EventDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance();
                        }

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

                    break;
                }

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

                    if (SyntaxAccessibility <EventFieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance();
                        }

                        walker.AddNodes(declaration.Declaration);
                    }

                    break;
                }

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

                    if (SyntaxAccessibility <FieldDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance();
                        }

                        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 <MethodDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        string methodName = declaration.Identifier.ValueText;

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

                            walker.AddNode(methodName, declaration);
                        }
                    }

                    break;
                }

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

                    if (declaration.ExplicitInterfaceSpecifier == null &&
                        SyntaxAccessibility <PropertyDeclarationSyntax> .Instance.GetAccessibility(declaration) == Accessibility.Private)
                    {
                        if (walker == null)
                        {
                            walker = UnusedMemberWalkerCache.GetInstance();
                        }

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

                    break;
                }
                }
            }

            if (walker == null)
            {
                return;
            }

            Collection <NodeSymbolInfo> nodes = walker.Nodes;

            if (ShouldAnalyzeDebuggerDisplayAttribute() &&
                nodes.Any(f => f.CanBeInDebuggerDisplayAttribute))
            {
                if (attributes.IsDefault)
                {
                    attributes = semanticModel.GetDeclaredSymbol(typeDeclaration, cancellationToken).GetAttributes();
                }

                string value = attributes
                               .FirstOrDefault(f => f.AttributeClass.HasMetadataName(MetadataNames.System_Diagnostics_DebuggerDisplayAttribute))?
                               .ConstructorArguments
                               .SingleOrDefault(shouldThrow: false)
                               .Value?
                               .ToString();

                if (value != null)
                {
                    RemoveMethodsAndPropertiesThatAreInDebuggerDisplayAttributeValue(value, ref nodes);
                }

                if (nodes.Count == 0)
                {
                    UnusedMemberWalkerCache.Free(walker);
                    return;
                }
            }

            walker.SemanticModel     = semanticModel;
            walker.CancellationToken = cancellationToken;

            walker.Visit(typeDeclaration);

            foreach (NodeSymbolInfo info in nodes)
            {
                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));
                }
            }

            UnusedMemberWalkerCache.Free(walker);

            bool ShouldAnalyzeDebuggerDisplayAttribute()
            {
                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 sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.SimplifyBooleanComparison:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean comparison",
                        cancellationToken => SimplifyBooleanComparisonRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    break;
                }

                case DiagnosticIdentifiers.CallSkipAndAnyInsteadOfCount:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Call 'Skip' and 'Any' instead of 'Count'",
                        cancellationToken => CallSkipAndAnyInsteadOfCountRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AvoidNullLiteralExpressionOnLeftSideOfBinaryExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        cancellationToken => CommonRefactorings.SwapBinaryOperandsAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        cancellationToken => UseStringIsNullOrEmptyMethodRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        cancellationToken => SimplifyCoalesceExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, expression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        cancellationToken => RemoveRedundantAsOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        cancellationToken => UseStringLengthInsteadOfComparisonWithEmptyStringRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        cancellationToken => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title;

                    if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) ||
                        typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(semanticModel, binaryExpression.Right.SpanStart);

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.Default)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        cancellationToken => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(context.Document, binaryExpression, typeSymbol, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        cancellationToken => JoinStringExpressionsRefactoring.RefactorAsync(context.Document, binaryExpression, context.Span, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        cancellationToken => UseExclusiveOrOperatorRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyBooleanExpression:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Simplify boolean expression",
                        cancellationToken => SimplifyBooleanExpressionRefactoring.RefactorAsync(context.Document, binaryExpression, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ExpressionIsAlwaysEqualToTrueOrFalse:
                {
                    LiteralExpressionSyntax newNode = BooleanLiteralExpression(binaryExpression.IsKind(SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanOrEqualExpression));

                    CodeAction codeAction = CodeAction.Create(
                        $"Replace expression with '{newNode}'",
                        cancellationToken => context.Document.ReplaceNodeAsync(binaryExpression, newNode.WithTriviaFrom(binaryExpression), cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out StatementSyntax statement))
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.AddEmptyLineBeforeWhileInDoStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Add empty line",
                        ct => AddEmptyLineBeforeWhileInDoStatementAsync(context.Document, statement, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.InlineLazyInitialization:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Inline lazy initialization",
                        cancellationToken =>
                        {
                            return(InlineLazyInitializationRefactoring.RefactorAsync(
                                       context.Document,
                                       (IfStatementSyntax)statement,
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantDisposeOrCloseCall:
                {
                    var expressionStatement = (ExpressionStatementSyntax)statement;
                    var invocation          = (InvocationExpressionSyntax)expressionStatement.Expression;
                    var memberAccess        = (MemberAccessExpressionSyntax)invocation.Expression;

                    CodeAction codeAction = CodeAction.Create(
                        $"Remove redundant '{memberAccess.Name?.Identifier.ValueText}' call",
                        cancellationToken => RemoveRedundantDisposeOrCloseCallRefactoring.RefactorAsync(context.Document, expressionStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantStatement:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Remove redundant {CSharpFacts.GetTitle(statement)}",
                        cancellationToken => RemoveRedundantStatementRefactoring.RefactorAsync(context.Document, statement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseMethodChaining:
                {
                    var expressionStatement = (ExpressionStatementSyntax)statement;

                    UseMethodChainingAnalysis analysis;
                    if (expressionStatement.Expression.Kind() == SyntaxKind.InvocationExpression)
                    {
                        analysis = UseMethodChainingAnalysis.WithoutAssignmentAnalysis;
                    }
                    else
                    {
                        analysis = UseMethodChainingAnalysis.WithAssignmentAnalysis;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Use method chaining",
                        cancellationToken => UseMethodChainingRefactoring.RefactorAsync(context.Document, analysis, expressionStatement, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Пример #11
0
        public static async Task <Document> InvertIfAsync(
            Document document,
            IfStatementSyntax ifStatement,
            bool recursive = false,
            CancellationToken cancellationToken = default)
        {
            cancellationToken.ThrowIfCancellationRequested();

            StatementSyntax statement = ifStatement.Statement;

            StatementListInfo statementsInfo = SyntaxInfo.StatementListInfo(ifStatement);

            SyntaxList <StatementSyntax> statements = statementsInfo.Statements;

            InvertIfAnalysis analysis = InvertIfAnalysis.Create(ifStatement, statement);

            int ifStatementIndex = statements.IndexOf(ifStatement);

            StatementSyntax lastStatement = analysis.LastStatement;

            int lastStatementIndex = statements.IndexOf(lastStatement);

            bool isLastStatementRedundant = IsLastStatementRedundant();

            bool shouldUseElseClause = !CSharpFacts.IsJumpStatement(lastStatement.Kind());

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            SyntaxList <StatementSyntax> newStatements = statements;

            if (!recursive)
            {
                Refactor();
            }
            else
            {
                IfStatementSyntax lastIfStatement;

                InvertIfAnalysis a = analysis.AnalyzeNextStatement();

                do
                {
                    lastIfStatement = a.IfStatement;

                    a = a.AnalyzeNextStatement();
                } while (a.Success);

                int firstLastStatementIndex = lastStatementIndex;

                int index = statements.IndexOf(lastIfStatement);

                int firstIndex = ifStatementIndex;

                while (index >= firstIndex)
                {
                    ifStatementIndex = index;
                    ifStatement      = (IfStatementSyntax)statements[ifStatementIndex];
                    statement        = ifStatement.Statement;
                    Refactor();
                    lastStatementIndex = firstLastStatementIndex + newStatements.Count - statements.Count;
                    lastStatement      = (statement is BlockSyntax block) ? block.Statements.Last() : statement;
                    index--;
                }
            }

            return(await document.ReplaceStatementsAsync(statementsInfo, newStatements, cancellationToken).ConfigureAwait(false));

            void Refactor()
            {
                cancellationToken.ThrowIfCancellationRequested();

                SyntaxList <StatementSyntax> nextStatements = newStatements
                                                              .Skip(ifStatementIndex + 1)
                                                              .Take(lastStatementIndex - ifStatementIndex)
                                                              .ToSyntaxList()
                                                              .TrimTrivia();

                BlockSyntax newStatement;
                SyntaxList <StatementSyntax> newNextStatements;

                if (statement is BlockSyntax block)
                {
                    newStatement      = block.WithStatements(nextStatements);
                    newNextStatements = block.Statements;
                }
                else
                {
                    newStatement      = Block(nextStatements);
                    newNextStatements = SingletonList(statement);
                }

                if (isLastStatementRedundant)
                {
                    newNextStatements = newNextStatements.RemoveAt(newNextStatements.Count - 1);
                }

                ElseClauseSyntax elseClause = null;

                if (newNextStatements.Any() &&
                    shouldUseElseClause)
                {
                    elseClause        = ElseClause(Block(newNextStatements));
                    newNextStatements = default;
                }

                IfStatementSyntax newIfStatement = ifStatement.Update(
                    ifKeyword: ifStatement.IfKeyword,
                    openParenToken: ifStatement.OpenParenToken,
                    condition: SyntaxInverter.LogicallyInvert(ifStatement.Condition, semanticModel, cancellationToken),
                    closeParenToken: ifStatement.CloseParenToken,
                    statement: newStatement,
                    @else: elseClause);

                newIfStatement = newIfStatement.WithFormatterAnnotation();

                SyntaxList <StatementSyntax> newNodes = newNextStatements.Insert(0, newIfStatement);

                newStatements = newStatements.ReplaceRange(ifStatementIndex, lastStatementIndex - ifStatementIndex + 1, newNodes);
            }

            bool IsLastStatementRedundant()
            {
                StatementSyntax jumpStatement = analysis.JumpStatement;

                switch (jumpStatement.Kind())
                {
                case SyntaxKind.ReturnStatement:
                {
                    if (((ReturnStatementSyntax)jumpStatement).Expression == null &&
                        RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ReturnStatement))
                    {
                        return(true);
                    }

                    break;
                }

                case SyntaxKind.ContinueStatement:
                {
                    if (RemoveRedundantStatementAnalysis.IsFixable(lastStatement, SyntaxKind.ContinueStatement))
                    {
                        return(true);
                    }

                    break;
                }
                }

                return(false);
            }
        }
        private static void AnalyzeCompilationUnit(SyntaxNodeAnalysisContext context)
        {
            var compilationUnit = (CompilationUnitSyntax)context.Node;

            SyntaxToken endOfFile = compilationUnit.EndOfFileToken;

            SyntaxTriviaList.Reversed.Enumerator en = endOfFile.LeadingTrivia.Reverse().GetEnumerator();

            bool?preferNewLineAtEndOfFile = context.PreferNewLineAtEndOfFile();

            if (preferNewLineAtEndOfFile == null)
            {
                return;
            }

            if (preferNewLineAtEndOfFile == false)
            {
                if (en.MoveNext() &&
                    (!en.Current.IsWhitespaceTrivia() ||
                     en.MoveNext()))
                {
                    if (en.Current.IsEndOfLineTrivia())
                    {
                        ReportDiagnostic(context, endOfFile);
                    }
                    else if (SyntaxFacts.IsPreprocessorDirective(en.Current.Kind()) &&
                             en.Current.GetStructure() is DirectiveTriviaSyntax directiveTrivia &&
                             directiveTrivia.GetTrailingTrivia().LastOrDefault().IsEndOfLineTrivia())
                    {
                        ReportDiagnostic(context, endOfFile);
                    }
                }
                else
                {
                    SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia;

                    if (trailing.Any())
                    {
                        Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End);

                        if (endOfFile.FullSpan.Start == trailing.Span.End &&
                            trailing.LastOrDefault().IsEndOfLineTrivia())
                        {
                            ReportDiagnostic(context, endOfFile);
                        }
                    }
                }
            }
            else if (en.MoveNext())
            {
                if (CSharpFacts.IsCommentTrivia(en.Current.Kind()) ||
                    SyntaxFacts.IsPreprocessorDirective(en.Current.Kind()))
                {
                    ReportDiagnostic(context, endOfFile);
                }
                else if (en.Current.IsWhitespaceOrEndOfLineTrivia() &&
                         endOfFile.LeadingTrivia.Span.Start == 0)
                {
                    while (en.MoveNext())
                    {
                        if (!en.Current.IsWhitespaceOrEndOfLineTrivia())
                        {
                            return;
                        }
                    }

                    ReportDiagnostic(context, endOfFile);
                }
            }
            else if (endOfFile.SpanStart > 0)
            {
                SyntaxTriviaList trailing = endOfFile.GetPreviousToken().TrailingTrivia;

                if (!trailing.Any())
                {
                    ReportDiagnostic(context, endOfFile);
                }
                else
                {
                    Debug.Assert(endOfFile.FullSpan.Start == trailing.Span.End);

                    if (endOfFile.FullSpan.Start == trailing.Span.End &&
                        !trailing.Last().IsEndOfLineTrivia())
                    {
                        ReportDiagnostic(context, endOfFile);
                    }
                }
            }
Пример #13
0
        private static bool HasConstantValue(
            ExpressionSyntax expression,
            ITypeSymbol typeSymbol,
            SemanticModel semanticModel,
            CancellationToken cancellationToken = default)
        {
            if (expression?.IsMissing != false)
            {
                return(false);
            }

            switch (typeSymbol.SpecialType)
            {
            case SpecialType.System_Boolean:
            {
                if (CSharpFacts.IsBooleanLiteralExpression(expression.Kind()))
                {
                    return(true);
                }

                break;
            }

            case SpecialType.System_Char:
            {
                if (expression.Kind() == SyntaxKind.CharacterLiteralExpression)
                {
                    return(true);
                }

                break;
            }

            case SpecialType.System_SByte:
            case SpecialType.System_Byte:
            case SpecialType.System_Int16:
            case SpecialType.System_UInt16:
            case SpecialType.System_Int32:
            case SpecialType.System_UInt32:
            case SpecialType.System_Int64:
            case SpecialType.System_UInt64:
            case SpecialType.System_Decimal:
            case SpecialType.System_Single:
            case SpecialType.System_Double:
            {
                if (expression.Kind() == SyntaxKind.NumericLiteralExpression)
                {
                    return(true);
                }

                break;
            }

            case SpecialType.System_String:
            {
                if (expression.Kind() == SyntaxKind.StringLiteralExpression)
                {
                    return(true);
                }

                break;
            }
            }

            return(semanticModel.HasConstantValue(expression, cancellationToken));
        }
        private static (bool containsReturnAwait, bool containsAwaitStatement) AnalyzeAwaitExpressions(SyntaxNode node)
        {
            if (node is MethodDeclarationSyntax methodDeclaration)
            {
                ArrowExpressionClauseSyntax expressionBody = methodDeclaration.ExpressionBody;

                if (expressionBody != null)
                {
                    return(expressionBody.Expression?.Kind() == SyntaxKind.AwaitExpression, false);
                }

                node = methodDeclaration.Body;
            }
            else
            {
                var localFunction = (LocalFunctionStatementSyntax)node;

                ArrowExpressionClauseSyntax expressionBody = localFunction.ExpressionBody;

                if (expressionBody != null)
                {
                    return(expressionBody.Expression?.Kind() == SyntaxKind.AwaitExpression, false);
                }

                node = localFunction.Body;
            }

            if (node == null)
            {
                return(false, false);
            }

            var containsReturnAwait    = false;
            var containsAwaitStatement = false;

            foreach (SyntaxNode descendant in node.DescendantNodes(node.Span, f => !CSharpFacts.IsFunction(f.Kind())))
            {
                switch (descendant)
                {
                case ReturnStatementSyntax returnStatement:
                {
                    if (returnStatement.Expression?.WalkDownParentheses().Kind() == SyntaxKind.AwaitExpression)
                    {
                        containsReturnAwait = true;
                    }

                    break;
                }

                case ExpressionStatementSyntax expressionStatement:
                {
                    if (expressionStatement.Expression?.Kind() == SyntaxKind.AwaitExpression)
                    {
                        containsAwaitStatement = true;
                    }

                    break;
                }
                }
            }

            return(containsReturnAwait, containsAwaitStatement);
        }
        private static void AnalyzeSingleLineDocumentationCommentTrivia(SyntaxNodeAnalysisContext context)
        {
            var documentationComment = (DocumentationCommentTriviaSyntax)context.Node;

            if (!documentationComment.IsPartOfMemberDeclaration())
            {
                return;
            }

            bool?useCorrectDocumentationTagEnabled = null;
            bool containsInheritDoc       = false;
            bool containsIncludeOrExclude = false;
            bool containsSummaryElement   = false;
            bool containsContentElement   = false;
            bool isFirst = true;

            CancellationToken cancellationToken = context.CancellationToken;

            SyntaxList <XmlNodeSyntax> content = documentationComment.Content;

            for (int i = 0; i < content.Count; i++)
            {
                cancellationToken.ThrowIfCancellationRequested();

                XmlElementInfo info = SyntaxInfo.XmlElementInfo(content[i]);

                if (info.Success)
                {
                    switch (info.GetTag())
                    {
                    case XmlTag.Include:
                    case XmlTag.Exclude:
                    {
                        if (isFirst)
                        {
                            containsIncludeOrExclude = true;
                        }

                        break;
                    }

                    case XmlTag.InheritDoc:
                    {
                        containsInheritDoc = true;
                        break;
                    }

                    case XmlTag.Content:
                    {
                        containsContentElement = true;
                        break;
                    }

                    case XmlTag.Summary:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryToDocumentationComment, info.Element);
                        }

                        containsSummaryElement = true;

                        if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.Example:
                    case XmlTag.Remarks:
                    case XmlTag.Returns:
                    case XmlTag.Value:
                    {
                        if (info.IsContentEmptyOrWhitespace)
                        {
                            ReportUnusedElement(context, info.Element, i, content);
                        }

                        if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.Exception:
                    case XmlTag.List:
                    case XmlTag.Param:
                    case XmlTag.Permission:
                    case XmlTag.TypeParam:
                    {
                        if (useCorrectDocumentationTagEnabled ??= !context.IsAnalyzerSuppressed(DiagnosticDescriptors.FixDocumentationCommentTag))
                        {
                            FixDocumentationCommentTagAnalysis.Analyze(context, info);
                        }

                        break;
                    }

                    case XmlTag.C:
                    case XmlTag.Code:
                    case XmlTag.Para:
                    case XmlTag.ParamRef:
                    case XmlTag.See:
                    case XmlTag.SeeAlso:
                    case XmlTag.TypeParamRef:
                    {
                        break;
                    }

                    default:
                    {
                        Debug.Fail(info.GetTag().ToString());
                        break;
                    }
                    }

                    if (isFirst)
                    {
                        isFirst = false;
                    }
                    else
                    {
                        containsIncludeOrExclude = false;
                    }
                }
            }

            if (containsInheritDoc ||
                containsIncludeOrExclude)
            {
                return;
            }

            if (!containsSummaryElement &&
                !containsContentElement)
            {
                ReportDiagnosticIfNotSuppressed(context, DiagnosticDescriptors.AddSummaryElementToDocumentationComment, documentationComment);
            }

            SyntaxNode parent = documentationComment.ParentTrivia.Token.Parent;

            bool unusedElement = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.UnusedElementInDocumentationComment);
            bool orderParams   = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.OrderElementsInDocumentationComment);
            bool addParam      = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddParamElementToDocumentationComment);
            bool addTypeParam  = !context.IsAnalyzerSuppressed(DiagnosticDescriptors.AddTypeParamElementToDocumentationComment);

            if (addParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <ParameterSyntax> parameters = CSharpUtility.GetParameters((CSharpFacts.HasParameterList(parent.Kind())) ? parent : parent.Parent);

                if (addParam &&
                    parameters.Any())
                {
                    foreach (ParameterSyntax parameter in parameters)
                    {
                        if (IsMissing(documentationComment, parameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, parameters, XmlTag.Param, (nodes, name) => nodes.IndexOf(name));
                }
            }

            if (addTypeParam ||
                orderParams ||
                unusedElement)
            {
                SeparatedSyntaxList <TypeParameterSyntax> typeParameters = CSharpUtility.GetTypeParameters((CSharpFacts.HasTypeParameterList(parent.Kind())) ? parent : parent.Parent);

                if (addTypeParam &&
                    typeParameters.Any())
                {
                    foreach (TypeParameterSyntax typeParameter in typeParameters)
                    {
                        if (IsMissing(documentationComment, typeParameter))
                        {
                            ReportDiagnostic(context, DiagnosticDescriptors.AddTypeParamElementToDocumentationComment, documentationComment);
                            break;
                        }
                    }
                }

                if (orderParams || unusedElement)
                {
                    Analyze(context, documentationComment.Content, typeParameters, XmlTag.TypeParam, (nodes, name) => nodes.IndexOf(name));
                }
            }
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly) &&
                !Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier))
            {
                return;
            }

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

            if (!TryFindToken(root, context.Span.Start, out SyntaxToken token))
            {
                return;
            }

            SyntaxNode node = token.Parent;

            if (!CSharpFacts.CanHaveModifiers(node.Kind()))
            {
                node = node.FirstAncestor(f => CSharpFacts.CanHaveModifiers(f.Kind()));
            }

            Debug.Assert(node != null, $"{nameof(node)} is null");

            if (node == null)
            {
                return;
            }

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case CompilerDiagnosticIdentifiers.ModifierIsNotValidForThisItem:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    SyntaxTokenList modifiers = SyntaxInfo.ModifierListInfo(node).Modifiers;

                    if (modifiers.Contains(token))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                        break;
                    }
                    else if (IsInterfaceMemberOrExplicitInterfaceImplementation(node))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, modifiers, f =>
                            {
                                switch (f.Kind())
                                {
                                case SyntaxKind.PublicKeyword:
                                case SyntaxKind.ProtectedKeyword:
                                case SyntaxKind.InternalKeyword:
                                case SyntaxKind.PrivateKeyword:
                                case SyntaxKind.StaticKeyword:
                                case SyntaxKind.VirtualKeyword:
                                case SyntaxKind.OverrideKeyword:
                                case SyntaxKind.AbstractKeyword:
                                    {
                                        return(true);
                                    }
                                }

                                return(false);
                            });
                    }
                    else if (node.IsKind(SyntaxKind.IndexerDeclaration))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword);
                    }
                    else if (node.IsKind(SyntaxKind.PropertyDeclaration))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MoreThanOneProtectionModifier:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AccessibilityModifiersMayNotBeUsedOnAccessorsInInterface:
                case CompilerDiagnosticIdentifiers.AccessModifiersAreNotAllowedOnStaticConstructors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ModifiersCannotBePlacedOnEventAccessorDeclarations:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.OnlyMethodsClassesStructsOrInterfacesMayBePartial:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ClassCannotBeBothStaticAndSealed:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword, additionalKey: nameof(SyntaxKind.SealedKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.FieldCanNotBeBothVolatileAndReadOnly:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    var fieldDeclaration = (FieldDeclarationSyntax)node;

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.VolatileKeyword, additionalKey: nameof(SyntaxKind.VolatileKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, fieldDeclaration, SyntaxKind.ReadOnlyKeyword, additionalKey: nameof(SyntaxKind.ReadOnlyKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.NewProtectedMemberDeclaredInSealedClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotContainProtectedMembers:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrPrivate);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.VirtualOrAbstractmembersCannotBePrivate:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AbstractPropertiesCannotHavePrivateAccessors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveAccessibility(context, diagnostic, node, additionalKey: CodeFixIdentifiers.RemoveInvalidModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternalOrProtected);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticMemberCannotBeMarkedOverrideVirtualOrAbstract:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    if (!node.IsParentKind(SyntaxKind.ClassDeclaration) ||
                        !((ClassDeclarationSyntax)node.Parent).Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.StaticKeyword, additionalKey: nameof(SyntaxKind.StaticKeyword));
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword, additionalKey: nameof(SyntaxKind.OverrideKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.VirtualKeyword, additionalKey: nameof(SyntaxKind.VirtualKeyword));
                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword, additionalKey: nameof(SyntaxKind.AbstractKeyword));
                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncModifierCanOnlyBeUsedInMethodsThatHaveBody:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.AsyncKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodCannotHaveAccessModifiersOrVirtualAbstractOverrideNewSealedOrExternModifiers:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifiers(context, diagnostic, node, f =>
                        {
                            switch (f.Kind())
                            {
                            case SyntaxKind.PublicKeyword:
                            case SyntaxKind.ProtectedKeyword:
                            case SyntaxKind.InternalKeyword:
                            case SyntaxKind.PrivateKeyword:
                            case SyntaxKind.VirtualKeyword:
                            case SyntaxKind.AbstractKeyword:
                            case SyntaxKind.OverrideKeyword:
                            case SyntaxKind.NewKeyword:
                            case SyntaxKind.SealedKeyword:
                            case SyntaxKind.ExternKeyword:
                                {
                                    return(true);
                                }
                            }

                            return(false);
                        });

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeStatic:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        var methodDeclaration = (MethodDeclarationSyntax)node;

                        ParameterSyntax parameter = methodDeclaration.ParameterList.Parameters.First();

                        SyntaxToken modifier = parameter.Modifiers.Find(SyntaxKind.ThisKeyword);

                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, parameter, modifier, additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ExtensionMethodMustBeDefinedInNonGenericStaticClass:
                {
                    if (!node.IsKind(SyntaxKind.ClassDeclaration))
                    {
                        return;
                    }

                    var classDeclaration = (ClassDeclarationSyntax)node;

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier) &&
                        !classDeclaration.Modifiers.Contains(SyntaxKind.StaticKeyword))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        IEnumerable <ParameterSyntax> thisParameters = classDeclaration.Members
                                                                       .Where(f => f.IsKind(SyntaxKind.MethodDeclaration))
                                                                       .Cast <MethodDeclarationSyntax>()
                                                                       .Select(f => f.ParameterList?.Parameters.FirstOrDefault())
                                                                       .Where(f => f?.Modifiers.Contains(SyntaxKind.ThisKeyword) == true);

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            thisParameters,
                            SyntaxKind.ThisKeyword,
                            title: "Remove 'this' modifier from extension methods",
                            additionalKey: CodeFixIdentifiers.RemoveThisModifier);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoDefiningDeclarationFoundForImplementingDeclarationOfPartialMethod:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodHasParameterModifierThisWhichIsNotOnFirstParameter:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveThisModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, token.Parent, token);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotDeclareInstanceMembersInStaticClass:
                case CompilerDiagnosticIdentifiers.StaticClassesCannotHaveInstanceConstructors:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node, CodeFixIdentifiers.AddStaticModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassNonStatic))
                    {
                        var classDeclaration = (ClassDeclarationSyntax)node.Parent;

                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            classDeclaration.Modifiers.Find(SyntaxKind.StaticKeyword),
                            title: "Make containing class non-static",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassNonStatic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.ElementsDefinedInNamespaceCannotBeExplicitlyDeclaredAsPrivateProtectedOrProtectedInternal:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.ChangeAccessibility))
                    {
                        ModifiersCodeFixRegistrator.ChangeAccessibility(context, diagnostic, node, _publicOrInternal);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NamespaceAlreadyContainsDefinition:
                case CompilerDiagnosticIdentifiers.TypeAlreadyContainsDefinition:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    if (!node.IsKind(
                            SyntaxKind.ClassDeclaration,
                            SyntaxKind.StructDeclaration,
                            SyntaxKind.InterfaceDeclaration,
                            SyntaxKind.MethodDeclaration))
                    {
                        return;
                    }

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

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

                    ImmutableArray <SyntaxReference> syntaxReferences = symbol.DeclaringSyntaxReferences;

                    if (syntaxReferences.Length <= 1)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        ImmutableArray.CreateRange(syntaxReferences, f => f.GetSyntax(context.CancellationToken)),
                        SyntaxKind.PartialKeyword);

                    break;
                }

                case CompilerDiagnosticIdentifiers.NoSuitableMethodFoundToOverride:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveInvalidModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OverrideKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.AsyncMethodsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.IteratorsCannotHaveRefOrOutParameters:
                case CompilerDiagnosticIdentifiers.ReadOnlyFieldCannotBePassedAsRefOrOutValue:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveRefModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.RefKeyword, additionalKey: nameof(SyntaxKind.RefKeyword));
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveOutModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.OutKeyword, additionalKey: nameof(SyntaxKind.OutKeyword));
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.CannotHaveInstancePropertyOrFieldInitializersInStruct:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddStaticModifier))
                    {
                        AddStaticModifier(context, diagnostic, node);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberMustDeclareBodyBecauseItIsNotMarkedAbstractExternOrPartial:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.AddModifierAbstract) &&
                        node.Kind() == SyntaxKind.MethodDeclaration &&
                        (node.Parent as ClassDeclarationSyntax)?.Modifiers.Contains(SyntaxKind.AbstractKeyword) == true)
                    {
                        ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.AbstractKeyword);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.NewVirtualMemberInSealedClass:
                {
                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveVirtualModifier))
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            node,
                            SyntaxKind.VirtualKeyword,
                            additionalKey: CodeFixIdentifiers.RemoveVirtualModifier);
                    }

                    if (Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeContainingClassUnsealed) &&
                        node.Parent is ClassDeclarationSyntax classDeclaration)
                    {
                        ModifiersCodeFixRegistrator.RemoveModifier(
                            context,
                            diagnostic,
                            classDeclaration,
                            SyntaxKind.SealedKeyword,
                            title: "Make containing class unsealed",
                            additionalKey: CodeFixIdentifiers.MakeContainingClassUnsealed);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.InstanceFieldsOfReadOnlyStructsMustBeReadOnly:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.MakeMemberReadOnly))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.ReadOnlyKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberCannotBeSealedBecauseItIsNotOverride:
                {
                    if (!Settings.IsCodeFixEnabled(CodeFixIdentifiers.RemoveSealedModifier))
                    {
                        break;
                    }

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

                    if (semanticModel.GetDiagnostic(
                            CompilerDiagnosticIdentifiers.MemberHidesInheritedMemberToMakeCurrentMethodOverrideThatImplementationAddOverrideKeyword,
                            CSharpUtility.GetIdentifier(node).Span,
                            context.CancellationToken) != null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.RemoveModifier(context, diagnostic, node, SyntaxKind.SealedKeyword);
                    break;
                }
                }
            }
        }
Пример #17
0
        public static async Task ComputeRefactoringsAsync(RefactoringContext context, MemberDeclarationSyntax member)
        {
            SyntaxKind kind = member.Kind();

            switch (kind)
            {
            case SyntaxKind.MethodDeclaration:
            case SyntaxKind.IndexerDeclaration:
            case SyntaxKind.PropertyDeclaration:
            case SyntaxKind.OperatorDeclaration:
            case SyntaxKind.ConversionOperatorDeclaration:
            case SyntaxKind.ConstructorDeclaration:
            case SyntaxKind.EventDeclaration:
            case SyntaxKind.NamespaceDeclaration:
            case SyntaxKind.ClassDeclaration:
            case SyntaxKind.RecordDeclaration:
            case SyntaxKind.StructDeclaration:
            case SyntaxKind.InterfaceDeclaration:
            case SyntaxKind.EnumDeclaration:
            {
                if (context.IsAnyRefactoringEnabled(
                        RefactoringIdentifiers.RemoveMember,
                        RefactoringIdentifiers.DuplicateMember,
                        RefactoringIdentifiers.CommentOutMember) &&
                    BraceContainsSpan(member, context.Span))
                {
                    if (member.IsParentKind(
                            SyntaxKind.NamespaceDeclaration,
                            SyntaxKind.ClassDeclaration,
                            SyntaxKind.StructDeclaration,
                            SyntaxKind.InterfaceDeclaration,
                            SyntaxKind.CompilationUnit))
                    {
                        if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveMember))
                        {
                            context.RegisterRefactoring(CodeActionFactory.RemoveMemberDeclaration(context.Document, member, equivalenceKey: RefactoringIdentifiers.RemoveMember));
                        }

                        if (context.IsRefactoringEnabled(RefactoringIdentifiers.DuplicateMember))
                        {
                            context.RegisterRefactoring(
                                $"Duplicate {CSharpFacts.GetTitle(member)}",
                                cancellationToken => DuplicateMemberDeclarationRefactoring.RefactorAsync(context.Document, member, cancellationToken),
                                RefactoringIdentifiers.DuplicateMember);
                        }
                    }

                    if (context.IsRefactoringEnabled(RefactoringIdentifiers.CommentOutMember))
                    {
                        CommentOutRefactoring.RegisterRefactoring(context, member);
                    }
                }

                break;
            }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllStatements))
            {
                RemoveAllStatementsRefactoring.ComputeRefactoring(context, member);
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.RemoveAllMemberDeclarations))
            {
                RemoveAllMemberDeclarationsRefactoring.ComputeRefactoring(context, member);
            }

            if (context.IsAnyRefactoringEnabled(
                    RefactoringIdentifiers.SwapMemberDeclarations,
                    RefactoringIdentifiers.RemoveMemberDeclarations) &&
                !member.Span.IntersectsWith(context.Span))
            {
                MemberDeclarationsRefactoring.ComputeRefactoring(context, member);
            }

            switch (kind)
            {
            case SyntaxKind.NamespaceDeclaration:
            {
                var namespaceDeclaration = (NamespaceDeclarationSyntax)member;
                NamespaceDeclarationRefactoring.ComputeRefactorings(context, namespaceDeclaration);

                if (MemberDeclarationListSelection.TryCreate(namespaceDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers))
                {
                    await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false);
                }

                break;
            }

            case SyntaxKind.ClassDeclaration:
            {
                var classDeclaration = (ClassDeclarationSyntax)member;
                await ClassDeclarationRefactoring.ComputeRefactoringsAsync(context, classDeclaration).ConfigureAwait(false);

                if (MemberDeclarationListSelection.TryCreate(classDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers))
                {
                    await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false);
                }

                break;
            }

            case SyntaxKind.RecordDeclaration:
            {
                var recordDeclaration = (RecordDeclarationSyntax)member;
                await RecordDeclarationRefactoring.ComputeRefactoringsAsync(context, recordDeclaration).ConfigureAwait(false);

                if (MemberDeclarationListSelection.TryCreate(recordDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers))
                {
                    await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false);
                }

                break;
            }

            case SyntaxKind.StructDeclaration:
            {
                var structDeclaration = (StructDeclarationSyntax)member;
                await StructDeclarationRefactoring.ComputeRefactoringsAsync(context, structDeclaration).ConfigureAwait(false);

                if (MemberDeclarationListSelection.TryCreate(structDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers))
                {
                    await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false);
                }

                break;
            }

            case SyntaxKind.InterfaceDeclaration:
            {
                var interfaceDeclaration = (InterfaceDeclarationSyntax)member;
                InterfaceDeclarationRefactoring.ComputeRefactorings(context, interfaceDeclaration);

                if (MemberDeclarationListSelection.TryCreate(interfaceDeclaration, context.Span, out MemberDeclarationListSelection selectedMembers))
                {
                    await SelectedMemberDeclarationsRefactoring.ComputeRefactoringAsync(context, selectedMembers).ConfigureAwait(false);
                }

                break;
            }

            case SyntaxKind.EnumDeclaration:
            {
                await EnumDeclarationRefactoring.ComputeRefactoringAsync(context, (EnumDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.EnumMemberDeclaration:
            {
                await EnumMemberDeclarationRefactoring.ComputeRefactoringAsync(context, (EnumMemberDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.DelegateDeclaration:
            {
                DelegateDeclarationRefactoring.ComputeRefactorings(context, (DelegateDeclarationSyntax)member);
                break;
            }

            case SyntaxKind.MethodDeclaration:
            {
                await MethodDeclarationRefactoring.ComputeRefactoringsAsync(context, (MethodDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.ConstructorDeclaration:
            {
                await ConstructorDeclarationRefactoring.ComputeRefactoringsAsync(context, (ConstructorDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.DestructorDeclaration:
            {
                DestructorDeclarationRefactoring.ComputeRefactorings(context, (DestructorDeclarationSyntax)member);
                break;
            }

            case SyntaxKind.IndexerDeclaration:
            {
                await IndexerDeclarationRefactoring.ComputeRefactoringsAsync(context, (IndexerDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.PropertyDeclaration:
            {
                await PropertyDeclarationRefactoring.ComputeRefactoringsAsync(context, (PropertyDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.OperatorDeclaration:
            {
                ComputeRefactorings(context, (OperatorDeclarationSyntax)member);
                break;
            }

            case SyntaxKind.ConversionOperatorDeclaration:
            {
                ComputeRefactorings(context, (ConversionOperatorDeclarationSyntax)member);
                break;
            }

            case SyntaxKind.FieldDeclaration:
            {
                await FieldDeclarationRefactoring.ComputeRefactoringsAsync(context, (FieldDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.EventDeclaration:
            {
                await EventDeclarationRefactoring.ComputeRefactoringsAsync(context, (EventDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }

            case SyntaxKind.EventFieldDeclaration:
            {
                await EventFieldDeclarationRefactoring.ComputeRefactoringsAsync(context, (EventFieldDeclarationSyntax)member).ConfigureAwait(false);

                break;
            }
            }

            if (context.IsRefactoringEnabled(RefactoringIdentifiers.MoveUnsafeContextToContainingDeclaration))
            {
                MoveUnsafeContextToContainingDeclarationRefactoring.ComputeRefactoring(context, member);
            }
        }
Пример #18
0
        private static async Task <ExpressionSyntax> CreateNewNodeAsync(
            Document document,
            BinaryExpressionSyntax binaryExpression,
            CancellationToken cancellationToken)
        {
            ExpressionSyntax left  = binaryExpression.Left;
            ExpressionSyntax right = binaryExpression.Right;

            TextSpan span = TextSpan.FromBounds(left.Span.End, right.SpanStart);

            IEnumerable <SyntaxTrivia> trivia = binaryExpression.DescendantTrivia(span);

            bool isWhiteSpaceOrEndOfLine = trivia.All(f => f.IsWhitespaceOrEndOfLineTrivia());

            SemanticModel semanticModel = await document.GetSemanticModelAsync(cancellationToken).ConfigureAwait(false);

            if (CSharpFacts.IsBooleanLiteralExpression(left.Kind()))
            {
                SyntaxTriviaList leadingTrivia = binaryExpression.GetLeadingTrivia();

                if (!isWhiteSpaceOrEndOfLine)
                {
                    leadingTrivia = leadingTrivia.AddRange(trivia);
                }

                if (right.IsKind(SyntaxKind.LogicalNotExpression))
                {
                    var logicalNot = (PrefixUnaryExpressionSyntax)right;

                    ExpressionSyntax operand = logicalNot.Operand;

                    if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean))
                    {
                        return(binaryExpression
                               .WithLeft(Inverter.LogicallyNegate(left, semanticModel, cancellationToken))
                               .WithRight(operand.WithTriviaFrom(right)));
                    }
                }

                return(Inverter.LogicallyNegate(right, semanticModel, cancellationToken)
                       .WithLeadingTrivia(leadingTrivia));
            }
            else if (CSharpFacts.IsBooleanLiteralExpression(right.Kind()))
            {
                SyntaxTriviaList trailingTrivia = binaryExpression.GetTrailingTrivia();

                if (!isWhiteSpaceOrEndOfLine)
                {
                    trailingTrivia = trailingTrivia.InsertRange(0, trivia);
                }

                if (left.IsKind(SyntaxKind.LogicalNotExpression))
                {
                    var logicalNot = (PrefixUnaryExpressionSyntax)left;

                    ExpressionSyntax operand = logicalNot.Operand;

                    if (semanticModel.GetTypeInfo(operand, cancellationToken).ConvertedType.IsNullableOf(SpecialType.System_Boolean))
                    {
                        return(binaryExpression
                               .WithLeft(operand.WithTriviaFrom(left))
                               .WithRight(Inverter.LogicallyNegate(right, semanticModel, cancellationToken)));
                    }
                }

                return(Inverter.LogicallyNegate(left, semanticModel, cancellationToken)
                       .WithTrailingTrivia(trailingTrivia));
            }

            Debug.Fail(binaryExpression.ToString());

            return(binaryExpression);
        }
Пример #19
0
        private static void AnalyzeParenthesizedExpression(SyntaxNodeAnalysisContext context)
        {
            var parenthesizedExpression = (ParenthesizedExpressionSyntax)context.Node;

            ExpressionSyntax expression = parenthesizedExpression.Expression;

            if (expression?.IsMissing != false)
            {
                return;
            }

            SyntaxToken openParen = parenthesizedExpression.OpenParenToken;

            if (openParen.IsMissing)
            {
                return;
            }

            SyntaxToken closeParen = parenthesizedExpression.CloseParenToken;

            if (closeParen.IsMissing)
            {
                return;
            }

            SyntaxNode parent = parenthesizedExpression.Parent;

            SyntaxKind parentKind = parent.Kind();

            switch (parentKind)
            {
            case SyntaxKind.ParenthesizedExpression:
            case SyntaxKind.ArrowExpressionClause:
            case SyntaxKind.AttributeArgument:
            case SyntaxKind.Argument:
            case SyntaxKind.ExpressionStatement:
            case SyntaxKind.ReturnStatement:
            case SyntaxKind.YieldReturnStatement:
            case SyntaxKind.WhileStatement:
            case SyntaxKind.DoStatement:
            case SyntaxKind.UsingStatement:
            case SyntaxKind.LockStatement:
            case SyntaxKind.IfStatement:
            case SyntaxKind.SwitchStatement:
            case SyntaxKind.ArrayRankSpecifier:
            {
                ReportDiagnostic();
                break;
            }

            case SyntaxKind.LessThanExpression:
            case SyntaxKind.GreaterThanExpression:
            case SyntaxKind.LessThanOrEqualExpression:
            case SyntaxKind.GreaterThanOrEqualExpression:
            case SyntaxKind.EqualsExpression:
            case SyntaxKind.NotEqualsExpression:
            {
                if (expression.IsKind(SyntaxKind.IdentifierName) ||
                    expression is LiteralExpressionSyntax)
                {
                    ReportDiagnostic();
                }

                break;
            }

            case SyntaxKind.MultiplyExpression:
            case SyntaxKind.DivideExpression:
            case SyntaxKind.ModuloExpression:
            case SyntaxKind.AddExpression:
            case SyntaxKind.SubtractExpression:
            case SyntaxKind.LeftShiftExpression:
            case SyntaxKind.RightShiftExpression:
            case SyntaxKind.BitwiseAndExpression:
            case SyntaxKind.ExclusiveOrExpression:
            case SyntaxKind.BitwiseOrExpression:
            case SyntaxKind.LogicalAndExpression:
            case SyntaxKind.LogicalOrExpression:
            {
                SyntaxKind kind = expression.Kind();

                if (kind == SyntaxKind.IdentifierName ||
                    expression is LiteralExpressionSyntax)
                {
                    ReportDiagnostic();
                }
                else if (kind == parentKind &&
                         ((BinaryExpressionSyntax)parent).Left == parenthesizedExpression)
                {
                    ReportDiagnostic();
                }

                break;
            }

            case SyntaxKind.LogicalNotExpression:
            {
                switch (expression.Kind())
                {
                case SyntaxKind.IdentifierName:
                case SyntaxKind.GenericName:
                case SyntaxKind.InvocationExpression:
                case SyntaxKind.SimpleMemberAccessExpression:
                case SyntaxKind.ElementAccessExpression:
                case SyntaxKind.ConditionalAccessExpression:
                {
                    ReportDiagnostic();
                    break;
                }
                }

                break;
            }

            case SyntaxKind.SimpleAssignmentExpression:
            case SyntaxKind.AddAssignmentExpression:
            case SyntaxKind.SubtractAssignmentExpression:
            case SyntaxKind.MultiplyAssignmentExpression:
            case SyntaxKind.DivideAssignmentExpression:
            case SyntaxKind.ModuloAssignmentExpression:
            case SyntaxKind.AndAssignmentExpression:
            case SyntaxKind.ExclusiveOrAssignmentExpression:
            case SyntaxKind.OrAssignmentExpression:
            case SyntaxKind.LeftShiftAssignmentExpression:
            case SyntaxKind.RightShiftAssignmentExpression:
            {
                if (((AssignmentExpressionSyntax)parent).Left == parenthesizedExpression)
                {
                    ReportDiagnostic();
                }
                else if (expression.IsKind(SyntaxKind.IdentifierName) ||
                         expression is LiteralExpressionSyntax)
                {
                    ReportDiagnostic();
                }

                break;
            }

            case SyntaxKind.Interpolation:
            {
                if (!expression.IsKind(SyntaxKind.ConditionalExpression) &&
                    !expression.DescendantNodes().Any(f => f.IsKind(SyntaxKind.AliasQualifiedName)) &&
                    ((InterpolationSyntax)parent).Expression == parenthesizedExpression)
                {
                    ReportDiagnostic();
                }

                break;
            }

            case SyntaxKind.AwaitExpression:
            {
                if (CSharpFacts.GetOperatorPrecedence(expression.Kind()) <= CSharpFacts.GetOperatorPrecedence(SyntaxKind.AwaitExpression))
                {
                    ReportDiagnostic();
                }

                break;
            }

            case SyntaxKind.ArrayInitializerExpression:
            case SyntaxKind.CollectionInitializerExpression:
            {
                if (!(expression is AssignmentExpressionSyntax))
                {
                    ReportDiagnostic();
                }

                break;
            }
            }

            void ReportDiagnostic()
            {
                DiagnosticHelpers.ReportDiagnostic(context,
                                                   DiagnosticDescriptors.RemoveRedundantParentheses,
                                                   openParen.GetLocation(),
                                                   additionalLocations: ImmutableArray.Create(closeParen.GetLocation()));

                DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.RemoveRedundantParenthesesFadeOut, openParen);
                DiagnosticHelpers.ReportToken(context, DiagnosticDescriptors.RemoveRedundantParenthesesFadeOut, closeParen);
            }
        }
Пример #20
0
        public override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            SyntaxNode root = await context.GetSyntaxRootAsync().ConfigureAwait(false);

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out BinaryExpressionSyntax binaryExpression))
            {
                return;
            }

            Document document = context.Document;

            foreach (Diagnostic diagnostic in context.Diagnostics)
            {
                switch (diagnostic.Id)
                {
                case DiagnosticIdentifiers.ConstantValuesShouldBePlacedOnRightSideOfComparisons:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Swap operands",
                        ct => document.ReplaceNodeAsync(binaryExpression, SyntaxRefactorings.SwapBinaryOperands(binaryExpression), ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringIsNullOrEmptyMethod:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use 'string.IsNullOrEmpty' method",
                        ct => UseStringIsNullOrEmptyMethodAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.SimplifyCoalesceExpression:
                {
                    ExpressionSyntax expression = binaryExpression.Left;

                    if (expression == null ||
                        !context.Span.Contains(expression.Span))
                    {
                        expression = binaryExpression.Right;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Simplify coalesce expression",
                        ct => SimplifyCoalesceExpressionRefactoring.RefactorAsync(document, binaryExpression, expression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantAsOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove redundant 'as' operator",
                        ct => RemoveRedundantAsOperatorRefactoring.RefactorAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseStringLengthInsteadOfComparisonWithEmptyString:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use string.Length",
                        ct => UseStringLengthInsteadOfComparisonWithEmptyStringAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnconstrainedTypeParameterCheckedForNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    CodeAction codeAction = CodeAction.Create(
                        $"Use EqualityComparer<{typeSymbol.Name}>.Default",
                        ct => UnconstrainedTypeParameterCheckedForNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.ValueTypeObjectIsNeverEqualToNull:
                {
                    SemanticModel semanticModel = await context.GetSemanticModelAsync().ConfigureAwait(false);

                    ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(binaryExpression.Left, context.CancellationToken);

                    string title;

                    if (CSharpFacts.IsSimpleType(typeSymbol.SpecialType) ||
                        typeSymbol.ContainsMember <IMethodSymbol>(WellKnownMemberNames.EqualityOperatorName))
                    {
                        ExpressionSyntax expression = typeSymbol.GetDefaultValueSyntax(document.GetDefaultSyntaxOptions());

                        title = $"Replace 'null' with '{expression}'";
                    }
                    else
                    {
                        title = $"Use EqualityComparer<{SymbolDisplay.ToMinimalDisplayString(typeSymbol, semanticModel, binaryExpression.Right.SpanStart, SymbolDisplayFormats.DisplayName)}>.Default";
                    }

                    CodeAction codeAction = CodeAction.Create(
                        title,
                        ct => ValueTypeObjectIsNeverEqualToNullRefactoring.RefactorAsync(document, binaryExpression, typeSymbol, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.JoinStringExpressions:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Join string expressions",
                        ct => JoinStringExpressionsRefactoring.RefactorAsync(document, binaryExpression, context.Span, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseExclusiveOrOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use ^ operator",
                        ct => UseExclusiveOrOperatorRefactoring.RefactorAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnnecessaryNullCheck:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Remove unnecessary null check",
                        ct => RemoveUnnecessaryNullCheckAsync(document, binaryExpression, ct),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UseShortCircuitingOperator:
                {
                    SyntaxToken operatorToken = binaryExpression.OperatorToken;

                    SyntaxKind kind = binaryExpression.Kind();

                    SyntaxToken newToken = default;

                    if (kind == SyntaxKind.BitwiseAndExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.AmpersandAmpersandToken, operatorToken.TrailingTrivia);
                    }
                    else if (kind == SyntaxKind.BitwiseOrExpression)
                    {
                        newToken = Token(operatorToken.LeadingTrivia, SyntaxKind.BarBarToken, operatorToken.TrailingTrivia);
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Use '{newToken.ToString()}' operator",
                        ct =>
                        {
                            BinaryExpressionSyntax newBinaryExpression = null;

                            if (kind == SyntaxKind.BitwiseAndExpression)
                            {
                                newBinaryExpression = LogicalAndExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }
                            else if (kind == SyntaxKind.BitwiseOrExpression)
                            {
                                newBinaryExpression = LogicalOrExpression(binaryExpression.Left, newToken, binaryExpression.Right);
                            }

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.UnnecessaryOperator:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Use '==' operator",
                        ct =>
                        {
                            SyntaxToken operatorToken = binaryExpression.OperatorToken;

                            BinaryExpressionSyntax newBinaryExpression = EqualsExpression(
                                binaryExpression.Left,
                                Token(operatorToken.LeadingTrivia, SyntaxKind.EqualsEqualsToken, operatorToken.TrailingTrivia),
                                binaryExpression.Right);

                            return(document.ReplaceNodeAsync(binaryExpression, newBinaryExpression, ct));
                        },
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Пример #21
0
        private static void AnalyzeElseClause(SyntaxNodeAnalysisContext context)
        {
            var elseClause = (ElseClauseSyntax)context.Node;

            StatementSyntax statement = elseClause.EmbeddedStatement(allowIfStatement: false);

            if (statement == null)
            {
                return;
            }

            if (statement.ContainsDirectives)
            {
                return;
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.AddBracesToIfElse, statement, CSharpFacts.GetTitle(elseClause));
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            Diagnostic diagnostic = context.Diagnostics[0];

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

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

            if (!TryFindFirstAncestorOrSelf(root, context.Span, out SyntaxNode node, predicate: f => f.IsKind(SyntaxKind.MethodDeclaration, SyntaxKind.LocalFunctionStatement)))
            {
                return;
            }

            BlockSyntax body = (node is MethodDeclarationSyntax methodDeclaration)
                ? methodDeclaration.Body
                : ((LocalFunctionStatementSyntax)node).Body;

            Debug.Assert(body != null, node.ToString());

            if (body == null)
            {
                return;
            }

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

            ITypeSymbol           typeSymbol           = null;
            HashSet <ITypeSymbol> typeSymbols          = null;
            INamedTypeSymbol      ienumerableOfTSymbol = null;

            foreach (SyntaxNode descendant in body.DescendantNodes(descendIntoChildren: f => !CSharpFacts.IsFunction(f.Kind())))
            {
                if (!descendant.IsKind(SyntaxKind.YieldReturnStatement))
                {
                    continue;
                }

                var yieldReturn = (YieldStatementSyntax)descendant;

                ExpressionSyntax expression = yieldReturn.Expression;

                if (expression == null)
                {
                    continue;
                }

                var namedTypeSymbol = semanticModel.GetTypeSymbol(expression, context.CancellationToken) as INamedTypeSymbol;

                if (namedTypeSymbol?.IsErrorType() != false)
                {
                    continue;
                }

                if (typeSymbol == null)
                {
                    typeSymbol = namedTypeSymbol;
                }
                else
                {
                    if (typeSymbols == null)
                    {
                        typeSymbols = new HashSet <ITypeSymbol>()
                        {
                            typeSymbol
                        };
                    }

                    if (!typeSymbols.Add(namedTypeSymbol))
                    {
                        continue;
                    }
                }

                if (ienumerableOfTSymbol == null)
                {
                    ienumerableOfTSymbol = semanticModel.GetTypeByMetadataName("System.Collections.Generic.IEnumerable`1");
                }

                CodeFixRegistrator.ChangeTypeOrReturnType(
                    context,
                    diagnostic,
                    node,
                    ienumerableOfTSymbol.Construct(namedTypeSymbol),
                    semanticModel,
                    additionalKey: SymbolDisplay.ToMinimalDisplayString(namedTypeSymbol, semanticModel, node.SpanStart, SymbolDisplayFormats.Default));
            }
        }
Пример #23
0
        private static void Analyze(
            SyntaxNodeAnalysisContext context,
            SyntaxNode declaration,
            ParameterListSyntax parameterList,
            CSharpSyntaxNode bodyOrExpressionBody)
        {
            if (parameterList == null)
            {
                return;
            }

            if (bodyOrExpressionBody == null)
            {
                return;
            }

            if (!parameterList.Parameters.Any())
            {
                return;
            }

            SemanticModel     semanticModel     = context.SemanticModel;
            CancellationToken cancellationToken = context.CancellationToken;

            var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(declaration, cancellationToken);

            SyntaxWalker walker = null;

            foreach (IParameterSymbol parameter in methodSymbol.Parameters)
            {
                cancellationToken.ThrowIfCancellationRequested();

                ITypeSymbol type = parameter.Type;

                if (type.Kind == SymbolKind.ErrorType)
                {
                    continue;
                }

                if (CSharpFacts.IsSimpleType(type.SpecialType))
                {
                    continue;
                }

                if (!type.IsReadOnlyStruct())
                {
                    if (parameter.RefKind == RefKind.In &&
                        type.TypeKind == TypeKind.Struct)
                    {
                        var parameterSyntax = (ParameterSyntax)parameter.GetSyntax(cancellationToken);

                        Debug.Assert(parameterSyntax.Modifiers.Contains(SyntaxKind.InKeyword), "");

                        DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.DoNotPassNonReadOnlyStructByReadOnlyReference, parameterSyntax.Identifier);
                    }

                    continue;
                }

                if (parameter.RefKind != RefKind.None)
                {
                    continue;
                }

                if (walker == null)
                {
                    if (methodSymbol.ImplementsInterfaceMember(allInterfaces: true))
                    {
                        break;
                    }

                    walker = SyntaxWalker.GetInstance();
                }
                else if (walker.Parameters.ContainsKey(parameter.Name))
                {
                    walker.Parameters.Clear();
                    break;
                }

                walker.Parameters.Add(parameter.Name, parameter);
            }

            if (walker == null)
            {
                return;
            }

            try
            {
                if (walker.Parameters.Count > 0)
                {
                    walker.SemanticModel     = semanticModel;
                    walker.CancellationToken = cancellationToken;

                    if (bodyOrExpressionBody.IsKind(SyntaxKind.Block))
                    {
                        walker.VisitBlock((BlockSyntax)bodyOrExpressionBody);
                    }
                    else
                    {
                        walker.VisitArrowExpressionClause((ArrowExpressionClauseSyntax)bodyOrExpressionBody);
                    }

                    if (walker.Parameters.Count > 0)
                    {
                        DataFlowAnalysis analysis = (bodyOrExpressionBody.IsKind(SyntaxKind.Block))
                            ? semanticModel.AnalyzeDataFlow((BlockSyntax)bodyOrExpressionBody)
                            : semanticModel.AnalyzeDataFlow(((ArrowExpressionClauseSyntax)bodyOrExpressionBody).Expression);

                        bool?isReferencedAsMethodGroup = null;

                        foreach (KeyValuePair <string, IParameterSymbol> kvp in walker.Parameters)
                        {
                            var isAssigned = false;

                            foreach (ISymbol assignedSymbol in analysis.AlwaysAssigned)
                            {
                                if (SymbolEqualityComparer.Default.Equals(assignedSymbol, kvp.Value))
                                {
                                    isAssigned = true;
                                    break;
                                }
                            }

                            if (isAssigned)
                            {
                                continue;
                            }

                            if (isReferencedAsMethodGroup ??= IsReferencedAsMethodGroup())
                            {
                                break;
                            }

                            if (kvp.Value.GetSyntaxOrDefault(cancellationToken) is ParameterSyntax parameter)
                            {
                                DiagnosticHelpers.ReportDiagnostic(
                                    context,
                                    DiagnosticRules.MakeParameterRefReadOnly,
                                    parameter.Identifier);
                            }
                        }
                    }
                }
            }
            finally
            {
                SyntaxWalker.Free(walker);
            }

            bool IsReferencedAsMethodGroup()
            {
                switch (declaration.Kind())
                {
                case SyntaxKind.MethodDeclaration:
                    return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.Parent, methodSymbol, semanticModel, cancellationToken));

                case SyntaxKind.LocalFunctionStatement:
                    return(MethodReferencedAsMethodGroupWalker.IsReferencedAsMethodGroup(declaration.FirstAncestor <MemberDeclarationSyntax>(), methodSymbol, semanticModel, cancellationToken));

                default:
                    return(false);
                }
            }
        }
Пример #24
0
        public sealed 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.FormatDeclarationBraces:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Format braces",
                        cancellationToken => FormatDeclarationBracesRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.RemoveRedundantOverridingMember:
                {
                    CodeAction codeAction = CodeAction.Create(
                        $"Remove {CSharpFacts.GetTitle(memberDeclaration)}",
                        cancellationToken => context.Document.RemoveMemberAsync(memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

                case DiagnosticIdentifiers.AddDefaultAccessModifier:
                {
                    var accessibility = (Accessibility)Enum.Parse(
                        typeof(Accessibility),
                        diagnostic.Properties[nameof(Accessibility)]);

                    CodeAction codeAction = CodeAction.Create(
                        "Add default access modifier",
                        cancellationToken => AddDefaultAccessModifierRefactoring.RefactorAsync(context.Document, memberDeclaration, accessibility, cancellationToken),
                        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.ReorderModifiers:
                {
                    CodeAction codeAction = CodeAction.Create(
                        "Reorder modifiers",
                        cancellationToken => ReorderModifiersRefactoring.RefactorAsync(context.Document, memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

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

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

                    string title = (declarators.Count == 1)
                                ? $"Mark '{declarators[0].Identifier.ValueText}' as read-only"
                                : "Mark fields as 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 => UseReadOnlyAutoPropertyRefactoring.RefactorAsync(context.Document, (PropertyDeclarationSyntax)memberDeclaration, cancellationToken),
                        GetEquivalenceKey(diagnostic));

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

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

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
Пример #25
0
        private static void AnalyzeAsExpression(SyntaxNodeAnalysisContext context)
        {
            var asExpression = (BinaryExpressionSyntax)context.Node;

            AsExpressionInfo asExpressionInfo = SyntaxInfo.AsExpressionInfo(asExpression);

            if (!asExpressionInfo.Success)
            {
                return;
            }

            SingleLocalDeclarationStatementInfo localInfo = SyntaxInfo.SingleLocalDeclarationStatementInfo(asExpression);

            if (!localInfo.Success)
            {
                return;
            }

            if (localInfo.Statement.SpanOrTrailingTriviaContainsDirectives())
            {
                return;
            }

            if (!(localInfo.Statement.NextStatement() is IfStatementSyntax ifStatement))
            {
                return;
            }

            if (!ifStatement.IsSimpleIf())
            {
                return;
            }

            if (ifStatement.SpanOrLeadingTriviaContainsDirectives())
            {
                return;
            }

            StatementSyntax statement = ifStatement.SingleNonBlockStatementOrDefault();

            if (statement == null)
            {
                return;
            }

            if (!CSharpFacts.IsJumpStatement(statement.Kind()))
            {
                return;
            }

            NullCheckExpressionInfo nullCheck = SyntaxInfo.NullCheckExpressionInfo(ifStatement.Condition, NullCheckStyles.EqualsToNull | NullCheckStyles.IsNull);

            if (!nullCheck.Success)
            {
                return;
            }

            if (!string.Equals(localInfo.IdentifierText, (nullCheck.Expression as IdentifierNameSyntax)?.Identifier.ValueText, StringComparison.Ordinal))
            {
                return;
            }

            if (!localInfo.Type.IsVar)
            {
                SemanticModel     semanticModel     = context.SemanticModel;
                CancellationToken cancellationToken = context.CancellationToken;

                ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(asExpressionInfo.Type, cancellationToken);

                if (typeSymbol.IsNullableType())
                {
                    return;
                }

                if (!SymbolEqualityComparer.Default.Equals(semanticModel.GetTypeSymbol(localInfo.Type, cancellationToken), typeSymbol))
                {
                    return;
                }
            }

            DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.UsePatternMatchingInsteadOfAsAndNullCheck, localInfo.Statement);
        }
        public sealed override async Task RegisterCodeFixesAsync(CodeFixContext context)
        {
            if (!Settings.IsEnabled(CodeFixIdentifiers.AddDocumentationComment) &&
                !Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType) &&
                !Settings.IsEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType) &&
                !Settings.IsEnabled(CodeFixIdentifiers.AddPartialModifier) &&
                !Settings.IsEnabled(CodeFixIdentifiers.MakeContainingClassAbstract) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RemoveMemberDeclaration) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName) &&
                !Settings.IsEnabled(CodeFixIdentifiers.RenameTupleElement) &&
                !Settings.IsEnabled(CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant))
            {
                return;
            }

            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 CompilerDiagnosticIdentifiers.MissingXmlCommentForPubliclyVisibleTypeOrMember:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.AddDocumentationComment))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Add documentation comment",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, false, cancellationToken),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);

                    CodeAction codeAction2 = CodeAction.Create(
                        "Add documentation comment (copy from base if available)",
                        cancellationToken => AddDocumentationCommentRefactoring.RefactorAsync(context.Document, memberDeclaration, true, cancellationToken),
                        GetEquivalenceKey(diagnostic, "CopyFromBaseIfAvailable"));

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

                case CompilerDiagnosticIdentifiers.MethodReturnTypeMustMatchOverriddenMethodReturnType:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

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

                    var methodSymbol = (IMethodSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                    ITypeSymbol typeSymbol = methodSymbol.OverriddenMethod.ReturnType;

                    CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel);

                    break;
                }

                case CompilerDiagnosticIdentifiers.PartialMethodsMustHaveVoidReturnType:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.ChangeMethodReturnType))
                    {
                        break;
                    }

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

                    var methodDeclaration = (MethodDeclarationSyntax)memberDeclaration;

                    MethodDeclarationSyntax otherPart = semanticModel.GetOtherPart(methodDeclaration, context.CancellationToken);

                    if (otherPart == null)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Change return type to 'void'",
                        cancellationToken =>
                        {
                            return(context.Document.Solution().ReplaceNodesAsync(
                                       new MethodDeclarationSyntax[] { methodDeclaration, otherPart },
                                       (node, _) => node.WithReturnType(CSharpFactory.VoidType().WithTriviaFrom(node.ReturnType)),
                                       cancellationToken));
                        },
                        GetEquivalenceKey(diagnostic));

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

                case CompilerDiagnosticIdentifiers.MemberTypeMustMatchOverriddenMemberType:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.MemberTypeMustMatchOverriddenMemberType))
                    {
                        break;
                    }

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

                    ITypeSymbol typeSymbol = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.PropertyDeclaration:
                    case SyntaxKind.IndexerDeclaration:
                    {
                        var propertySymbol = (IPropertySymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = propertySymbol.OverriddenProperty.Type;
                        break;
                    }

                    case SyntaxKind.EventDeclaration:
                    {
                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(memberDeclaration, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }

                    case SyntaxKind.EventFieldDeclaration:
                    {
                        VariableDeclaratorSyntax declarator = ((EventFieldDeclarationSyntax)memberDeclaration).Declaration.Variables.First();

                        var eventSymbol = (IEventSymbol)semanticModel.GetDeclaredSymbol(declarator, context.CancellationToken);

                        typeSymbol = eventSymbol.OverriddenEvent.Type;
                        break;
                    }
                    }

                    CodeFixRegistrator.ChangeTypeOrReturnType(context, diagnostic, memberDeclaration, typeSymbol, semanticModel);

                    break;
                }

                case CompilerDiagnosticIdentifiers.MissingPartialModifier:
                case CompilerDiagnosticIdentifiers.PartialMethodMustBeDeclaredInPartialClassOrPartialStruct:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.AddPartialModifier))
                    {
                        break;
                    }

                    SyntaxNode node = null;

                    switch (memberDeclaration.Kind())
                    {
                    case SyntaxKind.MethodDeclaration:
                    {
                        if (memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration, SyntaxKind.StructDeclaration))
                        {
                            node = memberDeclaration.Parent;
                        }

                        break;
                    }

                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.StructDeclaration:
                    case SyntaxKind.InterfaceDeclaration:
                    {
                        node = memberDeclaration;
                        break;
                    }
                    }

                    Debug.Assert(node != null, memberDeclaration.ToString());

                    if (node == null)
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(context, diagnostic, node, SyntaxKind.PartialKeyword);
                    break;
                }

                case CompilerDiagnosticIdentifiers.MemberIsAbstractButItIsContainedInNonAbstractClass:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.MakeContainingClassAbstract))
                    {
                        break;
                    }

                    if (!memberDeclaration.IsParentKind(SyntaxKind.ClassDeclaration))
                    {
                        break;
                    }

                    ModifiersCodeFixRegistrator.AddModifier(
                        context,
                        diagnostic,
                        memberDeclaration.Parent,
                        SyntaxKind.AbstractKeyword,
                        title: "Make containing class abstract");

                    break;
                }

                case CompilerDiagnosticIdentifiers.StaticConstructorMustBeParameterless:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveParametersFromStaticConstructor))
                    {
                        break;
                    }

                    var constructorDeclaration = (ConstructorDeclarationSyntax)memberDeclaration;

                    CodeAction codeAction = CodeAction.Create(
                        "Remove parameters",
                        cancellationToken =>
                        {
                            ParameterListSyntax parameterList = constructorDeclaration.ParameterList;

                            ParameterListSyntax newParameterList = parameterList
                                                                   .WithParameters(default(SeparatedSyntaxList <ParameterSyntax>))
                                                                   .WithOpenParenToken(parameterList.OpenParenToken.WithoutTrailingTrivia())
                                                                   .WithCloseParenToken(parameterList.CloseParenToken.WithoutLeadingTrivia());

                            ConstructorDeclarationSyntax newNode = constructorDeclaration.WithParameterList(newParameterList);

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

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

                case CompilerDiagnosticIdentifiers.ExplicitInterfaceDeclarationCanOnlyBeDeclaredInClassOrStruct:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainFields:
                case CompilerDiagnosticIdentifiers.InterfacesCannotContainOperators:
                case CompilerDiagnosticIdentifiers.InterfacesCannotDeclareTypes:
                case CompilerDiagnosticIdentifiers.OnlyClassTypesCanContainDestructors:
                case CompilerDiagnosticIdentifiers.StructsCannotContainExplicitParameterlessConstructors:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RemoveMemberDeclaration))
                    {
                        break;
                    }

                    CodeFixRegistrator.RemoveMemberDeclaration(context, diagnostic, memberDeclaration);
                    break;
                }

                case CompilerDiagnosticIdentifiers.NameOfDestructorMustMatchNameOfClass:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RenameDestructorToMatchClassName))
                    {
                        break;
                    }

                    if (!(memberDeclaration is DestructorDeclarationSyntax destructorDeclaration))
                    {
                        break;
                    }

                    if (!(memberDeclaration.Parent is ClassDeclarationSyntax classDeclaration))
                    {
                        break;
                    }

                    if (classDeclaration.Identifier.ValueText.Length == 0)
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        "Rename destructor to match class name",
                        cancellationToken =>
                        {
                            DestructorDeclarationSyntax newNode = destructorDeclaration.WithIdentifier(classDeclaration.Identifier.WithTriviaFrom(destructorDeclaration.Identifier));

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

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

                case CompilerDiagnosticIdentifiers.CannotChangeTupleElementNameWhenOverridingInheritedMember:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.RenameTupleElement))
                    {
                        break;
                    }

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

                    if (memberDeclaration is MethodDeclarationSyntax methodDeclaration)
                    {
                        IMethodSymbol methodSymbol = semanticModel.GetDeclaredSymbol(methodDeclaration, context.CancellationToken);

                        if (!(methodSymbol.ReturnType is INamedTypeSymbol tupleType))
                        {
                            break;
                        }

                        if (!tupleType.IsTupleType)
                        {
                            break;
                        }

                        if (!(methodSymbol.OverriddenMethod?.ReturnType is INamedTypeSymbol baseTupleType))
                        {
                            break;
                        }

                        if (!baseTupleType.IsTupleType)
                        {
                            break;
                        }

                        ImmutableArray <IFieldSymbol> elements     = tupleType.TupleElements;
                        ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements;

                        if (elements.Length != baseElements.Length)
                        {
                            break;
                        }

                        int i = 0;
                        while (i < elements.Length)
                        {
                            if (elements[i].Name != baseElements[i].Name)
                            {
                                break;
                            }

                            i++;
                        }

                        if (i == elements.Length)
                        {
                            break;
                        }

                        TupleElementSyntax tupleElement = ((TupleTypeSyntax)methodDeclaration.ReturnType).Elements[i];

                        CodeAction codeAction = CodeAction.Create(
                            $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'",
                            ct => RenameTupleElementAsync(context.Document, methodDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }
                    else if (memberDeclaration is PropertyDeclarationSyntax propertyDeclaration)
                    {
                        IPropertySymbol propertySymbol = semanticModel.GetDeclaredSymbol(propertyDeclaration, context.CancellationToken);

                        if (!(propertySymbol.Type is INamedTypeSymbol tupleType))
                        {
                            break;
                        }

                        if (!tupleType.IsTupleType)
                        {
                            break;
                        }

                        if (!(propertySymbol.OverriddenProperty?.Type is INamedTypeSymbol baseTupleType))
                        {
                            break;
                        }

                        if (!baseTupleType.IsTupleType)
                        {
                            break;
                        }

                        ImmutableArray <IFieldSymbol> elements     = tupleType.TupleElements;
                        ImmutableArray <IFieldSymbol> baseElements = baseTupleType.TupleElements;

                        if (elements.Length != baseElements.Length)
                        {
                            break;
                        }

                        int i = 0;
                        while (i < elements.Length)
                        {
                            if (elements[i].Name != baseElements[i].Name)
                            {
                                break;
                            }

                            i++;
                        }

                        if (i == elements.Length)
                        {
                            break;
                        }

                        TupleElementSyntax tupleElement = ((TupleTypeSyntax)propertyDeclaration.Type).Elements[i];

                        CodeAction codeAction = CodeAction.Create(
                            $"Rename '{elements[i].Name}' to '{baseElements[i].Name}'",
                            ct => RenameTupleElementAsync(context.Document, propertyDeclaration, tupleElement, elements[i], baseElements[i].Name, semanticModel, ct),
                            GetEquivalenceKey(diagnostic));

                        context.RegisterCodeFix(codeAction, diagnostic);
                    }

                    break;
                }

                case CompilerDiagnosticIdentifiers.MethodsWithVariableArgumentsAreNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ArgumentTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ReturnTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.TypeOfVariableIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.IdentifierDifferingOnlyInCaseIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyInRefOrOutOrInArrayRankIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.OverloadedMethodDifferingOnlyByUnnamedArrayTypesIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.IdentifierIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.BaseTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ArraysAsAttributeArgumentsIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.ConstraintTypeIsNotCLSCompliant:
                case CompilerDiagnosticIdentifiers.TypeIsNotCLSCompliantBecauseBaseInterfaceIsNotCLSCompliant:
                {
                    if (!Settings.IsEnabled(CodeFixIdentifiers.MarkDeclarationAsNonCLSCompliant))
                    {
                        break;
                    }

                    CodeAction codeAction = CodeAction.Create(
                        $"Mark {CSharpFacts.GetTitle(memberDeclaration)} as non-CLS-compliant",
                        ct => MarkDeclarationAsNonCLSCompliantAsync(context.Document, memberDeclaration, ct),
                        GetEquivalenceKey(diagnostic));

                    context.RegisterCodeFix(codeAction, diagnostic);
                    break;
                }
                }
            }
        }
        private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            var fieldDeclaration = (FieldDeclarationSyntax)context.Node;

            if (fieldDeclaration.ContainsDiagnostics)
            {
                return;
            }

            if (fieldDeclaration.Modifiers.Contains(SyntaxKind.ConstKeyword))
            {
                return;
            }

            if (fieldDeclaration.IsParentKind(SyntaxKind.StructDeclaration, SyntaxKind.RecordStructDeclaration))
            {
                var structSymbol = context.SemanticModel.GetDeclaredSymbol(fieldDeclaration.Parent, context.CancellationToken) as INamedTypeSymbol;

                if (structSymbol?.InstanceConstructors.Length > 1)
                {
                    return;
                }
            }

            VariableDeclarationSyntax declaration = fieldDeclaration.Declaration;

            if (declaration == null)
            {
                return;
            }

            foreach (VariableDeclaratorSyntax declarator in declaration.Variables)
            {
                EqualsValueClauseSyntax initializer = declarator.Initializer;
                if (initializer?.ContainsDirectives == false)
                {
                    ExpressionSyntax value = initializer.Value?.WalkDownParentheses();

                    if (value is CastExpressionSyntax castExpression)
                    {
                        value = castExpression.Expression.WalkDownParentheses();
                    }

                    if (CanBeConstantValue(value))
                    {
                        SemanticModel     semanticModel     = context.SemanticModel;
                        CancellationToken cancellationToken = context.CancellationToken;

                        ITypeSymbol typeSymbol = semanticModel.GetTypeSymbol(declaration.Type, cancellationToken);

                        if (typeSymbol != null)
                        {
                            if (CSharpFacts.IsNumericType(typeSymbol.SpecialType) &&
                                value.IsNumericLiteralExpression("0"))
                            {
                                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantFieldInitialization, initializer);
                            }
                            else if (semanticModel.IsDefaultValue(typeSymbol, value, cancellationToken))
                            {
                                DiagnosticHelpers.ReportDiagnostic(context, DiagnosticRules.RemoveRedundantFieldInitialization, initializer);
                            }
                        }
                    }
                }
            }
        }
Пример #28
0
        public async Task ComputeRefactoringsAsync(RefactoringContext context, TNode node)
        {
            if (!ValidateNode(node, context.Span))
            {
                return;
            }

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

            TSymbol symbol = GetMemberSymbol(node, semanticModel, context.CancellationToken);

            if (EqualityComparer <TSymbol> .Default.Equals(symbol, default(TSymbol)))
            {
                return;
            }

            TDeclaration declaration = await GetMemberDeclarationAsync(symbol, context.CancellationToken).ConfigureAwait(false);

            if (declaration == null)
            {
                return;
            }

            for (SyntaxNode parent = node.Parent; parent != null; parent = parent.Parent)
            {
                if (object.ReferenceEquals(declaration, parent))
                {
                    return;
                }
            }

            (ExpressionSyntax expression, SyntaxList <StatementSyntax> statements) = GetExpressionOrStatements(declaration);

            SyntaxNode nodeIncludingConditionalAccess = node.WalkUp(SyntaxKind.ConditionalAccessExpression);

            if (expression != null ||
                (statements.Any() && nodeIncludingConditionalAccess.IsParentKind(SyntaxKind.ExpressionStatement)))
            {
                ImmutableArray <ParameterInfo> parameterInfos = GetParameterInfos(node, symbol);

                if (parameterInfos.IsDefault)
                {
                    return;
                }

                INamedTypeSymbol enclosingType = semanticModel.GetEnclosingNamedType(node.SpanStart, context.CancellationToken);

                SemanticModel declarationSemanticModel = (node.SyntaxTree == declaration.SyntaxTree)
                    ? semanticModel
                    : await context.Solution.GetDocument(declaration.SyntaxTree).GetSemanticModelAsync(context.CancellationToken).ConfigureAwait(false);

                InlineRefactoring <TNode, TDeclaration, TSymbol> refactoring = CreateRefactoring(context.Document, nodeIncludingConditionalAccess, enclosingType, symbol, declaration, parameterInfos, semanticModel, declarationSemanticModel, context.CancellationToken);

                string title = CSharpFacts.GetTitle(declaration);

                if (expression != null)
                {
                    context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(nodeIncludingConditionalAccess, expression, cancellationToken));

                    context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(nodeIncludingConditionalAccess, expression, cancellationToken));
                }
                else
                {
                    var expressionStatement = (ExpressionStatementSyntax)nodeIncludingConditionalAccess.Parent;

                    context.RegisterRefactoring($"Inline {title}", cancellationToken => refactoring.InlineAsync(expressionStatement, statements, cancellationToken));

                    context.RegisterRefactoring($"Inline and remove {title}", cancellationToken => refactoring.InlineAndRemoveAsync(expressionStatement, statements, cancellationToken));
                }
            }
        }