private void AnalyzeIfOrElseStatement(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            IfStatementSyntax ifStatement = context.Node as IfStatementSyntax;

            // Is this an if statement followed directly by a call with no braces?
            if ((ifStatement != null) &&
                (ifStatement.Statement != null) &&
                (ifStatement.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location loc = ifStatement.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "if");
                context.ReportDiagnostic(diagnostic);
            }

            // Is this an else clause followed by a call with no braces?
            ElseClauseSyntax elseSyntax = context.Node as ElseClauseSyntax;
            if ((elseSyntax != null) &&
                (elseSyntax.Statement != null ) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.IfStatement) == false) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location loc = elseSyntax.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "else");
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeIfOrElseStatement(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            IfStatementSyntax ifStatement = context.Node as IfStatementSyntax;

            // Is this an if statement followed directly by a call with no braces?
            if ((ifStatement != null) &&
                (ifStatement.Statement != null) &&
                (ifStatement.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location   loc        = ifStatement.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "if");
                context.ReportDiagnostic(diagnostic);
            }

            // Is this an else clause followed by a call with no braces?
            ElseClauseSyntax elseSyntax = context.Node as ElseClauseSyntax;

            if ((elseSyntax != null) &&
                (elseSyntax.Statement != null) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.IfStatement) == false) &&
                (elseSyntax.Statement.IsKind(SyntaxKind.Block) == false))
            {
                Location   loc        = elseSyntax.GetLocation();
                Diagnostic diagnostic = Diagnostic.Create(Rule, loc, "else");
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeIdentifier(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }
            var typeName = "";
            // Look at the method
            // If it has parameters, check if see if the last parameter has the IsParams set.
            var indentifierName = context.Node as IdentifierNameSyntax;
            var methodSymbol    = MatchMethodOfType(context, "Inspur.GSP.Bef.Api.Lcp.IStandardLcp");

            if (methodSymbol == null)
            {
                return;
            }


            if (context.Node.IsNodeInALoop())
            {
                // We got us a problem here, boss.
                var diagnostic = Diagnostic.Create(Rule,
                                                   indentifierName.GetLocation(),
                                                   indentifierName.Parent.ToString());
                context.ReportDiagnostic(diagnostic);
            }
            //var count = methodSymbol.OriginalDefinition.Parameters.Length;
            //if (count == 0) return;
            //if (methodSymbol.OriginalDefinition.Parameters[count - 1].IsParams)
            //{
            //    // Only report the error if this call is inside a loop.

            //}
        }
        private void AnalyzeIdentifier(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            // Look at the method
            // If it has parameters, check if see if the last parameter has the IsParams set.
            IdentifierNameSyntax indentifierName = context.Node as IdentifierNameSyntax;
            IMethodSymbol        methodSymbol    = context.SemanticModel.GetSymbolInfo(indentifierName).Symbol as IMethodSymbol;

            if (methodSymbol != null)
            {
                Int32 count = methodSymbol.OriginalDefinition.Parameters.Length;
                if (count != 0)
                {
                    if (methodSymbol.OriginalDefinition.Parameters[count - 1].IsParams)
                    {
                        // Only report the error if this call is inside a loop.
                        if (context.Node.IsNodeInALoop())
                        {
                            // We got us a problem here, boss.
                            var diagnostic = Diagnostic.Create(Rule,
                                                               indentifierName.GetLocation(),
                                                               indentifierName.Parent.ToString());
                            context.ReportDiagnostic(diagnostic);
                        }
                    }
                }
            }
        }
        private static void AnalyzeFieldDeclaration(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode()) { return; }
            var fieldDeclaration = (FieldDeclarationSyntax)context.Node;
            if (IsStaticReadonlyField(fieldDeclaration)) { return; }

            SyntaxToken[] accessTokens = GetAccessTokenFor(fieldDeclaration, SyntaxKind.PrivateKeyword);
            if (accessTokens.Length != 1) {
                string fieldName = fieldDeclaration.DescendantTokens().FirstOrDefault(token => token.IsKind(SyntaxKind.IdentifierToken)).Value as string;
                Diagnostic diagnostic = Diagnostic.Create(Rule, fieldDeclaration.GetLocation(), fieldName);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeDateTimeUsage(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode()) { return; }
            var node = context.Node as IdentifierNameSyntax;

            var membersToSearch = new[] {
                new SearchMemberInfo("System", "DateTime", "Now"),
                new SearchMemberInfo("System", "DateTime", "Today")
            };
            var symbol = node.CheckNodeIsMemberOfType(context.SemanticModel, membersToSearch);
            if (symbol == null) { return; }
            Diagnostic diagnostic = Diagnostic.Create(Rule, node.GetLocation(), $"{symbol.ContainingType.Name}.{symbol.Name}");
            context.ReportDiagnostic(diagnostic);
        }
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            // Look for calls to Debug.Assert.
            // Ensure it's the
            // Look at the parameters.
            // If only one, trigger the error.

            // Take a quick peek and see if this is a call to an "Debug.Assert" method.
            InvocationExpressionSyntax invocationExpr = context.Node as InvocationExpressionSyntax;

            if (invocationExpr?.Expression.ToString() != "Debug.Assert")
            {
                return;
            }

            // Let's get serious and double check that we are dealing with System.Diagnostic.System.Assert.
            // In some scenarios, such as unit tests the module will be null because the whole tree hasn't been
            // built. In that case, I'll just have to assume it's the real method.
            IMethodSymbol memberSymbol = context.SemanticModel.GetSymbolInfo(invocationExpr).Symbol as IMethodSymbol;

            if (memberSymbol != null)
            {
                INamedTypeSymbol classSymbol = memberSymbol.ContainingSymbol as INamedTypeSymbol;
                if (classSymbol != null)
                {
                    if (!classSymbol.IsType(typeof(Debug)))
                    {
                        return;
                    }
                }
            }

            // How many parameters are there?
            ArgumentListSyntax argumentList = invocationExpr.ArgumentList as ArgumentListSyntax;

            if ((argumentList?.Arguments.Count ?? 0) > 1)
            {
                return;
            }

            // We got us a problem here, boss.
            var diagnostic = Diagnostic.Create(Rule, invocationExpr.GetLocation());

            context.ReportDiagnostic(diagnostic);
        }
        private void AnalyzeNode(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            // Look for calls to Debug.Assert.
            // Ensure it's the
            // Look at the parameters. 
            // If only one, trigger the error.

            // Take a quick peek and see if this is a call to an "Debug.Assert" method.
            InvocationExpressionSyntax invocationExpr = context.Node as InvocationExpressionSyntax;
            if (invocationExpr?.Expression.ToString() != "Debug.Assert")
            {
                return;
            }

            // Let's get serious and double check that we are dealing with System.Diagnostic.System.Assert.
            // In some scenarios, such as unit tests the module will be null because the whole tree hasn't been 
            // built. In that case, I'll just have to assume it's the real method.
            IMethodSymbol memberSymbol = context.SemanticModel.GetSymbolInfo(invocationExpr).Symbol as IMethodSymbol;
            if (memberSymbol != null)
            {
                INamedTypeSymbol classSymbol = memberSymbol.ContainingSymbol as INamedTypeSymbol;
                if (classSymbol != null)
                {
                    if (!classSymbol.IsType(typeof(Debug)))
                    {
                        return;
                    }
                }
            }

            // How many parameters are there?
            ArgumentListSyntax argumentList = invocationExpr.ArgumentList as ArgumentListSyntax;
            if ((argumentList?.Arguments.Count ?? 0) > 1)
            {
                return;
            }

            // We got us a problem here, boss.
            var diagnostic = Diagnostic.Create(Rule, invocationExpr.GetLocation());
            context.ReportDiagnostic(diagnostic);
        }
 private void AnalyzeIfStatementDeclaration(SyntaxNodeAnalysisContext context)
 {
     if (context.IsGeneratedOrNonUserCode()) { return; }
     var ifStatement = context.Node as IfStatementSyntax;
     if (ifStatement == null) { return; }
     CSharpSyntaxNode errorLocation = null;
     StatementSyntax thenClause = ifStatement.Statement;
     if (thenClause != null && !(thenClause is BlockSyntax)) {
         errorLocation = thenClause;
     }
     ElseClauseSyntax elseClause = ifStatement.Else;
     if (elseClause != null) {
         if (elseClause.Statement is BlockSyntax == false && elseClause.Statement is IfStatementSyntax == false) {
             errorLocation = errorLocation == null ? elseClause : (CSharpSyntaxNode)ifStatement;
         }
     }
     if (errorLocation == null) { return; }
     Diagnostic diagnostic = Diagnostic.Create(Rule, errorLocation.GetLocation(), errorLocation.ToString());
     context.ReportDiagnostic(diagnostic);
 }
