Пример #1
0
        /// <summary>
        /// Initializes a new instance of the Argument class.
        /// </summary>
        /// <param name="name">
        /// The optional name of the argument.
        /// </param>
        /// <param name="modifiers">
        /// Modifiers 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;
        }
Пример #2
0
        /////// <summary>
        /////// Joins the locations of the two tokens.
        /////// </summary>
        /////// <param name="token1">The first token.</param>
        /////// <param name="location2">The second location.</param>
        /////// <returns>Returns the joined locations.</returns>
        ////internal static CodeLocation JoinLocations(Node<CsToken> token1, CodeLocation location2)
        ////{
        ////    Param.Ignore(token1, location2);
        ////    return CsToken.JoinLocations(token1 == null ? null : token1.Value, location2);
        ////}

        /// <summary>
        /// Joins the locations of the two tokens.
        /// </summary>
        /// <param name="token1">
        /// The first token.
        /// </param>
        /// <param name="token2">
        /// The second token.
        /// </param>
        /// <returns>
        /// Returns the joined locations.
        /// </returns>
        internal static CodeLocation JoinLocations(CsToken token1, CsToken token2)
        {
            Param.AssertNotNull(token1, "token1");
            Param.AssertNotNull(token2, "token2");

            return(CodeLocation.Join(token1.Location, token2.Location));
        }
Пример #3
0
        /// <summary>
        /// Checks a string to determine whether it is using an incorrect empty string notation.
        /// </summary>
        /// <param name="stringNode">
        /// The node containing the string to check.
        /// </param>
        private void CheckEmptyString(Node <CsToken> stringNode)
        {
            Param.AssertNotNull(stringNode, "stringNode");

            CsToken @string = stringNode.Value;

            Debug.Assert(@string.CsTokenType == CsTokenType.String, "The token must be a string.");

            if (string.Equals(@string.Text, "\"\"", StringComparison.Ordinal) || string.Equals(@string.Text, "@\"\"", StringComparison.Ordinal) || string.Equals(@string.Text, "$\"\"", StringComparison.Ordinal))
            {
                // Look at the previous non-whitespace token. If it is the 'case' keyword, then do not throw this
                // exception. It is illegal to write case String.Empty : and instead case "": must be written.
                // We also check that the node is not part of a method parameter as these must be "" also.
                Node <CsToken> previousToken = null;
                for (Node <CsToken> previousNode = stringNode.Previous; previousNode != null; previousNode = previousNode.Previous)
                {
                    if (previousNode.Value.CsTokenType != CsTokenType.WhiteSpace && previousNode.Value.CsTokenType != CsTokenType.EndOfLine &&
                        previousNode.Value.CsTokenType != CsTokenType.SingleLineComment && previousNode.Value.CsTokenType != CsTokenType.MultiLineComment)
                    {
                        previousToken = previousNode;
                        break;
                    }
                }

                if (previousToken == null ||
                    (previousToken.Value.CsTokenType != CsTokenType.Case && !IsConstVariableDeclaration(previousToken) && !IsMethodParameterDeclaration(previousToken)))
                {
                    this.AddViolation(@string.FindParentElement(), @string.LineNumber, Rules.UseStringEmptyForEmptyStrings);
                }
            }
        }
Пример #4
0
        /// <summary>
        /// Checks the generic type uses the shorthand declaration format.
        /// </summary>
        /// <param name="type">
        /// The <see cref="CsToken"/> to check.
        /// </param>
        private void CheckShorthandForNullableTypes(CsToken type)
        {
            Param.AssertNotNull(type, "type");

            Debug.Assert(type.CsTokenClass == CsTokenClass.GenericType, "Expected a generic type.");
            GenericType genericType = (GenericType)type;

            // Check the declaration of the generic type for longhand, but allow Nullable<> which has no shorthand
            if (genericType.ChildTokens.Count > 0 && Utils.TokenContainNullable(genericType.ChildTokens.First))
            {
                if (genericType.Parent == null || !(genericType.Parent is TypeofExpression))
                {
                    if (genericType.Parent is Method)
                    {
                        Method parentMethod = genericType.Parent as Method;
                        if (parentMethod.Name == parentMethod.FriendlyTypeText + " " + genericType.Text)
                        {
                            return;
                        }
                    }

                    this.AddViolation(genericType.FindParentElement(), genericType.LineNumber, Rules.UseShorthandForNullableTypes);
                }
            }
            else
            {
                // Check the parameters of the generic type because the declaration may be nested
                foreach (
                    GenericTypeParameter genericTypeParameter in genericType.GenericTypesParameters.Where(token => token.Type.CsTokenClass == CsTokenClass.GenericType))
                {
                    this.CheckShorthandForNullableTypes(genericTypeParameter.Type);
                }
            }
        }
        /// <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 (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);
        }
