/// <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);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Initializes a new instance of the Delegate class.
        /// </summary>
        /// <param name="document">
        /// The document that contains the element.
        /// </param>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="header">
        /// The Xml header for this element.
        /// </param>
        /// <param name="attributes">
        /// The list of attributes attached to this element.
        /// </param>
        /// <param name="declaration">
        /// The declaration code for this element.
        /// </param>
        /// <param name="returnType">
        /// The return type.
        /// </param>
        /// <param name="parameters">
        /// The parameters to the delegate.
        /// </param>
        /// <param name="typeConstraints">
        /// The list of type constraints on the element.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the element resides within a block of unsafe code.
        /// </param>
        /// <param name="generated">
        /// Indicates whether this is generated code.
        /// </param>
        internal Delegate(
            CsDocument document,
            CsElement parent,
            XmlHeader header,
            ICollection <Attribute> attributes,
            Declaration declaration,
            TypeToken returnType,
            IList <Parameter> parameters,
            ICollection <TypeParameterConstraintClause> typeConstraints,
            bool unsafeCode,
            bool generated)
            : base(document, parent, ElementType.Delegate, "delegate " + declaration.Name, header, attributes, declaration, unsafeCode, generated)
        {
            Param.AssertNotNull(document, "document");
            Param.AssertNotNull(parent, "parent");
            Param.Ignore(header);
            Param.Ignore(attributes);
            Param.AssertNotNull(declaration, "declaration");
            Param.AssertNotNull(returnType, "returnType");
            Param.AssertNotNull(parameters, "parameters");
            Param.Ignore(typeConstraints);
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);

            this.returnType      = returnType;
            this.typeConstraints = typeConstraints;
            this.parameters      = parameters;

            Debug.Assert(parameters.IsReadOnly, "The parameters collection should be read-only.");

            // Add the qualifications
            this.QualifiedName = CodeParser.AddQualifications(this.parameters, this.QualifiedName);

            // Set the parent of the type constraint clauses.
            if (typeConstraints != null)
            {
                Debug.Assert(typeConstraints.IsReadOnly, "The collection of type constraints should be read-only.");

                foreach (TypeParameterConstraintClause constraint in typeConstraints)
                {
                    constraint.ParentElement = this;
                }
            }
        }
示例#3
0
        /// <summary>
        /// Initializes a new instance of the Constructor class.
        /// </summary>
        /// <param name="document">
        /// The document that contains the element.
        /// </param>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="header">
        /// The Xml header for this element.
        /// </param>
        /// <param name="attributes">
        /// The list of attributes attached to this element.
        /// </param>
        /// <param name="declaration">
        /// The declaration code for this element.
        /// </param>
        /// <param name="parameters">
        /// The parameters to the constructor.
        /// </param>
        /// <param name="initializerExpression">
        /// The constructor initializer, if there is one.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the element resides within a block of unsafe code.
        /// </param>
        /// <param name="generated">
        /// Indicates whether the code element was generated or written by hand.
        /// </param>
        internal Constructor(
            CsDocument document,
            CsElement parent,
            XmlHeader header,
            ICollection <Attribute> attributes,
            Declaration declaration,
            IList <Parameter> parameters,
            MethodInvocationExpression initializerExpression,
            bool unsafeCode,
            bool generated)
            : base(document, parent, ElementType.Constructor, "constructor " + declaration.Name, header, attributes, declaration, unsafeCode, generated)
        {
            Param.AssertNotNull(document, "document");
            Param.AssertNotNull(parent, "parent");
            Param.Ignore(header);
            Param.Ignore(attributes);
            Param.AssertNotNull(declaration, "declaration");
            Param.AssertNotNull(parameters, "parameters");
            Param.Ignore(initializerExpression);
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);

            // Static constructors are treated as private and handled as a special case for ordering.
            if (this.Declaration.ContainsModifier(CsTokenType.Static))
            {
                this.Declaration.AccessModifierType = AccessModifierType.Private;
            }

            this.parameters = parameters;
            Debug.Assert(parameters.IsReadOnly, "The parameters collection should be read-only.");

            // Add the qualifications
            this.QualifiedName = CodeParser.AddQualifications(this.parameters, this.QualifiedName);

            // If there is an initializer expression, add it to the statement list for this constructor.
            if (initializerExpression != null)
            {
                this.initializer = initializerExpression;

                ConstructorInitializerStatement initializerStatement = new ConstructorInitializerStatement(initializerExpression.Tokens, initializerExpression);
                this.AddStatement(initializerStatement);
            }
        }
示例#4
0
        /// <summary>
        /// Returns True if the text has incorrect spelling.
        /// </summary>
        /// <param name="element">
        /// The element containing the text we're checking.
        /// </param>
        /// <param name="text">
        /// The text to check.
        /// </param>
        /// <param name="spellingError">
        /// Returns a comma separated list of words encountered as spelling errors.
        /// </param>
        /// <returns>
        /// True if the text contains an incorrect spelling.
        /// </returns>
        private static bool TextContainsIncorectSpelling(CsElement element, string text, out string spellingError)
        {
            NamingService namingService = NamingService.GetNamingService(element.Document.SourceCode.Project.Culture);

            spellingError = string.Empty;

            if (namingService.SupportsSpelling)
            {
                ICollection <string> recognizedWords = element.Document.SourceCode.Project.RecognizedWords;

                WordParser parser = new WordParser(text, WordParserOptions.SplitCompoundWords, recognizedWords);
                if (parser.PeekWord() != null)
                {
                    string word = parser.NextWord();
                    do
                    {
                        // Ignore words starting and ending with '$'.
                        // Ignore if in our recognized words list or correct spelling
                        string hint = null;
                        if ((word.StartsWith("$") && word.EndsWith("$")) || (recognizedWords.Contains(word) || IsSpelledCorrectly(namingService, word, out hint)))
                        {
                            continue;
                        }

                        // If we already have a spelling error for this element, add a comma to separate them.
                        if (!string.IsNullOrEmpty(spellingError))
                        {
                            spellingError += ", ";
                        }

                        spellingError += "'" + word + "'";

                        // Append a hint message to this spelling error if we have one.
                        if (hint != null && hint.Trim().Length > 0)
                        {
                            spellingError += " " + hint;
                        }
                    }while ((word = parser.NextWord()) != null);
                }
            }

            return(!string.IsNullOrEmpty(spellingError));
        }
