Пример #1
0
        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
        {
            var statement = (IfStatementSyntax)node;
            var model = document.GetSemanticModel();
            var newStatement = statement.DropEmptyBranchesIfApplicable(Assumptions.All, model);
            if (newStatement == statement) return null;

            var r = new ReadyCodeAction("Omit useless code", document, statement, () => newStatement);
            return r.CodeIssues1(CodeIssue.Severity.Warning, statement.IfKeyword.Span, "Useless branch");
        }
Пример #2
0
        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
        {
            var ifStatement = node as IfStatementSyntax;
            if (ifStatement == null || ifStatement.Else != null) return null;
            var trueBlock = ifStatement.Statement as BlockSyntax;
            if (trueBlock == null) return null;
            if (trueBlock.Statements.Count != 1) return null;
            if (!trueBlock.IsGuaranteedToJumpOut()) return null;
            var r = new ReadyCodeAction("Remove unnecessary braces", document, trueBlock, () => trueBlock.Statements.Single());

            return new[] {
                new CodeIssue(CodeIssue.Severity.Warning, trueBlock.OpenBraceToken.Span, "Unnecessary braces", new[] { r })
            };
        }
Пример #3
0
        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
        {
            var model = document.TryGetSemanticModel();
            if (model == null) return null;
            if (model.GetDiagnostics().Any(e => e.Info.Severity == DiagnosticSeverity.Error)) return null;
            if (document.Project.Documents.Any(e => e.GetSyntaxTree() == null || e.GetSemanticModel() == null)) return null;

            var fieldNode = (FieldDeclarationSyntax)node;
            if (fieldNode.IsReadOnly()) return null;

            var classDecl = fieldNode.Ancestors().OfType<ClassDeclarationSyntax>().FirstOrDefault();
            if (classDecl == null) return null;
            var constructors = classDecl.Members.OfType<ConstructorDeclarationSyntax>().ToRet();

            var modsWithReadOnly = fieldNode.Modifiers.Append(SyntaxKind.ReadOnlyKeyword.AsToken()).AsTokenList();

            var scopes = fieldNode.IsPrivate()
                       ? new[] {Tuple.Create((CommonSyntaxNode)classDecl, model)}
                       : document.Project.Documents.Select(e => Tuple.Create(e.GetSyntaxTree().GetRoot(), e.GetSemanticModel()));

            var unmutatedVars = fieldNode.Declaration.Variables.Where(v => {
                var field = model.GetDeclaredSymbol(v);
                if (scopes.Any(c => c.Item1.DescendantNodes(e => !constructors.Contains(e)).OfType<ExpressionSyntax>().Any(e => SurfaceWritesTo(e, c.Item2, field)))) return false;
                return true;
            }).ToArray();

            if (unmutatedVars.Length == 0) return null;
            if (unmutatedVars.Length == fieldNode.Declaration.Variables.Count) {
                var r = new ReadyCodeAction("Make readonly", document, fieldNode, () => fieldNode.WithModifiers(modsWithReadOnly));
                var desc = unmutatedVars.Length == 1 ? "Mutable field is never modified." : "Mutable fields are never modified.";
                return r.CodeIssues1(CodeIssue.Severity.Warning, fieldNode.Declaration.Type.Span, desc);
            }

            return unmutatedVars.Select(v => {
                var singleReadOnly = fieldNode.WithModifiers(modsWithReadOnly)
                                              .WithDeclaration(fieldNode.Declaration.WithVariables(v.SepList1()));
                var rest = fieldNode
                           .WithLeadingTrivia()
                           .WithTrailingTrivia(Syntax.Whitespace(Environment.NewLine))
                           .WithDeclaration(fieldNode.Declaration.WithVariables(fieldNode.Declaration.Variables.Without(v)));
                var newClassDecl = classDecl.With(members: classDecl.Members.WithItemReplacedByMany(fieldNode, new[] { singleReadOnly, rest }));
                var action = new ReadyCodeAction("Split readonly", document, classDecl, () => newClassDecl);
                return new CodeIssue(CodeIssue.Severity.Warning, v.Identifier.Span, "Mutable field is never modified.", new[] { action });
            }).ToArray();
        }