Пример #6
0
        /// <summary>
        /// Checks the built-in types and empty strings within a document.
        /// </summary>
        /// <param name="document">
        /// The document containing the tokens.
        /// </param>
        /// <param name="settings">
        /// The current settings.
        /// </param>
        private void IterateTokenList(CsDocument document, Settings settings)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(settings);

            for (Node <CsToken> tokenNode = document.Tokens.First; tokenNode != null; tokenNode = tokenNode.Next)
            {
                CsToken token = tokenNode.Value;

                if (token.CsTokenClass == CsTokenClass.Type || token.CsTokenClass == CsTokenClass.GenericType)
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType(tokenNode, document);

                    if (token.CsTokenClass == CsTokenClass.GenericType)
                    {
                        this.CheckShorthandForNullableTypes(tokenNode.Value);
                    }
                }
                else if (token.CsTokenType == CsTokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(tokenNode);
                }
                else if (token.CsTokenClass == CsTokenClass.RegionDirective && settings.DoNotUseRegions)
                {
                    Region region = (Region)token;
                    if (region.Beginning && !region.Generated && !region.IsGeneratedCodeRegion)
                    {
                        // There should not be any regions in the code.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.DoNotUseRegions);
                    }
                }
            }
        }
        /// <summary>
        /// Parses the given literal token.
        /// </summary>
        /// <param name="tokenNode">
        /// The literal token node.
        /// </param>
        /// <param name="expression">
        /// The expression that contains the token.
        /// </param>
        /// <param name="parentExpression">
        /// The parent of the expression that contains the token.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expression.
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        private void CheckClassMemberRulesForLiteralToken(
            Node <CsToken> tokenNode,
            Expression expression,
            Expression parentExpression,
            CsElement parentElement,
            ClassBase parentClass,
            Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(tokenNode, "token");
            Param.AssertNotNull(expression, "expression");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Skip types. We only care about named members.
            if (!(tokenNode.Value is TypeToken) || tokenNode.Value.CsTokenClass == CsTokenClass.GenericType)
            {
                // If the name starts with a dot, ignore it.
                if (!tokenNode.Value.Text.StartsWith(".", StringComparison.Ordinal))
                {
                    if (tokenNode.Value.Text == "base" && parentExpression != null)
                    {
                        CsToken name = Utils.ExtractBaseClassMemberName(parentExpression, tokenNode);
                        if (name != null)
                        {
                            if (!this.IsBaseRequired(name.Text, parentClass, members))
                            {
                                this.AddViolation(parentElement, name.Location, Rules.DoNotPrefixCallsWithBaseUnlessLocalImplementationExists, name);
                            }
                        }
                    }
                    else if (tokenNode.Value.Text != "this")
                    {
                        if (this.IsThisRequired(tokenNode, expression, parentClass, members))
                        {
                            if ((parentClass.BaseClass != string.Empty) || (tokenNode.Value.Text == "Equals" || tokenNode.Value.Text == "ReferenceEquals"))
                            {
                                string className = parentClass.FullyQualifiedName.SubstringAfterLast('.');

                                if (parentClass.BaseClass != string.Empty)
                                {
                                    className = className + ".' or '" + parentClass.BaseClass;
                                }

                                this.AddViolation(parentElement, tokenNode.Value.Location, Rules.PrefixCallsCorrectly, tokenNode.Value.Text, className);
                            }
                            else
                            {
                                this.AddViolation(parentElement, tokenNode.Value.Location, Rules.PrefixLocalCallsWithThis, tokenNode.Value.Text);
                            }
                        }
                    }
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Initializes a new instance of the FileHeader class.
        /// </summary>
        /// <param name="headerText">
        /// The header text.
        /// </param>
        /// <param name="tokens">
        /// The collection of tokens in the header.
        /// </param>
        /// <param name="parent">
        /// The parent of the header.
        /// </param>
        internal FileHeader(string headerText, CsTokenList tokens, Reference <ICodePart> parent)
        {
            Param.AssertNotNull(headerText, "headerText");
            Param.AssertNotNull(tokens, "tokens");
            Param.AssertNotNull(parent, "parent");

            this.headerText = headerText;
            this.tokens     = tokens;
            this.parent     = parent;

            this.location = this.tokens.First != null?CsToken.JoinLocations(this.tokens.First, this.tokens.Last) : CodeLocation.Empty;

            // Attempt to load this into an Xml document.
            try
            {
                if (this.headerText.Length > 0)
                {
                    this.headerXml = string.Format(CultureInfo.InvariantCulture, "<root>{0}</root>", HtmlEncode(this.headerText));

                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(this.headerXml);

                    // Check whether the header has the autogenerated tag.
                    if (doc.DocumentElement != null)
                    {
                        XmlNode node = doc.DocumentElement["autogenerated"];
                        if (node != null)
                        {
                            // Set this as generated code.
                            this.generated = true;
                        }
                        else
                        {
                            node = doc.DocumentElement["auto-generated"];
                            if (node != null)
                            {
                                // Set this as generated code.
                                this.generated = true;
                            }
                        }

                        StringCollection unstyledElements = new StringCollection();
                        unstyledElements.AddRange(new[] { "unstyled", "stylecopoff", "nostyle" });

                        XmlNodeList childNodes = doc.DocumentElement.ChildNodes;
                        if (childNodes.Cast <XmlNode>().Any(xmlNode => unstyledElements.Contains(xmlNode.Name.ToLowerInvariant())))
                        {
                            this.UnStyled = true;
                        }
                    }
                }
            }
            catch (XmlException)
            {
            }
        }
Пример #9
0
        /// <summary>
        /// Checks the built-in types and empty strings within a document.
        /// </summary>
        /// <param name="document">
        /// The document containing the tokens.
        /// </param>
        /// <param name="settings">
        /// The current settings.
        /// </param>
        private void IterateTokenList(CsDocument document, Settings settings)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(settings);

            for (Node <CsToken> tokenNode = document.Tokens.First; tokenNode != null; tokenNode = tokenNode.Next)
            {
                CsToken token = tokenNode.Value;

                if (token.CsTokenClass == CsTokenClass.Type || token.CsTokenClass == CsTokenClass.GenericType)
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType(tokenNode, document);

                    if (token.CsTokenClass == CsTokenClass.GenericType)
                    {
                        this.CheckShorthandForNullableTypes(tokenNode.Value);
                    }
                }
                else if (token.CsTokenType == CsTokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(tokenNode);
                }
                else if (token.CsTokenClass == CsTokenClass.RegionDirective && settings.DoNotUseRegions)
                {
                    Region region = (Region)token;
                    if (region.Beginning && !region.Generated && !region.IsGeneratedCodeRegion)
                    {
                        // There should not be any regions in the code.
                        this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.DoNotUseRegions);
                    }
                }
                else if (settings.AvoidStringFormatUseStringInterpolation && token.CsTokenType == CsTokenType.Other && token.Text == "Format")
                {
                    // Check this rule only if project target framework version is greater or equal 4.6
                    if (document.SourceCode.Project.TargetFrameworkVersion >= 4.6)
                    {
                        MemberAccessExpression expression = token.Parent?.Parent as MemberAccessExpression;

                        // Check if literal expression is not null and check text to avoid user's custom code like enumeration.
                        if (expression != null && expression.Text == "string.Format")
                        {
                            CsToken region = (CsToken)token;
                            if (!region.Generated)
                            {
                                // There should not be any regions in the code.
                                this.AddViolation(token.FindParentElement(), token.LineNumber, Rules.AvoidStringFormatUseStringInterpolation);
                            }
                        }
                    }
                }
            }
        }
