/// <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; }
/// <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)); }
/// <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); }