Пример #4
0
        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
        {
            var forLoop = (ForEachStatementSyntax)node;
            var model = document.TryGetSemanticModel();
            if (model == null) return null;

            // list created just before loop starts?
            var initStatement = forLoop.TryGetPrevStatement();
            var lhs = initStatement.TryGetLHSExpOfAssignmentOrInit() as IdentifierNameSyntax;
            if (lhs == null) return null;
            var target = lhs.Identifier;
            var rhs = initStatement.TryGetRHSOfAssignmentOrInit() as ObjectCreationExpressionSyntax;
            if (rhs == null) return null;
            var cr = model.GetTypeInfo(rhs).Type;
            if (cr.AllInterfaces.All(e => e.Name != "IList")) return null;

            // loop adds things directly into the list?
            var adderStatement = forLoop.Statement.Statements().SingleOrDefaultAllowMany() as ExpressionStatementSyntax;
            if (adderStatement == null) return null;
            var adderInvoke = adderStatement.Expression as InvocationExpressionSyntax;
            if (adderInvoke == null) return null;
            var adderAccess = adderInvoke.Expression as MemberAccessExpressionSyntax;
            if (adderAccess == null) return null;
            var adderTarget = adderAccess.Expression as IdentifierNameSyntax;
            if (adderTarget == null) return null;
            if (adderTarget.PlainName != target.ValueText) return null;
            if (adderAccess.Name.PlainName != "Add") return null;
            if (adderInvoke.ArgumentList.Arguments.Count != 1) return null;
            var adderExp = adderInvoke.ArgumentList.Arguments.Single().Expression as SimpleNameSyntax;
            if (adderExp == null) return null;
            if (adderExp.PlainName != forLoop.Identifier.ValueText) return null;

            var linqed = forLoop.Expression.Accessing("ToList").Invoking();
            var replacedInit = initStatement.TryWithNewRightHandSideOfAssignmentOrSingleInit(linqed);

            var action = new ReadyCodeAction(
                "Select into list",
                document,
                new[] { initStatement, forLoop },
                (e, a) => e == initStatement ? replacedInit : a.Dropped());
            return action.CodeIssues1(
                CodeIssue.Severity.Warning,
                forLoop.ForEachKeyword.Span,
                "Initializing a list with a 'for each' loop.");
        }
Пример #5
0
        public IEnumerable<CodeIssue> GetIssues(IDocument document, CommonSyntaxNode node, CancellationToken cancellationToken)
        {
            var assume = Assumptions.All;
            var ifNode = (IfStatementSyntax)node;
            var model = document.GetSemanticModel();

            // try to get single statement branches created by the if statement's existence
            var branches = ifNode.TryGetImplicitBranchSingleStatements(model, assume);
            if (branches == null) return null;

            // check for same LHS/ret in both branches but not in condition
            if (!branches.True.HasMatchingLHSOrRet(branches.False, model, assume)) return null;
            var lhs = branches.True.TryGetLHSOfAssignmentOrInit(model);
            if (lhs != null) {
                var dataFlow = model.AnalyzeExpressionDataFlow(ifNode.Condition);
                if (dataFlow.ReadInside.Contains(lhs)) return null;
                if (dataFlow.WrittenInside.Contains(lhs)) return null;
            }

            // determine how to replace the if statement
            var expTrue = branches.True.TryGetRHSOfAssignmentOrInitOrReturn();
            var expFalse = branches.False.TryGetRHSOfAssignmentOrInitOrReturn();
            var expConditional = ifNode.Condition.Conditional(expTrue, expFalse);
            var replacement = branches.Base.TryUpdateRHSForAssignmentOrInitOrReturn(expConditional);

            // return as code issue / action
            var action = new ReadyCodeAction(
                "Fold into expression",
                document,
                new[] { ifNode, branches.True, branches.False, branches.ReplacePoint },
                (e, a) => e == branches.ReplacePoint ? replacement : a.Dropped());
            return action.CodeIssues1(
                CodeIssue.Severity.Warning,
                ifNode.IfKeyword.Span,
                "'If' statement folds into an expression");
        }