Пример #10
0
        /// <summary>
        /// Checks the token text matches a ReSharper suppression.
        /// </summary>
        /// <param name="token">
        /// The token to check.
        /// </param>
        /// <returns>
        /// True if its a ReSharper token otherwise false.
        /// </returns>
        public static bool IsAReSharperComment(CsToken token)
        {
            Param.AssertNotNull(token, "token");

            if (token.CsTokenType != CsTokenType.MultiLineComment && token.CsTokenType != CsTokenType.SingleLineComment && token.CsTokenType != CsTokenType.XmlHeader &&
                token.CsTokenType != CsTokenType.XmlHeaderLine)
            {
                return(false);
            }

            string tokenText = token.Text;

            return(tokenText.StartsWith("// ReSharper disable ") || tokenText.StartsWith("// ReSharper restore "));
        }
        /// <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 constrained.
        /// </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>
        /// 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 constrained.
        /// </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 the curly at the end of a statement which trails the rest of the statement.
        /// </summary>
        /// <param name="element">
        /// The element containing the statement.
        /// </param>
        /// <param name="statement">
        /// The statement to check.
        /// </param>
        private void CheckTrailingStatementCurlyBracketPlacement(CsElement element, Statement statement)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(statement, "statement");

            Node <CsToken> curlyBracket = GetClosingBracketFromStatement(statement);

            if (curlyBracket != null)
            {
                // Find the next token after this closing curly bracket.
                CsToken nextToken = GetNextToken(curlyBracket.Next, statement.Tokens.MasterList);
                if (nextToken != null)
                {
                    this.CheckTokenPrecedingOrFollowingCurlyBracket(element, nextToken);
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Checks a method or method invocation to ensure that the opening bracket is
        /// on the same line as the method declaration.
        /// </summary>
        /// <param name="element">
        /// The element containing the expression.
        /// </param>
        /// <param name="parameterListTokens">
        /// The tokens in the parameter list.
        /// </param>
        /// <param name="openingBracketType">
        /// The type of the bracket that opens the parameter list.
        /// </param>
        /// <param name="textToUseForContainingElement">
        /// The text to use in the violation.
        /// </param>
        /// <returns>
        /// Returns the opening bracket.
        /// </returns>
        private Node <CsToken> CheckMethodOpeningBracket(
            CsElement element, CsTokenList parameterListTokens, CsTokenType openingBracketType, string textToUseForContainingElement)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(parameterListTokens, "parameterListTokens");
            Param.Ignore(openingBracketType);

            // Find the opening bracket.
            Node <CsToken> openingBracketNode = null;

            for (Node <CsToken> tokenNode = parameterListTokens.First; tokenNode != null; tokenNode = tokenNode.Next)
            {
                if (tokenNode.Value.CsTokenType == openingBracketType)
                {
                    openingBracketNode = tokenNode;
                    break;
                }
            }

            CsToken lastWord = null;

            if (openingBracketNode != null)
            {
                // Find the last word before the opening bracket.
                for (Node <CsToken> tokenNode = openingBracketNode.Previous; tokenNode != null; tokenNode = tokenNode.Previous)
                {
                    if (tokenNode.Value.CsTokenType != CsTokenType.WhiteSpace && tokenNode.Value.CsTokenType != CsTokenType.EndOfLine &&
                        tokenNode.Value.CsTokenType != CsTokenType.SingleLineComment && tokenNode.Value.CsTokenType != CsTokenType.MultiLineComment)
                    {
                        lastWord = tokenNode.Value;
                        break;
                    }
                }
            }

            if (lastWord != null)
            {
                if (openingBracketNode.Value.LineNumber != lastWord.LineNumber)
                {
                    this.AddViolation(element, openingBracketNode.Value.LineNumber, Rules.OpeningParenthesisMustBeOnDeclarationLine, textToUseForContainingElement);
                }
            }

            return(openingBracketNode);
        }
        /// <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)
            {
                if (!Utils.IsAReSharperComment(previousOrNextToken))
                {
                    this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedComments);
                }
            }
            else if (previousOrNextToken.CsTokenType == CsTokenType.PreprocessorDirective && previousOrNextToken is Region)
            {
                this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedRegions);
            }
        }
        /// <summary>
        /// Checks the curly bracket placement on a block statement.
        /// </summary>
        /// <param name="element">
        /// The element containing the statement.
        /// </param>
        /// <param name="statement">
        /// The statement to check.
        /// </param>
        private void CheckBlockStatementsCurlyBracketPlacement(CsElement element, Statement statement)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(statement, "statement");

            // Find the opening curly bracket.
            Node <CsToken> curlyBracket = GetOpeningCurlyBracketFromStatement(statement);

            if (curlyBracket != null)
            {
                // Find the previous token before this opening curly bracket.
                CsToken previousToken = GetPreviousToken(curlyBracket.Previous, statement.Tokens.MasterList);
                if (previousToken != null)
                {
                    this.CheckTokenPrecedingOrFollowingCurlyBracket(element, previousToken);
                }
            }
        }
