Example #1
0
 /// <summary>
 /// Analyzes class declaration.
 /// </summary>
 /// <param name="context">Syntax node analysis context.</param>
 private static void AnalyzeClassDeclaration(SyntaxNodeAnalysisContext context)
 {
     if (BTAnalyzer.IsGenerated(context))
     {
         return;
     }
     BTAnalyzer.AnalyzeSummaryComments(context);
 }
Example #2
0
        /// <summary>
        /// Analyzes items inside methods.
        /// </summary>
        /// <param name="context">Code block analysis context.</param>
        private static void AnalyzeInsideMethod(SyntaxNodeAnalysisContext context)
        {
            if (BTAnalyzer.IsGenerated(context))
            {
                return;
            }

            // Analyze comments inside methods
            BTAnalyzer.AnalyzeInsideMethodComment(context);
            BTAnalyzer.AnalyzeLogicalExpressions(context);
        }
Example #3
0
        /// <summary>
        /// Analyzes equal comments.
        /// </summary>
        /// <param name="context">Context.</param>
        private static void AnalyzeLogicalExpressions(SyntaxNodeAnalysisContext context)
        {
            // Get method declaration node
            MethodDeclarationSyntax methodDeclaration = context.Node as MethodDeclarationSyntax;

            if (null == methodDeclaration)
            {
                return;
            }

            // Get all equal family expressions
            // Check that constants are on the left
            IEnumerable <SyntaxNode> equalFamilyExpressions = methodDeclaration.DescendantNodes().Where(node => BTAnalyzer.IsEqualFamilyExpression(node.Kind()) && (SyntaxKind.ForStatement != node.Parent.Kind()));

            foreach (SyntaxNode equalNode in equalFamilyExpressions)
            {
                SyntaxNode[] twoSideExpressionNodes = equalNode.ChildNodes().ToArray();
                if (2 != twoSideExpressionNodes.Count())
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, equalNode.GetLocation(), ErrorCode.InvalidExpression));
                    continue;
                }
                if (!BTAnalyzer.IsConstant(twoSideExpressionNodes[0]) && BTAnalyzer.IsConstant(twoSideExpressionNodes[1]))
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, equalNode.GetLocation(), ErrorCode.ConstantOnLeft));
                }
            }

            // Get all logical expressions
            // Check that full parenthization is used in logical expressions
            // IEnumerable<SyntaxNode> logicalExpressions = methodDeclaration.DescendantNodes().Where(node => BTAnalyzer.IsLogicalExpression(node.Kind()));
            // foreach (SyntaxNode logicalNode in logicalExpressions)
            // {
            //    foreach (SyntaxNode node in logicalNode.ChildNodes().Where(node => BTAnalyzer.IsEqualFamilyExpression(node.Kind())))
            //        context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, node.GetLocation(), ErrorCode.MissingFullParenthization));
            // }

            // Check that statements with 1 expression statement should ignore parenthesis
            IEnumerable <SyntaxNode> blockStatements = methodDeclaration.DescendantNodes().Where(node => BTAnalyzer.IsBlockStatement(node.Kind()));

            foreach (SyntaxNode node in blockStatements)
            {
                BlockSyntax block = node.ChildNodes().Where(nodee => SyntaxKind.Block == nodee.Kind()).OfType <BlockSyntax>().FirstOrDefault();
                if (null == block)
                {
                    continue;
                }
                IEnumerable <SyntaxNode> expressionNodes = block.ChildNodes().Where(nodee => BTAnalyzer.IsSingleLineStatement(nodee));
                if ((1 == expressionNodes.Count()) && (1 == block.ChildNodes().Count()))
                {
                    context.ReportDiagnostic(Diagnostic.Create(BTAnalyzer.Rule, node.GetLocation(), ErrorCode.UnnecessaryBlock));
                }
            }
        }
