/// <summary> /// Determine whether the argument passed in is equivalent to "" /// </summary> /// <param name="argument">The Argument to check.</param> /// <returns>True if equivalent to string.empty otherwise false.</returns> private static bool ArgumentTokensMatchStringEmpty(Argument argument) { CsToken firstToken = argument.Tokens.First.Value; if (firstToken.CsTokenType == CsTokenType.String && IsEmptyString(firstToken.Text)) { return(true); } if (firstToken.CsTokenType == CsTokenType.Null) { return(true); } if (argument.Tokens.MatchTokens(StringComparison.OrdinalIgnoreCase, "string", ".", "empty")) { return(true); } if (argument.Tokens.MatchTokens(StringComparison.OrdinalIgnoreCase, "system", ".", "string", ".", "empty")) { return(true); } if (argument.Tokens.MatchTokens(StringComparison.OrdinalIgnoreCase, "global", "::", "system", ".", "string", ".", "empty")) { return(true); } return(false); }
private static IEnumerable <CsToken> Flatten(CsToken token) { var typeToken = token as TypeToken; if (typeToken != null) { return(typeToken.ChildTokens.SelectMany(child => Flatten(child))); } var attributeToken = token as Attribute; if (attributeToken != null) { return(attributeToken.ChildTokens.SelectMany(child => Flatten(child))); } var xmlHeader = token as XmlHeader; if (xmlHeader != null) { return(xmlHeader.ChildTokens.SelectMany(child => Flatten(child))); } return(Enumerable.Repeat(token, 1)); }
/// <summary> /// Checks a multi-line comment. /// </summary> /// <param name="rootElement">The root element.</param> /// <param name="token">The token.</param> /// <param name="checkDelegate">The delegate that checks each comment /// line.</param> /// <param name="violatedRuleIfCheckFails">The rule that is violated if /// the check succeeds.</param> /// <param name="violationContext">Context to make the violation /// message more meaningful.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="rootElement"/>, <paramref name="token"/> or <paramref /// name="checkDelegate"/> is <c>null</c>.</exception> /// <exception cref="ArgumentException">Thrown if the supplied token is /// not a multi-line comment.</exception> /// <remarks>This method does not check if the supplied token is /// generated or not. If generated code should not be checked, this has /// to be taken care of in the calling method.</remarks> private void CheckMultiLineComment( DocumentRoot rootElement, CsToken token, Func <string, int, bool> checkDelegate, Rules violatedRuleIfCheckFails, params object[] violationContext) { Param.RequireNotNull(rootElement, "rootElement"); Param.RequireNotNull(token, "token"); Param.RequireNotNull(checkDelegate, "checkDelegate"); Param.Require( token.CsTokenType == CsTokenType.MultiLineComment, "token", "The supplied token is not a multi-line comment."); string[] newLine = new[] { Environment.NewLine }; string[] splitComment = token.Text.Split(newLine, StringSplitOptions.None); for (int index = 0; index < splitComment.Length; index++) { if (checkDelegate(splitComment[index], index)) { this.AddViolation( rootElement, token.LineNumber + index, violatedRuleIfCheckFails, violationContext); } } }
/// <summary> /// Initializes a new instance of the Argument class. /// </summary> /// <param name="name">The optional name of the argument.</param> /// <param name="modifiers">Modifers applied to this argument.</param> /// <param name="argumentExpression">The expression that forms the body of the argument.</param> /// <param name="location">The location of the argument in the code.</param> /// <param name="parent">The parent code part.</param> /// <param name="tokens">The tokens that form the argument.</param> /// <param name="generated">Indicates whether the argument is located within a block of generated code.</param> internal Argument( CsToken name, ParameterModifiers modifiers, Expression argumentExpression, CodeLocation location, Reference<ICodePart> parent, CsTokenList tokens, bool generated) { Param.Ignore(name); Param.Ignore(modifiers); Param.AssertNotNull(argumentExpression, "argumentExpression"); Param.AssertNotNull(location, "location"); Param.AssertNotNull(parent, "parent"); Param.Ignore(tokens); Param.Ignore(generated); this.name = name; this.modifiers = modifiers; this.argumentExpression = argumentExpression; this.location = location; this.parent = parent; this.tokens = tokens; this.generated = generated; }
internal TypeParameterConstraintClause(CsTokenList tokens, CsToken type, ICollection<CsToken> constraints) { this.tokens = tokens; this.type = type; this.constraints = constraints; this.tokens.Trim(); }
public IEnumerable <StyleCopCodeIssue> GetCodeIssues( ISourceCode sourceCode, Func <ElementTypeFilter, IEnumerable <IElement> > enumerate, Violation violation, CsElement csElement) { CsToken startToken = null; foreach (var token in from token in csElement.ElementTokens where violation.Line == token.Location.StartPoint.LineNumber && (token.CsTokenType == CsTokenType.OpenCurlyBracket || token.CsTokenType == CsTokenType.CloseCurlyBracket) select token) { if (token.CsTokenType == CsTokenType.OpenCurlyBracket) { startToken = token; continue; } if (token.CsTokenType == CsTokenType.CloseCurlyBracket) { var sourceRange = new SourceRange(startToken.Location.StartPoint.LineNumber, startToken.Location.StartPoint.IndexOnLine + 1, token.Location.EndPoint.LineNumber, token.Location.EndPoint.IndexOnLine + 2); yield return(new StyleCopCodeIssue(CodeIssueType.CodeSmell, sourceRange)); } } }
public IEnumerable <StyleCopCodeIssue> GetCodeIssues( ISourceCode sourceCode, Func <ElementTypeFilter, IEnumerable <IElement> > enumerate, Violation violation, CsElement csElement) { CsToken potentialViolation = null; bool whitespaceFound = false; foreach (var token in this.getTokens(csElement).Flatten().Where(x => x.LineNumber == violation.Line)) { if (potentialViolation != null && token.CsTokenType == CsTokenType.WhiteSpace) { whitespaceFound = true; } else if (potentialViolation != null && whitespaceFound && isBannedFollower(token)) { yield return(new StyleCopCodeIssue(CodeIssueType.CodeSmell, new SourceRange(potentialViolation.Location.StartPoint.LineNumber, potentialViolation.Location.StartPoint.IndexOnLine + 1, potentialViolation.Location.EndPoint.LineNumber, potentialViolation.Location.EndPoint.IndexOnLine + 2))); whitespaceFound = false; potentialViolation = null; } else if (this.reportIssueFor(token, violation)) { potentialViolation = token; whitespaceFound = false; } else { whitespaceFound = false; potentialViolation = null; } } }
/// <summary> /// Determines whether the type of the given token is allowed /// to appear after a closing parenthesis, with no space between /// the parenthesis and the token. /// </summary> /// <param name="token">The token to check.</param> /// <returns>True if it is allowed; false otherwise.</returns> private static bool IsAllowedAfterClosingParenthesis(CsToken token) { Param.AssertNotNull(token, "token"); CsTokenType type = token.CsTokenType; if (type == CsTokenType.CloseParenthesis || type == CsTokenType.OpenParenthesis || type == CsTokenType.CloseSquareBracket || type == CsTokenType.OpenSquareBracket || type == CsTokenType.CloseAttributeBracket || type == CsTokenType.Semicolon || type == CsTokenType.Comma) { return true; } else if (type == CsTokenType.OperatorSymbol) { OperatorSymbol symbol = (OperatorSymbol)token; if (symbol.SymbolType == OperatorType.Decrement || symbol.SymbolType == OperatorType.Increment || symbol.SymbolType == OperatorType.MemberAccess || symbol.SymbolType == OperatorType.Pointer) { return true; } } return false; }
/// <summary> /// Checks length of the lines. /// </summary> /// <param name="rootElement">The root element.</param> /// <param name="token">The document token.</param> /// <param name="maximumLineLength">Maximum allowed length of a line. /// </param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="rootElement"/> or <paramref name="token"/> is <c>null</c>. /// </exception> /// <exception cref="ArgumentOutOfRangeException">Thrown if <paramref /// name="maximumLineLength"/> is not positive.</exception> private void CheckLineLength( DocumentRoot rootElement, CsToken token, int maximumLineLength) { Param.RequireNotNull(rootElement, "rootElement"); Param.RequireNotNull(token, "token"); Param.RequireGreaterThanZero( maximumLineLength, "maximumLineLength"); if (!this.IncludeGenerated && token.Generated) { return; } if (token.CsTokenType == CsTokenType.MultiLineComment) { int startIndex = token.Location.StartPoint.IndexOnLine; Func <string, int, bool> checkDelegate = (s, i) => ((i == 0) ? startIndex : 0) + s.Length > maximumLineLength; this.CheckMultiLineComment( rootElement, token, checkDelegate, Rules.LinesMustNotBeLongerThanNumCharacters, maximumLineLength); } else { Debug.Assert( token.Location.LineSpan == 1, "Token unexpectedly spans multiple lines."); int lineLength; if (token.CsTokenType == CsTokenType.EndOfLine) { // don't count end-of-line character(s) lineLength = token.Location.StartPoint.IndexOnLine - 1; } else { lineLength = token.Location.EndPoint.IndexOnLine; } if (lineLength > maximumLineLength) { this.AddViolation( rootElement, token.Location.EndPoint.LineNumber, Rules.LinesMustNotBeLongerThanNumCharacters, maximumLineLength); } } }
public IEnumerable <StyleCopCodeIssue> GetCodeIssues( ISourceCode sourceCode, Func <ElementTypeFilter, IEnumerable <IElement> > enumerate, Violation violation, CsElement csElement) { bool inTypeOfOrSizeOfOrDefault = false; bool openParenFound = false; bool typeFound = false; CsToken potentialViolation = null; foreach (var token in this.getTokens(csElement).Where(x => x.LineNumber == violation.Line)) { if (token.CsTokenType == CsTokenType.Typeof || token.CsTokenType == CsTokenType.Sizeof || token.CsTokenType == CsTokenType.DefaultValue) { inTypeOfOrSizeOfOrDefault = true; } else if (inTypeOfOrSizeOfOrDefault && token.CsTokenType == CsTokenType.CloseParenthesis) { inTypeOfOrSizeOfOrDefault = false; } else if (!inTypeOfOrSizeOfOrDefault && token.CsTokenType == CsTokenType.OpenParenthesis) { openParenFound = true; } else if (!inTypeOfOrSizeOfOrDefault && openParenFound && potentialViolation == null && token.CsTokenType == CsTokenType.WhiteSpace) { } else if (!inTypeOfOrSizeOfOrDefault && openParenFound && potentialViolation == null && token is TypeToken) { typeFound = true; } else if (!inTypeOfOrSizeOfOrDefault && openParenFound && typeFound && potentialViolation == null && token.CsTokenType == CsTokenType.CloseParenthesis) { potentialViolation = token; } else if (!inTypeOfOrSizeOfOrDefault && potentialViolation != null && token.CsTokenType == CsTokenType.WhiteSpace) { yield return(new StyleCopCodeIssue(CodeIssueType.CodeSmell, new SourceRange(potentialViolation.Location.StartPoint.LineNumber, potentialViolation.Location.StartPoint.IndexOnLine + 1, potentialViolation.Location.EndPoint.LineNumber, potentialViolation.Location.EndPoint.IndexOnLine + 2))); openParenFound = false; typeFound = false; potentialViolation = null; } else { openParenFound = false; typeFound = false; potentialViolation = null; } } }
private void CheckTabsInComment(CsToken comment) { Param.AssertNotNull(comment, "comment"); var lines = comment.Text.Split('\n'); for (int i = 0; i < lines.Length; i++) { if (Regex.IsMatch(lines[i], "^ +")) { this.AddViolation(comment.FindParentElement(), comment.LineNumber + i, "TabsMustBeUsed"); } } }
/// <summary> /// Checks that parenthesis are used correctly within an anonymous method. /// </summary> /// <param name="element">The parent element.</param> /// <param name="expression">The expression to check.</param> private void CheckAnonymousMethodParenthesis(CsElement element, AnonymousMethodExpression expression) { Param.AssertNotNull(element, "element"); Param.AssertNotNull(expression, "expression"); if (expression.Parameters == null || expression.Parameters.Count == 0) { // Check for parenthesis. for (Node <CsToken> tokenNode = expression.Tokens.First; tokenNode != expression.Tokens.Last; tokenNode = tokenNode.Next) { if (tokenNode.Value.CsTokenType == CsTokenType.OpenCurlyBracket) { break; } else if (tokenNode.Value.CsTokenType == CsTokenType.OpenParenthesis) { // If we're inside a MethodInvocation and the method being called is a method on our class // with at least 2 signatures then the parens are required. if (expression.Parent is MethodInvocationExpression) { MethodInvocationExpression parentExpression = expression.Parent as MethodInvocationExpression; CsToken classMemberName = CSharp.Utils.ExtractBaseClassMemberName(parentExpression, parentExpression.Tokens.First); if (classMemberName == null) { break; } ClassBase classBase = CSharp.Utils.GetClassBase(element); Dictionary <string, List <CsElement> > allClassMembers = CSharp.Utils.CollectClassMembers(classBase); var classMembers = CSharp.Utils.FindClassMember(classMemberName.Text, classBase, allClassMembers, false); if (classMembers != null && classMembers.Count > 1) { break; } } this.AddViolation(element, tokenNode.Value.LineNumber, Rules.RemoveDelegateParenthesisWhenPossible); break; } } } }
/// <summary> /// Initializes a new instance of the TypeParameterConstraintClause class. /// </summary> /// <param name="tokens">The list of tokens that form the constraint.</param> /// <param name="type">The type being constrainted.</param> /// <param name="constraints">The list of constraints on the type, if any.</param> /// <param name="parent">The parent of the constraint clause.</param> internal TypeParameterConstraintClause(CsTokenList tokens, CsToken type, ICollection<CsToken> constraints, Reference<ICodePart> parent) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(type, "type"); Param.Ignore(constraints); Param.AssertNotNull(parent, "parent"); this.tokens = tokens; this.type = type; this.constraints = constraints; this.parent = parent; Debug.Assert(this.constraints == null || this.constraints.IsReadOnly, "Constraints must be read-only"); this.tokens.Trim(); Debug.Assert(this.tokens.First != null, "The type parameter constraint claus should not be empty."); }
/// <summary> /// Checks for lines with trailing whitespace. /// </summary> /// <param name="rootElement">The root element.</param> /// <param name="token">The current token.</param> /// <param name="previousToken">The previous token or <c>null</c> if /// there is no previous token.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="rootElement"/> or <paramref name="token"/> is <c>null</c>. /// </exception> private void CheckForLinesWithTrailingWhitespace( DocumentRoot rootElement, CsToken token, CsToken previousToken) { Param.RequireNotNull(rootElement, "rootElement"); Param.RequireNotNull(token, "token"); if (!this.IncludeGenerated && token.Generated) { return; } // simple case: whitespace followed by newline if (previousToken != null && previousToken.CsTokenType == CsTokenType.WhiteSpace && token.CsTokenType == CsTokenType.EndOfLine) { this.AddViolation( rootElement, token.LineNumber, Rules.LinesMustNotEndWithWhitespace); } // check if a token which includes the rest of the line contains // trailing whitespace if (IsEatLineToken(token) && HasTrailingWhitespace(token.Text)) { this.AddViolation( rootElement, token.LineNumber, Rules.LinesMustNotEndWithWhitespace); } // multi-line comment (/* */): split by lines and check each line // for trailing whitespace if (token.CsTokenType == CsTokenType.MultiLineComment) { this.CheckMultiLineComment( rootElement, token, (s, i) => HasTrailingWhitespace(s), Rules.LinesMustNotEndWithWhitespace); } }
/// <summary> /// Determines whether the specified token type occupies the rest of /// the line. /// </summary> /// <param name="token">The token.</param> /// <returns><c>true</c> if the specified token occupies the rest of /// the line; otherwise, <c>false</c>.</returns> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="token"/> is <c>null</c>.</exception> private static bool IsEatLineToken(CsToken token) { Param.RequireNotNull(token, "token"); switch (token.CsTokenType) { case CsTokenType.PreprocessorDirective: case CsTokenType.SingleLineComment: case CsTokenType.XmlHeaderLine: Debug.Assert( token.Location.LineSpan == 1, "Token unexpectedly spans multiple lines."); return(true); default: return(false); } }
/// <summary> /// Checks if the file ends with newline. /// </summary> /// <param name="rootElement">The root element.</param> /// <param name="lastToken">The last document token.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="rootElement"/> or <paramref name="lastToken"/> is /// <c>null</c>.</exception> private void CheckIfFileEndsWithNewline( DocumentRoot rootElement, CsToken lastToken) { Param.RequireNotNull(rootElement, "rootElement"); Param.RequireNotNull(lastToken, "lastToken"); if (!this.IncludeGenerated && lastToken.Generated) { return; } if (lastToken.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation( rootElement, lastToken.LineNumber, Rules.FilesMustEndWithNewline); } }
/// <summary> /// Checks if the file starts with whitespace. /// </summary> /// <param name="rootElement">The root element.</param> /// <param name="firstToken">The first document token.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="rootElement"/> or <paramref name="firstToken"/> is /// <c>null</c>.</exception> private void CheckIfFileStartsWithWhitespace( DocumentRoot rootElement, CsToken firstToken) { Param.RequireNotNull(rootElement, "rootElement"); Param.RequireNotNull(firstToken, "firstToken"); if (!this.IncludeGenerated && firstToken.Generated) { return; } if (firstToken.CsTokenType == CsTokenType.WhiteSpace || firstToken.CsTokenType == CsTokenType.EndOfLine) { this.AddViolation( rootElement, firstToken.LineNumber, Rules.FilesMustNotStartWithWhitespace); } }
/// <summary> /// Iterates through the document tokens. /// </summary> /// <param name="csDocument">The C# document.</param> /// <exception cref="ArgumentNullException">Thrown if <paramref /// name="csDocument"/> is <c>null</c>.</exception> private void IterateDocumentTokens(CsDocument csDocument) { Param.RequireNotNull(csDocument, "csDocument"); int maximumLineLength = this.GetValue <int>( csDocument.Settings, Strings.MaximumLineLength); CsToken previousToken = null; foreach ( CsToken token in new ChildTokenCollection(csDocument.Tokens)) { this.CheckForLinesWithTrailingWhitespace( csDocument.RootElement, token, previousToken); this.CheckLineLength( csDocument.RootElement, token, maximumLineLength); previousToken = token; } }
/// <summary> /// Determines whether a matching local variable is contained in the given variable list. /// </summary> /// <param name="variables">The variable list.</param> /// <param name="word">The variable name to check.</param> /// <param name="item">The token containing the variable name.</param> /// <returns>Returns true if there is a matching local variable.</returns> private static bool ContainsVariable(VariableCollection variables, string word, CsToken item) { Param.AssertNotNull(variables, "variables"); Param.AssertValidString(word, "word"); Param.AssertNotNull(item, "item"); Variable variable = variables[word]; if (variable != null) { // Make sure the variable appears before the word. if (variable.Location.LineNumber < item.LineNumber) { return true; } else if (variable.Location.LineNumber == item.LineNumber) { if (variable.Location.StartPoint.IndexOnLine < item.Location.StartPoint.IndexOnLine) { return true; } } } return false; }
/// <summary> /// Reads the next variable declaration statement from the file and returns it. /// </summary> /// <param name="parentReference">The parent code unit.</param> /// <param name="unsafeCode">Indicates whether the code being parsed resides in an unsafe code block.</param> /// <param name="variables">Returns the list of variables defined in the statement.</param> /// <returns>Returns the statement.</returns> private VariableDeclarationStatement ParseVariableDeclarationStatement( Reference<ICodePart> parentReference, bool unsafeCode, VariableCollection variables) { Param.AssertNotNull(parentReference, "parentReference"); Param.Ignore(unsafeCode); Param.Ignore(variables); bool constant = false; // Get the first symbol and make sure it is an unknown word or a const. Symbol symbol = this.GetNextSymbol(parentReference); CsToken firstToken = null; Node<CsToken> firstTokenNode = null; var statementReference = new Reference<ICodePart>(); if (symbol.SymbolType == SymbolType.Const) { constant = true; firstToken = new CsToken(symbol.Text, CsTokenType.Const, symbol.Location, statementReference, this.symbols.Generated); firstTokenNode = this.tokens.InsertLast(this.GetToken(CsTokenType.Const, SymbolType.Const, statementReference)); symbol = this.GetNextSymbol(statementReference); } if (symbol.SymbolType != SymbolType.Other) { throw this.CreateSyntaxException(); } // Get the expression representing the type. LiteralExpression type = this.GetTypeTokenExpression(statementReference, unsafeCode, true); if (type == null || type.Tokens.First == null) { throw new SyntaxException(this.document.SourceCode, firstToken.LineNumber); } if (firstTokenNode == null) { firstTokenNode = type.Tokens.First; } // Get the rest of the declaration. VariableDeclarationExpression expression = this.GetVariableDeclarationExpression(type, ExpressionPrecedence.None, unsafeCode); // Get the closing semicolon. this.tokens.Add(this.GetToken(CsTokenType.Semicolon, SymbolType.Semicolon, statementReference)); // Add each of the variables defined in this statement to the variable list being returned. if (variables != null) { VariableModifiers modifiers = constant ? VariableModifiers.Const : VariableModifiers.None; foreach (VariableDeclaratorExpression declarator in expression.Declarators) { Variable variable = new Variable( expression.Type, declarator.Identifier.Token.Text, modifiers, CodeLocation.Join(expression.Type.Location, declarator.Identifier.Token.Location), statementReference, expression.Tokens.First.Value.Generated || declarator.Identifier.Token.Generated); // There might already be a variable in this scope with the same name. This can happen // in valid situation when there are ifdef's surrounding portions of the code. // Just accept the first variable and ignore others. if (!variables.Contains(declarator.Identifier.Token.Text)) { variables.Add(variable); } } } // Create the token list for the statement. CsTokenList partialTokens = new CsTokenList(this.tokens, firstTokenNode, this.tokens.Last); var statement = new VariableDeclarationStatement(partialTokens, constant, expression); statementReference.Target = statement; return statement; }
/// <summary> /// Determines whether the given word is the name of a local variable. /// </summary> /// <param name="word">The name to check.</param> /// <param name="item">The token containing the word.</param> /// <param name="parent">The code unit that the word appears in.</param> /// <returns>True if the word is the name of a local variable, false if not.</returns> private static bool IsLocalMember(string word, CsToken item, ICodeUnit parent) { Param.AssertValidString(word, "word"); Param.AssertNotNull(item, "item"); Param.AssertNotNull(parent, "parent"); while (parent != null) { // Check to see if the name matches a local variable. if (ReadabilityRules.ContainsVariable(parent.Variables, word, item)) { return true; } // If the parent is an element, do not look any higher up the stack than this. if (parent.CodePartType == CodePartType.Element) { break; } // Check to see whether the variable is defined within the parent. parent = parent.Parent as ICodeUnit; } return false; }
private MasterList<CsToken> GetGenericArgumentList(bool unsafeCode, CsToken name, int startIndex, out int endIndex) { endIndex = -1; MasterList<CsToken> list = null; int count = startIndex; while (true) { Symbol symbol = this.symbols.Peek(count); if ((symbol == null) || (((symbol.SymbolType != SymbolType.WhiteSpace) && (symbol.SymbolType != SymbolType.EndOfLine)) && (((symbol.SymbolType != SymbolType.SingleLineComment) && (symbol.SymbolType != SymbolType.MultiLineComment)) && (symbol.SymbolType != SymbolType.PreprocessorDirective)))) { break; } count++; } Symbol symbol2 = this.symbols.Peek(count); if ((symbol2 == null) || (symbol2.SymbolType != SymbolType.LessThan)) { return list; } list = new MasterList<CsToken>(); if (name != null) { list.Add(name); } Microsoft.StyleCop.Node<CsToken> node = null; for (int i = startIndex; i <= count; i++) { symbol2 = this.symbols.Peek(i); if (symbol2.SymbolType == SymbolType.LessThan) { if (node != null) { return null; } Bracket item = new Bracket(symbol2.Text, CsTokenType.OpenGenericBracket, symbol2.Location, this.symbols.Generated); node = list.InsertLast(item); } else { list.Add(this.ConvertSymbol(symbol2, TokenTypeFromSymbolType(symbol2.SymbolType))); } } Label_00F4: symbol2 = this.symbols.Peek(++count); if (symbol2 == null) { throw new SyntaxException(this.document.SourceCode, name.LineNumber); } if (symbol2.SymbolType == SymbolType.GreaterThan) { if (node == null) { return null; } Bracket bracket2 = new Bracket(symbol2.Text, CsTokenType.CloseGenericBracket, symbol2.Location, this.symbols.Generated); Microsoft.StyleCop.Node<CsToken> node2 = list.InsertLast(bracket2); ((Bracket) node.Value).MatchingBracketNode = node2; bracket2.MatchingBracketNode = node; endIndex = count; return list; } if (symbol2.SymbolType == SymbolType.Other) { int num3 = 0; CsToken token = this.GetTypeTokenAux(unsafeCode, true, false, count, out num3); if (token == null) { throw new SyntaxException(this.document.SourceCode, symbol2.LineNumber); } count = num3; list.Add(token); goto Label_00F4; } if (((symbol2.SymbolType == SymbolType.WhiteSpace) || (symbol2.SymbolType == SymbolType.EndOfLine)) || (((symbol2.SymbolType == SymbolType.SingleLineComment) || (symbol2.SymbolType == SymbolType.MultiLineComment)) || (symbol2.SymbolType == SymbolType.PreprocessorDirective))) { list.Add(this.ConvertSymbol(symbol2, TokenTypeFromSymbolType(symbol2.SymbolType))); goto Label_00F4; } if (symbol2.SymbolType == SymbolType.Comma) { list.Add(this.ConvertSymbol(symbol2, CsTokenType.Comma)); goto Label_00F4; } return null; }
/// <summary> /// Processes a newline character found while checking line spacing rules. /// </summary> /// <param name="precedingTokenNode">The preceding token before the newline.</param> /// <param name="token">The newline token.</param> /// <param name="count">The current newline count.</param> private void CheckLineSpacingNewline(Node<CsToken> precedingTokenNode, CsToken token, int count) { Param.Ignore(precedingTokenNode); Param.AssertNotNull(token, "token"); Param.AssertGreaterThanOrEqualToZero(count, "count"); // If we've seen two end-of-line characters in a row, then there is a blank // line in the code. if (count == 2) { // Check whether we've seen at least one token before this blank line. if (precedingTokenNode != null && !precedingTokenNode.Value.Generated) { if (precedingTokenNode.Value.CsTokenType == CsTokenType.OpenCurlyBracket) { // The blank line comes just after an opening curly bracket. this.AddViolation( precedingTokenNode.Value.FindParentElement(), precedingTokenNode.Value.LineNumber, Rules.OpeningCurlyBracketsMustNotBeFollowedByBlankLine); } else if (precedingTokenNode.Value.CsTokenType == CsTokenType.XmlHeader) { // The blank line comes just after an Xml header. this.AddViolation( precedingTokenNode.Value.FindParentElement(), precedingTokenNode.Value.LineNumber, Rules.ElementDocumentationHeadersMustNotBeFollowedByBlankLine); } } } else if (count == 3 && !token.Generated) { // There are two or more blank lines in a row. this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.CodeMustNotContainMultipleBlankLinesInARow); } }
private CsToken ConvertOperatorOverloadSymbol(Reference<ICodePart> parentReference) { Param.AssertNotNull(parentReference, "parentReference"); CsToken token = null; Symbol symbol = this.symbols.Peek(1); if (symbol != null) { if (symbol.SymbolType == SymbolType.GreaterThan) { Symbol next = this.symbols.Peek(2); if (next != null && next.SymbolType == SymbolType.GreaterThan) { // This could be a right-shift-equals. next = this.symbols.Peek(3); if (next != null && next.SymbolType == SymbolType.Equals) { // This is a right-shift-equals. this.symbols.Combine(1, 3, ">>=", SymbolType.RightShiftEquals); } else { // This is a right-shift. this.symbols.Combine(1, 2, ">>", SymbolType.RightShift); } } symbol = this.symbols.Peek(1); token = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, parentReference, this.symbols.Generated); this.symbols.Advance(); } else { token = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, parentReference, this.symbols.Generated); this.symbols.Advance(); } } return token; }
private VariableDeclarationStatement ParseVariableDeclarationStatement(bool unsafeCode, VariableCollection variables) { bool constant = false; Symbol nextSymbol = this.GetNextSymbol(); CsToken token = null; Microsoft.StyleCop.Node<CsToken> firstItemNode = null; if (nextSymbol.SymbolType == SymbolType.Const) { constant = true; token = new CsToken(nextSymbol.Text, CsTokenType.Const, nextSymbol.Location, this.symbols.Generated); firstItemNode = this.tokens.InsertLast(this.GetToken(CsTokenType.Const, SymbolType.Const)); nextSymbol = this.GetNextSymbol(); } if (nextSymbol.SymbolType != SymbolType.Other) { throw this.CreateSyntaxException(); } LiteralExpression typeTokenExpression = this.GetTypeTokenExpression(unsafeCode, true); if ((typeTokenExpression == null) || (typeTokenExpression.Tokens.First == null)) { throw new SyntaxException(this.document.SourceCode, token.LineNumber); } if (firstItemNode == null) { firstItemNode = typeTokenExpression.Tokens.First; } VariableDeclarationExpression expression = this.GetVariableDeclarationExpression(typeTokenExpression, ExpressionPrecedence.None, unsafeCode); this.tokens.Add(this.GetToken(CsTokenType.Semicolon, SymbolType.Semicolon)); if (variables != null) { VariableModifiers modifiers = constant ? VariableModifiers.Const : VariableModifiers.None; foreach (VariableDeclaratorExpression expression3 in expression.Declarators) { Variable variable = new Variable(expression.Type, expression3.Identifier.Token.Text, modifiers, expression3.Tokens.First.Value.Location.StartPoint, expression.Tokens.First.Value.Generated || expression3.Identifier.Token.Generated); if (!variables.Contains(expression3.Identifier.Token.Text)) { variables.Add(variable); } } } return new VariableDeclarationStatement(new CsTokenList(this.tokens, firstItemNode, this.tokens.Last), constant, expression); }
/// <summary> /// Checks the token that follows or precedes a curly bracket in a blocked statement to verify /// that there is no comment or region embedded within the statement. /// </summary> /// <param name="element">The element containing the statement.</param> /// <param name="previousOrNextToken">The previous or next token.</param> private void CheckTokenPrecedingOrFollowingCurlyBracket(CsElement element, CsToken previousOrNextToken) { Param.AssertNotNull(element, "element"); Param.AssertNotNull(previousOrNextToken, "previousOrNextToken"); if (previousOrNextToken.CsTokenType == CsTokenType.MultiLineComment || previousOrNextToken.CsTokenType == CsTokenType.SingleLineComment || previousOrNextToken.CsTokenType == CsTokenType.XmlHeader || previousOrNextToken.CsTokenType == CsTokenType.XmlHeaderLine) { this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedComments); } else if (previousOrNextToken.CsTokenType == CsTokenType.PreprocessorDirective && previousOrNextToken is Region) { this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedRegions); } }
private Variable GetVariable(bool unsafeCode, bool allowTypelessVariable, bool onlyTypelessVariable) { this.AdvanceToNextCodeSymbol(); TypeToken item = this.GetTypeToken(unsafeCode, true, false); if (item == null) { throw this.CreateSyntaxException(); } if (onlyTypelessVariable) { this.tokens.Add(item.ChildTokens.First.Value); return new Variable(null, item.Text, VariableModifiers.None, item.Location.StartPoint, item.Generated); } this.AdvanceToNextCodeSymbol(); Symbol symbol = this.symbols.Peek(1); if ((symbol == null) || (symbol.SymbolType != SymbolType.Other)) { if (!allowTypelessVariable) { throw this.CreateSyntaxException(); } this.tokens.Add(item.ChildTokens.First.Value); return new Variable(null, item.Text, VariableModifiers.None, item.Location.StartPoint, item.Generated); } this.tokens.Add(item); CsToken token2 = new CsToken(symbol.Text, CsTokenType.Other, CsTokenClass.Token, symbol.Location, this.symbols.Generated); this.tokens.Add(token2); this.symbols.Advance(); return new Variable(item, token2.Text, VariableModifiers.None, item.Location.StartPoint, item.Generated || token2.Generated); }
private Expression GetNextConditionalPreprocessorExpression(SourceCode sourceCode, ExpressionPrecedence previousPrecedence) { this.AdvanceToNextConditionalDirectiveCodeSymbol(); Expression leftSide = null; Symbol symbol = this.symbols.Peek(1); if (symbol != null) { CsToken token; Microsoft.StyleCop.Node<CsToken> node; SymbolType symbolType = symbol.SymbolType; if (symbolType <= SymbolType.Not) { switch (symbolType) { case SymbolType.OpenParenthesis: leftSide = this.GetConditionalPreprocessorParenthesizedExpression(sourceCode); goto Label_012D; case SymbolType.Not: leftSide = this.GetConditionalPreprocessorNotExpression(sourceCode); goto Label_012D; } goto Label_010E; } switch (symbolType) { case SymbolType.False: this.symbols.Advance(); token = new CsToken(symbol.Text, CsTokenType.False, symbol.Location, this.symbols.Generated); node = this.tokens.InsertLast(token); leftSide = new LiteralExpression(new CsTokenList(this.tokens, node, node), node); goto Label_012D; case SymbolType.True: this.symbols.Advance(); token = new CsToken(symbol.Text, CsTokenType.True, symbol.Location, this.symbols.Generated); node = this.tokens.InsertLast(token); leftSide = new LiteralExpression(new CsTokenList(this.tokens, node, node), node); goto Label_012D; } if (symbolType != SymbolType.Other) { goto Label_010E; } leftSide = this.GetConditionalPreprocessorConstantExpression(); } goto Label_012D; Label_010E: throw new SyntaxException(sourceCode, symbol.LineNumber); Label_012D: while (leftSide != null) { Expression expression2 = this.GetConditionalPreprocessorExpressionExtension(sourceCode, leftSide, previousPrecedence); if (expression2 == null) { return leftSide; } leftSide = expression2; } return leftSide; }
private GenericType GetGenericTokenAux(bool unsafeCode, int startIndex, out int lastIndex) { lastIndex = -1; Symbol symbol = this.symbols.Peek(startIndex); GenericType type = null; CsToken name = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, this.symbols.Generated); MasterList<CsToken> childTokens = this.GetGenericArgumentList(unsafeCode, name, startIndex + 1, out lastIndex); if (childTokens != null) { type = new GenericType(childTokens, CodeLocation.Join<CsToken>(symbol.Location, childTokens.Last), this.symbols.Generated); } return type; }
/// <summary> /// Determines whether the given xml header is empty. /// </summary> /// <param name="token">The xml header line token.</param> /// <returns>Returns true if the header is empty.</returns> private static bool IsXmlHeaderLineEmpty(CsToken token) { Param.AssertNotNull(token, "token"); Debug.Assert(token.CsTokenType == CsTokenType.XmlHeaderLine, "The token should be an xml header line"); int slashCount = 0; for (int i = 0; i < token.Text.Length; ++i) { char character = token.Text[i]; if (slashCount < 3) { if (character == '/') { ++slashCount; } else { return false; } } else { if (!char.IsWhiteSpace(character)) { return false; } } } return true; }
public void TestTokens() { UserToken token = new CsToken(); Assert.That(TestHelpers.TokenId(token), Is.SameAs(token)); }
private CsToken ConvertOperatorOverloadSymbol() { CsToken token = null; Symbol symbol = this.symbols.Peek(1); if (symbol != null) { if (symbol.SymbolType == SymbolType.GreaterThan) { Symbol symbol2 = this.symbols.Peek(2); if ((symbol2 != null) && (symbol2.SymbolType == SymbolType.GreaterThan)) { symbol2 = this.symbols.Peek(3); if ((symbol2 != null) && (symbol2.SymbolType == SymbolType.Equals)) { this.symbols.Combine(1, 3, ">>=", SymbolType.RightShiftEquals); } else { this.symbols.Combine(1, 2, ">>", SymbolType.RightShift); } } symbol = this.symbols.Peek(1); token = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, this.symbols.Generated); this.symbols.Advance(); return token; } token = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, this.symbols.Generated); this.symbols.Advance(); } return token; }
/// <summary> /// Reads a generic token from the document. /// </summary> /// <param name="genericTokenReference">A reference to the generic token.</param> /// <param name="unsafeCode">Indicates whether the code is marked as unsafe.</param> /// <param name="startIndex">The first index of the generic.</param> /// <param name="lastIndex">Returns the last index of the generic.</param> /// <returns>Returns the generic token, or null if the symbol manager is not sitting on a generic.</returns> /// <remarks>This should only be called by GetGenericToken.</remarks> private GenericType GetGenericTokenAux(Reference<ICodePart> genericTokenReference, bool unsafeCode, int startIndex, out int lastIndex) { Param.AssertNotNull(genericTokenReference, "genericTokenReference"); Param.Ignore(unsafeCode); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); lastIndex = -1; // Get the first symbol. This should be an unknown word type. Symbol firstSymbol = this.symbols.Peek(startIndex); Debug.Assert(firstSymbol != null && firstSymbol.SymbolType == SymbolType.Other, "Expected a text symbol"); // This will hold the generic type if we create one. GenericType generic = null; // Create a token for the name. CsToken name = new CsToken(firstSymbol.Text, CsTokenType.Other, firstSymbol.Location, genericTokenReference, this.symbols.Generated); // Get the argument list. This will return null if this is not a generic. MasterList<CsToken> genericArgumentTokens = this.GetGenericArgumentList( genericTokenReference, unsafeCode, name, startIndex + 1, out lastIndex); if (genericArgumentTokens != null) { generic = new GenericType( genericArgumentTokens, CsToken.JoinLocations(firstSymbol.Location, genericArgumentTokens.Last), genericTokenReference, this.symbols.Generated); var genericTypeReference = new Reference<ICodePart>(generic); foreach (CsToken token in genericArgumentTokens) { token.ParentRef = genericTypeReference; } } return generic; }
private void CheckLineSpacingNonWhitespace( CsDocument document, Node<CsToken> precedingTokenNode, CsToken token, bool fileHeader, bool firstTokenOnLine, int count) { Param.AssertNotNull(document, "document"); Param.Ignore(precedingTokenNode); Param.AssertNotNull(token, "token"); Param.Ignore(fileHeader); Param.Ignore(firstTokenOnLine); Param.AssertGreaterThanOrEqualToZero(count, "count"); // Skip generated tokens. if (!token.Generated) { // If there is at least one blank line in front of the current token. if (count > 1) { if (token.CsTokenType == CsTokenType.CloseCurlyBracket) { // The blank line is just before a closing curly bracket. this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.ClosingCurlyBracketsMustNotBePrecededByBlankLine); } else if (token.CsTokenType == CsTokenType.OpenCurlyBracket) { // The blank line is just before an opening curly bracket. this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.OpeningCurlyBracketsMustNotBePrecededByBlankLine); } else if (token.CsTokenType == CsTokenType.Else || token.CsTokenType == CsTokenType.Catch || token.CsTokenType == CsTokenType.Finally) { // The blank line is just before an else, catch, or finally statement. this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.ChainedStatementBlocksMustNotBePrecededByBlankLine); } else if (token.CsTokenType == CsTokenType.WhileDo) { // The blank line is just before the while keyword from a do/while statement. this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.WhileDoFooterMustNotBePrecededByBlankLine); } // Check if there is a blank line after a single-line comment. The exceptions // are if this is the file header, or if the line after the blank line contains // another comment or an Xml header. This is ok if the comment is not // the first item on its line. if (!fileHeader && precedingTokenNode != null && precedingTokenNode.Value.CsTokenType == CsTokenType.SingleLineComment && token.CsTokenType != CsTokenType.SingleLineComment && token.CsTokenType != CsTokenType.MultiLineComment && token.CsTokenType != CsTokenType.XmlHeader) { // Now check whether the comment is the first item on its line. If the comment // is not the first item on the line, then this is not a violation. bool tokenSeen = false; if (precedingTokenNode != null) { foreach (CsToken lineToken in document.Tokens.ReverseIterator(precedingTokenNode.Previous)) { if (lineToken.CsTokenType == CsTokenType.EndOfLine) { break; } else if (lineToken.CsTokenType != CsTokenType.WhiteSpace) { tokenSeen = true; break; } } } // Now make sure this comment does not begin with '////'. If so, this is the signal // that StyleCop should ignore this particular error. This is used when the // developer is commenting out a line of code. In this case it is not a true comment. string trimmedComment = precedingTokenNode.Value.Text.Trim(); if (!tokenSeen && !trimmedComment.StartsWith(@"////", StringComparison.Ordinal)) { // The blank line appears after a file header, we want to allow this. if (!IsCommentInFileHeader(precedingTokenNode)) { this.AddViolation( precedingTokenNode.Value.FindParentElement(), precedingTokenNode.Value.LineNumber, Rules.SingleLineCommentsMustNotBeFollowedByBlankLine); } } } } else if (count == 1) { // There is one line return in front of the current token, which means // the line in front of the current token is not blank. Check if the current // token is an Xml header. if (token.CsTokenType == CsTokenType.XmlHeader) { // This is a violation unless the previous line contains another // Xml header, an opening curly bracket, or a preprocessor directive. if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType != CsTokenType.XmlHeader && precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket && precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective) { this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.ElementDocumentationHeaderMustBePrecededByBlankLine); } } else if (token.CsTokenType == CsTokenType.SingleLineComment) { // The current line contains a single line comment and the previous line // is not blank. This is a violation unless the previous line contains // another single line comment, an opening curly bracket, a preprocessor // directive, or if the last character on the previous line is a colon, // which can only mean that it is a label or a case statement, in which // case this is ok. if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType != CsTokenType.SingleLineComment && precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket && precedingTokenNode.Value.CsTokenType != CsTokenType.LabelColon && precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective) { // Now make sure this comment does not begin with '////'. If so, this is the signal // that StyleCop should ignore this particular error. This is used when the // developer is commenting out a line of code. In this case it is not a true comment. string trimmedComment = token.Text.Trim(); if (!trimmedComment.StartsWith(@"////", StringComparison.Ordinal)) { this.AddViolation( token.FindParentElement(), token.LineNumber, Rules.SingleLineCommentMustBePrecededByBlankLine); } } } else if (precedingTokenNode != null && precedingTokenNode.Value.CsTokenType == CsTokenType.CloseCurlyBracket) { // Closing curly brackets cannot be followed directly by another bracket keyword. Bracket closingCurlyBracket = precedingTokenNode.Value as Bracket; if (closingCurlyBracket.MatchingBracket != null && closingCurlyBracket.MatchingBracket.LineNumber != closingCurlyBracket.LineNumber && firstTokenOnLine && token.CsTokenType != CsTokenType.CloseCurlyBracket && token.CsTokenType != CsTokenType.Finally && token.CsTokenType != CsTokenType.Catch && token.CsTokenType != CsTokenType.WhileDo && token.CsTokenType != CsTokenType.Else && token.CsTokenType != CsTokenType.PreprocessorDirective) { this.AddViolation( closingCurlyBracket.FindParentElement(), closingCurlyBracket.LineNumber, Rules.ClosingCurlyBracketMustBeFollowedByBlankLine); } } } } }
private void CheckTabsInComment(CsElement element, CsToken comment) { int num = 0; for (int i = 0; i < comment.Text.Length; i++) { if (comment.Text[i] == '\t') { base.AddViolation(element, comment.LineNumber + num, Microsoft.StyleCop.CSharp.Rules.TabsMustNotBeUsed, new object[0]); } else if (comment.Text[i] == '\n') { num++; } } }
/// <summary> /// Checks for tabs in the given comment. /// </summary> /// <param name="element">The element containin the comment.</param> /// <param name="comment">The comment token.</param> private void CheckTabsInComment(CsElement element, CsToken comment) { Param.AssertNotNull(element, "element"); Param.AssertNotNull(comment, "comment"); int lineEnds = 0; for (int i = 0; i < comment.Text.Length; ++i) { if (comment.Text[i] == '\t') { this.AddViolation(element, comment.LineNumber + lineEnds, Rules.TabsMustNotBeUsed); } else if (comment.Text[i] == '\n') { ++lineEnds; } } }
/// <summary> /// Reads the next expression from a conditional preprocessor directive. /// </summary> /// <param name="sourceCode">The source code.</param> /// <param name="previousPrecedence">The precedence of the expression just before this one.</param> /// <returns>Returns the expression.</returns> private Expression GetNextConditionalPreprocessorExpression(SourceCode sourceCode, ExpressionPrecedence previousPrecedence) { Param.AssertNotNull(sourceCode, "sourceCode"); Param.Ignore(previousPrecedence); var parentReference = new Reference<ICodePart>(); // Move past comments and whitepace. this.AdvanceToNextConditionalDirectiveCodeSymbol(parentReference); // Saves the next expression. Expression expression = null; // Get the next symbol. Symbol symbol = this.symbols.Peek(1); if (symbol != null) { switch (symbol.SymbolType) { case SymbolType.Other: expression = this.GetConditionalPreprocessorConstantExpression(); break; case SymbolType.Not: expression = this.GetConditionalPreprocessorNotExpression(sourceCode, parentReference); break; case SymbolType.OpenParenthesis: expression = this.GetConditionalPreprocessorParenthesizedExpression(sourceCode, parentReference); break; case SymbolType.False: this.symbols.Advance(); var falseExpressionReference = new Reference<ICodePart>(); CsToken token = new CsToken(symbol.Text, CsTokenType.False, symbol.Location, falseExpressionReference, this.symbols.Generated); Node<CsToken> tokenNode = this.tokens.InsertLast(token); expression = new LiteralExpression(new CsTokenList(this.tokens, tokenNode, tokenNode), tokenNode); falseExpressionReference.Target = expression; break; case SymbolType.True: this.symbols.Advance(); var trueExpressionReference = new Reference<ICodePart>(); token = new CsToken(symbol.Text, CsTokenType.True, symbol.Location, trueExpressionReference, this.symbols.Generated); tokenNode = this.tokens.InsertLast(token); expression = new LiteralExpression(new CsTokenList(this.tokens, tokenNode, tokenNode), tokenNode); trueExpressionReference.Target = expression; break; default: throw new SyntaxException(sourceCode, symbol.LineNumber); } } // Gather up all extensions to this expression. while (expression != null) { var expressionReference = new Reference<ICodePart>(expression); // Check if there is an extension to this expression. Expression extension = this.GetConditionalPreprocessorExpressionExtension( sourceCode, expressionReference, expression, previousPrecedence); if (extension != null) { // The larger expression is what we want to return here. expression = extension; } else { // There are no more extensions. break; } } // Return the expression. return expression; }
private void CheckLineSpacingNewline(CsDocument document, Microsoft.StyleCop.Node<CsToken> precedingTokenNode, CsToken token, int count) { if (count == 2) { if ((precedingTokenNode != null) && !precedingTokenNode.Value.Generated) { if (precedingTokenNode.Value.CsTokenType == CsTokenType.OpenCurlyBracket) { base.AddViolation(document.RootElement, precedingTokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningCurlyBracketsMustNotBeFollowedByBlankLine, new object[0]); } else if (precedingTokenNode.Value.CsTokenType == CsTokenType.XmlHeader) { base.AddViolation(document.RootElement, precedingTokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.ElementDocumentationHeadersMustNotBeFollowedByBlankLine, new object[0]); } } } else if ((count == 3) && !token.Generated) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.CodeMustNotContainMultipleBlankLinesInARow, new object[0]); } }
private LiteralExpression GetConditionalPreprocessorConstantExpression() { Symbol symbol = this.symbols.Peek(1); this.symbols.Advance(); CsToken item = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, this.symbols.Generated); return new LiteralExpression(this.tokens, this.tokens.InsertLast(item)); }
private MasterList<CsToken> GetGenericArgumentList( Reference<ICodePart> genericTypeReference, bool unsafeCode, CsToken name, int startIndex, out int endIndex) { Param.AssertNotNull(genericTypeReference, "genericTypeReference"); Param.Ignore(unsafeCode); Param.Ignore(name); Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex"); endIndex = -1; MasterList<CsToken> genericArgumentListTokens = null; // Move past whitespace and comments. int index = startIndex; while (true) { Symbol next = this.symbols.Peek(index); if (next == null || (next.SymbolType != SymbolType.WhiteSpace && next.SymbolType != SymbolType.EndOfLine && next.SymbolType != SymbolType.SingleLineComment && next.SymbolType != SymbolType.MultiLineComment && next.SymbolType != SymbolType.PreprocessorDirective)) { break; } ++index; } // The next symbol should be an opening bracket, if this is a generic. Symbol symbol = this.symbols.Peek(index); if (symbol != null && symbol.SymbolType == SymbolType.LessThan) { // This might be a generic. Assume that it is and start creating tokens. genericArgumentListTokens = new MasterList<CsToken>(); // Add the name if one was provided. if (name != null) { genericArgumentListTokens.Add(name); } Node<CsToken> openingGenericBracketNode = null; // Add everything up to the opening bracket into the token list. for (int i = startIndex; i <= index; ++i) { symbol = this.symbols.Peek(i); Debug.Assert(symbol != null, "The next symbol should not be null"); if (symbol.SymbolType == SymbolType.LessThan) { if (openingGenericBracketNode != null) { // This is not a generic statement. return null; } Bracket openingGenericBracket = new Bracket( symbol.Text, CsTokenType.OpenGenericBracket, symbol.Location, genericTypeReference, this.symbols.Generated); openingGenericBracketNode = genericArgumentListTokens.InsertLast(openingGenericBracket); } else { genericArgumentListTokens.Add(this.ConvertSymbol(symbol, TokenTypeFromSymbolType(symbol.SymbolType), genericTypeReference)); } } // Loop through the rest of the symbols. while (true) { symbol = this.symbols.Peek(++index); if (symbol == null) { // The code ran out before we found the end of the generic. throw new SyntaxException(this.document.SourceCode, name.LineNumber); } else if (symbol.SymbolType == SymbolType.GreaterThan) { if (openingGenericBracketNode == null) { // This is not a generic statement. return null; } // This is the end of the generic statement. Add the closing bracket to the token list. Bracket closingGenericBracket = new Bracket( symbol.Text, CsTokenType.CloseGenericBracket, symbol.Location, genericTypeReference, this.symbols.Generated); Node<CsToken> closingGenericBracketNode = genericArgumentListTokens.InsertLast(closingGenericBracket); ((Bracket)openingGenericBracketNode.Value).MatchingBracketNode = closingGenericBracketNode; closingGenericBracket.MatchingBracketNode = openingGenericBracketNode; endIndex = index; break; } else if (symbol.SymbolType == SymbolType.Out || symbol.SymbolType == SymbolType.In) { // Get the in or out keyword. genericArgumentListTokens.Add(this.ConvertSymbol( symbol, symbol.SymbolType == SymbolType.In ? CsTokenType.In : CsTokenType.Out, genericTypeReference)); } else if (symbol.SymbolType == SymbolType.Other) { int lastIndex = 0; var wordReference = new Reference<ICodePart>(); CsToken word = this.GetTypeTokenAux(wordReference, genericTypeReference, unsafeCode, true, false, index, out lastIndex); if (word == null) { throw new SyntaxException(this.document.SourceCode, symbol.LineNumber); } // Advance the index to the end of the token. index = lastIndex; // Add the token. genericArgumentListTokens.Add(word); } else if (symbol.SymbolType == SymbolType.WhiteSpace || symbol.SymbolType == SymbolType.EndOfLine || symbol.SymbolType == SymbolType.SingleLineComment || symbol.SymbolType == SymbolType.MultiLineComment || symbol.SymbolType == SymbolType.PreprocessorDirective) { // Add these to the token list. genericArgumentListTokens.Add(this.ConvertSymbol(symbol, TokenTypeFromSymbolType(symbol.SymbolType), genericTypeReference)); } else if (symbol.SymbolType == SymbolType.Comma) { genericArgumentListTokens.Add(this.ConvertSymbol(symbol, CsTokenType.Comma, genericTypeReference)); } else if (symbol.SymbolType == SymbolType.OpenSquareBracket) { // An attribute on the generic type. genericArgumentListTokens.Add(this.GetAttribute(genericTypeReference, unsafeCode)); } else { // Any other symbol signifies that this is not a generic statement. genericArgumentListTokens = null; break; } } } return genericArgumentListTokens; }
private void CheckLineSpacingNonWhitespace(CsDocument document, Microsoft.StyleCop.Node<CsToken> precedingTokenNode, CsToken token, bool fileHeader, bool firstTokenOnLine, int count) { if (!token.Generated) { if (count <= 1) { if (count == 1) { if (token.CsTokenType == CsTokenType.XmlHeader) { if (((precedingTokenNode != null) && (precedingTokenNode.Value.CsTokenType != CsTokenType.XmlHeader)) && ((precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket) && (precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective))) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.ElementDocumentationHeaderMustBePrecededByBlankLine, new object[0]); } } else if (token.CsTokenType == CsTokenType.SingleLineComment) { if ((((precedingTokenNode != null) && (precedingTokenNode.Value.CsTokenType != CsTokenType.SingleLineComment)) && ((precedingTokenNode.Value.CsTokenType != CsTokenType.OpenCurlyBracket) && (precedingTokenNode.Value.CsTokenType != CsTokenType.LabelColon))) && ((precedingTokenNode.Value.CsTokenType != CsTokenType.PreprocessorDirective) && !token.Text.Trim().StartsWith("////", StringComparison.Ordinal))) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.SingleLineCommentMustBePrecededByBlankLine, new object[0]); } } else if ((precedingTokenNode != null) && (precedingTokenNode.Value.CsTokenType == CsTokenType.CloseCurlyBracket)) { Bracket bracket = precedingTokenNode.Value as Bracket; if (((((bracket.MatchingBracket != null) && (bracket.MatchingBracket.LineNumber != bracket.LineNumber)) && (firstTokenOnLine && (token.CsTokenType != CsTokenType.CloseCurlyBracket))) && (((token.CsTokenType != CsTokenType.Finally) && (token.CsTokenType != CsTokenType.Catch)) && ((token.CsTokenType != CsTokenType.WhileDo) && (token.CsTokenType != CsTokenType.Else)))) && (token.CsTokenType != CsTokenType.PreprocessorDirective)) { base.AddViolation(document.RootElement, bracket.LineNumber, Microsoft.StyleCop.CSharp.Rules.ClosingCurlyBracketMustBeFollowedByBlankLine, new object[0]); } } } } else { if (token.CsTokenType == CsTokenType.CloseCurlyBracket) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.ClosingCurlyBracketsMustNotBePrecededByBlankLine, new object[0]); } else if (token.CsTokenType == CsTokenType.OpenCurlyBracket) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningCurlyBracketsMustNotBePrecededByBlankLine, new object[0]); } else if (((token.CsTokenType == CsTokenType.Else) || (token.CsTokenType == CsTokenType.Catch)) || (token.CsTokenType == CsTokenType.Finally)) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.ChainedStatementBlocksMustNotBePrecededByBlankLine, new object[0]); } else if (token.CsTokenType == CsTokenType.WhileDo) { base.AddViolation(document.RootElement, token.LineNumber, Microsoft.StyleCop.CSharp.Rules.WhileDoFooterMustNotBePrecededByBlankLine, new object[0]); } if (((!fileHeader && (precedingTokenNode != null)) && ((precedingTokenNode.Value.CsTokenType == CsTokenType.SingleLineComment) && (token.CsTokenType != CsTokenType.SingleLineComment))) && ((token.CsTokenType != CsTokenType.MultiLineComment) && (token.CsTokenType != CsTokenType.XmlHeader))) { bool flag = false; if (precedingTokenNode != null) { foreach (CsToken token2 in document.Tokens.ReverseIterator(precedingTokenNode.Previous)) { if (token2.CsTokenType == CsTokenType.EndOfLine) { break; } if (token2.CsTokenType != CsTokenType.WhiteSpace) { flag = true; break; } } } string str = precedingTokenNode.Value.Text.Trim(); if ((!flag && !str.StartsWith("////", StringComparison.Ordinal)) && !IsCommentInFileHeader(precedingTokenNode)) { base.AddViolation(document.RootElement, precedingTokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.SingleLineCommentsMustNotBeFollowedByBlankLine, new object[0]); } } } } }
/// <summary> /// Gets the next variable. /// </summary> /// <param name="parentReference">The parent code unit.</param> /// <param name="unsafeCode">Indicates whether the code is within an unsafe block.</param> /// <param name="allowTypelessVariable">Indicates whether to allow a variable with no type defined.</param> /// <param name="onlyTypelessVariable">Indicates whether to only get a typeless variable.</param> /// <returns>Returns the variable.</returns> private Variable GetVariable(Reference<ICodePart> parentReference, bool unsafeCode, bool allowTypelessVariable, bool onlyTypelessVariable) { Param.AssertNotNull(parentReference, "parentReference"); Param.Ignore(unsafeCode); Param.Ignore(allowTypelessVariable); Param.Ignore(onlyTypelessVariable); this.AdvanceToNextCodeSymbol(parentReference); var variableReference = new Reference<ICodePart>(); // Get the type token representing either the type or the identifier. TypeToken type = this.GetTypeToken(variableReference, unsafeCode, true, false); if (type == null) { throw this.CreateSyntaxException(); } Variable variable = null; if (onlyTypelessVariable) { // The token is not a type, just an identifier. Debug.Assert(type.ChildTokens.Count == 1, "The count is invalid"); CsToken identifierToken = type.ChildTokens.First.Value; this.tokens.Add(identifierToken); variable = new Variable(null, type.Text, VariableModifiers.None, type.Location, parentReference, type.Generated); identifierToken.ParentRef = new Reference<ICodePart>(variable); } else { this.AdvanceToNextCodeSymbol(variableReference); // Look ahead to the next symbol to see what it is. Symbol symbol = this.symbols.Peek(1); if (symbol == null || symbol.SymbolType != SymbolType.Other) { // This variable has no type, only an identifier. if (!allowTypelessVariable) { throw this.CreateSyntaxException(); } // The token is not a type, just an identifier. Debug.Assert(type.ChildTokens.Count == 1, "The count is invalid"); this.tokens.Add(type.ChildTokens.First.Value); variable = new Variable( null, type.Text, VariableModifiers.None, type.Location, parentReference, type.Generated); } else { // There is a type so add the type token. this.tokens.Add(type); // Create and add the identifier token. CsToken identifier = new CsToken( symbol.Text, CsTokenType.Other, CsTokenClass.Token, symbol.Location, variableReference, this.symbols.Generated); this.tokens.Add(identifier); this.symbols.Advance(); // The variable has both a type and an identifier. variable = new Variable( type, identifier.Text, VariableModifiers.None, CodeLocation.Join(type.Location, identifier.Location), parentReference, type.Generated || identifier.Generated); } } variableReference.Target = variable; return variable; }
/// <summary> /// Checks a word to see if it should start with this. or base. /// </summary> /// <param name="word">The word text to check.</param> /// <param name="item">The word being checked.</param> /// <param name="line">The line that the word appears on.</param> /// <param name="expression">The expression the word appears within.</param> /// <param name="parentElement">The element that contains the word.</param> /// <param name="parentClass">The parent class that this element belongs to.</param> /// <param name="members">The collection of members of the parent class.</param> private void CheckWordUsageAgainstClassMemberRules( string word, CsToken item, int line, Expression expression, CsElement parentElement, ClassBase parentClass, Dictionary<string, List<CsElement>> members) { Param.AssertValidString(word, "word"); Param.AssertNotNull(item, "item"); Param.AssertGreaterThanZero(line, "line"); Param.AssertNotNull(expression, "expression"); Param.AssertNotNull(parentElement, "parentElement"); Param.Ignore(parentClass); Param.Ignore(members); // If there is a local variable with the same name, or if the item we're checking is within the left-hand side // of an object initializer expression, then ignore it. if (!IsLocalMember(word, item, expression) && !IsObjectInitializerLeftHandSideExpression(expression)) { // Determine if this is a member of our class. CsElement foundMember = null; ICollection<CsElement> classMembers = ReadabilityRules.FindClassMember(word, parentClass, members, false); if (classMembers != null) { if (classMembers != null) { foreach (CsElement classMember in classMembers) { if (classMember.Declaration.ContainsModifier(CsTokenType.Static) || (classMember.ElementType == ElementType.Field && ((Field)classMember).Const)) { // There is a member with a matching name that is static or is a const field. In this case, // ignore the issue and quit. foundMember = null; break; } else if (classMember.ElementType != ElementType.Class && classMember.ElementType != ElementType.Struct && classMember.ElementType != ElementType.Delegate && classMember.ElementType != ElementType.Enum) { // Found a matching member. if (foundMember == null) { foundMember = classMember; } } } } if (foundMember != null) { if (foundMember.ElementType == ElementType.Property) { // If the property's name and type are the same, then this is not a violation. // In this case, the type is being accessed, not the property. Property property = (Property)foundMember; if (property.ReturnType.Text != property.Declaration.Name) { this.AddViolation(parentElement, line, Rules.PrefixLocalCallsWithThis, word); } } else { this.AddViolation(parentElement, line, Rules.PrefixLocalCallsWithThis, word); } } } } }
private void CheckPreprocessorSpacing(DocumentRoot root, CsToken preprocessor) { if (((preprocessor.Text.Length > 1) && (preprocessor.Text[0] == '#')) && ((preprocessor.Text[1] == ' ') || (preprocessor.Text[1] == '\t'))) { base.AddViolation(root, preprocessor.LineNumber, Microsoft.StyleCop.CSharp.Rules.PreprocessorKeywordsMustNotBePrecededBySpace, new object[0]); } }
/// <summary> /// Reads an expression starting with an unknown word. /// </summary> /// <returns>Returns the expression.</returns> private LiteralExpression GetConditionalPreprocessorConstantExpression() { // Get the first symbol. Symbol symbol = this.symbols.Peek(1); Debug.Assert(symbol != null && symbol.SymbolType == SymbolType.Other, "Expected a text symbol"); var expressionReference = new Reference<ICodePart>(); // Convert the symbol to a token. this.symbols.Advance(); CsToken literalToken = new CsToken(symbol.Text, CsTokenType.Other, symbol.Location, expressionReference, this.symbols.Generated); Node<CsToken> literalTokenNode = this.tokens.InsertLast(literalToken); // Create a literal expression from this token. var expression = new LiteralExpression(this.tokens, literalTokenNode); expressionReference.Target = expression; return expression; }