Пример #17
0
        //public override void VisitElement(CsElement element, CsElement parentElement, object context)
        //{
        //    if (element.ElementType == ElementType.Root)
        //    {
        //        element.
        //    }
        //}
        /// <summary>
        /// Visits the token.
        /// </summary>
        /// <param name="document">The document.</param>
        /// <param name="token">The token.</param>
        public override void VisitToken(CodeDocument document, CsToken token)
        {
            if (token.CsTokenType == CsTokenType.EndOfLine && this.lastTokenWasWhitespace)
            {
                this.SourceAnalyzer.AddViolation(document.DocumentContents, token.LineNumber, ContribRule.NoTrailingWhiteSpace);
            }

            if (this.isBeginningOfLine)
            {
                if ((token.CsTokenType == CsTokenType.WhiteSpace) &&
                    (!SpacingAnalyzer.IsValidIndentationWhitespace(token.Text)))
                {
                    this.SourceAnalyzer.AddViolation(document.DocumentContents, token.LineNumber, ContribRule.IndentUsingTabs);
                }

                this.isBeginningOfLine = false;
            }

            this.lastTokenWasWhitespace = token.CsTokenType == CsTokenType.WhiteSpace;
            if (token.CsTokenType == CsTokenType.EndOfLine) this.isBeginningOfLine = true;
        }
Пример #18
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");

            Reference <ICodePart> 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.
            LiteralExpression expression = new LiteralExpression(this.tokens, literalTokenNode);

            expressionReference.Target = expression;

            return(expression);
        }
        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);
        }