示例#5
0
        /// <summary>
        /// Adds a rule suppression for the given element.
        /// </summary>
        /// <param name="element">
        /// The element.
        /// </param>
        /// <param name="ruleId">
        /// The ID of the rule to suppress.
        /// </param>
        /// <param name="ruleName">
        /// The name of the rule.
        /// </param>
        /// <param name="ruleNamespace">
        /// The namespace in which the rule is contained.
        /// </param>
        internal void AddRuleSuppression(CsElement element, string ruleId, string ruleName, string ruleNamespace)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertValidString(ruleId, "ruleId");
            Param.Assert(ruleId == "*" || !string.IsNullOrEmpty(ruleName), "ruleName", "Rule name is invalid.");
            Param.AssertValidString(ruleNamespace, "ruleNamespace");

            SuppressedRule suppressedRule = new SuppressedRule {
                RuleId = ruleId, RuleName = ruleName, RuleNamespace = ruleNamespace
            };

            // Need a writer lock arond this entire section to ensure thread safety of dictionary
            // and the lists contained inside.
            this.suppressionsLock.AcquireWriterLock(Timeout.Infinite);

            try
            {
                // Determine whether there is already at least one suppression for some element for this rule.
                List <CsElement> elementsContainingSuppressedRule = null;
                bool             foundElementList = false;

                if (this.suppressions.Count != 0)
                {
                    foundElementList = this.suppressions.TryGetValue(suppressedRule, out elementsContainingSuppressedRule);
                }

                Debug.Assert(
                    !foundElementList || elementsContainingSuppressedRule != null, "The returned list of elements containing the suppressed rule should never be null.");

                if (!foundElementList)
                {
                    // This is the first suppression for this rule type.
                    elementsContainingSuppressedRule = new List <CsElement>();
                    this.suppressions.Add(suppressedRule, elementsContainingSuppressedRule);
                }

                elementsContainingSuppressedRule.Add(element);
            }
            finally
            {
                this.suppressionsLock.ReleaseWriterLock();
            }
        }
        private bool WalkMethods(CsElement element, CsElement parentElement, object context)
        {
            if (element.ElementType != ElementType.Method)
            {
                return(true);
            }

            var method = (Method)element;

            foreach (MethodVisitorInfo methodVisitor in this.methodVisitors)
            {
                foreach (MethodViolationData violationData in methodVisitor.MethodVisitor.Visit(method))
                {
                    this.AddViolation(method, method.Location, methodVisitor.RuleName, violationData.Parameters);
                }
            }

            return(true);
        }
        /// <summary>
        /// Checks the given list of expressions.
        /// </summary>
        /// <param name="element">
        /// The element containing the expressions.
        /// </param>
        /// <param name="expressions">
        /// The list of expressions.
        /// </param>
        private void CheckStatementFormattingRulesForExpressions(CsElement element, ICollection <Expression> expressions)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(expressions, "expressions");

            foreach (Expression expression in expressions)
            {
                if (expression.ExpressionType == ExpressionType.AnonymousMethod)
                {
                    // Check the statements within this anonymous method expression.
                    AnonymousMethodExpression anonymousMethod = expression as AnonymousMethodExpression;
                    this.CheckStatementFormattingRulesForStatements(element, anonymousMethod.ChildStatements);
                }
                else
                {
                    // Check the child expressions under this expression.
                    this.CheckStatementFormattingRulesForExpressions(element, expression.ChildExpressions);
                }
            }
        }
示例#8
0
文件: Utils.cs 项目: sarvex/StyleCop
        /// <summary>
        /// Finds the ClassBase object above this element representing a Class or Struct.
        /// </summary>
        /// <param name="element">
        /// The element to start at.
        /// </param>
        /// <returns>
        /// The ClassBase for the element.
        /// </returns>
        public static ClassBase GetClassBase(CsElement element)
        {
            bool foundParentClass = false;

            ICodePart parent = element.Parent;

            while (!foundParentClass && parent != null)
            {
                if (parent is ClassBase)
                {
                    foundParentClass = true;
                }
                else
                {
                    parent = parent.Parent;
                }
            }

            return(parent as ClassBase);
        }
示例#9
0
        /// <summary>
        /// Checks the argument list to a method or method invocation to ensure that the arguments are
        /// positioned correctly.
        /// </summary>
        /// <param name="element">
        /// The element containing the expression.
        /// </param>
        /// <param name="arguments">
        /// The arguments to the method.
        /// </param>
        /// <param name="openingBracketNode">
        /// The opening bracket token.
        /// </param>
        /// <param name="methodLineNumber">
        /// The line number on which the method begins.
        /// </param>
        /// <param name="friendlyTypeText">
        /// The text to use for the type in reporting violations.
        /// </param>
        private void CheckMethodArgumentList(CsElement element, IArgumentList arguments, Node <CsToken> openingBracketNode, int methodLineNumber, string friendlyTypeText)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(arguments, "arguments");
            Param.AssertNotNull(openingBracketNode, "openingBracketNode");
            Param.AssertGreaterThanZero(methodLineNumber, "methodLineNumber");

            // Determine whether all of the parameters are on the same line as one another.
            bool someParametersShareLine;
            bool someParameterOnDifferentLines;

            DetermineMethodParameterPlacementScheme(arguments, out someParametersShareLine, out someParameterOnDifferentLines);

            // All parameters must either be on the same line, or each parameter must begin on its own line.
            if (someParametersShareLine && someParameterOnDifferentLines)
            {
                this.AddViolation(element, methodLineNumber, Rules.ParametersMustBeOnSameLineOrSeparateLines, friendlyTypeText);
            }

            // Determine whether all of the parameters are on the same line as one another.
            if (someParameterOnDifferentLines)
            {
                this.CheckSplitMethodArgumentList(element, arguments, openingBracketNode, friendlyTypeText);
            }
            else if (arguments.Count > 0)
            {
                // The first argument must start on the same line as the opening bracket, or
                // on the line after it.
                int firstArgumentStartLine = arguments.Location(0).LineNumber;

                if (firstArgumentStartLine != openingBracketNode.Value.LineNumber && firstArgumentStartLine != openingBracketNode.Value.LineNumber + 1)
                {
                    int commentLineSpan = MeasureCommentLinesAfter(openingBracketNode);

                    if (firstArgumentStartLine != openingBracketNode.Value.LineNumber + commentLineSpan + 1)
                    {
                        this.AddViolation(element, firstArgumentStartLine, Rules.ParameterListMustFollowDeclaration);
                    }
                }
            }
        }
        /// <summary>
        /// Checks the placement of statements within the given element.
        /// </summary>
        /// <param name="element">
        /// The element to check.
        /// </param>
        private void CheckStatementFormattingRulesForElement(CsElement element)
        {
            Param.AssertNotNull(element, "element");

            if (!element.Generated)
            {
                if (element.ElementType == ElementType.EmptyElement)
                {
                    this.AddViolation(element, element.LineNumber, Rules.CodeMustNotContainEmptyStatements);
                }
                else
                {
                    this.CheckStatementFormattingRulesForStatements(element, element.ChildStatements);

                    foreach (CsElement child in element.ChildElements)
                    {
                        this.CheckStatementFormattingRulesForElement(child);
                    }
                }
            }
        }
