Beispiel #1
0
        /// <summary>
        /// Walks through the children of the given code unit.
        /// </summary>
        /// <param name="codeUnit">The code unit to walk.</param>
        /// <param name="callback">Callback executed when a code unit is visited.</param>
        /// <param name="parentElement">The parent element of the code unit, if any.</param>
        /// <param name="parentStatement">The parent statement of the code unit, if any.</param>
        /// <param name="parentExpression">The parent expression of the code unit, if any.</param>
        /// <param name="parentQueryClause">The parent query clause of the code unit, if any.</param>
        /// <param name="parentToken">The parent token of the code unit, if any.</param>
        /// <param name="context">Optional context.</param>
        /// <param name="codeUnitTypes">The types of code units to visit.</param>
        /// <returns>Returns true to continue walking, false otherwise.</returns>
        private static bool WalkCodeUnitChildren(
            CodeUnit codeUnit,
            CodeUnitVisitor <T> callback,
            Element parentElement,
            Statement parentStatement,
            Expression parentExpression,
            QueryClause parentQueryClause,
            Token parentToken,
            T context,
            CodeUnitType[] codeUnitTypes)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.Ignore(codeUnitTypes);
            Param.AssertNotNull(callback, "callback");
            Param.Ignore(parentElement);
            Param.Ignore(parentStatement);
            Param.Ignore(parentExpression);
            Param.Ignore(parentQueryClause);
            Param.Ignore(parentToken);
            Param.Ignore(context);

            if (codeUnit.Children != null && codeUnit.Children.Count > 0)
            {
                for (CodeUnit child = codeUnit.FindFirstChild(); child != null; child = child.FindNextSibling())
                {
                    if (!WalkCodeUnit(child, callback, parentElement, parentStatement, parentExpression, parentQueryClause, parentToken, context, codeUnitTypes))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
        /// <summary>
        /// Visits one code unit in the document.
        /// </summary>
        /// <param name="codeUnit">The item being visited.</param>
        /// <param name="parentElement">The parent element, if any.</param>
        /// <param name="parentStatement">The parent statement, if any.</param>
        /// <param name="parentExpression">The parent expression, if any.</param>
        /// <param name="parentClause">The parent query clause, if any.</param>
        /// <param name="parentToken">The parent token, if any.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>Returns true to continue, or false to stop the walker.</returns>
        private bool VisitCodeUnit(
            CodeUnit codeUnit,
            Element parentElement,
            Statement parentStatement,
            Expression parentExpression,
            QueryClause parentClause,
            Token parentToken,
            Settings settings)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.Ignore(parentElement, parentStatement, parentExpression, parentClause, parentToken);
            Param.AssertNotNull(settings, "settings");

            if (codeUnit.CodeUnitType == CodeUnitType.Element)
            {
                return this.VisitElement((Element)codeUnit, settings);
            }
            else if (codeUnit.CodeUnitType == CodeUnitType.Expression)
            {
                return this.VisitExpression((Expression)codeUnit, parentElement);
            }
            else if (codeUnit.Is(LexicalElementType.Token))
            {
                Token token = (Token)codeUnit;
                if (token.TokenType == TokenType.Type && !token.Parent.Is(TokenType.Type))
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType((TypeToken)token, parentElement);
                }
                else if (token.TokenType == TokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(token, parentElement);
                }
            }
            else if (codeUnit.Is(PreprocessorType.Region))
            {
                this.CheckRegion((RegionDirective)codeUnit, parentElement, settings);
            }
            else if (codeUnit.Is(LexicalElementType.Comment))
            {
                this.CheckForEmptyComments((Comment)codeUnit, parentElement);
            }

            return !this.Cancel;
        }
        /// <summary>
        /// Parses the given query clause.
        /// </summary>
        /// <param name="clause">The query clause.</param>
        /// <param name="parentExpression">The parent expression, if there is one.</param>
        /// <param name="parentElement">The element that contains the expressions.</param>
        /// <param name="parentClass">The class that the element belongs to.</param>
        /// <param name="members">The collection of members of the parent class.</param>
        private void CheckClassMemberRulesForQueryClause(
            QueryClause clause,
            Expression parentExpression,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(clause, "clause");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");

            for (CodeUnit child = clause.FindFirstChild(); child != null; child = child.FindNextSibling())
            {
                if (child.Is(CodeUnitType.QueryClause))
                {
                    this.CheckClassMemberRulesForQueryClause((QueryClause)child, parentExpression, parentElement, parentClass, members);
                }
                else if (child.Is(CodeUnitType.Expression))
                {
                    this.CheckClassMemberRulesForExpression((Expression)child, parentExpression, parentElement, parentClass, members);
                }
                else if (child.Is(TokenType.Literal))
                {
                    Token token = (Token)child;

                    // Check to see whether this literal is preceded by a member access symbol. If not
                    // then we want to check whether this is a reference to one of our class members.
                    if (!IsLiteralTokenPrecededByMemberAccessSymbol(token))
                    {
                        // Process the literal.
                        this.CheckClassMemberRulesForLiteralToken(
                            token,
                            parentExpression,
                            parentExpression,
                            parentElement,
                            parentClass,
                            members);
                    }
                }
            }
        }
        /// <summary>
        /// Analyzes the given query clauses.
        /// </summary>
        /// <param name="element">The element containing the clauses.</param>
        /// <param name="expression">The expression containing the clauses.</param>
        /// <param name="clauseParent">The direct parent of the collection of clauses to analyze.</param>
        /// <param name="previousClause">The previous clause in the expression, if any.</param>
        /// <param name="clauseOnSameLine">Indicates whether any clause has been seen previously which
        /// starts on the same line as the clause before it.</param>
        /// <param name="clauseOnSeparateLine">Indicates whether any clause has been seen previously which
        /// starts on the line after the clause before it.</param>
        /// <returns>Returns true to continue checking the query clause, or false to quit.</returns>
        private bool ProcessQueryClauses(
            Element element,
            QueryExpression expression,
            CodeUnit clauseParent,
            ref QueryClause previousClause,
            ref bool clauseOnSameLine,
            ref bool clauseOnSeparateLine)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(expression, "expression");
            Param.AssertNotNull(clauseParent, "clauseParent");
            Param.Ignore(previousClause);
            Param.Ignore(clauseOnSameLine);
            Param.Ignore(clauseOnSeparateLine);

            for (QueryClause clause = clauseParent.FindFirstChildQueryClause(); clause != null; clause = clause.FindNextSiblingQueryClause())
            {
                if (previousClause != null)
                {
                    // Figure out the line number that the previous clause ends on. For most 
                    // clauses, this is simply the end point of the clause location property,
                    // but for continuation clauses we want to use the location of the 'into' variable,
                    // which conceptually represents the end of the continuation line.
                    int previousClauseEndLineNumber = previousClause.Location.EndPoint.LineNumber;

                    if (previousClause.QueryClauseType == QueryClauseType.Continuation)
                    {
                        previousClauseEndLineNumber = ((QueryContinuationClause)previousClause).Variable.Location.LineNumber;
                    }

                    // Ensure that the clause either starts on the same line as the expression, or 
                    // on the very next line.
                    if (clause.LineNumber == previousClauseEndLineNumber)
                    {
                        // This is only ok if the previous clause does not span multiple lines.
                        if (previousClause.Location.LineSpan > 1)
                        {
                            this.AddViolation(element, clause.LineNumber, Rules.QueryClauseMustBeginOnNewLineWhenPreviousClauseSpansMultipleLines);
                            return false;
                        }

                        // The rest of the checks are only applied when the clause is not a query continuation clause. A continuation
                        // clause is allowed to begin at the end of the previous clause, on the same line.
                        if (clause.QueryClauseType != QueryClauseType.Continuation)
                        {
                            // The clause starts on the same line as the ending of the previous clause.
                            // This is ok as long as we have not previously seen a clause which starts
                            // on its own line. The one exception is that query continuation clauses
                            // are allowed to be inserted at the end of the previous claus.
                            if (clauseOnSeparateLine)
                            {
                                this.AddViolation(element, clause.LineNumber, Rules.QueryClausesMustBeOnSeparateLinesOrAllOnOneLine);
                                return false;
                            }

                            // If the clause spans multiple lines, it must begin on its own line. The exception is query continuation
                            // clauses, which are allowed to begin at the end of the previous claus.
                            if (clause.Location.LineSpan > 1)
                            {
                                this.AddViolation(element, clause.LineNumber, Rules.QueryClausesSpanningMultipleLinesMustBeginOnOwnLine);
                                return false;
                            }

                            // Indicate that we have seen a clause which starts on the same line as the
                            // previous clause.
                            clauseOnSameLine = true;
                        }
                    }
                    else if (clause.LineNumber == previousClauseEndLineNumber + 1)
                    {
                        // The clause starts on the line just after the previous clause. 
                        // This is fine unless we have previously seen two clauses on the same line.
                        if (clauseOnSameLine)
                        {
                            this.AddViolation(element, clause.LineNumber, Rules.QueryClausesMustBeOnSeparateLinesOrAllOnOneLine);
                            return false;
                        }

                        // Indicate that we have seen a clause which begins on the line after
                        // the previous clause.
                        clauseOnSeparateLine = true;
                    }
                    else if (clause.LineNumber > previousClauseEndLineNumber + 1)
                    {
                        // The clause does not start on the line after the previous clause.
                        this.AddViolation(element, clause.LineNumber, Rules.QueryClauseMustFollowPreviousClause);
                        return false;
                    }
                }

                previousClause = clause;

                if (clause.QueryClauseType == QueryClauseType.Continuation)
                {
                    QueryContinuationClause continuationClause = (QueryContinuationClause)clause;
                    if (!this.ProcessQueryClauses(
                        element,
                        expression,
                        continuationClause,
                        ref previousClause,
                        ref clauseOnSameLine,
                        ref clauseOnSeparateLine))
                    {
                        return false;
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Visits one code unit in the document.
        /// </summary>
        /// <param name="codeUnit">The item being visited.</param>
        /// <param name="parentElement">The parent element, if any.</param>
        /// <param name="parentStatement">The parent statement, if any.</param>
        /// <param name="parentExpression">The parent expression, if any.</param>
        /// <param name="parentClause">The parent query clause, if any.</param>
        /// <param name="parentToken">The parent token, if any.</param>
        /// <param name="topLevelElements">The number of classes and namespaces seen in the document.</param>
        /// <returns>Returns true to continue, or false to stop the walker.</returns>
        private bool VisitCodeUnit(
            CodeUnit codeUnit,
            Element parentElement,
            Statement parentStatement,
            Expression parentExpression,
            QueryClause parentClause,
            Token parentToken,
            TopLevelElements topLevelElements)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.Ignore(parentElement, parentStatement, parentExpression, parentClause, parentToken);
            Param.AssertNotNull(topLevelElements, "topLevelElements");

            if (codeUnit.CodeUnitType == CodeUnitType.Element)
            {
                return this.VisitElement((Element)codeUnit, parentElement, topLevelElements);
            }
            else if (codeUnit.CodeUnitType == CodeUnitType.Statement)
            {
                return this.VisitStatement((Statement)codeUnit, parentExpression, parentStatement, parentElement);
            }
            else if (codeUnit.CodeUnitType == CodeUnitType.Expression)
            {
                return this.VisitExpression((Expression)codeUnit, parentExpression, parentStatement, parentElement);
            }

            return !this.Cancel;
        }
Beispiel #6
0
        /// <summary>
        /// Visits the given code unit and walks through its children.
        /// </summary>
        /// <param name="codeUnit">The code unit to walk.</param>
        /// <param name="callback">Callback executed when a code unit is visited.</param>
        /// <param name="context">Optional context.</param>
        /// <param name="codeUnitTypes">The types of code units to visit.</param>
        /// <returns>Returns true to continue walking, false otherwise.</returns>
        private static bool WalkCodeUnit(CodeUnit codeUnit, CodeUnitVisitor <T> callback, T context, CodeUnitType[] codeUnitTypes)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.AssertNotNull(callback, "callback");
            Param.Ignore(context);
            Param.Ignore(codeUnitTypes);

            // Gather up the various parent types for this code unit.
            Element     parentElement     = null;
            Statement   parentStatement   = null;
            Expression  parentExpression  = null;
            QueryClause parentQueryClause = null;
            Token       parentToken       = null;

            CodeUnit parent = codeUnit.Parent;

            while (parent != null)
            {
                switch (parent.CodeUnitType)
                {
                case CodeUnitType.Element:
                    if (parentElement != null)
                    {
                        parentElement = (Element)parent;

                        // Elements are the top-level code units, so we can stop now.
                        parent = null;
                    }

                    break;

                case CodeUnitType.Statement:
                    if (parentStatement != null)
                    {
                        parentStatement = (Statement)parent;
                    }

                    break;

                case CodeUnitType.Expression:
                    if (parentExpression != null)
                    {
                        parentExpression = (Expression)parent;
                    }

                    break;

                case CodeUnitType.QueryClause:
                    if (parentQueryClause != null)
                    {
                        parentQueryClause = (QueryClause)parent;
                    }

                    break;

                case CodeUnitType.LexicalElement:
                    if (parentToken != null)
                    {
                        parentToken = (Token)parent;
                    }

                    break;
                }

                parent = parent == null ? null : parent.Parent;
            }

            return(WalkCodeUnit(codeUnit, callback, parentElement, parentStatement, parentExpression, parentQueryClause, parentToken, context, codeUnitTypes));
        }
Beispiel #7
0
        /// <summary>
        /// Visits the given code unit and walks through its children.
        /// </summary>
        /// <param name="codeUnit">The code unit to walk.</param>
        /// <param name="callback">Callback executed when a code unit is visited.</param>
        /// <param name="parentElement">The parent element of the code unit, if any.</param>
        /// <param name="parentStatement">The parent statement of the code unit, if any.</param>
        /// <param name="parentExpression">The parent expression of the code unit, if any.</param>
        /// <param name="parentQueryClause">The parent query clause of the code unit, if any.</param>
        /// <param name="parentToken">The parent token of the code unit, if any.</param>
        /// <param name="context">Optional context.</param>
        /// <param name="codeUnitTypes">The types of code units to visit.</param>
        /// <returns>Returns true to continue walking, false otherwise.</returns>
        private static bool WalkCodeUnit(
            CodeUnit codeUnit,
            CodeUnitVisitor <T> callback,
            Element parentElement,
            Statement parentStatement,
            Expression parentExpression,
            QueryClause parentQueryClause,
            Token parentToken,
            T context,
            CodeUnitType[] codeUnitTypes)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.AssertNotNull(callback, "callback");
            Param.Ignore(parentElement);
            Param.Ignore(parentStatement);
            Param.Ignore(parentExpression);
            Param.Ignore(parentQueryClause);
            Param.Ignore(parentToken);
            Param.Ignore(context);
            Param.Ignore(codeUnitTypes);

            if (CompareCodeUnitType(codeUnitTypes, codeUnit.CodeUnitType))
            {
                if (!callback(codeUnit, parentElement, parentStatement, parentExpression, parentQueryClause, parentToken, context))
                {
                    return(false);
                }
            }

            if (codeUnit.Children != null && codeUnit.Children.Count > 0)
            {
                switch (codeUnit.CodeUnitType)
                {
                case CodeUnitType.Element:
                    parentElement = (Element)codeUnit;
                    break;

                case CodeUnitType.Statement:
                    parentStatement = (Statement)codeUnit;
                    break;

                case CodeUnitType.Expression:
                    parentExpression = (Expression)codeUnit;
                    break;

                case CodeUnitType.QueryClause:
                    parentQueryClause = (QueryClause)codeUnit;
                    break;

                case CodeUnitType.LexicalElement:
                    if (codeUnit.Is(LexicalElementType.Token))
                    {
                        parentToken = (Token)codeUnit;
                    }

                    break;
                }

                return(WalkCodeUnitChildren(codeUnit, callback, parentElement, parentStatement, parentExpression, parentQueryClause, parentToken, context, codeUnitTypes));
            }

            return(true);
        }