Пример #20
0
            /// <summary>
            /// Gets the location of one of the parameters in the list.
            /// </summary>
            /// <param name="index">
            /// The index of a parameter in the list.
            /// </param>
            /// <returns>
            /// Returns the location of the parameters.
            /// </returns>
            public CodeLocation Location(int index)
            {
                Param.AssertValueBetween(index, 0, this.parameters.Count - 1, "index");

                // The location must be calculated by finding the first and last tokens
                // in the parameter and joining their locations.
                CsTokenList tokens = this.parameters[index].Tokens;

                CsToken firstToken = null;

                for (Node <CsToken> tokenNode = tokens.First.Previous; tokenNode != null; tokenNode = tokenNode.Previous)
                {
                    if (tokenNode.Value.CsTokenType == CsTokenType.Comma || tokenNode.Value.CsTokenType == CsTokenType.OpenSquareBracket ||
                        tokenNode.Value.CsTokenType == CsTokenType.OpenParenthesis)
                    {
                        // We've found the start of the parameter list. Now move forward to find the first word.
                        for (tokenNode = tokenNode.Next; tokenNode != null; tokenNode = tokenNode.Next)
                        {
                            if (tokenNode.Value.CsTokenType != CsTokenType.Attribute && tokenNode.Value.CsTokenType != CsTokenType.WhiteSpace &&
                                tokenNode.Value.CsTokenType != CsTokenType.EndOfLine && tokenNode.Value.CsTokenType != CsTokenType.SingleLineComment &&
                                tokenNode.Value.CsTokenType != CsTokenType.MultiLineComment)
                            {
                                firstToken = tokenNode.Value;
                                break;
                            }
                        }

                        break;
                    }
                }

                if (firstToken != null)
                {
                    return(CodeLocation.Join(firstToken.Location, tokens.Last.Value.Location));
                }

                return(this.parameters[index].Location);
            }
        /// <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 || symbol.SymbolType == OperatorType.NullConditional)
                {
                    return true;
                }
            }

            return false;
        }
        /// <summary>
        /// Determines whether the given token is preceded by a member access symbol.
        /// </summary>
        /// <param name="literalTokenNode">
        /// The token to check.
        /// </param>
        /// <param name="masterList">
        /// The list containing the token.
        /// </param>
        /// <returns>
        /// Returns true if the token is preceded by a member access symbol.
        /// </returns>
        private static bool IsLiteralTokenPrecededByMemberAccessSymbol(Node <CsToken> literalTokenNode, MasterList <CsToken> masterList)
        {
            Param.AssertNotNull(literalTokenNode, "literalTokenNode");
            Param.AssertNotNull(masterList, "masterList");

            // Get the previous non-whitespace token.
            CsToken previousToken = ReadabilityRules.GetPreviousToken(literalTokenNode.Previous, masterList);

            if (previousToken == null)
            {
                return(false);
            }

            if (previousToken.CsTokenType == CsTokenType.OperatorSymbol)
            {
                OperatorSymbol symbol = (OperatorSymbol)previousToken;
                if (symbol.SymbolType == OperatorType.MemberAccess || symbol.SymbolType == OperatorType.Pointer || symbol.SymbolType == OperatorType.QualifiedAlias)
                {
                    return(true);
                }
            }

            return(false);
        }
        /// <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 (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;
        }
        /// <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)
            {
                if (!Utils.IsAReSharperComment(previousOrNextToken))
                {
                    this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedComments);
                }
            }
            else if (previousOrNextToken.CsTokenType == CsTokenType.PreprocessorDirective && previousOrNextToken is Region)
            {
                this.AddViolation(element, previousOrNextToken.LineNumber, Rules.BlockStatementsMustNotContainEmbeddedRegions);
            }
        }
        /// <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);

            Reference<ICodePart> 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();

                        Reference<ICodePart> 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();

                        Reference<ICodePart> 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)
            {
                Reference<ICodePart> 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;
        }
        /// <summary>
        /// Checks the token text matches a ReSharper suppression.
        /// </summary>
        /// <param name="token">
        /// The token to check. 
        /// </param>
        /// <returns>
        /// True if its a ReSharper token otherwise false. 
        /// </returns>
        public static bool IsAReSharperComment(CsToken token)
        {
            Param.AssertNotNull(token, "token");

            if (token.CsTokenType != CsTokenType.MultiLineComment && token.CsTokenType != CsTokenType.SingleLineComment && token.CsTokenType != CsTokenType.XmlHeader
                && token.CsTokenType != CsTokenType.XmlHeaderLine)
            {
                return false;
            }

            string tokenText = token.Text;
            return tokenText.StartsWith("// ReSharper disable ") || tokenText.StartsWith("// ReSharper restore ");
        }
        /// <summary>
        /// Checks to make sure that preprocessor type keyword is not preceded by a space.
        /// </summary>
        /// <param name="preprocessor">
        /// The preprocessor token.
        /// </param>
        private void CheckPreprocessorSpacing(CsToken preprocessor)
        {
            Param.AssertNotNull(preprocessor, "preprocessor");

            if (preprocessor.Text.Length > 1)
            {
                if (preprocessor.Text[0] == '#')
                {
                    if (preprocessor.Text[1] == ' ' || preprocessor.Text[1] == '\t')
                    {
                        this.AddViolation(preprocessor.FindParentElement(), preprocessor.Location, Rules.PreprocessorKeywordsMustNotBePrecededBySpace);
                    }
                }
            }
        }