Example #4
0
        private static async Task <Document> MakeConstantLeft(Document document, SyntaxNode node, CancellationToken cancellationToken)
        {
            // Sometimes the equal node is the child of the node passed in
            if (!BTAnalyzer.IsEqualFamilyExpression(node.Kind()))
            {
                node = node.ChildNodes().FirstOrDefault();
            }

            // Get child nodes
            if (null == node)
            {
                return(null);
            }

            // Get child node
            SyntaxNode[] childNodes = node.ChildNodes().ToArray();
            if (2 != childNodes.Count())
            {
                return(null);
            }

            // Replace the old local declaration with the new local declaration
            var oldRoot = await document.GetSyntaxRootAsync(cancellationToken);

            SyntaxNode newNode0 = childNodes[0].ReplaceToken(childNodes[0].GetFirstToken(), SyntaxFactory.ParseToken(childNodes[0].GetFirstToken().ToString().Trim()));
            SyntaxNode newNode1 = childNodes[1].ReplaceToken(childNodes[1].GetFirstToken(), SyntaxFactory.ParseToken(childNodes[1].GetFirstToken().ToString() + " "));

            SyntaxNode newRoot = null;
            SyntaxNode newNode = null;

            try
            {
                newNode = node.ReplaceNodes(childNodes, (original, _) => original == childNodes[0] ? newNode1 : newNode0);
                SyntaxToken token = newNode.ChildTokens().FirstOrDefault();
                if (null == token)
                {
                    return(null);
                }

                if (BTCodeFixProvider.GreaterDictionary.ContainsKey(token.Kind()))
                {
                    newNode = newNode.ReplaceToken(token, SyntaxFactory.ParseToken(SyntaxFactory.Token(BTCodeFixProvider.GreaterDictionary[token.Kind()]).ToString() + " "));
                }

                newRoot = oldRoot.ReplaceNode(node, newNode);
            }
            catch (Exception e)
            {
            }

            // Return document with transformed tree
            return(document.WithSyntaxRoot(newRoot));
        }
Example #5
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);
        }
Example #6
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);
        }
Example #7
0
        /// <summary>
        /// Checks XML start and end tags.
        /// </summary>
        /// <param name="xmlElement">XML element.</param>
        /// <param name="location">Location.</param>
        /// <param name="message">Message.</param>
        /// <returns>True if valid.</returns>
        private static bool CheckXmlTags(XmlElementSyntax xmlElement, ref Location location, ref string message)
        {
            // Start/End tag
            string startTag = xmlElement.StartTag.Name.ToString();
            string endTag   = xmlElement.EndTag.Name.ToString();

            if (string.IsNullOrWhiteSpace(startTag) || string.IsNullOrWhiteSpace(endTag))
            {
                message  = ErrorCode.ErrorsInComment;
                location = xmlElement.GetLocation();
                return(false);
            }

            // Only allows summary or param tag
            if (!BTAnalyzer.IsValidXmlCommentTag(startTag) || !BTAnalyzer.IsValidXmlCommentTag(endTag))
            {
                message  = ErrorCode.InvalidXmlTag;
                location = xmlElement.GetLocation();
                return(false);
            }

            // Return true
            return(true);
        }
Example #8
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));
                    }
                }
            }
        }
Example #9
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);
        }
Example #10
0
        /// <summary>
        /// Checks documentation comment trivia.
        /// </summary>
        /// <param name="commentTria">Comment trivia.</param>
        /// <param name="nodeKind">Kind of node.</param>
        /// <param name="messageList">Message list.</param>
        /// <param name="locationList">Location list.</param>
        /// <param name="paramCommentNameList">Parameter comment name list.</param>
        /// <param name="returnCount">Return count.</param>
        /// <returns>Ture if there is no error.</returns>
        private static bool CheckDocumentationCommentTrivia(SyntaxTrivia commentTria, SyntaxKind nodeKind, ref List <string> messageList, ref List <Location> locationList, ref List <string> paramCommentNameList, ref int returnCount)
        {
            // Preset result to true
            bool result = true;

            // Return early if the trivia has no structure
            if (!commentTria.HasStructure)
            {
                messageList.Add(ErrorCode.ClassCommentStart);
                return(false);
            }

            // Check XML elements
            SyntaxNode commentNode = commentTria.GetStructure();
            IEnumerable <XmlElementSyntax> xmlElements = commentNode.DescendantNodes().Where(node => typeof(XmlElementSyntax) == node.GetType()).OfType <XmlElementSyntax>();

            // Return false if no XML element is found
            if (0 == xmlElements.Count())
            {
                messageList.Add(ErrorCode.ErrorsInComment);
                return(false);
            }

            // Check each XML element
            Location location = commentTria.GetLocation();
            string   message  = string.Empty;

            foreach (XmlElementSyntax xmlElement in xmlElements)
            {
                // Swtich
                switch (xmlElement.StartTag.Name.ToString())
                {
                case "summary":
                {
                    if (!BTAnalyzer.CheckSummaryElement(nodeKind, xmlElement, ref location, ref message))
                    {
                        result = false;
                        messageList.Add(message);
                        locationList.Add(location);
                    }
                    break;
                }

                case "param":
                {
                    if (!BTAnalyzer.CheckParamElement(xmlElement, ref location, ref message, ref paramCommentNameList))
                    {
                        result = false;
                        messageList.Add(message);
                        locationList.Add(location);
                    }
                    break;
                }

                case "returns":
                {
                    if (!BTAnalyzer.CheckReturnElement(xmlElement, ref location, ref message, ref returnCount))
                    {
                        result = false;
                        messageList.Add(message);
                        locationList.Add(location);
                    }
                    break;
                }
                }
            }

            // Return true
            return(result);
        }