示例#11
0
        /// <summary>
        /// Checks the order of elements that appear within the given element.
        /// </summary>
        /// <param name="element">
        /// The element to check.
        /// </param>
        /// <param name="checkGeneratedCode">
        /// True to check the element order of generated code blocks.
        /// </param>
        private void CheckElementOrder(CsElement element, bool checkGeneratedCode)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(checkGeneratedCode);

            // Check the ordering of the keywords in the element's declaration.
            if (!element.Generated &&
                (element.ElementType == ElementType.Class || element.ElementType == ElementType.Field || element.ElementType == ElementType.Enum ||
                 element.ElementType == ElementType.Struct || element.ElementType == ElementType.Interface || element.ElementType == ElementType.Delegate ||
                 element.ElementType == ElementType.Event || element.ElementType == ElementType.Property || element.ElementType == ElementType.Indexer ||
                 element.ElementType == ElementType.Method || element.ElementType == ElementType.Constructor || element.ElementType == ElementType.Accessor))
            {
                this.CheckDeclarationKeywordOrder(element);
            }

            // Make sure that using directives are inside of namespace elements.
            this.CheckUsingDirectivePlacement(element);

            // Checks the order of the children of this element.
            this.CheckChildElementOrdering(element, checkGeneratedCode);
        }
        /// <summary>
        /// Parses the given statement list.
        /// </summary>
        /// <param name="statements">
        /// The list of statements to parse.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the statements.
        /// </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 CheckClassMemberRulesForStatements(
            ICollection <Statement> statements, CsElement parentElement, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(statements, "statements");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the statements.
            foreach (Statement statement in statements)
            {
                if (statement.ChildStatements.Count > 0)
                {
                    // Parse the sub-statements.
                    this.CheckClassMemberRulesForStatements(statement.ChildStatements, parentElement, parentClass, members);
                }

                // Parse the expressions in the statement.
                this.CheckClassMemberRulesForExpressions(statement.ChildExpressions, null, parentElement, parentClass, members);
            }
        }
示例#13
0
        /// <summary>
        /// Initializes a new instance of the <see cref="CodeWalker{T}"/> class.
        /// Initializes a new instance of the CodeWalker class.
        /// </summary>
        /// <param name="element">
        /// The element to walk through.
        /// </param>
        /// <param name="elementCallback">
        /// Callback executed when an element is visited.
        /// </param>
        /// <param name="statementCallback">
        /// Callback executed when a statement is visited.
        /// </param>
        /// <param name="expressionCallback">
        /// Callback executed when an expression is visited.
        /// </param>
        /// <param name="queryClauseCallback">
        /// Callback executed when a query clause is visited.
        /// </param>
        /// <param name="context">
        /// The optional visitor context data.
        /// </param>
        private CodeWalker(
            CsElement element,
            CodeWalkerElementVisitor <T> elementCallback,
            CodeWalkerStatementVisitor <T> statementCallback,
            CodeWalkerExpressionVisitor <T> expressionCallback,
            CodeWalkerQueryClauseVisitor <T> queryClauseCallback,
            T context)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(elementCallback);
            Param.Ignore(statementCallback);
            Param.Ignore(expressionCallback);
            Param.Ignore(queryClauseCallback);
            Param.Ignore(context);

            this.elementCallback     = elementCallback;
            this.statementCallback   = statementCallback;
            this.expressionCallback  = expressionCallback;
            this.queryClauseCallback = queryClauseCallback;

            this.WalkElement(element, element.FindParentElement(), context);
        }
示例#14
0
        /// <summary>
        /// Fills in the details of the get accessor.
        /// </summary>
        /// <param name="parent">
        /// The parent of the accessor.
        /// </param>
        private void FillGetAccessorDetails(CsElement parent)
        {
            Param.AssertNotNull(parent, "parent");

            Property property = parent as Property;

            if (property != null)
            {
                // Get accessors on properties have the return type of their parent property,
                // and have no input parameters.
                this.returnType = property.ReturnType;
            }
            else
            {
                // Get accessors on indexers have the return type of their parent indexer,
                // and have the input parameters of the parent indexer.
                Indexer indexer = (Indexer)parent;

                this.returnType = indexer.ReturnType;
                this.parameters = indexer.Parameters;
            }
        }
示例#15
0
        /// <summary>
        /// Checks a variable for hungarian notation.
        /// </summary>
        /// <param name="name">
        /// The variable name.
        /// </param>
        /// <param name="startIndex">
        /// The index in the name where the actual name begins.
        /// </param>
        /// <param name="line">
        /// The number number that this variable appears on, or if 0, uses the line number
        /// from the element object.
        /// </param>
        /// <param name="element">
        /// The element that the variable appears in.
        /// </param>
        /// <param name="validPrefixes">
        /// A list of valid prefixes that should not be considered hungarian.
        /// </param>
        private void CheckHungarian(string name, int startIndex, int line, CsElement element, Dictionary <string, string> validPrefixes)
        {
            Param.AssertValidString(name, "name");
            Param.AssertGreaterThanOrEqualToZero(startIndex, "startIndex");
            Param.AssertGreaterThanZero(line, "line");
            Param.AssertNotNull(element, "element");
            Param.Ignore(validPrefixes);

            if (name.Length - startIndex > 3)
            {
                string prefix = null;
                for (int i = startIndex + 1; i < 3 + startIndex; ++i)
                {
                    if (char.IsUpper(name, i))
                    {
                        prefix = name.Substring(startIndex, i - startIndex);
                        break;
                    }
                }

                if (prefix != null)
                {
                    bool found = false;
                    if (validPrefixes != null)
                    {
                        if (validPrefixes.ContainsKey(prefix))
                        {
                            found = true;
                        }
                    }

                    if (!found)
                    {
                        this.AddViolation(element, line, Rules.FieldNamesMustNotUseHungarianNotation, name);
                    }
                }
            }
        }
