/// <summary> /// Gets the non-whitespace token that appears before the given token. /// </summary> /// <param name="tokenNode"> /// The token node. /// </param> /// <param name="tokenList"> /// The list that contains the token. /// </param> /// <returns> /// Returns the previous token. /// </returns> private static CsToken GetPreviousToken(Node <CsToken> tokenNode, MasterList <CsToken> tokenList) { Param.AssertNotNull(tokenNode, "tokenNode"); Param.AssertNotNull(tokenList, "tokenList"); foreach (CsToken temp in tokenList.ReverseIterator(tokenNode)) { if (temp.CsTokenType != CsTokenType.EndOfLine && temp.CsTokenType != CsTokenType.WhiteSpace) { return(temp); } } return(null); }
private void CheckMemberAccessSymbol(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Node<CsToken> previous = tokenNode.Previous; if (previous == null) { switch (previous.Value.CsTokenType) { case CsTokenType.WhiteSpace: case CsTokenType.EndOfLine: case CsTokenType.SingleLineComment: case CsTokenType.MultiLineComment: base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.MemberAccessSymbolsMustBeSpacedCorrectly, new object[0]); break; } } Node<CsToken> next = tokenNode.Next; if (next == null) { switch (next.Value.CsTokenType) { case CsTokenType.WhiteSpace: case CsTokenType.EndOfLine: case CsTokenType.SingleLineComment: case CsTokenType.MultiLineComment: if (previous != null) { foreach (CsToken token in tokens.ReverseIterator(previous)) { CsTokenType csTokenType = token.CsTokenType; if (csTokenType == CsTokenType.Operator) { return; } if (((csTokenType != CsTokenType.WhiteSpace) && (csTokenType != CsTokenType.EndOfLine)) && ((csTokenType != CsTokenType.SingleLineComment) && (csTokenType != CsTokenType.MultiLineComment))) { break; } } } base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.MemberAccessSymbolsMustBeSpacedCorrectly, new object[0]); break; } } }
private void CheckSymbol(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Node<CsToken> previous = tokenNode.Previous; if (((previous != null) && (previous.Value.CsTokenType != CsTokenType.WhiteSpace)) && (previous.Value.CsTokenType != CsTokenType.EndOfLine)) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.SymbolsMustBeSpacedCorrectly, new object[] { tokenNode.Value.Text }); } Node<CsToken> next = tokenNode.Next; if (((next != null) && (next.Value.CsTokenType != CsTokenType.WhiteSpace)) && (next.Value.CsTokenType != CsTokenType.EndOfLine)) { if (previous != null) { foreach (CsToken token in tokens.ReverseIterator(previous)) { if (token.CsTokenType == CsTokenType.Operator) { return; } if (((token.CsTokenType != CsTokenType.WhiteSpace) && (token.CsTokenType != CsTokenType.EndOfLine)) && (((token.CsTokenType != CsTokenType.SingleLineComment) && (token.CsTokenType != CsTokenType.MultiLineComment)) && (token.CsTokenType != CsTokenType.PreprocessorDirective))) { break; } } } base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.SymbolsMustBeSpacedCorrectly, new object[] { tokenNode.Value.Text }); } }
private void CheckOpenParen(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); bool firstOnLine = false; bool lastOnLine = false; // Open parenthesis should never be preceded by whitespace unless it is the // first thing on the line or it follows a keyword or it follows a symbol or a number. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null) { if (previousNode.Value.CsTokenType == CsTokenType.WhiteSpace) { foreach (CsToken item in tokens.ReverseIterator(previousNode)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.WhiteSpace) { continue; } if (itemType == CsTokenType.EndOfLine) { firstOnLine = true; break; } if (itemType == CsTokenType.Case || itemType == CsTokenType.Catch || itemType == CsTokenType.CloseSquareBracket || itemType == CsTokenType.Comma || itemType == CsTokenType.Equals || itemType == CsTokenType.Fixed || itemType == CsTokenType.For || itemType == CsTokenType.Foreach || itemType == CsTokenType.From || ////itemType == CsTokenType.Goto || itemType == CsTokenType.Group || itemType == CsTokenType.If || itemType == CsTokenType.In || itemType == CsTokenType.Into || itemType == CsTokenType.Join || itemType == CsTokenType.Let || itemType == CsTokenType.Lock || itemType == CsTokenType.MultiLineComment || ////itemType == CsTokenType.New || itemType == CsTokenType.Number || itemType == CsTokenType.OperatorSymbol || itemType == CsTokenType.OpenCurlyBracket || itemType == CsTokenType.OrderBy || itemType == CsTokenType.Return || itemType == CsTokenType.Select || itemType == CsTokenType.Semicolon || ////itemType == CsTokenType.SingleLineComment || itemType == CsTokenType.Switch || itemType == CsTokenType.Throw || itemType == CsTokenType.Using || itemType == CsTokenType.Where || itemType == CsTokenType.While || itemType == CsTokenType.WhileDo || itemType == CsTokenType.Yield || itemType == CsTokenType.LabelColon || itemType == CsTokenType.Async || itemType == CsTokenType.By || itemType == CsTokenType.When) { break; } this.AddViolation(tokenNode.Value.FindParentElement(), previousNode.Value.Location, Rules.OpeningParenthesisMustBeSpacedCorrectly); } } } // Open parens should never be followed by whitespace unless // it is the last thing on the line. Node<CsToken> next = tokenNode.Next; if (next != null && (next.Value.CsTokenType == CsTokenType.WhiteSpace || next.Value.CsTokenType == CsTokenType.EndOfLine)) { // Look to see if there is any non whitespace character // on this line other than a comment. foreach (CsToken item in tokens.ForwardIterator(next)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.EndOfLine) { lastOnLine = true; break; } else if (itemType != CsTokenType.WhiteSpace && itemType != CsTokenType.SingleLineComment && itemType != CsTokenType.MultiLineComment) { this.AddViolation(tokenNode.Value.FindParentElement(), next.Value.Location, Rules.OpeningParenthesisMustBeSpacedCorrectly); break; } } } // Open parens cannot be the only thing on the line. if (firstOnLine && lastOnLine) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.OpeningParenthesisMustBeSpacedCorrectly); } }
/// <summary> /// Checks a open bracket for spacing. /// </summary> /// <param name="tokens"> /// The list of tokens being parsed. /// </param> /// <param name="tokenNode"> /// The token to check. /// </param> private void CheckOpenCurlyBracket(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // Open curly brackets should be preceded either by whitespace, or an open paren. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null) { CsTokenType lastType = previousNode.Value.CsTokenType; if (lastType != CsTokenType.WhiteSpace && lastType != CsTokenType.EndOfLine && lastType != CsTokenType.OpenParenthesis) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.OpeningCurlyBracketsMustBeSpacedCorrectly); } if (lastType == CsTokenType.WhiteSpace) { // If this is preceded by whitespace, make sure that the character just // before the whitespace is not an open paren. foreach (CsToken item in tokens.ReverseIterator(previousNode)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.OpenParenthesis) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.OpeningCurlyBracketsMustBeSpacedCorrectly); } else if (itemType != CsTokenType.WhiteSpace) { break; } } } } // Open curly brackets should always be followed by whitespace. Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null && nextNode.Value.CsTokenType != CsTokenType.WhiteSpace && nextNode.Value.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.OpeningCurlyBracketsMustBeSpacedCorrectly); } }
/// <summary> /// Checks a member access symbol for spacing. /// </summary> /// <param name="tokens"> /// The list of tokens being parsed. /// </param> /// <param name="tokenNode"> /// The token to check. /// </param> private void CheckMemberAccessSymbol(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // Member access symbols should not have any whitespace on either side. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null) { CsTokenType previousTokenType = previousNode.Value.CsTokenType; if (previousTokenType == CsTokenType.WhiteSpace || previousTokenType == CsTokenType.EndOfLine || previousTokenType == CsTokenType.SingleLineComment || previousTokenType == CsTokenType.MultiLineComment) { if (!this.IsTokenFirstNonWhitespaceTokenOnLine(tokens, tokenNode)) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.MemberAccessSymbolsMustBeSpacedCorrectly); } } } Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null) { CsTokenType tokenType = nextNode.Value.CsTokenType; if (tokenType == CsTokenType.WhiteSpace || tokenType == CsTokenType.EndOfLine || tokenType == CsTokenType.SingleLineComment || tokenType == CsTokenType.MultiLineComment) { // Make sure the previous token is not the operator keyword. if (previousNode != null) { foreach (CsToken item in tokens.ReverseIterator(previousNode)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.Operator) { return; } else if (itemType != CsTokenType.WhiteSpace && itemType != CsTokenType.EndOfLine && itemType != CsTokenType.SingleLineComment && itemType != CsTokenType.MultiLineComment) { break; } } } this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.MemberAccessSymbolsMustBeSpacedCorrectly); } } }
/// <summary> /// Checks a close paren for spacing. /// </summary> /// <param name="root">The document root.</param> /// <param name="tokens">The list of tokens being parsed.</param> /// <param name="tokenNode">The token to check.</param> private void CheckCloseParen(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(root, "root"); Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // Close parens should never be preceded by whitespace. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null && (previousNode.Value.CsTokenType == CsTokenType.WhiteSpace || previousNode.Value.CsTokenType == CsTokenType.EndOfLine)) { this.AddViolation(root, tokenNode.Value.LineNumber, Rules.ClosingParenthesisMustBeSpacedCorrectly); } // This not a violation if the token following the close paren is an unknown token, // which means that this is probably the closing paren of a cast operation. The same // goes if the next token is "base" or "this". Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null) { CsTokenType nextType = nextNode.Value.CsTokenType; // The closing parenthesis could be the end of a cast expression if it comes // before one of the following types of tokens. // TODO: Once it is possible to determine the parent expression of a token, // we can explicitly check whether the closing parenthesis is part of a cast // expression, and all of the following cases. if (nextType != CsTokenType.WhiteSpace && nextType != CsTokenType.EndOfLine && nextType != CsTokenType.CloseParenthesis && nextType != CsTokenType.OpenParenthesis && nextType != CsTokenType.CloseSquareBracket && nextType != CsTokenType.OpenSquareBracket && nextType != CsTokenType.CloseAttributeBracket && nextType != CsTokenType.Semicolon && nextType != CsTokenType.Comma && nextType != CsTokenType.Other && nextType != CsTokenType.Base && nextType != CsTokenType.This && nextType != CsTokenType.Null && nextType != CsTokenType.New && nextType != CsTokenType.Number && nextType != CsTokenType.String && nextType != CsTokenType.Delegate && (nextType != CsTokenType.OperatorSymbol || ((OperatorSymbol)nextNode.Value).SymbolType != OperatorType.AddressOf) && !nextNode.Value.Text.StartsWith(".", StringComparison.Ordinal)) { // This is allowed also if the next token is a positive or negative sign. bool cancel = false; if (nextType == CsTokenType.OperatorSymbol) { OperatorSymbol operatorSymbol = nextNode.Value as OperatorSymbol; if (operatorSymbol.SymbolType == OperatorType.Negative || operatorSymbol.SymbolType == OperatorType.Positive) { cancel = true; } } if (!cancel) { // If the next token is a colon, this is allowed if we are in a switch\case statement. bool followsCase = false; if (nextType == CsTokenType.LabelColon) { foreach (CsToken item in tokens.ReverseIterator(tokenNode.Previous)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.EndOfLine) { break; } else if (itemType == CsTokenType.Case) { followsCase = true; break; } } } if (!followsCase) { this.AddViolation(root, tokenNode.Value.LineNumber, Rules.ClosingParenthesisMustBeSpacedCorrectly); } } } if (nextType == CsTokenType.WhiteSpace) { // If this is followed by whitespace, make sure that the character just // after the whitespace is not a paren, bracket, a comma, or a semicolon. foreach (CsToken item in tokens.ForwardIterator(tokenNode.Next.Next)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.CloseParenthesis || itemType == CsTokenType.OpenParenthesis || itemType == CsTokenType.CloseSquareBracket || itemType == CsTokenType.OpenSquareBracket || itemType == CsTokenType.Semicolon || itemType == CsTokenType.Comma) { this.AddViolation(root, tokenNode.Value.LineNumber, Rules.ClosingParenthesisMustBeSpacedCorrectly); } else if (itemType != CsTokenType.WhiteSpace) { break; } } } } }
private void CheckCloseParen(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Node<CsToken> previous = tokenNode.Previous; if ((previous != null) && ((previous.Value.CsTokenType == CsTokenType.WhiteSpace) || (previous.Value.CsTokenType == CsTokenType.EndOfLine))) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.ClosingParenthesisMustBeSpacedCorrectly, new object[0]); } Node<CsToken> next = tokenNode.Next; if (next == null) { return; } CsTokenType csTokenType = next.Value.CsTokenType; if (((csTokenType == CsTokenType.WhiteSpace || csTokenType == CsTokenType.EndOfLine || csTokenType == CsTokenType.CloseParenthesis || csTokenType == CsTokenType.OpenParenthesis || csTokenType == CsTokenType.CloseSquareBracket || csTokenType == CsTokenType.OpenSquareBracket || csTokenType == CsTokenType.CloseAttributeBracket || csTokenType == CsTokenType.Semicolon || csTokenType == CsTokenType.Comma || csTokenType == CsTokenType.Other || csTokenType == CsTokenType.Base || csTokenType == CsTokenType.This || csTokenType == CsTokenType.Null || csTokenType == CsTokenType.New || csTokenType == CsTokenType.Number || csTokenType == CsTokenType.String // Oleg Shuruev added || csTokenType == CsTokenType.Typeof) || ((csTokenType == CsTokenType.Delegate) || ((csTokenType == CsTokenType.OperatorSymbol) && (((OperatorSymbol)next.Value).SymbolType == OperatorType.AddressOf)))) || next.Value.Text.StartsWith(".", StringComparison.Ordinal)) { goto Label_01C1; } bool flag = false; if (csTokenType == CsTokenType.OperatorSymbol) { OperatorSymbol symbol = next.Value as OperatorSymbol; if ((symbol.SymbolType == OperatorType.Negative) || (symbol.SymbolType == OperatorType.Positive)) { flag = true; } } if (flag) { goto Label_01C1; } bool flag2 = false; if (csTokenType == CsTokenType.LabelColon) { foreach (CsToken token in tokens.ReverseIterator(tokenNode.Previous)) { switch (token.CsTokenType) { case CsTokenType.EndOfLine: goto Label_019E; case CsTokenType.Case: flag2 = true; goto Label_019E; } } } Label_019E: if (!flag2) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.ClosingParenthesisMustBeSpacedCorrectly, new object[0]); } Label_01C1: if (csTokenType == CsTokenType.WhiteSpace) { foreach (CsToken token2 in tokens.ForwardIterator(tokenNode.Next.Next)) { CsTokenType type3 = token2.CsTokenType; switch (type3) { case CsTokenType.CloseParenthesis: case CsTokenType.OpenParenthesis: case CsTokenType.CloseSquareBracket: case CsTokenType.OpenSquareBracket: case CsTokenType.Semicolon: case CsTokenType.Comma: { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.ClosingParenthesisMustBeSpacedCorrectly, new object[0]); continue; } } if (type3 != CsTokenType.WhiteSpace) { return; } } } }
/// <summary> /// Checks a unary symbol for spacing. /// </summary> /// <param name="tokens"> /// The master list of tokens. /// </param> /// <param name="tokenNode"> /// The token to check. /// </param> private void CheckUnarySymbol(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // These symbols should be preceded by whitespace but not followed by whitespace. They can // also be preceded by an open paren or an open square bracket. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null) { CsTokenType previousNodeTokenType = previousNode.Value.CsTokenType; if (previousNodeTokenType != CsTokenType.WhiteSpace && previousNodeTokenType != CsTokenType.EndOfLine && previousNodeTokenType != CsTokenType.OpenParenthesis && previousNodeTokenType != CsTokenType.OpenSquareBracket && previousNodeTokenType != CsTokenType.CloseParenthesis) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } // They should not be preceded by whitespace if the whitespace is preceded by a paranthesis. if (previousNodeTokenType == CsTokenType.WhiteSpace || previousNodeTokenType == CsTokenType.EndOfLine) { foreach (CsToken item in tokens.ReverseIterator(previousNode)) { if (item.CsTokenType == CsTokenType.OpenParenthesis || item.CsTokenType == CsTokenType.OpenSquareBracket) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } else if (item.CsTokenType == CsTokenType.WhiteSpace) { continue; } if (item.CsTokenType != CsTokenType.OpenParenthesis && item.CsTokenType != CsTokenType.OpenSquareBracket && item.CsTokenType != CsTokenType.WhiteSpace) { break; } } } } Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null) { CsTokenType tokenType = nextNode.Value.CsTokenType; if (tokenType == CsTokenType.WhiteSpace || tokenType == CsTokenType.EndOfLine || tokenType == CsTokenType.SingleLineComment || tokenType == CsTokenType.MultiLineComment) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } } }
/// <summary> /// Checks a symbol for spacing. /// </summary> /// <param name="tokens"> /// The list of tokens being parsed. /// </param> /// <param name="tokenNode"> /// The token to check. /// </param> private void CheckSymbol(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); OperatorSymbol operatorSymbol = tokenNode.Value as OperatorSymbol; if (operatorSymbol != null && operatorSymbol.SymbolType == OperatorType.NullConditional) { // Symbols should not have whitespace on both sides for operator '?.'. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null && previousNode.Value.CsTokenType == CsTokenType.WhiteSpace && previousNode.Value.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null && nextNode.Value.CsTokenType == CsTokenType.WhiteSpace && nextNode.Value.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } if (operatorSymbol.Text.Length > 2 || operatorSymbol.Text.Contains("\r") || operatorSymbol.Text.Contains("\n") || operatorSymbol.Text.Contains(" ")) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.DoNotSplitNullConditionalOperators, tokenNode.Value.Text); } } else { // Symbols should have whitespace on both sides. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null && previousNode.Value.CsTokenType != CsTokenType.WhiteSpace && previousNode.Value.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null && nextNode.Value.CsTokenType != CsTokenType.WhiteSpace && nextNode.Value.CsTokenType != CsTokenType.EndOfLine) { // Make sure the previous token is not operator. if (previousNode != null) { foreach (CsToken item in tokens.ReverseIterator(previousNode)) { if (item.CsTokenType == CsTokenType.Operator) { return; } else if (item.CsTokenType != CsTokenType.WhiteSpace && item.CsTokenType != CsTokenType.EndOfLine && item.CsTokenType != CsTokenType.SingleLineComment && item.CsTokenType != CsTokenType.MultiLineComment && item.CsTokenType != CsTokenType.PreprocessorDirective) { break; } } } this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.LineNumber, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } } }
/// <summary> /// Checks to make sure that the slashes in in the comment are followed by a space. /// </summary> /// <param name="tokens"> /// The list of tokens being parsed. /// </param> /// <param name="tokenNode"> /// The comment token. /// </param> private void CheckSingleLineComment(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // If the token length is less then two, this is not a valid comment so just ignore it. if (tokenNode.Value.Text.Length > 2) { bool addViolation = false; // The first character in the comment must be a space, except for the following four cases: // 1. The comment may start with three or more slashes: ///whatever // 2. The command may start with a backwards slash: //\whatever // 3. The comment may start with a dash if there are at last two dashes: //-- // 4. The character after the second slash may be a newline character. string text = tokenNode.Value.Text; if (text[2] != ' ' && text[2] != '\t' && text[2] != '/' && text[2] != '\\' && text[1] != '\n' && text[1] != '\r' && (text.Length < 4 || text[2] != '-' || text[3] != '-')) { // The comment does not start with a single space. addViolation = true; } else if (text.Length > 3 && (text[3] == ' ' || text[3] == '\t') && text[2] != '\\') { // The comment starts with more than one space. This is only a violation if this is the first // single-line comment in a row. If there is another single-line comment directly above this one // with no blank line between them, this is not a violation. bool first = true; int newLineCount = 0; foreach (CsToken previousToken in tokens.ReverseIterator(tokenNode.Previous)) { if (previousToken.CsTokenType == CsTokenType.EndOfLine) { if (++newLineCount == 2) { break; } } else if (previousToken.CsTokenType == CsTokenType.SingleLineComment) { first = false; break; } else if (previousToken.CsTokenType != CsTokenType.WhiteSpace) { break; } } if (first) { addViolation = true; } if (tokenNode.Value.Parent is FileHeader) { // Starting with multiple spaces is only an issue if we're outside the FileHeader addViolation = false; } } if (addViolation) { this.AddViolation(tokenNode.Value.FindParentElement(), tokenNode.Value.Location, Rules.SingleLineCommentsMustBeginWithSingleSpace); } } }
private void CheckSemicolonAndComma(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokenNode, "tokenNode"); Param.AssertNotNull(tokens, "tokens"); bool comma = false; if (tokenNode.Value.Text == ",") { comma = true; } else { Debug.Assert(tokenNode.Value.Text == ";", "The token should either be a comma or a semicolon"); } // There is a special case here where we allow <,,> [,,] or (;;), or variations thereof. // In these cases, there should be no spaces around the comma or semicolon. string[] open = new[] { "[", "<" }; string[] close = new[] { "]", ">" }; if (!comma) { open = new[] { "(" }; close = new[] { ")" }; } bool specialCaseBackwards = true; bool specialCaseForwards = true; // Work backwards and look for the previous character on this line. bool found = false; Node<CsToken> itemNode = tokenNode.Previous; if (itemNode != null) { for (int i = 0; i < open.Length; ++i) { if (itemNode.Value.Text == open[i]) { found = true; break; } } if (!found) { if (itemNode.Value.Text == tokenNode.Value.Text) { found = true; } else { specialCaseBackwards = false; } } } if (!found) { specialCaseBackwards = false; } // Work backwards until the first non-whitespace or newline. // If thats a LabelColon then thats fine too. Fix for #7183 foreach (CsToken previousNonWhitespaceToken in tokens.ReverseIterator(tokenNode.Previous)) { if (previousNonWhitespaceToken.CsTokenType == CsTokenType.LabelColon) { specialCaseBackwards = true; break; } if (previousNonWhitespaceToken.CsTokenType != CsTokenType.WhiteSpace && previousNonWhitespaceToken.CsTokenType != CsTokenType.EndOfLine) { break; } } // Work forwards and look for the next character on this line. found = false; itemNode = tokenNode.Next; if (itemNode != null) { for (int i = 0; i < close.Length; ++i) { if (itemNode.Value.Text == close[i]) { found = true; break; } } if (!found) { if (itemNode.Value.Text == tokenNode.Value.Text) { found = true; } else { specialCaseForwards = false; } } } if (!found) { specialCaseForwards = false; } if (!specialCaseBackwards) { Node<CsToken> previousNode = tokenNode.Previous; // Make sure this is not preceded by whitespace. if (previousNode != null && (previousNode.Value.CsTokenType == CsTokenType.WhiteSpace || previousNode.Value.CsTokenType == CsTokenType.EndOfLine)) { this.AddViolation( tokenNode.Value.FindParentElement(), tokenNode.Value.Location, comma ? Rules.CommasMustBeSpacedCorrectly : Rules.SemicolonsMustBeSpacedCorrectly); } } if (!specialCaseForwards) { Node<CsToken> nextNode = tokenNode.Next; // Make sure this is followed by whitespace or a close paren. if (nextNode != null && nextNode.Value.CsTokenType != CsTokenType.WhiteSpace && nextNode.Value.CsTokenType != CsTokenType.EndOfLine && nextNode.Value.CsTokenType != CsTokenType.CloseParenthesis) { this.AddViolation( tokenNode.Value.FindParentElement(), tokenNode.Value.Location, comma ? Rules.CommasMustBeSpacedCorrectly : Rules.SemicolonsMustBeSpacedCorrectly); } } }
/// <summary> /// Gets the non-whitespace token that appears before the given token. /// </summary> /// <param name="tokenNode"> /// The token node. /// </param> /// <param name="tokenList"> /// The list that contains the token. /// </param> /// <returns> /// Returns the previous token. /// </returns> private static CsToken GetPreviousToken(Node<CsToken> tokenNode, MasterList<CsToken> tokenList) { Param.AssertNotNull(tokenNode, "tokenNode"); Param.AssertNotNull(tokenList, "tokenList"); foreach (CsToken temp in tokenList.ReverseIterator(tokenNode)) { if (temp.CsTokenType != CsTokenType.EndOfLine && temp.CsTokenType != CsTokenType.WhiteSpace) { return temp; } } return null; }
private void CheckOpenCurlyBracket(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Node<CsToken> previous = tokenNode.Previous; if (previous != null) { CsTokenType csTokenType = previous.Value.CsTokenType; if (((csTokenType != CsTokenType.WhiteSpace) && (csTokenType != CsTokenType.EndOfLine)) && (csTokenType != CsTokenType.OpenParenthesis)) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningCurlyBracketsMustBeSpacedCorrectly, new object[0]); } if (csTokenType == CsTokenType.WhiteSpace) { foreach (CsToken token in tokens.ReverseIterator(previous)) { CsTokenType type2 = token.CsTokenType; if (type2 == CsTokenType.OpenParenthesis) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningCurlyBracketsMustBeSpacedCorrectly, new object[0]); } else if (type2 != CsTokenType.WhiteSpace) { break; } } } } Node<CsToken> next = tokenNode.Next; if (((next != null) && (next.Value.CsTokenType != CsTokenType.WhiteSpace)) && (next.Value.CsTokenType != CsTokenType.EndOfLine)) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningCurlyBracketsMustBeSpacedCorrectly, new object[0]); } }
/// <summary> /// Checks to see if the passed in node is the first node on its line. /// </summary> /// <param name="tokens"> /// The master list of tokens. /// </param> /// <param name="node"> /// The node to check. /// </param> /// <returns> /// True if this node is the first on the line, otherwise false. /// </returns> private bool IsTokenFirstNonWhitespaceTokenOnLine(MasterList<CsToken> tokens, Node<CsToken> node) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(node, "node"); Node<CsToken> previousNode = node.Previous; if (previousNode == null) { return true; } bool returnValue = true; foreach (CsToken item in tokens.ReverseIterator(previousNode)) { if (item.LineNumber != node.Value.LineNumber) { break; } if (item.CsTokenType != CsTokenType.WhiteSpace) { returnValue = false; break; } } return returnValue; }
private void CheckOpenParen(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Node<CsToken> node2; bool flag = false; bool flag2 = false; Node<CsToken> previous = tokenNode.Previous; if ((previous != null) && (previous.Value.CsTokenType == CsTokenType.WhiteSpace)) { foreach (CsToken token in tokens.ReverseIterator(previous)) { switch (token.CsTokenType) { case CsTokenType.WhiteSpace: { continue; } case CsTokenType.EndOfLine: flag = true; goto Label_017C; case CsTokenType.Case: case CsTokenType.Catch: case CsTokenType.CloseSquareBracket: case CsTokenType.Comma: case CsTokenType.Equals: case CsTokenType.Fixed: case CsTokenType.For: case CsTokenType.Foreach: case CsTokenType.From: case CsTokenType.Group: case CsTokenType.If: case CsTokenType.In: case CsTokenType.Into: case CsTokenType.Join: case CsTokenType.Let: case CsTokenType.Lock: case CsTokenType.MultiLineComment: case CsTokenType.Number: case CsTokenType.OperatorSymbol: case CsTokenType.OpenCurlyBracket: case CsTokenType.OrderBy: case CsTokenType.Return: case CsTokenType.Select: case CsTokenType.Semicolon: case CsTokenType.Switch: case CsTokenType.Throw: case CsTokenType.Using: case CsTokenType.Where: case CsTokenType.While: case CsTokenType.WhileDo: case CsTokenType.Yield: goto Label_017C; } base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningParenthesisMustBeSpacedCorrectly, new object[0]); } } Label_017C: node2 = tokenNode.Next; if ((node2 != null) && ((node2.Value.CsTokenType == CsTokenType.WhiteSpace) || (node2.Value.CsTokenType == CsTokenType.EndOfLine))) { foreach (CsToken token2 in tokens.ForwardIterator(node2)) { CsTokenType csTokenType = token2.CsTokenType; if (csTokenType == CsTokenType.EndOfLine) { flag2 = true; break; } if (((csTokenType != CsTokenType.WhiteSpace) && (csTokenType != CsTokenType.SingleLineComment)) && (csTokenType != CsTokenType.MultiLineComment)) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningParenthesisMustBeSpacedCorrectly, new object[0]); break; } } } if (flag && flag2) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.OpeningParenthesisMustBeSpacedCorrectly, new object[0]); } }
private void CheckCloseParen(MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // Close parens should never be preceded by whitespace. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null) { if (previousNode.Value.CsTokenType == CsTokenType.WhiteSpace || (previousNode.Value.CsTokenType == CsTokenType.EndOfLine && previousNode.Previous.Value.CsTokenType != CsTokenType.SingleLineComment)) { this.AddViolation(tokenNode.Value.FindParentElement(), previousNode.Value.Location, Rules.ClosingParenthesisMustBeSpacedCorrectly); } } // Find out what comes after the closing paren. Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null) { CsTokenType nextType = nextNode.Value.CsTokenType; CsTokenType nextNextType = nextNode.Next == null ? CsTokenType.Other : nextNode.Next.Value.CsTokenType; if (tokenNode.Value.Parent is CastExpression) { // There should not be any whitespace after the closing parenthesis in a cast expression. if (nextType == CsTokenType.WhiteSpace) { this.AddViolation(tokenNode.Value.FindParentElement(), nextNode.Value.Location, Rules.ClosingParenthesisMustBeSpacedCorrectly); } } else if (nextType == CsTokenType.LabelColon || nextNextType == CsTokenType.LabelColon) { // If the next token is a colon, it's allowed to omit the whitespace only if we are in a switch\case statement. bool followsCase = false; foreach (CsToken item in tokens.ReverseIterator(tokenNode.Previous)) { CsTokenType itemType = item.CsTokenType; if (itemType == CsTokenType.EndOfLine) { break; } else if (itemType == CsTokenType.Case) { followsCase = true; break; } } if ((followsCase && nextType == CsTokenType.WhiteSpace) || (!followsCase && nextType != CsTokenType.WhiteSpace)) { this.AddViolation(tokenNode.Value.FindParentElement(), nextNode.Value.Location, Rules.ClosingParenthesisMustBeSpacedCorrectly); } } else if (nextType == CsTokenType.WhiteSpace) { // Make sure that the character just after the whitespace is not a paren, bracket, a comma, or a semicolon. foreach (CsToken item in tokens.ForwardIterator(tokenNode.Next.Next)) { if (IsAllowedAfterClosingParenthesis(item)) { this.AddViolation(tokenNode.Value.FindParentElement(), nextNode.Value.Location, Rules.ClosingParenthesisMustBeSpacedCorrectly); } else if (item.CsTokenType != CsTokenType.WhiteSpace) { break; } } } else { // For all other types, the parenthesis must be followed by whitespace, unless the next character is a paren, bracket, comma, or a semicolon. if (nextNode.Value.CsTokenType != CsTokenType.EndOfLine && !IsAllowedAfterClosingParenthesis(nextNode.Value)) { this.AddViolation(tokenNode.Value.FindParentElement(), nextNode.Value.Location, Rules.ClosingParenthesisMustBeSpacedCorrectly); } } } }
private void CheckSingleLineComment(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { if (tokenNode.Value.Text.Length > 2) { string text = tokenNode.Value.Text; if ((((text[2] != ' ') && (text[2] != '\t')) && ((text[2] != '/') && (text[2] != '\\'))) && (((text[1] != '\n') && (text[1] != '\r')) && (((text.Length < 4) || (text[2] != '-')) || (text[3] != '-')))) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.SingleLineCommentsMustBeginWithSingleSpace, new object[0]); } else if (((text.Length > 3) && ((text[3] == ' ') || (text[3] == '\t'))) && (text[2] != '\\')) { bool flag = true; int num = 0; foreach (CsToken token in tokens.ReverseIterator(tokenNode.Previous)) { if (token.CsTokenType == CsTokenType.EndOfLine) { if (++num != 2) { continue; } break; } if (token.CsTokenType == CsTokenType.SingleLineComment) { flag = false; break; } if (token.CsTokenType != CsTokenType.WhiteSpace) { break; } } if (flag) { base.AddViolation(root, tokenNode.Value.LineNumber, Microsoft.StyleCop.CSharp.Rules.SingleLineCommentsMustBeginWithSingleSpace, new object[0]); } } } }
/// <summary> /// Checks a symbol for spacing. /// </summary> /// <param name="root">The document root.</param> /// <param name="tokens">The list of tokens being parsed.</param> /// <param name="tokenNode">The token to check.</param> private void CheckSymbol(DocumentRoot root, MasterList<CsToken> tokens, Node<CsToken> tokenNode) { Param.AssertNotNull(root, "root"); Param.AssertNotNull(tokens, "tokens"); Param.AssertNotNull(tokenNode, "tokenNode"); // Symbols should have whitespace on both sides. Node<CsToken> previousNode = tokenNode.Previous; if (previousNode != null && previousNode.Value.CsTokenType != CsTokenType.WhiteSpace && previousNode.Value.CsTokenType != CsTokenType.EndOfLine) { this.AddViolation(root, tokenNode.Value.LineNumber, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } Node<CsToken> nextNode = tokenNode.Next; if (nextNode != null && nextNode.Value.CsTokenType != CsTokenType.WhiteSpace && nextNode.Value.CsTokenType != CsTokenType.EndOfLine) { // Make sure the previous token is not operator. if (previousNode != null) { foreach (CsToken item in tokens.ReverseIterator(previousNode)) { if (item.CsTokenType == CsTokenType.Operator) { return; } else if (item.CsTokenType != CsTokenType.WhiteSpace && item.CsTokenType != CsTokenType.EndOfLine && item.CsTokenType != CsTokenType.SingleLineComment && item.CsTokenType != CsTokenType.MultiLineComment && item.CsTokenType != CsTokenType.PreprocessorDirective) { break; } } } this.AddViolation(root, tokenNode.Value.LineNumber, Rules.SymbolsMustBeSpacedCorrectly, tokenNode.Value.Text); } }