Пример #28
0
        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)
                    {
                        bool throwViolation = false;

                        // The blank line is just before an opening curly bracket.
                        // If next element back is if,while,catch,try,finally,do,else,lock,switch,unsafe, using, array init, delegate, it's a violation.
                        if (precedingTokenNode == null)
                        {
                            throwViolation = true;
                        }
                        else
                        {
                            Statement parentStatement = precedingTokenNode.Value.FindParentStatement();
                            if (parentStatement == null)
                            {
                                throwViolation = true;
                            }
                            else
                            {
                                StatementType statementType = parentStatement.StatementType;

                                if (statementType == StatementType.If || statementType == StatementType.While || statementType == StatementType.Catch
                                    || statementType == StatementType.Try || statementType == StatementType.Finally || statementType == StatementType.DoWhile
                                    || statementType == StatementType.Else || statementType == StatementType.Lock || statementType == StatementType.Switch
                                    || statementType == StatementType.Unsafe || statementType == StatementType.Using)
                                {
                                    throwViolation = true;
                                }
                                else if (statementType == StatementType.VariableDeclaration && precedingTokenNode.Value.CsTokenType != CsTokenType.Semicolon)
                                {
                                    throwViolation = true;
                                }
                                else if (statementType == StatementType.Expression && precedingTokenNode.Value.CsTokenType == CsTokenType.Delegate)
                                {
                                    throwViolation = true;
                                }
                            }
                        }

                        if (throwViolation)
                        {
                            this.AddViolation(token.FindParentElement(), token.Location, 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) && !Utils.IsAReSharperComment(token))
                            {
                                CsElement element = token.FindParentElement();

                                if (element != null)
                                {
                                    this.AddViolation(element, 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 && token.CsTokenType != CsTokenType.Select && token.CsTokenType != CsTokenType.From
                            && token.CsTokenType != CsTokenType.Let && token.CsTokenType != CsTokenType.OperatorSymbol && token.CsTokenType != CsTokenType.By)
                        {
                            this.AddViolation(closingCurlyBracket.FindParentElement(), closingCurlyBracket.LineNumber, Rules.ClosingCurlyBracketMustBeFollowedByBlankLine);
                        }
                    }
                }
            }
        }
Пример #29
0
        /// <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);

                Reference<ICodePart> genericTypeReference = new Reference<ICodePart>(generic);
                foreach (CsToken token in genericArgumentTokens)
                {
                    token.ParentRef = genericTypeReference;
                }
            }

            return generic;
        }
Пример #30
0
        private void CheckForEmptyComments(DocumentRoot element)
        {
            Param.AssertNotNull(element, "element");

            // Loop through all the tokens in the file looking for comments.
            for (Node <CsToken> tokenNode = element.Tokens.First; !element.Tokens.OutOfBounds(tokenNode); tokenNode = tokenNode.Next)
            {
                if (this.Cancel)
                {
                    break;
                }

                CsToken token = tokenNode.Value;

                // Skip generated code.
                if (!token.Generated)
                {
                    // Check for the two comment types.
                    if (token.CsTokenType == CsTokenType.SingleLineComment)
                    {
                        // This is a single line comment.
                        int  slashCount = 0;
                        bool found      = false;

                        // Loop through the characters in the comment text.
                        for (int character = 0; character < token.Text.Length; ++character)
                        {
                            // See if we've found the slashes at the beginning of the comment
                            if (slashCount == 2)
                            {
                                // Check whether there's anything here other than whitespace.
                                // If so, then this comment is ok.
                                if (token.Text[character] != ' ' && token.Text[character] != '\t' && token.Text[character] != '\r' && token.Text[character] != '\n')
                                {
                                    found = true;
                                    break;
                                }
                            }
                            else if (token.Text[character] == '/')
                            {
                                ++slashCount;
                            }
                        }

                        // Check whether the comment contained any text.
                        if (!found)
                        {
                            // This is only allowed if this comment is sandwiched in between two other comments.
                            bool comment = false;
                            int  lines   = 0;
                            foreach (CsToken item in element.Tokens.ReverseIterator(tokenNode.Previous))
                            {
                                if (item.Text == "\n")
                                {
                                    ++lines;
                                    if (lines > 1)
                                    {
                                        break;
                                    }
                                }
                                else if (item.CsTokenType == CsTokenType.SingleLineComment)
                                {
                                    comment = true;
                                    break;
                                }
                                else if (item.CsTokenType != CsTokenType.WhiteSpace)
                                {
                                    break;
                                }
                            }

                            if (!comment)
                            {
                                CsElement errorElement = token.Parent as CsElement ?? element;
                                this.AddViolation(errorElement, token.Location, Rules.CommentsMustContainText);
                            }
                            else
                            {
                                comment = false;
                                lines   = 0;
                                foreach (CsToken item in element.Tokens.ForwardIterator(tokenNode.Next))
                                {
                                    if (item.Text == "\n")
                                    {
                                        ++lines;
                                        if (lines > 1)
                                        {
                                            break;
                                        }
                                    }
                                    else if (item.CsTokenType == CsTokenType.SingleLineComment)
                                    {
                                        comment = true;
                                        break;
                                    }
                                    else if (item.CsTokenType != CsTokenType.WhiteSpace)
                                    {
                                        break;
                                    }
                                }

                                if (!comment)
                                {
                                    CsElement errorElement = token.Parent as CsElement ?? element;
                                    this.AddViolation(errorElement, token.Location, Rules.CommentsMustContainText);
                                }
                            }
                        }
                    }
                    else if (token.CsTokenType == CsTokenType.MultiLineComment)
                    {
                        // The is a multi-line comment. Get the start of the comment.
                        int start = token.Text.IndexOf("/*", StringComparison.Ordinal);
                        if (start > -1)
                        {
                            // Get the end of the comment
                            int end = token.Text.IndexOf("*/", start + 2, StringComparison.Ordinal);
                            if (end > -1)
                            {
                                // Look at the characters between the start and the end and see if there
                                // is anything here besides whitespace.
                                bool found = false;
                                for (int character = start + 2; character < end; ++character)
                                {
                                    if (token.Text[character] != ' ' && token.Text[character] != '\t' && token.Text[character] != '\r' && token.Text[character] != '\n')
                                    {
                                        found = true;
                                        break;
                                    }
                                }

                                // Check whether the comment contained any text.
                                if (!found)
                                {
                                    CsElement errorElement = token.Parent as CsElement ?? element;
                                    this.AddViolation(errorElement, token.Location, Rules.CommentsMustContainText);
                                }
                            }
                        }
                    }
                }
            }
        }
