Beispiel #1
0
        /// <summary>
        /// Checks summary element.
        /// </summary>
        /// <param name="nodeKind">Kind of node.</param>
        /// <param name="xmlElement">The XML element.</param>
        /// <param name="location">Location.</param>
        /// <param name="message">Message.</param>
        /// <returns>True if there is no error.</returns>
        private static bool CheckSummaryElement(SyntaxKind nodeKind, XmlElementSyntax xmlElement, ref Location location, ref string message)
        {
            // Check xml start/end tags
            if (!BTAnalyzer.CheckXmlTags(xmlElement, ref location, ref message))
            {
                return(false);
            }

            // Set location
            location = xmlElement.StartTag.GetLocation();
            Position position = Position.Origin;

            // Check XML element text
            string[] lines = xmlElement.ToString().Split(new string[] { "///" }, StringSplitOptions.None);

            // Check
            int offset = lines[0].Length + 3;

            for (int i = 1; i < lines.Length; i++)
            {
                string trimmedLine = lines[i].TrimEnd(' ', '\r', '\n');
                if (' ' != trimmedLine[0])
                {
                    message  = ErrorCode.MissingSpace;
                    location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, new Position(0, 0), offset);
                    return(false);
                }

                // Ignore first and last lines
                if ((0 < i) && (i < lines.Length - 1))
                {
                    // Validate text
                    foreach (StringValidator.Validate validate in BTAnalyzer.GetSummaryValidator(nodeKind))
                    {
                        if (!validate(trimmedLine, ref message, ref position))
                        {
                            location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, position, offset);
                            return(false);
                        }
                    }
                }

                // Increase offset
                offset += lines[i].Length + 3;
            }

            // Return true
            return(true);
        }
Beispiel #2
0
        /// <summary>
        /// Checks param element.
        /// </summary>
        /// <param name="xmlElement">XML element.</param>
        /// <param name="location">Location.</param>
        /// <param name="message">Message.</param>
        /// <param name="paramCommentNameList">Parameter comment name list.</param>
        /// <returns>True if there is no error.</returns>
        private static bool CheckParamElement(XmlElementSyntax xmlElement, ref Location location, ref string message, ref List <string> paramCommentNameList)
        {
            // Check tags
            if (!BTAnalyzer.CheckXmlTags(xmlElement, ref location, ref message))
            {
                return(false);
            }

            // Set location
            location = xmlElement.StartTag.GetLocation();
            Position position = Position.Origin;

            // Add param name to the list
            XmlNameAttributeSyntax xmlNameAttribute = xmlElement.StartTag.Attributes.Where(attr => SyntaxKind.XmlNameAttribute == attr.Kind()).FirstOrDefault() as XmlNameAttributeSyntax;

            if (null == xmlNameAttribute)
            {
                message = ErrorCode.MissingNameAttribute;
                return(false);
            }
            paramCommentNameList.Add(xmlNameAttribute.Identifier.ToString());

            // Remove <see cref .. /> elements, remove start and end tags
            // Check XML element text
            string text = xmlElement.ToString().Replace(xmlElement.StartTag.ToString(), String.Empty).Replace(xmlElement.EndTag.ToString(), String.Empty).TrimStart('/');

            foreach (StringValidator.Validate validate in BTAnalyzer.ParamTextValidators)
            {
                if (!validate(text, ref message, ref position))
                {
                    location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, position, xmlElement.StartTag.ToString().Length);
                    return(false);
                }
            }

            // Return true
            return(true);
        }