示例#16
0
        private bool IsSpecialCaseExclusion(CsElement first, CsElement second)
        {
            //// Note: While many checks here are redundant/unnecessary, they are explictly specified to
            //// avoid any ambiguity.

            // Special case for static constructors, which are always private but should still appear in front of all other constructors.
            if (first.ElementType == ElementType.Constructor && second.ElementType == ElementType.Constructor &&
                first.Declaration.ContainsModifier(CsTokenType.Static) && !second.Declaration.ContainsModifier(CsTokenType.Static))
            {
                return(true);
            }

            // Special case for readonly dependency property pattern.
            if (first.ElementType == ElementType.Field && second.ElementType == ElementType.Field &&
                first.Declaration.ContainsModifier(CsTokenType.Static) && second.Declaration.ContainsModifier(CsTokenType.Static) &&
                first.AccessModifier == AccessModifierType.Private && second.AccessModifier == AccessModifierType.Public &&
                first.Declaration.Tokens.Any(t => t.CsTokenClass == CsTokenClass.Type && t.Text == "DependencyPropertyKey"))
            {
                return(true);
            }

            return(false);
        }
示例#17
0
        /// <summary>
        /// Processes the given element.
        /// </summary>
        /// <param name="element">
        /// The element being visited.
        /// </param>
        private void CheckMethodParameters(CsElement element)
        {
            Param.AssertNotNull(element, "element");

            IList <Parameter> parameters       = null;
            CsTokenType       openBracketType  = CsTokenType.OpenParenthesis;
            CsTokenType       closeBracketType = CsTokenType.CloseParenthesis;

            if (element.ElementType == ElementType.Constructor)
            {
                parameters = ((Constructor)element).Parameters;
            }
            else if (element.ElementType == ElementType.Delegate)
            {
                parameters = ((Delegate)element).Parameters;
            }
            else if (element.ElementType == ElementType.Method)
            {
                parameters = ((Method)element).Parameters;
            }
            else if (element.ElementType == ElementType.Indexer)
            {
                parameters       = ((Indexer)element).Parameters;
                openBracketType  = CsTokenType.OpenSquareBracket;
                closeBracketType = CsTokenType.CloseSquareBracket;
            }

            if (parameters != null)
            {
                ParameterList parameterList       = new ParameterList(parameters);
                CsTokenList   parameterListTokens = GetParameterListTokens(element.Declaration.Tokens, openBracketType, closeBracketType);
                if (parameterListTokens != null)
                {
                    this.CheckParameters(element, parameterListTokens, parameterList, element.LineNumber, openBracketType, closeBracketType, element.FriendlyTypeText);
                }
            }
        }
示例#18
0
        /// <summary>
        /// Initializes a new instance of the Indexer class.
        /// </summary>
        /// <param name="document">
        /// The document that contains the element.
        /// </param>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="header">
        /// The Xml header for this element.
        /// </param>
        /// <param name="attributes">
        /// The list of attributes attached to this element.
        /// </param>
        /// <param name="declaration">
        /// The declaration code for this element.
        /// </param>
        /// <param name="returnType">
        /// The return type of the indexer.
        /// </param>
        /// <param name="parameters">
        /// The parameters to the indexer.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the element resides within a block of unsafe code.
        /// </param>
        /// <param name="generated">
        /// Indicates whether the code element was generated or written by hand.
        /// </param>
        internal Indexer(
            CsDocument document,
            CsElement parent,
            XmlHeader header,
            ICollection <Attribute> attributes,
            Declaration declaration,
            TypeToken returnType,
            IList <Parameter> parameters,
            bool unsafeCode,
            bool generated)
            : base(document, parent, ElementType.Indexer, "indexer " + declaration.Name, header, attributes, declaration, unsafeCode, generated)
        {
            Param.AssertNotNull(document, "document");
            Param.AssertNotNull(parent, "parent");
            Param.Ignore(header);
            Param.Ignore(attributes);
            Param.AssertNotNull(declaration, "declaration");
            Param.Ignore(returnType);
            Param.AssertNotNull(parameters, "parameters");
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);

            this.returnType = returnType;
            this.parameters = parameters;

            Debug.Assert(parameters.IsReadOnly, "The parameters collection should be read-only.");

            // Add the qualifications
            this.QualifiedName = CodeParser.AddQualifications(this.parameters, this.QualifiedName);

            // If this is an explicit interface member implementation and our access modifier
            // is currently set to private because we don't have one, then it should be public instead.
            if (this.Declaration.Name.IndexOf(".", StringComparison.Ordinal) > -1 && !this.Declaration.Name.StartsWith("this.", StringComparison.Ordinal))
            {
                this.Declaration.AccessModifierType = AccessModifierType.Public;
            }
        }
示例#19
0
        /// <summary>
        /// Fills in the details of the accessor based on its type.
        /// </summary>
        /// <param name="parent">
        /// The parent of the accessor.
        /// </param>
        private void FillDetails(CsElement parent)
        {
            Param.AssertNotNull(parent, "parent");

            // Set the return type and parameters.
            if (this.accessorType == AccessorType.Get)
            {
                this.FillGetAccessorDetails(parent);
            }
            else if (this.accessorType == AccessorType.Set)
            {
                this.FillSetAccessorDetails(parent);
            }
            else
            {
                // Add and remove accessors have no return type but have an implied
                // parameter based on the type of the event handler.
                Event parentEvent = (Event)parent;
                Reference <ICodePart> accessorReference = new Reference <ICodePart>(this);

                this.returnType = CreateVoidTypeToken(accessorReference);

                this.parameters = new[]
                {
                    new Parameter(
                        parentEvent.EventHandlerType,
                        "value",
                        accessorReference,
                        ParameterModifiers.None,
                        null,
                        CodeLocation.Empty,
                        null,
                        parentEvent.EventHandlerType.Generated)
                };
            }
        }
示例#20
0
        /// <summary>
        /// Checks a method invocation expression to make that the parameters are positioned correctly.
        /// </summary>
        /// <param name="element">
        /// The element containing the expression.
        /// </param>
        /// <param name="expression">
        /// The expression to check.
        /// </param>
        private void CheckMethodInvocationParameters(CsElement element, MethodInvocationExpression expression)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(expression, "expression");

            if (expression.Tokens.First != null && !expression.Tokens.First.Value.Generated)
            {
                ArgumentList argumentList       = new ArgumentList(expression.Arguments);
                CsTokenList  argumentListTokens = GetArgumentListTokens(
                    expression.Tokens, expression.Name.Tokens.Last, CsTokenType.OpenParenthesis, CsTokenType.CloseParenthesis);

                if (argumentListTokens != null)
                {
                    this.CheckParameters(
                        element,
                        argumentListTokens,
                        argumentList,
                        expression.LineNumber,
                        CsTokenType.OpenParenthesis,
                        CsTokenType.CloseParenthesis,
                        element.FriendlyTypeText);
                }
            }
        }