Пример #31
0
        /// <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;
        }
        /// <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");

            word = word.SubstringAfter('@');
            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>
        /// 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");

            word = word.SubstringAfter('@');
            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>
        /// Compares the token to the Operator symbol and to a dot '.'.
        /// </summary>
        /// <param name="token">
        /// The token to check.
        /// </param>
        /// <returns>
        /// True is the token is an operator and a dot '.', otherwise false.
        /// </returns>
        private static bool IsTokenADot(CsToken token)
        {
            Param.AssertNotNull(token, "token");

            if (token.CsTokenType == CsTokenType.OperatorSymbol)
            {
                OperatorSymbol symbol = (OperatorSymbol)token;
                if (symbol.SymbolType == OperatorType.MemberAccess)
                {
                    return symbol.Text == ".";
                }
            }

            return false;
        }
Пример #35
0
        /// <summary>
        /// Checks the generic type uses the shorthand declaration format.
        /// </summary>
        /// <param name="type">
        /// The <see cref="CsToken"/> to check.
        /// </param>
        private void CheckShorthandForNullableTypes(CsToken type)
        {
            Param.AssertNotNull(type, "type");

            Debug.Assert(type.CsTokenClass == CsTokenClass.GenericType, "Expected a generic type.");
            GenericType genericType = (GenericType)type;

            // Check the declaration of the generic type for longhand, but allow Nullable<> which has no shorthand
            if (genericType.ChildTokens.Count > 0 && Utils.TokenContainNullable(genericType.ChildTokens.First))
            {
                if (genericType.Parent == null || !(genericType.Parent is TypeofExpression))
                {
                    if (genericType.Parent is Method)
                    {
                        Method parentMethod = genericType.Parent as Method;
                        if (parentMethod.Name == parentMethod.FriendlyTypeText + " " + genericType.Text)
                        {
                            return;
                        }
                    }

                    this.AddViolation(genericType.FindParentElement(), genericType.LineNumber, Rules.UseShorthandForNullableTypes);
                }
            }
            else
            {
                // Check the parameters of the generic type because the declaration may be nested
                foreach (
                    GenericTypeParameter genericTypeParameter in genericType.GenericTypesParameters.Where(token => token.Type.CsTokenClass == CsTokenClass.GenericType))
                {
                    this.CheckShorthandForNullableTypes(genericTypeParameter.Type);
                }
            }
        }
        /// <summary>
        /// Checks for tabs in the given comment.
        /// </summary>
        /// <param name="comment">
        /// The comment token.
        /// </param>
        private void CheckTabsInComment(CsToken comment)
        {
            Param.AssertNotNull(comment, "comment");

            int lineEnds = 0;

            for (int i = 0; i < comment.Text.Length; ++i)
            {
                if (comment.Text[i] == '\t')
                {
                    this.AddViolation(comment.FindParentElement(), comment.Location, Rules.TabsMustNotBeUsed);
                }
                else if (comment.Text[i] == '\n')
                {
                    ++lineEnds;
                }
            }
        }
 /// <summary>
 /// Joins the locations of the two tokens.
 /// </summary>
 /// <param name="location1">
 /// The first location.
 /// </param>
 /// <param name="token2">
 /// The second token.
 /// </param>
 /// <returns>
 /// Returns the joined locations.
 /// </returns>
 internal static CodeLocation JoinLocations(CodeLocation location1, CsToken token2)
 {
     Param.Ignore(location1, token2);
     return token2 == null ? CodeLocation.Join(location1, null) : CodeLocation.Join(location1, token2.Location);
 }
        /////// <summary>
        /////// Joins the locations of the two tokens.
        /////// </summary>
        /////// <param name="token1">The first token.</param>
        /////// <param name="location2">The second location.</param>
        /////// <returns>Returns the joined locations.</returns>
        ////internal static CodeLocation JoinLocations(Node<CsToken> token1, CodeLocation location2)
        ////{
        ////    Param.Ignore(token1, location2);
        ////    return CsToken.JoinLocations(token1 == null ? null : token1.Value, location2);
        ////}

        /// <summary>
        /// Joins the locations of the two tokens.
        /// </summary>
        /// <param name="token1">
        /// The first token.
        /// </param>
        /// <param name="token2">
        /// The second token.
        /// </param>
        /// <returns>
        /// Returns the joined locations.
        /// </returns>
        internal static CodeLocation JoinLocations(CsToken token1, CsToken token2)
        {
            Param.AssertNotNull(token1, "token1");
            Param.AssertNotNull(token2, "token2");
            
            return CodeLocation.Join(token1.Location, token2.Location);
        }
        /// <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");

            Reference<ICodePart> 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.
            LiteralExpression expression = new LiteralExpression(this.tokens, literalTokenNode);
            expressionReference.Target = expression;

            return expression;
        }