Beispiel #3
0
        /// <summary>
        /// Analyzes comment inside block.
        /// </summary>
        /// <param name="context">Context.</param>
        private static void AnalyzeInsideMethodComment(SyntaxNodeAnalysisContext context)
        {
            // Get the block
            MethodDeclarationSyntax methodDeclarationSyntax = context.Node as MethodDeclarationSyntax;

            if (null == methodDeclarationSyntax)
            {
                return;
            }

            // Get all single line comment trivia
            IEnumerable <SyntaxTrivia> singleLineCommentTrivias = methodDeclarationSyntax.Body.DescendantTrivia().Where(trivia => (SyntaxKind.SingleLineCommentTrivia == trivia.Kind()) ||
                                                                                                                        (SyntaxKind.SingleLineDocumentationCommentTrivia == trivia.Kind()));

            // Iterate through each single line comment
            string message = string.Empty;

            foreach (SyntaxTrivia singleLineComment in singleLineCommentTrivias)
            {
                Location location = singleLineComment.GetLocation();
                Position position = Position.Origin;
                if (!StringValidator.StartWithTwoSlashes(singleLineComment.ToString(), ref message, ref position))
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, BTAnalyzer.GetLocation(singleLineComment.SyntaxTree, location, position), message));
                    continue;
                }
                string trimmedText = singleLineComment.ToString().Substring(3);
                foreach (StringValidator.Validate validate in BTAnalyzer.NormalCommentValidator)
                {
                    if (!validate(trimmedText, ref message, ref position))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, BTAnalyzer.GetLocation(singleLineComment.SyntaxTree, location, position, 3), message));
                    }
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Checks returns element.
        /// </summary>
        /// <param name="xmlElement">XML element.</param>
        /// <param name="location">Location.</param>
        /// <param name="message">Message.</param>
        /// <param name="returnCount">Return count.</param>
        /// <returns>True if valid.</returns>
        private static bool CheckReturnElement(XmlElementSyntax xmlElement, ref Location location, ref string message, ref int returnCount)
        {
            // Check tags
            if (!BTAnalyzer.CheckXmlTags(xmlElement, ref location, ref message))
            {
                return(false);
            }

            // Increment number of <returns>
            returnCount++;

            // Set location
            location = xmlElement.StartTag.GetLocation();
            Position position = Position.Origin;

            // Check
            if (xmlElement.ToString().Contains("\r\n"))
            {
                string[] lines  = xmlElement.ToString().Split(new string[] { "///" }, StringSplitOptions.None);
                int      offset = lines[0].Length + 3;
                for (int i = 1; i < lines.Length; i++)
                {
                    string trimmedLine = lines[i].TrimEnd(' ', '\r', '\n');
                    if (' ' != trimmedLine[0])
                    {
                        message  = ErrorCode.MissingSpace;
                        location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, new Position(0, 0), offset);
                        return(false);
                    }

                    // Ignore first and last line
                    if ((0 < i) && (i < lines.Length - 1))
                    {
                        // Validate text
                        foreach (StringValidator.Validate validate in BTAnalyzer.ReturnTextValidators)
                        {
                            if (!validate(trimmedLine, ref message, ref position))
                            {
                                location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, position, offset);
                                return(false);
                            }
                        }
                    }

                    // Add offset, 3 for the removed ///
                    offset += lines[i].Length + 3;
                }
            }
            else
            {
                string text        = xmlElement.ToString().Replace(xmlElement.StartTag.ToString(), string.Empty).Replace(xmlElement.EndTag.ToString(), string.Empty);
                string trimmedLine = text.TrimEnd(' ', '\r', '\n');
                foreach (StringValidator.Validate validate in BTAnalyzer.ReturnTextValidators)
                {
                    if (!validate(trimmedLine, ref message, ref position))
                    {
                        location = BTAnalyzer.GetLocation(xmlElement.SyntaxTree, location, position, xmlElement.StartTag.ToString().Length);
                        return(false);
                    }
                }
            }

            // Return true
            return(true);
        }