Example #11
0
        /// <summary>
        /// Analyzes class comments.
        /// </summary>
        /// <param name="context">Context.</param>
        private static void AnalyzeSummaryComments(SyntaxNodeAnalysisContext context)
        {
            // Get declaration node
            SyntaxNode declarationNode = context.Node;

            if (null == declarationNode)
            {
                return;
            }

            // Check all trivia under the first token
            SyntaxToken?firstToken = declarationNode?.DescendantTokens().FirstOrDefault();

            // No single line comment
            IEnumerable <SyntaxTrivia> singleLineCommentTrivias = firstToken?.GetAllTrivia().Where(trivia => SyntaxKind.SingleLineCommentTrivia == trivia.Kind());

            if (0 < singleLineCommentTrivias.Count())
            {
                BTAnalyzer.ReportDiagnostic(context, singleLineCommentTrivias.First().GetLocation(), ErrorCode.ClassCommentStart);
                return;
            }

            // Only 1 single documentation line comment
            IEnumerable <SyntaxTrivia> singleDocumentationCommentTrivias = firstToken?.GetAllTrivia().Where(trivia => SyntaxKind.SingleLineDocumentationCommentTrivia == trivia.Kind());

            if (0 == singleDocumentationCommentTrivias.Count())
            {
                BTAnalyzer.ReportDiagnostic(context, declarationNode.GetFirstToken().GetLocation(), ErrorCode.MissingComment);
                return;
            }
            else if (1 < singleDocumentationCommentTrivias.Count())
            {
                BTAnalyzer.ReportDiagnostic(context, declarationNode.GetFirstToken().GetLocation(), ErrorCode.ErrorsInComment);
                return;
            }

            // Get the only single line documentation comment trivia
            SyntaxTrivia    singleDocCommentTrivia = singleDocumentationCommentTrivias.First();
            List <string>   messageList            = new List <string>();
            List <Location> locationList           = new List <Location>();
            List <string>   paramCommentNameList   = new List <string>();
            int             returnCount            = 0;

            if (!BTAnalyzer.CheckDocumentationCommentTrivia(singleDocCommentTrivia, declarationNode.Kind(), ref messageList, ref locationList, ref paramCommentNameList, ref returnCount))
            {
                for (int i = 0; i < messageList.Count(); i++)
                {
                    BTAnalyzer.ReportDiagnostic(context, locationList[i], messageList[i]);
                }
            }

            // Check method declaration
            // Check parameter comments
            MethodDeclarationSyntax methodDeclarationSyntax = declarationNode as MethodDeclarationSyntax;

            if (null == methodDeclarationSyntax)
            {
                return;
            }

            // Check parameter comment count
            IEnumerable <ParameterSyntax> parameters = methodDeclarationSyntax.ParameterList.Parameters;

            if (paramCommentNameList.Count() != parameters.Count())
            {
                BTAnalyzer.ReportDiagnostic(context, methodDeclarationSyntax.ParameterList.GetLocation(), ErrorCode.IncompatibleParamComments);
            }

            // Check that all parameters have comment
            foreach (ParameterSyntax parameter in parameters)
            {
                if (!paramCommentNameList.Any(p => p == parameter.Identifier.Text))
                {
                    BTAnalyzer.ReportDiagnostic(context, parameter.GetLocation(), ErrorCode.MissingParamComment);
                    break;
                }
            }

            // Check number of returns comments
            if ("void" == methodDeclarationSyntax.ReturnType.ToString())
            {
                if (0 < returnCount)
                {
                    BTAnalyzer.ReportDiagnostic(context, methodDeclarationSyntax.ReturnType.GetLocation(), ErrorCode.IncorrectReturnComment);
                    return;
                }
            }
            else
            {
                if (1 != returnCount)
                {
                    BTAnalyzer.ReportDiagnostic(context, methodDeclarationSyntax.ReturnType.GetLocation(), ErrorCode.IncorrectReturnComment);
                    return;
                }
            }
        }
Example #12
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));
                }
            }
        }