示例#21
0
        /// <summary>
        /// Processes the given statement container.
        /// </summary>
        /// <param name="element">
        /// The statement container element to process.
        /// </param>
        /// <param name="validPrefixes">
        /// The list of acceptable Hungarian-type prefixes.
        /// </param>
        private void ProcessStatementContainer(CsElement element, Dictionary <string, string> validPrefixes)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(validPrefixes, "validPrefixes");

            // Check the statement container's variables.
            if (element.Variables != null)
            {
                foreach (Variable variable in element.Variables)
                {
                    if (!variable.Generated)
                    {
                        this.CheckMethodVariablePrefix(variable, element, validPrefixes);
                        this.CheckUnderscores(element, element.Variables);
                    }
                }
            }

            // Check each of the statements under this container.
            foreach (Statement statement in element.ChildStatements)
            {
                this.ProcessStatement(statement, element, validPrefixes);
            }
        }
示例#22
0
        /// <summary>
        /// Checks the order of child elements of the given element.
        /// </summary>
        /// <param name="element">
        /// The element to check.
        /// </param>
        /// <param name="checkGeneratedCode">
        /// Indicates whether to check the order of elements
        /// within generated blocks of code.
        /// </param>
        private void CheckChildElementOrdering(CsElement element, bool checkGeneratedCode)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(checkGeneratedCode);

            // Check the ordering of this element compared with other elements at the same level.
            if (element.ChildElements.Count > 0)
            {
                bool firstValid = true;

                CsElement[] elementsArray = new CsElement[element.ChildElements.Count];
                element.ChildElements.CopyTo(elementsArray, 0);

                for (int i = 0; i < elementsArray.Length; ++i)
                {
                    CsElement first = elementsArray[i];

                    if (first.AnalyzerTag == null)
                    {
                        for (int j = i + 1; j < elementsArray.Length; ++j)
                        {
                            CsElement second = elementsArray[j];

                            if (second.AnalyzerTag == null)
                            {
                                // If we're supposed to be checking the order of generated code as well,
                                // then only perform this check if at least one of the two elements is not
                                // generated code. Otherwise, only perform this check if both of the two
                                // elements is not generated code.
                                if ((checkGeneratedCode && (!first.Generated || !second.Generated)) || (!checkGeneratedCode && !first.Generated && !second.Generated))
                                {
                                    // Determine whether first is actually supposed to come before second
                                    if (!this.CompareItems(first, second, !firstValid))
                                    {
                                        // Determine whether this means that first is out of order or second
                                        // is out of order. If we have not found the first item in the list that
                                        // is in the correct order, then first is marked out of order, otherwise
                                        // second is marked out of order.
                                        if (firstValid)
                                        {
                                            first.AnalyzerTag = false;
                                        }
                                        else
                                        {
                                            second.AnalyzerTag = false;
                                        }
                                    }
                                    else
                                    {
                                        // At this point we know that we've found an item that is in the correct order.
                                        if (firstValid)
                                        {
                                            firstValid = false;
                                        }
                                    }

                                    // If both of the elements are accessors, check that they appear in the correct order.
                                    if (first.ElementType == ElementType.Accessor && second.ElementType == ElementType.Accessor)
                                    {
                                        Accessor firstAccessor  = (Accessor)first;
                                        Accessor secondAccessor = (Accessor)second;

                                        if (firstAccessor.AccessorType == AccessorType.Set && secondAccessor.AccessorType == AccessorType.Get)
                                        {
                                            this.AddViolation(first, Rules.PropertyAccessorsMustFollowOrder);
                                        }
                                        else if (firstAccessor.AccessorType == AccessorType.Remove && secondAccessor.AccessorType == AccessorType.Add)
                                        {
                                            this.AddViolation(first, Rules.EventAccessorsMustFollowOrder);
                                        }
                                    }
                                }
                            }
                        }
                    }

                    this.CheckElementOrder(first, checkGeneratedCode);
                }
            }
        }
示例#23
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);
                                }
                            }
                        }
                    }
                }
            }
        }