Example #10
0
        private void AnalyzeCatchBlock(SyntaxNodeAnalysisContext context)
        {
            // As always skip generated code.
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            CatchClauseSyntax theCatch = (CatchClauseSyntax)context.Node;

            // I want to be smart about how I look at the catch blocks as the control flow could
            // be slow on very large blocks. Consequently, I only want to look at those blocks
            // that don't have any diagnostics (errors) in them.
            TextSpan span           = theCatch.GetLocation().SourceSpan;
            var      allDiagnostics = context.SemanticModel.Compilation.GetDiagnostics();

            for (Int32 i = 0; i < allDiagnostics.Length; i++)
            {
                if (allDiagnostics[i].Location.SourceSpan.IntersectsWith(span))
                {
                    return;
                }
            }

            // Take a look at the control flow.
            ControlFlowAnalysis flowAnalysis = context.SemanticModel.AnalyzeControlFlow(theCatch.Block);

            if (flowAnalysis.Succeeded)
            {
                if ((flowAnalysis.ReturnStatements.Length == 0) &&
                    (flowAnalysis.EndPointIsReachable == false) &&
                    (flowAnalysis.EntryPoints.Length == 0))
                {
                    return;
                }

                // Now we know this catch block either eats the exception or has a return.
                var diagnostic = Diagnostic.Create(Rule, theCatch.GetLocation());
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzePredefinedType(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            PredefinedTypeSyntax predefinedType = context.Node as PredefinedTypeSyntax;

            // Don't touch the void. :)
            if (!predefinedType.ToString().Equals("void", StringComparison.OrdinalIgnoreCase))
            {
                String typeString = predefinedType.ToString();
                String realString = TypeMap[typeString];
                var diagnostic = Diagnostic.Create(Rule,
                                                   predefinedType.GetLocation(),
                                                   typeString,
                                                   realString);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzePredefinedType(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            PredefinedTypeSyntax predefinedType = context.Node as PredefinedTypeSyntax;

            // Don't touch the void. :)
            if (!predefinedType.ToString().Equals("void", StringComparison.OrdinalIgnoreCase))
            {
                String typeString = predefinedType.ToString();
                String realString = TypeMap[typeString];
                var    diagnostic = Diagnostic.Create(Rule,
                                                      predefinedType.GetLocation(),
                                                      typeString,
                                                      realString);
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeCatchBlock(SyntaxNodeAnalysisContext context)
        {
            // As always skip generated code.
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            CatchClauseSyntax theCatch = (CatchClauseSyntax)context.Node;

            // I want to be smart about how I look at the catch blocks as the control flow could
            // be slow on very large blocks. Consequently, I only want to look at those blocks
            // that don't have any diagnostics (errors) in them.
            TextSpan span = theCatch.GetLocation().SourceSpan;
            var allDiagnostics = context.SemanticModel.Compilation.GetDiagnostics();
            for (Int32 i = 0; i < allDiagnostics.Length; i++)
            {
                if (allDiagnostics[i].Location.SourceSpan.IntersectsWith(span))
                {
                    return;
                }
            }

            // Take a look at the control flow.
            ControlFlowAnalysis flowAnalysis = context.SemanticModel.AnalyzeControlFlow(theCatch.Block);

            if (flowAnalysis.Succeeded)
            {
                if ((flowAnalysis.ReturnStatements.Length == 0) &&
                    (flowAnalysis.EndPointIsReachable == false) &&
                    (flowAnalysis.EntryPoints.Length == 0))
                {
                    return;
                }

                // Now we know this catch block either eats the exception or has a return.
                var diagnostic = Diagnostic.Create(Rule, theCatch.GetLocation());
                context.ReportDiagnostic(diagnostic);
            }
        }
        private void AnalyzeThrowDocumentation(SyntaxNodeAnalysisContext context)
        {
            if (context.IsGeneratedOrNonUserCode())
            {
                return;
            }

            // Get the method that contains this throw statement. I'm asking for the symbol table because
            // it's got all the XML data and doesn't require me walking the SyntaxNode trees.
            var methodSymbol = context.SemanticModel.GetEnclosingSymbol(context.Node.SpanStart) as IMethodSymbol;

            // I skip private methods because the <exception> tag is for methods called by derived classes or
            // external classes.
            if (methodSymbol.DeclaredAccessibility == Accessibility.Private)
            {
                return;
            }

            ThrowStatementSyntax throwSyntax = context.Node as ThrowStatementSyntax;

            // If there's no descendant nodes, it's a "throw;" so there's nothing to do here.
            if (!throwSyntax.DescendantNodes().Any())
            {
                return;
            }

            // Get the type being thrown by searching for the IdentifierNameSyntax. This works for both "throw new BlahException" and
            // "throw ex" (in case someone's crazy enough to do that).
            IdentifierNameSyntax ident = throwSyntax.DescendantNodes().First(node => node is IdentifierNameSyntax) as IdentifierNameSyntax;

            if (ident != null)
            {
                // The type being thrown. I'm getting the fully qualified name because that's the form they
                // are in the ISymbol.GetDocumentationCommentXml.
                ISymbol thrownTypeSymbol = context.SemanticModel.GetSymbolInfo(ident).Symbol;
                String  thrownType       = thrownTypeSymbol.ToDisplayString();

                String rawDocComment = methodSymbol.GetDocumentationCommentXml(expandIncludes: true);

                // If this method is a property, GetEnclosingSymbol returns the set or get method, which
                // does not have the XML comments on it only the actual property declaration has those.
                // To go from the setter or getter to the property, use the AssociatedSymbol.
                if (methodSymbol.AssociatedSymbol != null)
                {
                    var propertySymbol = methodSymbol.AssociatedSymbol as IPropertySymbol;
                    rawDocComment = propertySymbol?.GetDocumentationCommentXml();
                }

                // Get all the documented exceptions and the reasons why that exception is thrown.
                Dictionary <String, String> exceptions = this.DocumentedExceptionInformation(rawDocComment);

                // Assume the exception is not documented.
                Boolean properlyDocumented = false;

                foreach (var exception in exceptions)
                {
                    // If the exception type is documented and the reason why is not null, we are
                    // good to go.
                    if ((thrownType.Equals(exception.Key)) && (!String.IsNullOrEmpty(exception.Value)))
                    {
                        properlyDocumented = true;
                        break;
                    }
                }

                if (properlyDocumented == false)
                {
                    // I report only the exception type name, not the fully qualified name, because that's
                    // how they should be documented.
                    var diagnostic = Diagnostic.Create(Rule, throwSyntax.GetLocation(), thrownTypeSymbol.Name);
                    context.ReportDiagnostic(diagnostic);
                }
            }
        }