Пример #40
0
        /// <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);

            Reference <ICodePart> 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();

                    Reference <ICodePart> 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();

                    Reference <ICodePart> 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)
            {
                Reference <ICodePart> 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);
        }
Пример #41
0
        /// <summary>
        /// Returns the net count of opening and closing 'code' and 'c' elements for the token provided.
        /// </summary>
        /// <param name="token">
        /// The xml header line token.
        /// </param>
        /// <returns>
        /// The net count of open and close 'code' and 'c' elements.
        /// </returns>
        private static int XmlHeaderLineCodeElementCount(CsToken token)
        {
            Param.AssertNotNull(token, "token");
            Debug.Assert(token.CsTokenType == CsTokenType.XmlHeaderLine, "The token should be an xml header line");

            string lineText = token.Text;

            // Search for '<code ' without the closing tag because sometimes users have added attributes like <code lang="C#"> and <code> too
            int openCodeTagCount = CountOfStringInStringOccurrences(lineText, "<code ", "<code>", "<c>");
            int closeCodeTagCount = CountOfStringInStringOccurrences(lineText, "</code>", "</c>");

            return openCodeTagCount - closeCodeTagCount;
        }
Пример #42
0
 /// <summary>
 /// Joins the locations of the two tokens.
 /// </summary>
 /// <param name="location1">
 /// The first location.
 /// </param>
 /// <param name="token2">
 /// The second token.
 /// </param>
 /// <returns>
 /// Returns the joined locations.
 /// </returns>
 internal static CodeLocation JoinLocations(CodeLocation location1, CsToken token2)
 {
     Param.Ignore(location1, token2);
     return(token2 == null?CodeLocation.Join(location1, null) : CodeLocation.Join(location1, token2.Location));
 }
Пример #43
0
        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;
        }
Пример #44
0
        /////// <summary>
        /////// Joins the locations of the two tokens.
        /////// </summary>
        /////// <param name="token1">The first token.</param>
        /////// <param name="token2">The second token.</param>
        /////// <returns>Returns the joined locations.</returns>
        ////internal static CodeLocation JoinLocations(Node<CsToken> token1, CsToken token2)
        ////{
        ////    Param.Ignore(token1, token2);
        ////    return CsToken.JoinLocations(token1 == null ? null : token1.Value, token2);
        ////}

        /////// <summary>
        /////// Joins the locations of the two tokens.
        /////// </summary>
        /////// <param name="token1">The first token.</param>
        /////// <param name="token2">The second token.</param>
        /////// <returns>Returns the joined locations.</returns>
        ////internal static CodeLocation JoinLocations(CsToken token1, Node<CsToken> token2)
        ////{
        ////    Param.Ignore(token1, token2);
        ////    return CsToken.JoinLocations(token1, token2 == null ? null : token2.Value);
        ////}

        /// <summary>
        /// Joins the locations of the two tokens.
        /// </summary>
        /// <param name="token1">
        /// The first token.
        /// </param>
        /// <param name="token2">
        /// The second token.
        /// </param>
        /// <returns>
        /// Returns the joined locations.
        /// </returns>
        internal static CodeLocation JoinLocations(Node <CsToken> token1, Node <CsToken> token2)
        {
            Param.Ignore(token1, token2);
            return(CsToken.JoinLocations(token1 == null ? null : token1.Value, token2 == null ? null : token2.Value));
        }
        /// <summary>
        /// Initializes a new instance of the Argument class.
        /// </summary>
        /// <param name="name">
        /// The optional name of the argument.
        /// </param>
        /// <param name="modifiers">
        /// Modifiers 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;
        }
Пример #46
0
        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;
                        Reference<ICodePart> 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;
        }
Пример #47
0
        /// <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;

            Reference<ICodePart> 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);

            VariableDeclarationStatement statement = new VariableDeclarationStatement(partialTokens, constant, expression);
            statementReference.Target = statement;

            return statement;
        }
Пример #48
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);

            Reference<ICodePart> 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
            {
                int index = this.GetNextCodeSymbolIndex(1);
                if (index != -1)
                {
                    // Look ahead to the next symbol to see what it is.
                    Symbol symbol = this.symbols.Peek(index);

                    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);
                        this.AdvanceToNextCodeSymbol(variableReference);

                        // 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;
        }
Пример #49
0
 /// <summary>
 /// Visits the token.
 /// </summary>
 /// <param name="document">The document.</param>
 /// <param name="token">The token.</param>
 public virtual void VisitToken(CodeDocument document, CsToken token)
 {
 }