示例#24
0
        /// <summary>
        /// Initializes a new instance of the Method class.
        /// </summary>
        /// <param name="document">
        /// The document that contains the element.
        /// </param>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="header">
        /// The Xml header for this element.
        /// </param>
        /// <param name="attributes">
        /// The list of attributes attached to this element.
        /// </param>
        /// <param name="declaration">
        /// The declaration code for this element.
        /// </param>
        /// <param name="returnType">
        /// The method's return type.
        /// </param>
        /// <param name="parameters">
        /// The parameters to the method.
        /// </param>
        /// <param name="typeConstraints">
        /// The list of type constraints on the element.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the element resides within a block of unsafe code.
        /// </param>
        /// <param name="generated">
        /// Indicates whether the code element was generated or written by hand.
        /// </param>
        internal Method(
            CsDocument document,
            CsElement parent,
            XmlHeader header,
            ICollection <Attribute> attributes,
            Declaration declaration,
            TypeToken returnType,
            IList <Parameter> parameters,
            ICollection <TypeParameterConstraintClause> typeConstraints,
            bool unsafeCode,
            bool generated)
            : base(document, parent, ElementType.Method, "method " + declaration.Name, header, attributes, declaration, unsafeCode, generated)
        {
            Param.AssertNotNull(document, "document");
            Param.AssertNotNull(parent, "parent");
            Param.Ignore(header);
            Param.Ignore(attributes);
            Param.AssertNotNull(declaration, "declaration");
            Param.Ignore(returnType);
            Param.AssertNotNull(parameters, "parameters");
            Param.Ignore(typeConstraints);
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);

            Debug.Assert(
                returnType != null || declaration.ContainsModifier(CsTokenType.Explicit, CsTokenType.Implicit),
                "A method's return type can only be null in an explicit or implicit operator overload method.");

            this.returnType      = returnType;
            this.parameters      = parameters;
            this.typeConstraints = typeConstraints;

            Debug.Assert(parameters.IsReadOnly, "The parameters collection should be read-only.");

            // Determine whether this is an extension method. The method must be static.
            if (this.parameters.Count > 0 && this.Declaration.ContainsModifier(CsTokenType.Static))
            {
                // Look at this first parameter. Since the parameters collection is not an indexable list, the
                // easiest way to do this is to foreach through the parameter list and break after the first one.
                foreach (Parameter parameter in this.parameters)
                {
                    if ((parameter.Modifiers & ParameterModifiers.This) != 0)
                    {
                        this.extensionMethod = true;
                    }

                    break;
                }
            }

            // Add the qualifications.
            this.QualifiedName = CodeParser.AddQualifications(this.parameters, this.QualifiedName);

            // If this is an explicit interface member implementation and our access modifier
            // is currently set to private because we don't have one, then it should be public instead.
            if (this.Declaration.Name.IndexOf(".", StringComparison.Ordinal) > -1 && !this.Declaration.Name.StartsWith("this.", StringComparison.Ordinal))
            {
                this.Declaration.AccessModifierType = AccessModifierType.Public;
            }

            // Set the parent of the type constraint clauses.
            if (typeConstraints != null)
            {
                foreach (TypeParameterConstraintClause constraint in typeConstraints)
                {
                    constraint.ParentElement = this;
                }
            }
        }
        /// <summary>
        /// Parses the given expression.
        /// </summary>
        /// <param name="expression">
        /// The expression.
        /// </param>
        /// <param name="parentExpression">
        /// The parent expression, if there is one.
        /// </param>
        /// <param name="parentElement">
        /// The element that contains the expressions.
        /// </param>
        /// <param name="parentClass">
        /// The class that the element belongs to.
        /// </param>
        /// <param name="members">
        /// The collection of members of the parent class.
        /// </param>
        private void CheckClassMemberRulesForExpression(
            Expression expression, Expression parentExpression, CsElement parentElement, ClassBase parentClass, Dictionary <string, List <CsElement> > members)
        {
            Param.AssertNotNull(expression, "expression");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");

            if (expression.ExpressionType == ExpressionType.Literal)
            {
                LiteralExpression literalExpression = (LiteralExpression)expression;

                // Check to see whether this literal is preceded by a member access symbol. If not
                // then we want to check whether this is a reference to one of our class members.
                if (!IsLiteralTokenPrecededByMemberAccessSymbol(literalExpression.TokenNode, expression.Tokens.MasterList))
                {
                    // Process the literal.
                    this.CheckClassMemberRulesForLiteralToken(literalExpression.TokenNode, expression, parentExpression, parentElement, parentClass, members);
                }
            }
            else
            {
                if (expression.ExpressionType == ExpressionType.Assignment && parentExpression != null &&
                    parentExpression.ExpressionType == ExpressionType.CollectionInitializer)
                {
                    // When we encounter assignment expressions within collection initializer expressions, we ignore the expression
                    // on the left-hand side of the assignment. This is because we know that the left-hand side refers to a property on
                    // the type being initialized, not a property on the local class. Thus, it does not ever need to be prefixed by this.
                    // Without this check we can get name collisions, such as:
                    // public sealed class Person
                    //// {
                    ////     public string FirstName { get; }
                    ////     public void CreateAnonymousType()
                    ////     {
                    ////         var anonymousType = new { FirstName = this.FirstName };
                    ////     }
                    //// }
                    this.CheckClassMemberRulesForExpression(((AssignmentExpression)expression).RightHandSide, expression, parentElement, parentClass, members);
                }
                else if (expression.ChildExpressions.Count > 0)
                {
                    // Check each child expression within this expression.
                    this.CheckClassMemberRulesForExpressions(expression.ChildExpressions, expression, parentElement, parentClass, members);
                }

                // Check if this is an anonymous method expression, which contains a child statement list.
                if (expression.ExpressionType == ExpressionType.AnonymousMethod)
                {
                    // Check the statements under this anonymous method.
                    this.CheckClassMemberRulesForStatements(expression.ChildStatements, parentElement, parentClass, members);
                }
                else if (expression.ExpressionType == ExpressionType.MethodInvocation)
                {
                    // Check each of the arguments passed into the method call.
                    MethodInvocationExpression methodInvocation = (MethodInvocationExpression)expression;
                    foreach (Argument argument in methodInvocation.Arguments)
                    {
                        // Check each expression within this child expression.
                        if (argument.Expression.ExpressionType != ExpressionType.MethodInvocation)
                        {
                            this.CheckClassMemberRulesForExpression(argument.Expression, null, parentElement, parentClass, members);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Analyzes the given query clauses.
        /// </summary>
        /// <param name="element">
        /// The element containing the clauses.
        /// </param>
        /// <param name="expression">
        /// The expression containing the clauses.
        /// </param>
        /// <param name="clauses">
        /// The list of clauses to analyze.
        /// </param>
        /// <param name="previousClause">
        /// The previous clause in the expression, if any.
        /// </param>
        /// <param name="clauseOnSameLine">
        /// Indicates whether any clause has been seen previously which
        /// starts on the same line as the clause before it.
        /// </param>
        /// <param name="clauseOnSeparateLine">
        /// Indicates whether any clause has been seen previously which
        /// starts on the line after the clause before it.
        /// </param>
        /// <returns>
        /// Returns true to continue checking the query clause, or false to quit.
        /// </returns>
        private bool ProcessQueryClauses(
            CsElement element,
            QueryExpression expression,
            ICollection <QueryClause> clauses,
            ref QueryClause previousClause,
            ref bool clauseOnSameLine,
            ref bool clauseOnSeparateLine)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(expression, "expression");
            Param.AssertNotNull(clauses, "clauses");
            Param.Ignore(previousClause);
            Param.Ignore(clauseOnSameLine);
            Param.Ignore(clauseOnSeparateLine);

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

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

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

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

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

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

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

                previousClause = clause;

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

            return(true);
        }
示例#27
0
 /// <summary>
 /// Initializes a new instance of the Namespace class.
 /// </summary>
 /// <param name="document">
 /// The document that contains the element.
 /// </param>
 /// <param name="parent">
 /// The parent of the element.
 /// </param>
 /// <param name="header">
 /// The Xml header for this element.
 /// </param>
 /// <param name="attributes">
 /// The list of attributes attached to this element.
 /// </param>
 /// <param name="declaration">
 /// The declaration code for this element.
 /// </param>
 /// <param name="unsafeCode">
 /// Indicates whether the element resides within a block of unsafe code.
 /// </param>
 /// <param name="generated">
 /// Indicates whether the code element was generated or written by hand.
 /// </param>
 internal Namespace(
     CsDocument document, CsElement parent, XmlHeader header, ICollection <Attribute> attributes, Declaration declaration, bool unsafeCode, bool generated)
     : base(document, parent, ElementType.Namespace, "namespace " + declaration.Name, header, attributes, declaration, unsafeCode, generated)
 {
     Param.Ignore(document, parent, header, attributes, declaration, unsafeCode, generated);
 }
示例#28
0
        /// <summary>
        /// Initializes a new instance of the CsElement class.
        /// </summary>
        /// <param name="document">
        /// The document that contains the element.
        /// </param>
        /// <param name="parent">
        /// The parent of the element.
        /// </param>
        /// <param name="type">
        /// The element type.
        /// </param>
        /// <param name="name">
        /// The name of this element.
        /// </param>
        /// <param name="header">
        /// The Xml header for this element.
        /// </param>
        /// <param name="attributes">
        /// The list of attributes attached to this element.
        /// </param>
        /// <param name="declaration">
        /// The declaration code for this element.
        /// </param>
        /// <param name="unsafeCode">
        /// Indicates whether the element is unsafe.
        /// </param>
        /// <param name="generated">
        /// Indicates whether the element was generated or written by hand.
        /// </param>
        internal CsElement(
            CsDocument document,
            CsElement parent,
            ElementType type,
            string name,
            XmlHeader header,
            ICollection <Attribute> attributes,
            Declaration declaration,
            bool unsafeCode,
            bool generated)
            : base(CodePartType.Element)
        {
            Param.AssertNotNull(document, "document");
            Param.Ignore(parent);
            Param.Ignore(type);
            Param.AssertNotNull(name, "name");
            Param.Ignore(header);
            Param.Ignore(attributes);
            Param.Ignore(declaration);
            Param.Ignore(unsafeCode);
            Param.Ignore(generated);

            this.document = document;
            if (this.document == null)
            {
                throw new ArgumentException(Strings.DocumentMustBeCsDocument, "document");
            }

            if (parent != null && parent.Document != document)
            {
                throw new ArgumentException(Strings.ElementMustBeInParentsDocument, "parent");
            }

            this.type        = type;
            this.name        = CodeLexer.DecodeEscapedText(name, true);
            this.header      = header;
            this.attributes  = attributes;
            this.declaration = declaration;
            this.unsafeCode  = unsafeCode;
            this.generated   = generated;

            if (!unsafeCode && this.declaration.ContainsModifier(CsTokenType.Unsafe))
            {
                this.unsafeCode = true;
            }

            // Fill in the element reference in the header object.
            if (this.header != null)
            {
                Debug.Assert(this.header.Element == null, "The header element should not be empty.");
                this.header.Element = this;
            }

            // Fill in the element reference in the attributes list items.
            if (this.attributes != null)
            {
                Debug.Assert(this.attributes.IsReadOnly, "The attributes collection should be read-only.");

                foreach (Attribute attribute in this.attributes)
                {
                    Debug.Assert(attribute.Element == null, "The attribute element should not be empty");
                    attribute.Element = this;
                }
            }

            // Set the fully qualified base name
            if (parent != null)
            {
                this.fullyQualifiedBase = parent.FullyQualifiedName;
                this.MergeAccess(parent.ActualAccess);
            }
            else
            {
                if (this.declaration != null)
                {
                    this.actualAccess = this.declaration.AccessModifierType;
                }
                else
                {
                    this.actualAccess = AccessModifierType.Public;
                }
            }

            // Set the fully qualified name
            this.fullyQualifiedName = this.fullyQualifiedBase;
            if (this.declaration != null && this.declaration.Name != null && this.declaration.Name.Length > 0)
            {
                if (this.fullyQualifiedBase != null && this.fullyQualifiedBase.Length > 0)
                {
                    this.fullyQualifiedName += ".";
                }

                int index = this.declaration.Name.LastIndexOf("\\", StringComparison.Ordinal);
                if (index != -1)
                {
                    this.fullyQualifiedName += this.declaration.Name.Substring(index + 1, this.declaration.Name.Length - index - 1);
                }
                else
                {
                    this.fullyQualifiedName += this.declaration.Name;
                }

                index = this.fullyQualifiedName.IndexOf(".cs.", StringComparison.OrdinalIgnoreCase);
                if (-1 == index)
                {
                    this.fullNamespaceName = this.fullyQualifiedName;
                }
                else
                {
                    this.fullNamespaceName = this.fullyQualifiedName.Substring(index + 4, this.fullyQualifiedName.Length - index - 4);
                }
            }

            // There is only one type of element which is allowed to have a token
            // list consisting of nothing other than whitespace, newlines, etc.,
            // which is the document root. This happens if you have a document which
            // contains nothing other than whitespace. Due to this we do not want to
            // trim down the token list for the root element, but we do want to for
            // all other types of elements.
            if (type == ElementType.Root)
            {
                this.TrimTokens = false;
            }
        }
示例#29
0
        private bool CompareItems(CsElement first, CsElement second, bool foundFirst)
        {
            Param.AssertNotNull(first, "first");
            Param.AssertNotNull(second, "second");
            Param.Ignore(foundFirst);

            // We don't care about the order of accessors and we don't care about the order of empty elements.
            if ((first.ElementType != ElementType.EmptyElement && second.ElementType != ElementType.EmptyElement) &&
                (first.ElementType != ElementType.Accessor || second.ElementType != ElementType.Accessor))
            {
                // If the order turns out to be incorrect, determine which of the items is at fault.
                CsElement invalidElement = second;
                if (!foundFirst)
                {
                    invalidElement = first;
                }

                // Check the item types to see if the second item type should appear before the first item type.
                if (first.ElementType > second.ElementType)
                {
                    this.AddViolation(
                        first, invalidElement.LineNumber, Rules.ElementsMustAppearInTheCorrectOrder, first.FriendlyPluralTypeText, second.FriendlyPluralTypeText);

                    return(false);
                }
                else if (first.ElementType == second.ElementType)
                {
                    // Make sure that both items have a declaration, or else we can go no further.
                    if (first.Declaration != null && second.Declaration != null)
                    {
                        // Check the access modifiers to see if they are in the correct order.
                        if (first.Declaration.AccessModifierType > second.Declaration.AccessModifierType)
                        {
                            // Special case for static constructors, which are always private but should still appear in front of all other constructors.
                            if (first.ElementType != ElementType.Constructor || second.ElementType != ElementType.Constructor ||
                                !first.Declaration.ContainsModifier(CsTokenType.Static) || second.Declaration.ContainsModifier(CsTokenType.Static))
                            {
                                // If one of the elements is partial and does not have an access modifier defined, and the element
                                // is not a method, show a special message. Partial methods are not allowed to have modifiers and are
                                // private by default.
                                if ((!first.Declaration.AccessModifier && first.ElementType != ElementType.Method &&
                                     first.Declaration.ContainsModifier(CsTokenType.Partial)) ||
                                    (!second.Declaration.AccessModifier && second.ElementType != ElementType.Method &&
                                     second.Declaration.ContainsModifier(CsTokenType.Partial)))
                                {
                                    // Make sure to use the line number of the partial element which does not contain
                                    // an access modifier.
                                    CsElement elementWithoutAccessModifier = first;
                                    if (first.Declaration.AccessModifier || !first.Declaration.ContainsModifier(CsTokenType.Partial))
                                    {
                                        elementWithoutAccessModifier = second;
                                    }

                                    this.AddViolation(
                                        elementWithoutAccessModifier,
                                        Rules.PartialElementsMustDeclareAccess,
                                        elementWithoutAccessModifier.FriendlyTypeText,
                                        elementWithoutAccessModifier.FriendlyPluralTypeText);
                                }
                                else
                                {
                                    this.AddViolation(
                                        first,
                                        invalidElement.LineNumber,
                                        Rules.ElementsMustBeOrderedByAccess,
                                        OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                        first.FriendlyPluralTypeText,
                                        OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                        second.FriendlyPluralTypeText);
                                }

                                return(false);
                            }
                        }
                        else if (first.Declaration.AccessModifierType == second.Declaration.AccessModifierType)
                        {
                            // order should be :
                            // 0  const
                            // 1  static readonly
                            // 2  static non-readonly
                            // 3  instance readonly
                            // 4  instance non-readonly
                            int firstOrder  = GetElementOrder(first);
                            int secondOrder = GetElementOrder(second);

                            // Check to make sure that constant are first
                            if (secondOrder == 0 && firstOrder > 0)
                            {
                                this.AddViolation(first, invalidElement.LineNumber, Rules.ConstantsMustAppearBeforeFields);
                                return(false);
                            }

                            // Static Readonly fields are next
                            if (secondOrder == 1 && firstOrder == 2)
                            {
                                this.AddViolation(
                                    first,
                                    invalidElement.LineNumber,
                                    Rules.StaticReadonlyElementsMustAppearBeforeStaticNonReadonlyElements,
                                    OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                    first.FriendlyPluralTypeText,
                                    OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                    second.FriendlyPluralTypeText);

                                return(false);
                            }

                            if (secondOrder == 1 && firstOrder > 2)
                            {
                                this.AddViolation(
                                    first,
                                    invalidElement.LineNumber,
                                    Rules.StaticElementsMustAppearBeforeInstanceElements,
                                    OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                    first.FriendlyPluralTypeText,
                                    OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                    second.FriendlyPluralTypeText);

                                return(false);
                            }

                            // Static non-Readonly fields are next
                            if (secondOrder == 2 && firstOrder > 2)
                            {
                                this.AddViolation(
                                    first,
                                    invalidElement.LineNumber,
                                    Rules.StaticElementsMustAppearBeforeInstanceElements,
                                    OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                    first.FriendlyPluralTypeText,
                                    OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                    second.FriendlyPluralTypeText);

                                return(false);
                            }

                            // instance readonly
                            if (secondOrder == 3 && firstOrder > 3)
                            {
                                this.AddViolation(
                                    first,
                                    invalidElement.LineNumber,
                                    Rules.InstanceReadonlyElementsMustAppearBeforeInstanceNonReadonlyElements,
                                    OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                    first.FriendlyPluralTypeText,
                                    OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                    second.FriendlyPluralTypeText);

                                return(false);
                            }
                        }
                        else if (first.ElementType == ElementType.Constructor && second.ElementType == ElementType.Constructor &&
                                 second.Declaration.ContainsModifier(CsTokenType.Static) && !first.Declaration.ContainsModifier(CsTokenType.Static))
                        {
                            // If we have 2 constructors and the second one is static then they're in the wrong order, since static
                            // constructors must always come in front of all instance constructors.
                            this.AddViolation(
                                first,
                                invalidElement.LineNumber,
                                Rules.StaticElementsMustAppearBeforeInstanceElements,
                                OrderingRules.AccessModifierTypeString(first.Declaration.AccessModifierType),
                                first.FriendlyPluralTypeText,
                                OrderingRules.AccessModifierTypeString(second.Declaration.AccessModifierType),
                                second.FriendlyPluralTypeText);

                            return(false);
                        }
                    }
                }
            }

            return(true);
        }
示例#30
0
        private void CheckDeclarationKeywordOrder(CsElement element)
        {
            Param.AssertNotNull(element, "element");

            int accessModifierIndex = -1;
            int staticIndex         = -1;
            int otherWordIndex      = -1;

            int index = 0;

            foreach (CsToken token in element.Declaration.Tokens)
            {
                CsTokenType type = token.CsTokenType;
                if (type == CsTokenType.Private || type == CsTokenType.Public || type == CsTokenType.Protected || type == CsTokenType.Internal)
                {
                    if (accessModifierIndex == -1)
                    {
                        accessModifierIndex = index++;
                    }
                }
                else if (type == CsTokenType.Static)
                {
                    if (staticIndex == -1)
                    {
                        staticIndex = index++;
                    }
                }
                else if (type != CsTokenType.WhiteSpace && type != CsTokenType.EndOfLine && type != CsTokenType.SingleLineComment && type != CsTokenType.MultiLineComment)
                {
                    if (otherWordIndex == -1)
                    {
                        otherWordIndex = index++;
                    }
                }
            }

            if (accessModifierIndex != -1)
            {
                if (staticIndex > -1 && staticIndex < accessModifierIndex)
                {
                    this.AddViolation(
                        element, Rules.DeclarationKeywordsMustFollowOrder, Strings.AccessModifier, string.Format(CultureInfo.InvariantCulture, "'{0}'", Strings.Static));
                }

                if (otherWordIndex > -1 && otherWordIndex < accessModifierIndex)
                {
                    this.AddViolation(
                        element, Rules.DeclarationKeywordsMustFollowOrder, Strings.AccessModifier, string.Format(CultureInfo.InvariantCulture, "'{0}'", Strings.Other));
                }
            }

            if (staticIndex > -1)
            {
                if (otherWordIndex > -1 && otherWordIndex < staticIndex)
                {
                    this.AddViolation(
                        element,
                        Rules.DeclarationKeywordsMustFollowOrder,
                        string.Format(CultureInfo.InvariantCulture, "'{0}'", Strings.Static),
                        string.Format(CultureInfo.InvariantCulture, "'{0}'", Strings.Other));
                }
            }

            // Check to make sure that 'protected' comes just before 'internal'.
            if (element.Declaration.AccessModifierType == AccessModifierType.ProtectedInternal)
            {
                bool foundProtected = false;
                foreach (CsToken token in element.Declaration.Tokens)
                {
                    if (foundProtected)
                    {
                        if (token.CsTokenType == CsTokenType.Internal)
                        {
                            break;
                        }
                        else if (token.CsTokenType != CsTokenType.WhiteSpace)
                        {
                            this.AddViolation(element, Rules.ProtectedMustComeBeforeInternal);
                            break;
                        }
                    }
                    else
                    {
                        if (token.CsTokenType == CsTokenType.Protected)
                        {
                            foundProtected = true;
                        }
                        else if (token.CsTokenType == CsTokenType.Internal)
                        {
                            this.AddViolation(element, Rules.ProtectedMustComeBeforeInternal);
                            break;
                        }
                    }
                }
            }
        }