Beispiel #5
0
        /// <summary>
        /// Analyzes empty lines inside blocks.
        /// </summary>
        /// <param name="context">Context.</param>
        private static void AnalyzeBlockEmptyLines(SyntaxNodeAnalysisContext context)
        {
            // Return early
            if (BTAnalyzer.IsGenerated(context))
            {
                return;
            }

            // Get the block
            ClassDeclarationSyntax classDeclarationSyntax = context.Node as ClassDeclarationSyntax;

            // Check method spacing
            SyntaxNode[] nodes    = classDeclarationSyntax.ChildNodes().Where(node => SyntaxKind.BaseList != node.Kind() && SyntaxKind.AttributeList != node.Kind()).ToArray();
            Location     location = default(Location);

            for (int i = 0; i < nodes.Length; i++)
            {
                SyntaxNode method = nodes[i];
                IEnumerable <SyntaxTrivia> trivias = method.GetFirstToken().LeadingTrivia;
                int count = 0;
                int j     = 0;
                foreach (SyntaxTrivia trivia in trivias)
                {
                    if (j == 0)
                    {
                        location = BTAnalyzer.GetLocation(trivia.SyntaxTree, trivia.GetLocation(), Position.Origin);
                        j++;
                    }

                    if (SyntaxKind.EndOfLineTrivia == trivia.Kind())
                    {
                        count++;
                    }
                    else if (!(SyntaxKind.WhitespaceTrivia == trivia.Kind()))
                    {
                        break;
                    }
                }
                if ((i == 0 && count > 0) || (i > 0 && count > 1))
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, location, ErrorCode.ExtraLine));
                }
                if (i > 0 && count < 1)
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, location, ErrorCode.MissingEmptyLine));
                }
            }


            // Check blocks
            IEnumerable <BlockSyntax> blocks = classDeclarationSyntax.DescendantNodes().Where(node => SyntaxKind.Block == node.Kind()).OfType <BlockSyntax>();

            // Iterate through each block
            foreach (BlockSyntax block in blocks)
            {
                // Get a list of node, single line comment and end of line
                List <Tuple <object, SyntaxKind> > blockObjectList = new List <Tuple <object, SyntaxKind> >();
                foreach (SyntaxNode node in block.ChildNodes())
                {
                    // Check whether the node is a block node
                    bool isBlockNode = node.ChildNodes().Any(nodee => SyntaxKind.Block == nodee.Kind());

                    // Get all trivias
                    SyntaxTrivia[] allTrivias = node.DescendantTrivia().Where(trivia => (SyntaxKind.SingleLineCommentTrivia == trivia.Kind()) ||
                                                                              (SyntaxKind.EndOfLineTrivia == trivia.Kind())).ToArray();

                    // Add trivias before the node
                    foreach (SyntaxTrivia trivia in allTrivias)
                    {
                        if (trivia.Span.End <= node.SpanStart)
                        {
                            blockObjectList.Add(Tuple.Create <object, SyntaxKind>(trivia, trivia.Kind()));
                        }
                    }

                    // Add the node
                    blockObjectList.Add(Tuple.Create <object, SyntaxKind>(node, SyntaxKind.None));

                    // Add trivia after the node
                    foreach (SyntaxTrivia trivia in allTrivias)
                    {
                        if ((trivia.SpanStart >= node.Span.End) && !isBlockNode)
                        {
                            blockObjectList.Add(Tuple.Create <object, SyntaxKind>(trivia, trivia.Kind()));
                        }
                    }

                    // Add an additional end of line trivia for block node
                    if (isBlockNode)
                    {
                        blockObjectList.Add(Tuple.Create <object, SyntaxKind>(null, SyntaxKind.EndOfLineTrivia));
                    }
                }

                // Trim the block object list
                // Remove end of line after a statement
                List <Tuple <object, SyntaxKind> > trimmedBlockObjectList = new List <Tuple <object, SyntaxKind> >();
                for (int i = 0; i < blockObjectList.Count(); i++)
                {
                    if (SyntaxKind.EndOfLineTrivia != blockObjectList[i].Item2)
                    {
                        if ((i + 1 < blockObjectList.Count()) && (SyntaxKind.EndOfLineTrivia == blockObjectList[i + 1].Item2))
                        {
                            trimmedBlockObjectList.Add(blockObjectList[i]);
                            i++;
                            continue;
                        }
                    }
                    trimmedBlockObjectList.Add(blockObjectList[i]);
                }

                // Cannot start with empty lines
                for (int i = 0; i < trimmedBlockObjectList.Count(); i++)
                {
                    if (SyntaxKind.EndOfLineTrivia == blockObjectList[i].Item2)
                    {
                        SyntaxTrivia trivia = (SyntaxTrivia)trimmedBlockObjectList[i].Item1;
                        context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, trivia.GetLocation(), ErrorCode.ExtraLine));
                    }
                    else
                    {
                        break;
                    }
                }

                // Check if there is only syntax node inside the block
                bool isOnlySyntaxNode = trimmedBlockObjectList.All(tuple => SyntaxKind.None == tuple.Item2);

                // Statement should have comments before
                for (int i = 0; i < trimmedBlockObjectList.Count(); i++)
                {
                    // Skip nodes
                    while ((i < trimmedBlockObjectList.Count()) && (SyntaxKind.None != trimmedBlockObjectList[i].Item2))
                    {
                        i++;
                    }

                    // Check for missing comment
                    if (i < trimmedBlockObjectList.Count())
                    {
                        if ((((0 < i - 1) && (SyntaxKind.SingleLineCommentTrivia != trimmedBlockObjectList[i - 1].Item2)) || i == 0) && !isOnlySyntaxNode)
                        {
                            SyntaxNode node = (SyntaxNode)trimmedBlockObjectList[i].Item1;
                            context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, Location.Create(node.SyntaxTree, new TextSpan(node.SpanStart, 10)), ErrorCode.MissingComment));
                        }
                    }
                    while ((i < trimmedBlockObjectList.Count()) && (SyntaxKind.None == trimmedBlockObjectList[i].Item2))
                    {
                        i++;
                    }

                    // Check for missing empty line
                    if ((i < trimmedBlockObjectList.Count()) && (SyntaxKind.EndOfLineTrivia != trimmedBlockObjectList[i].Item2))
                    {
                        context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, ((SyntaxTrivia)trimmedBlockObjectList[i].Item1).GetLocation(), ErrorCode.MissingEmptyLine));
                    }
                }

                // Cannot end with empty lines
                IEnumerable <SyntaxTrivia> triviaBeforeClosingBrackets = block.CloseBraceToken.LeadingTrivia;
                if (1 < triviaBeforeClosingBrackets.Count())
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, block.CloseBraceToken.GetLocation(), ErrorCode.UnexpectedComponentsBeforeClosingBracket));
                }
            }
        }