Example #1
0
        /// <summary>
        /// Initializes a new instance of the ElementWrapper class.
        /// </summary>
        /// <param name="element">The element to wrap.</param>
        public ElementWrapper(Element element)
        {
            Param.AssertNotNull(element, "element");
            this.element = element;

            // Add any suppressed rules.
            this.AddRuleSuppressionsForElement();
        }
        /// <summary>
        /// Parses the body of an element that contains a list of statements as children.
        /// </summary>
        /// <param name="elementProxy">Proxy for the element being created.</param>
        /// <param name="element">The element to parse.</param>
        /// <param name="interfaceType">Indicates whether this type of statement container can appear in an interface.</param>
        /// <param name="unsafeCode">Indicates whether the code being parsed resides in an unsafe code block.</param>
        private void ParseStatementContainer(CodeUnitProxy elementProxy, Element element, bool interfaceType, bool unsafeCode)
        {
            Param.AssertNotNull(elementProxy, "elementProxy");
            Param.AssertNotNull(element, "element");
            Param.Ignore(interfaceType);
            Param.Ignore(unsafeCode);

            // Check to see if the item is unsafe. This is the case if the item's parent is unsafe, or if it
            // has the unsafe keyword itself.
            unsafeCode |= element.ContainsModifier(TokenType.Unsafe);

            // The next symbol must be an opening curly bracket.
            Symbol symbol = this.PeekNextSymbol();
            if (symbol == null)
            {
                throw this.CreateSyntaxException();
            }

            if (symbol.SymbolType == SymbolType.OpenCurlyBracket)
            {
                // Add the bracket token to the document.
                BracketToken openingBracket = (BracketToken)this.GetToken(elementProxy, TokenType.OpenCurlyBracket, SymbolType.OpenCurlyBracket);

                // Parse the contents of the element.
                BracketToken closingBracket = this.ParseStatementScope(elementProxy, unsafeCode);
                if (closingBracket == null)
                {
                    // If we failed to get a closing bracket back, then there is a syntax
                    // error in the document since there is an opening bracket with no matching
                    // closing bracket.
                    throw this.CreateSyntaxException();
                }

                openingBracket.MatchingBracket = closingBracket;
                closingBracket.MatchingBracket = openingBracket;
            }
            else if (interfaceType && symbol.SymbolType == SymbolType.Semicolon)
            {
                // Add the semicolon to the document.
                this.GetToken(elementProxy, TokenType.Semicolon, SymbolType.Semicolon);
            }
            else
            {
                throw new SyntaxException(this.document, symbol.LineNumber);
            }
        }
        /// <summary>
        /// Attempts to add an element to the partial elements service, if that element is partial.
        /// </summary>
        /// <param name="element">The element to add.</param>
        /// <returns>Returns true if the element was added, or false if the element was not partial.</returns>
        public bool TryAdd(Element element)
        {
            Param.RequireNotNull(element, "element");

            // If the element is partial, add it to the partial elements list.
            if (element.ContainsModifier(TokenType.Partial) && element is ClassBase)
            {
                [email protected]();

                try
                {
                    List<Element> elementList = null;

                    // Get the partial element list for this element.
                    string elementFullyQualifiedName = element.FullyQualifiedName;
                    this.partialElements.TryGetValue(elementFullyQualifiedName, out elementList);

                    if (elementList == null)
                    {
                        // Create a new partial element list for this element name.
                        elementList = new List<Element>();
                        this.partialElements.Add(elementFullyQualifiedName, elementList);
                    }
                    else if (elementList.Count > 0)
                    {
                        // Make sure this elements is the same type as the item(s) already in the list.
                        if (elementList[0].ElementType != element.ElementType)
                        {
                            throw new SyntaxException(element.Document, element.LineNumber);
                        }
                    }

                    // Add the element to the list.
                    elementList.Add(element);
                }
                finally
                {
                    [email protected]();
                }

                return true;
            }

            return false;
        }
        /// <summary>
        /// Processes the given query expression.
        /// </summary>
        /// <param name="element">The element that contains the expression.</param>
        /// <param name="queryExpression">The query expression.</param>
        private void CheckQueryExpression(Element element, QueryExpression queryExpression)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(queryExpression, "queryExpression");

            QueryClause previousClause = null;

            bool clauseOnSameLine = false;
            bool clauseOnSeparateLine = false;

            this.ProcessQueryClauses(
                element,
                queryExpression,
                queryExpression,
                ref previousClause,
                ref clauseOnSameLine,
                ref clauseOnSeparateLine);
        }
        private void CheckForEmptyComments(Comment comment, Element parentElement)
        {
            Param.AssertNotNull(comment, "comment");
            Param.AssertNotNull(parentElement, "parentElement");

            // Skip generated code.
            if (!comment.Generated)
            {
                // Check for the two comment types.
                if (comment.CommentType == CommentType.SingleLineComment)
                {
                    this.CheckSingleLineComment(comment, parentElement);
                }
                else if (comment.CommentType == CommentType.MultilineComment)
                {
                    this.CheckMultilineComment(comment, parentElement);
                }
            }
        }
Example #6
0
        /// <summary>
        /// Checks a region.
        /// </summary>
        /// <param name="region">The region to check.</param>
        /// <param name="parentElement">The parent element.</param>
        /// <param name="settings">The current settings.</param>
        private void CheckRegion(RegionDirective region, Element parentElement, Settings settings)
        {
            Param.AssertNotNull(region, "region");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(settings, "settings");

            if (settings.DoNotUseRegions)
            {
                if (!region.Generated && !region.IsGeneratedCodeRegion)
                {
                    // There should not be any regions in the code.
                    this.AddViolation(parentElement, region.LineNumber, Rules.DoNotUseRegions);
                }
            }
        }
Example #7
0
        /// <summary>
        /// Checks a type to determine whether it should use one of the built-in types.
        /// </summary>
        /// <param name="type">The type to check.</param>
        /// <param name="parentElement">The parent element.</param>
        private void CheckBuiltInType(TypeToken type, Element parentElement)
        {
            Param.AssertNotNull(type, "type");
            Param.AssertNotNull(parentElement, "parentElement");

            if (!type.IsGeneric)
            {
                for (int i = 0; i < this.builtInTypes.Length; ++i)
                {
                    string[] builtInType = this.builtInTypes[i];

                    if (type.MatchTokens(builtInType[ShortNameIndex]) ||
                        type.MatchTokens("System", ".", builtInType[ShortNameIndex]))
                    {
                        // If the previous token is an equals sign, then this is a using alias directive. For example:
                        // using SomeAlias = System.String;
                        bool usingAliasDirective = false;
                        for (LexicalElement previous = type.FindPreviousLexicalElement(); previous != null; previous = previous.FindPreviousLexicalElement())
                        {
                            if (previous.LexicalElementType != LexicalElementType.Comment &&
                                previous.LexicalElementType != LexicalElementType.WhiteSpace &&
                                previous.LexicalElementType != LexicalElementType.EndOfLine)
                            {
                                if (previous.Text == "=")
                                {
                                    usingAliasDirective = true;
                                }

                                break;
                            }
                        }

                        if (!usingAliasDirective)
                        {
                            this.Violation(
                                Rules.UseBuiltInTypeAlias,
                                new ViolationContext(parentElement, type.LineNumber, builtInType[AliasIndex], builtInType[ShortNameIndex], builtInType[LongNameIndex]),
                                (c, o) =>
                                {
                                    // Insert a new type token with the correct aliased version of the type.
                                    CsDocument document = type.Document;
                                    TypeToken aliasType = document.CreateTypeToken(document.CreateLiteralToken(builtInType[AliasIndex]));
                                    document.Replace(type, aliasType);
                                });
                        }

                        break;
                    }
                }
            }
        }
Example #8
0
        /// <summary>
        /// Checks the given element.
        /// </summary>
        /// <param name="element">The element being visited.</param>
        /// <param name="settings">The current settings.</param>
        /// <returns>Returns true to continue, or false to stop the walker.</returns>
        private bool VisitElement(Element element, Settings settings)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(settings);

            this.CheckMethodParameters(element);
            this.CheckForRegionsInElement(element, settings);

            return true;
        }
        /// <summary>
        /// Determines whether the given element contains any partial members.
        /// </summary>
        /// <param name="element">The element to check.</param>
        /// <returns>Returns true if the element contains at least one partial member.</returns>
        private bool ContainsPartialMembers(Element element)
        {
            Param.AssertNotNull(element, "element");

            if (element.ElementType == ElementType.Class ||
                element.ElementType == ElementType.Struct ||
                element.ElementType == ElementType.Interface)
            {
                if (element.ContainsModifier(TokenType.Partial))
                {
                    return true;
                }
            }

            if (element.ElementType == ElementType.Document ||
                element.ElementType == ElementType.Namespace ||
                element.ElementType == ElementType.Class ||
                element.ElementType == ElementType.Struct)
            {
                for (Element child = element.FindFirstChildElement(); child != null; child = child.FindNextSiblingElement())
                {
                    if (this.ContainsPartialMembers(child))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
        /// <summary>
        /// Parses the given literal token.
        /// </summary>
        /// <param name="token">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(
            Token token,
            Expression expression,
            Expression parentExpression,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(token, "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 (token.TokenType != TokenType.Type)
            {
                // If the name starts with a dot, ignore it.
                if (!token.Text.StartsWith(".", StringComparison.Ordinal))
                {
                    if (token.Text == "base" && parentExpression != null)
                    {
                        // An item is only allowed to start with base if there is an implementation of the
                        // item in the local class and the caller is trying to explicitly call the base
                        // class implementation instead of the local class implementation. Extract the name
                        // of the item being accessed.
                        Token name = ReadabilityRules.ExtractBaseClassMemberName(parentExpression, token);
                        if (name != null)
                        {
                            ICollection<Element> matches = ReadabilityRules.FindClassMember(name.Text, parentClass, members, true);

                            // Check to see if there is a non-static match.
                            bool found = false;
                            if (matches != null)
                            {
                                foreach (Element match in matches)
                                {
                                    if (!match.ContainsModifier(TokenType.Static))
                                    {
                                        found = true;
                                        break;
                                    }
                                }
                            }

                            if (!found)
                            {
                                this.AddViolation(parentElement, name.LineNumber, Rules.DoNotPrefixCallsWithBaseUnlessLocalImplementationExists, name);
                            }
                        }
                    }
                    else if (token.Text != "this")
                    {
                        // Check whether this word should really start with this.
                        this.CheckWordUsageAgainstClassMemberRules(
                            token.Text,
                            token,
                            token.LineNumber,
                            expression,
                            parentElement,
                            parentClass,
                            members);
                    }
                }
            }
        }
        /// <summary>
        /// Parses the given query clause.
        /// </summary>
        /// <param name="clause">The query clause.</param>
        /// <param name="parentExpression">The parent expression, if there is one.</param>
        /// <param name="parentElement">The element that contains the expressions.</param>
        /// <param name="parentClass">The class that the element belongs to.</param>
        /// <param name="members">The collection of members of the parent class.</param>
        private void CheckClassMemberRulesForQueryClause(
            QueryClause clause,
            Expression parentExpression,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(clause, "clause");
            Param.Ignore(parentExpression);
            Param.AssertNotNull(parentElement, "parentElement");
            Param.AssertNotNull(parentClass, "parentClass");
            Param.AssertNotNull(members, "members");

            for (CodeUnit child = clause.FindFirstChild(); child != null; child = child.FindNextSibling())
            {
                if (child.Is(CodeUnitType.QueryClause))
                {
                    this.CheckClassMemberRulesForQueryClause((QueryClause)child, parentExpression, parentElement, parentClass, members);
                }
                else if (child.Is(CodeUnitType.Expression))
                {
                    this.CheckClassMemberRulesForExpression((Expression)child, parentExpression, parentElement, parentClass, members);
                }
                else if (child.Is(TokenType.Literal))
                {
                    Token token = (Token)child;

                    // Check to see whether this literal is preceded by a member access symbol. If not
                    // then we want to check whether this is a reference to one of our class members.
                    if (!IsLiteralTokenPrecededByMemberAccessSymbol(token))
                    {
                        // Process the literal.
                        this.CheckClassMemberRulesForLiteralToken(
                            token,
                            parentExpression,
                            parentExpression,
                            parentElement,
                            parentClass,
                            members);
                    }
                }
            }
        }
Example #12
0
        /// <summary>
        /// Checks the prefix for a variable defined within a method or property.
        /// </summary>
        /// <param name="variable">The variable to check.</param>
        /// <param name="element">The element that contains the variable.</param>
        /// <param name="validPrefixes">A list of valid prefixes that should not be considered hungarian.</param>
        private void CheckMethodVariablePrefix(
            IVariable variable, Element element, Dictionary<string, string> validPrefixes)
        {
            Param.AssertNotNull(variable, "variable");
            Param.AssertNotNull(element, "element");
            Param.Ignore(validPrefixes);

            // Skip past any prefixes in the name.
            int index = NamingRules.MovePastPrefix(variable.VariableName);

            // Do not check for name casing on fields and events. These are checked elsewhere since they are elements, not simple variables,
            // and therefor fall under different rules.
            bool checkCasing = element.ElementType != ElementType.Field && element.ElementType != ElementType.Event;

            // Check whether the name starts with a lower-case letter.
            if (variable.VariableName.Length > index && char.IsLower(variable.VariableName, index))
            {
                // Check for hungarian notation.
                this.CheckHungarian(variable.VariableName, index, variable.Location.LineNumber, element, validPrefixes);

                // Check casing on the variable.
                if (checkCasing && (variable.VariableModifiers & VariableModifiers.Const) == VariableModifiers.Const)
                {
                    // Constants must start with an upper-case letter.
                    this.AddViolation(element, variable.Location.LineNumber, Rules.ConstFieldNamesMustBeginWithUpperCaseLetter, variable.VariableName);
                }
            }
            else if (checkCasing && (variable.VariableModifiers & VariableModifiers.Const) == 0)
            {
                // Non-constant method variables must start with a lower-case letter.
                this.AddViolation(element, variable.Location.LineNumber, Rules.FieldNamesMustBeginWithLowerCaseLetter, variable.VariableName);
            }
        }
Example #13
0
        /// <summary>
        /// Checks the field name to look for underscores.
        /// </summary>
        /// <param name="field">The field ot check.</param>
        private void CheckFieldUnderscores(Element field)
        {
            Param.AssertNotNull(field, "field");

            if (field.Name.StartsWith("s_", StringComparison.Ordinal) ||
                field.Name.StartsWith("m_", StringComparison.Ordinal))
            {
                this.AddViolation(field, Rules.VariableNamesMustNotBePrefixed);
            }
            else if (field.Name.StartsWith("_", StringComparison.Ordinal))
            {
                this.AddViolation(field, Rules.FieldNamesMustNotBeginWithUnderscore);
            }
            else if (field.Name.IndexOf("_", StringComparison.Ordinal) > -1)
            {
                this.AddViolation(field, Rules.FieldNamesMustNotContainUnderscore);
            }
        }
Example #14
0
        /// <summary>
        /// Checks variables to look for underscores.
        /// </summary>
        /// <param name="element">The parent element.</param>
        /// <param name="variables">The variables to check.</param>
        private void CheckUnderscores(Element element, VariableCollection variables)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(variables, "variables");

            foreach (IVariable variable in variables)
            {
                if (variable.VariableName.StartsWith("_", StringComparison.Ordinal) && variable.VariableName != "__arglist")
                {
                    this.AddViolation(element, variable.Location.LineNumber, Rules.FieldNamesMustNotBeginWithUnderscore);
                }
            }
        }
Example #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, Element 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)
                {
                    string character = name.Substring(i, 1);
                    if (character == character.ToUpper(CultureInfo.InvariantCulture))
                    {
                        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);
                    }
                }
            }
        }
        /// <summary>
        /// Parses the given statement list.
        /// </summary>
        /// <param name="statementParent">The direct parent of the statements to check.</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(
            CodeUnit statementParent,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(statementParent, "statementParent");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the statements.
            for (Statement statement = statementParent.FindFirstChildStatement(); statement != null; statement = statement.FindNextSiblingStatement())
            {
                if (statement.Children.StatementCount > 0)
                {
                    // Parse the sub-statements.
                    this.CheckClassMemberRulesForStatements(statement, parentElement, parentClass, members);
                }

                // Parse the expressions in the statement.
                this.CheckClassMemberRulesForExpressions(statement, null, parentElement, parentClass, members);
            }
        }
        /// <summary>
        /// Parses the list of expressions.
        /// </summary>
        /// <param name="expressionParent">The direct parent of the expressions to check.</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 CheckClassMemberRulesForExpressions(
            CodeUnit expressionParent,
            Expression parentExpression,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(expressionParent, "expressionParent");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentExpression);
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Loop through each of the expressions in the list.
            for (Expression expression = expressionParent.FindFirstChildExpression(); expression != null; expression = expression.FindNextSiblingExpression())
            {
                // If the expression is a variable declarator expression, we don't 
                // want to match against the identifier tokens.
                if (expression.ExpressionType == ExpressionType.VariableDeclarator)
                {
                    VariableDeclaratorExpression declarator = (VariableDeclaratorExpression)expression;
                    if (declarator.Initializer != null)
                    {
                        this.CheckClassMemberRulesForExpression(declarator.Initializer, parentExpression, parentElement, parentClass, members);
                    }
                }
                else
                {
                    this.CheckClassMemberRulesForExpression(expression, parentExpression, parentElement, parentClass, members);
                }
            }
        }
Example #18
0
        private bool ProcessElement(Element element, Dictionary<string, string> validPrefixes, bool nativeMethods)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(validPrefixes, "validPrefixes");
            Param.Ignore(nativeMethods);

            if (this.Cancel)
            {
                return false;
            }

            if (!element.Generated && element.Name != null)
            {
                switch (element.ElementType)
                {
                    case ElementType.Namespace:
                    case ElementType.Class:
                    case ElementType.Enum:
                    case ElementType.Struct:
                    case ElementType.Delegate:
                    case ElementType.Property:
                        if (!nativeMethods)
                        {
                            this.CheckCase(element, element.Name, element.LineNumber, true);
                        }

                        break;

                    case ElementType.Event:
                        if (!nativeMethods)
                        { 
                            for (EventDeclaratorExpression declarator = element.FindFirstChild<EventDeclaratorExpression>(); declarator != null; declarator = declarator.FindNextSibling<EventDeclaratorExpression>())
                            {
                                this.CheckCase(element, declarator.Identifier.Text, declarator.LineNumber, true);
                            }
                        }

                        break;

                    case ElementType.Method:
                        if (!nativeMethods &&
                            !element.Name.StartsWith("operator", StringComparison.Ordinal) &&
                            element.Name != "foreach")
                        {
                            this.CheckCase(element, element.Name, element.LineNumber, true);
                        }

                        break;

                    case ElementType.Interface:
                        if (element.Name.Length < 1 || element.Name[0] != 'I')
                        {
                            this.AddViolation(element, Rules.InterfaceNamesMustBeginWithI, element.Name);
                        }

                        break;

                    case ElementType.Field:
                        if (!nativeMethods)
                        {
                            this.CheckFieldUnderscores(element);
                            this.CheckFieldPrefix(element as Field, validPrefixes);
                        }

                        break;

                    default:
                        break;
                }
            }

            if (!nativeMethods &&
                (element.ElementType == ElementType.Class || element.ElementType == ElementType.Struct) &&
                element.Name.EndsWith("NativeMethods", StringComparison.Ordinal))
            {
                nativeMethods = true;
            }

            if (element.Children.ElementCount > 0)
            {
                for (Element child = element.FindFirstChildElement(); child != null; child = child.FindNextSiblingElement())
                {
                    if (!this.ProcessElement(child, validPrefixes, nativeMethods))
                    {
                        return false;
                    }
                }
            }

            if (!nativeMethods)
            {
                this.ProcessStatementContainer(element, validPrefixes);
            }

            return true;
        }
        /// <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,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> 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.Token))
                {
                    // Process the literal.
                    this.CheckClassMemberRulesForLiteralToken(
                        literalExpression.Token,
                        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.Children.ExpressionCount > 0)
                {
                    // Check each child expression within this expression.
                    this.CheckClassMemberRulesForExpressions(expression, expression, parentElement, parentClass, members);
                }

                if (expression.Children.QueryClauseCount > 0)
                {
                    for (QueryClause clause = expression.FindFirstChildQueryClause(); clause != null; clause = clause.FindNextSiblingQueryClause())
                    {
                        this.CheckClassMemberRulesForQueryClause(clause, 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, 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.ArgumentList)
                    {
                        // Check each expression within this child expression.
                        this.CheckClassMemberRulesForExpression(
                            argument.Expression,
                            null,
                            parentElement,
                            parentClass,
                            members);
                    }
                }
            }
        }
Example #20
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(Element element, Dictionary<string, string> validPrefixes)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(validPrefixes, "validPrefixes");

            // Check the statement container's variables.
            VariableCollection variables = element.Variables;

            if (variables != null)
            {
                foreach (IVariable variable in variables)
                {
                    if (!variable.Generated)
                    {
                        this.CheckMethodVariablePrefix(variable, element, validPrefixes);
                        this.CheckUnderscores(element, variables);
                    }
                }
            }

            // Check each of the statements under this container.
            if (element.Children.StatementCount > 0)
            {
                for (Statement statement = element.FindFirstChildStatement(); statement != null; statement = statement.FindNextSiblingStatement())
                {
                    this.ProcessStatement(statement, element, validPrefixes);
                }
            }
        }
        /// <summary>
        /// Checks a word to see if it should start with this. or base.
        /// </summary>
        /// <param name="word">The word text to check.</param>
        /// <param name="item">The word being checked.</param>
        /// <param name="line">The line that the word appears on.</param>
        /// <param name="expression">The expression the word appears within.</param>
        /// <param name="parentElement">The element that contains the word.</param>
        /// <param name="parentClass">The parent class that this element belongs to.</param>
        /// <param name="members">The collection of members of the parent class.</param>
        private void CheckWordUsageAgainstClassMemberRules(
            string word,
            Token item,
            int line,
            Expression expression,
            Element parentElement,
            ClassBase parentClass,
            Dictionary<string, List<Element>> members)
        {
            Param.AssertValidString(word, "word");
            Param.AssertNotNull(item, "item");
            Param.AssertGreaterThanZero(line, "line");
            Param.AssertNotNull(expression, "expression");
            Param.AssertNotNull(parentElement, "parentElement");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // If there is a local variable with the same name, or if the item we're checking is within the left-hand side
            // of an object initializer expression, then ignore it.
            if (!IsLocalMember(word, item, expression) && !IsObjectInitializerLeftHandSideExpression(expression))
            {
                // Determine if this is a member of our class.
                Element foundMember = null;
                ICollection<Element> classMembers = ReadabilityRules.FindClassMember(word, parentClass, members, false);
                if (classMembers != null)
                {
                    foreach (Element classMember in classMembers)
                    {
                        if (classMember.ContainsModifier(TokenType.Static) ||
                            (classMember.ElementType == ElementType.Field && ((Field)classMember).Const))
                        {
                            // There is a member with a matching name that is static or is a const field. In this case, 
                            // ignore the issue and quit.
                            foundMember = null;
                            break;
                        }
                        else if (classMember.ElementType != ElementType.Class &&
                            classMember.ElementType != ElementType.Struct &&
                            classMember.ElementType != ElementType.Delegate &&
                            classMember.ElementType != ElementType.Enum)
                        {
                            // Found a matching member.
                            if (foundMember == null)
                            {
                                foundMember = classMember;
                            }
                        }
                    }

                    if (foundMember != null)
                    {
                        if (foundMember.ElementType == ElementType.Property)
                        {
                            // If the property's name and type are the same, then this is not a violation.
                            // In this case, the type is being accessed, not the property.
                            Property property = (Property)foundMember;
                            if (property.ReturnType.Text != property.Name)
                            {
                                this.Violation<Token>(
                                    Rules.PrefixLocalCallsWithThis,
                                    new ViolationContext(parentElement, line, word),
                                    this.FixPrefixLocalCallsWithThisViolation,
                                    item);
                            }
                        }
                        else
                        {
                            this.Violation<Token>(
                                Rules.PrefixLocalCallsWithThis,
                                new ViolationContext(parentElement, line, word),
                                this.FixPrefixLocalCallsWithThisViolation,
                                item);
                        }
                    }
                }
            }
        }
Example #22
0
        /// <summary>
        /// Processes the given statement.
        /// </summary>
        /// <param name="statement">The statement to process.</param>
        /// <param name="element">The parent element.</param>
        /// <param name="validPrefixes">The list of acceptable Hungarian-type prefixes.</param>
        private void ProcessStatement(Statement statement, Element element, Dictionary<string, string> validPrefixes)
        {
            Param.AssertNotNull(statement, "statement");
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(validPrefixes, "validPrefixes");

            // Check the statement's variables.
            VariableCollection variables = statement.Variables;

            if (variables != null)
            {
                foreach (IVariable variable in variables)
                {
                    this.CheckMethodVariablePrefix(variable, element, validPrefixes);
                    this.CheckUnderscores(element, variables);
                }
            }

            // Check the expressions under this statement.
            if (statement.Children.ExpressionCount > 0)
            {
                for (Expression expression = statement.FindFirstChildExpression(); expression != null; expression = expression.FindNextSiblingExpression())
                {
                    this.ProcessExpression(expression, element, validPrefixes);
                }
            }

            // Check each of the statements under this statement.
            if (statement.Children.StatementCount > 0)
            {
                for (Statement childStatement = statement.FindFirstChildStatement(); childStatement != null; childStatement = childStatement.FindNextSiblingStatement())
                {
                    this.ProcessStatement(childStatement, element, validPrefixes);
                }
            }
        }
Example #23
0
        /// <summary>
        /// Visits one code unit in the document.
        /// </summary>
        /// <param name="codeUnit">The item being visited.</param>
        /// <param name="parentElement">The parent element, if any.</param>
        /// <param name="parentStatement">The parent statement, if any.</param>
        /// <param name="parentExpression">The parent expression, if any.</param>
        /// <param name="parentClause">The parent query clause, if any.</param>
        /// <param name="parentToken">The parent token, if any.</param>
        /// <param name="settings">The settings.</param>
        /// <returns>Returns true to continue, or false to stop the walker.</returns>
        private bool VisitCodeUnit(
            CodeUnit codeUnit,
            Element parentElement,
            Statement parentStatement,
            Expression parentExpression,
            QueryClause parentClause,
            Token parentToken,
            Settings settings)
        {
            Param.AssertNotNull(codeUnit, "codeUnit");
            Param.Ignore(parentElement, parentStatement, parentExpression, parentClause, parentToken);
            Param.AssertNotNull(settings, "settings");

            if (codeUnit.CodeUnitType == CodeUnitType.Element)
            {
                return this.VisitElement((Element)codeUnit, settings);
            }
            else if (codeUnit.CodeUnitType == CodeUnitType.Expression)
            {
                return this.VisitExpression((Expression)codeUnit, parentElement);
            }
            else if (codeUnit.Is(LexicalElementType.Token))
            {
                Token token = (Token)codeUnit;
                if (token.TokenType == TokenType.Type && !token.Parent.Is(TokenType.Type))
                {
                    // Check that the type is using the built-in types, if applicable.
                    this.CheckBuiltInType((TypeToken)token, parentElement);
                }
                else if (token.TokenType == TokenType.String)
                {
                    // Check that the string is not using the empty string "" syntax.
                    this.CheckEmptyString(token, parentElement);
                }
            }
            else if (codeUnit.Is(PreprocessorType.Region))
            {
                this.CheckRegion((RegionDirective)codeUnit, parentElement, settings);
            }
            else if (codeUnit.Is(LexicalElementType.Comment))
            {
                this.CheckForEmptyComments((Comment)codeUnit, parentElement);
            }

            return !this.Cancel;
        }
Example #24
0
        /// <summary>
        /// Processes the given expression.
        /// </summary>
        /// <param name="expression">The expression to process.</param>
        /// <param name="element">The parent element.</param>
        /// <param name="validPrefixes">The list of acceptable Hungarian-type prefixes.</param>
        private void ProcessExpression(Expression expression, Element element, Dictionary<string, string> validPrefixes)
        {
            Param.AssertNotNull(expression, "expression");
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(validPrefixes, "validPrefixes");

            // Check the type of the expression.
            if (expression.ExpressionType == ExpressionType.AnonymousMethod)
            {
                AnonymousMethodExpression anonymousMethod = (AnonymousMethodExpression)expression;

                // Check the anonymous method's variables.
                VariableCollection variables = anonymousMethod.Variables;
                if (variables != null)
                {
                    foreach (IVariable variable in variables)
                    {
                        this.CheckMethodVariablePrefix(variable, element, validPrefixes);
                    }

                    // Check the statements under the anonymous method.
                    if (anonymousMethod.Children.StatementCount > 0)
                    {
                        for (Statement statement = anonymousMethod.FindFirstChildStatement(); statement != null; statement = statement.FindNextSiblingStatement())
                        {
                            this.ProcessStatement(statement, element, validPrefixes);
                        }
                    }
                }
            }

            // Check the child expressions under this expression.
            if (expression.Children.StatementCount > 0)
            {
                for (Expression childExpression = expression.FindFirstChildExpression(); childExpression != null; childExpression = childExpression.FindNextSiblingExpression())
                {
                    this.ProcessExpression(childExpression, element, validPrefixes);
                }
            }
        }
Example #25
0
        /// <summary>
        /// Checks the given expression.
        /// </summary>
        /// <param name="expression">The expression being visited.</param>
        /// <param name="parentElement">The parent element, if any.</param>
        /// <returns>Returns true to continue, or false to stop the walker.</returns>
        private bool VisitExpression(Expression expression, Element parentElement)
        {
            Param.AssertNotNull(expression, "expression");
            Param.AssertNotNull(parentElement, "parentElement");

            if (!parentElement.Generated)
            {
                if (expression.ExpressionType == ExpressionType.Query)
                {
                    this.CheckQueryExpression(parentElement, (QueryExpression)expression);
                }
                else if (expression.ExpressionType == ExpressionType.MethodInvocation)
                {
                    this.CheckMethodInvocationParameters(parentElement, (MethodInvocationExpression)expression);
                }
            }

            return true;
        }
Example #26
0
        /// <summary>
        /// Checks the case of the first character in the given word.
        /// </summary>
        /// <param name="element">The element that the word appears in.</param>
        /// <param name="name">The word to check.</param>
        /// <param name="line">The line that the word appears on.</param>
        /// <param name="upper">True if the character should be upper, false if it should be lower.</param>
        private void CheckCase(Element element, string name, int line, bool upper)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertValidString(name, "name");
            Param.AssertGreaterThanZero(line, "line");
            Param.Ignore(upper);

            if (name.Length >= 1)
            {
                char firstLetter = name[0];

                // If the first character is not a letter, then it does not make any sense to check
                // for upper or lower case.
                if (char.IsLetter(firstLetter))
                {
                    if (upper)
                    {
                        if (!char.IsUpper(firstLetter))
                        {
                            this.AddViolation(element, line, Rules.ElementMustBeginWithUpperCaseLetter, element.FriendlyTypeText, name);
                        }
                    }
                    else
                    {
                        if (!char.IsLower(firstLetter))
                        {
                            this.AddViolation(element, line, Rules.ElementMustBeginWithLowerCaseLetter, element.FriendlyTypeText, name);
                        }
                    }
                }
            }
        }
Example #27
0
        /// <summary>
        /// Checks a string to determine whether it is using an incorrect empty string notation.
        /// </summary>
        /// <param name="text">The string to check.</param>
        /// <param name="parentElement">The parent element.</param>
        private void CheckEmptyString(Token text, Element parentElement)
        {
            Param.AssertNotNull(text, "text");
            Param.AssertNotNull(parentElement, "parentElement");
            
            Debug.Assert(text.TokenType == TokenType.String, "The token must be a string.");

            if (string.Equals(text.Text, "\"\"", StringComparison.Ordinal) ||
                string.Equals(text.Text, "@\"\"", StringComparison.Ordinal))
            {
                // Look at the previous 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.
                Token previousToken = text.FindPreviousToken();
                if (previousToken == null || (previousToken.TokenType != TokenType.Case && !IsConstVariableDeclaration(previousToken)))
                {
                    this.Violation(
                        Rules.UseStringEmptyForEmptyStrings,
                        new ViolationContext(parentElement, text.LineNumber),
                        (c, o) =>
                        {
                            // Fix the violation.
                            CsDocument document = text.Document;

                            // Create a member access expression which represents "string.Empty".
                            var stringEmpty = document.CreateMemberAccessExpression(document.CreateLiteralExpression("string"), document.CreateLiteralExpression("Empty"));

                            // The parent of the token should be a literal expression.
                            if (text.Parent != null && text.Parent.Is(ExpressionType.Literal))
                            {
                                document.Replace(text.Parent, stringEmpty);
                            }
                            else
                            {
                                Debug.Fail("Unhandled situation");
                            }
                        });
                }
            }
        }
        /// <summary>
        /// Adds a class members to the dictionary.
        /// </summary>
        /// <param name="members">The dictionary of class members.</param>
        /// <param name="child">The class member.</param>
        /// <param name="name">The name of the class member.</param>
        private static void AddClassMember(Dictionary<string, List<Element>> members, Element child, string name)
        {
            Param.AssertNotNull(members, "members");
            Param.AssertNotNull(child, "member");
            Param.AssertValidString(name, "name");

            List<Element> items = null;
            if (!members.TryGetValue(name, out items))
            {
                items = new List<Element>(1);
                members.Add(name, items);
            }

            items.Add(child);
        }
Example #29
0
        /// <summary>
        /// Processes the given element.
        /// </summary>
        /// <param name="element">The element being visited.</param>
        /// <param name="settings">The settings.</param>
        private void CheckForRegionsInElement(Element element, Settings settings)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(settings, "settings");

            // If the DoNotUseRegions setting is enabled, then skip this check as the region 
            // will be discovered during the overall regions rule check.
            if (settings.DoNotPlaceRegionsWithinElements && !settings.DoNotUseRegions && !element.Generated)
            {
                if (element.ElementType == ElementType.Method ||
                    element.ElementType == ElementType.Accessor ||
                    element.ElementType == ElementType.Constructor ||
                    element.ElementType == ElementType.Destructor ||
                    element.ElementType == ElementType.Field)
                {
                    for (RegionDirective region = element.FindFirstDescendent<RegionDirective>(); region != null; region = region.FindNextDescendentOf<RegionDirective>(element))
                    {
                        // If this token is an opening region directive, this is a violation.
                        if (!region.Generated && !region.IsGeneratedCodeRegion)
                        {
                            this.AddViolation(element, region.LineNumber, Rules.DoNotPlaceRegionsWithinElements);
                        }
                    }
                }
            }
        }
        /// <summary>
        /// Checks the items within the given element.
        /// </summary>
        /// <param name="element">The element to check.</param>
        /// <param name="parentClass">The class that the element belongs to.</param>
        /// <param name="members">The collection of members of the parent class.</param>
        /// <returns>Returns false if the analyzer should quit.</returns>
        private bool CheckClassMemberRulesForElements(Element element, ClassBase parentClass, Dictionary<string, List<Element>> members)
        {
            Param.AssertNotNull(element, "element");
            Param.Ignore(parentClass);
            Param.Ignore(members);

            // Check whether processing has been cancelled by the user.
            if (this.Cancel)
            {
                return false;
            }

            if (element.ElementType == ElementType.Class ||
                element.ElementType == ElementType.Struct ||
                element.ElementType == ElementType.Interface)
            {
                parentClass = element as ClassBase;
                members = CollectClassMembers(parentClass);
            }

            for (Element child = element.FindFirstChildElement(); child != null; child = child.FindNextSiblingElement())
            {
                if (!child.Generated)
                {
                    if (child.ElementType == ElementType.Method ||
                        child.ElementType == ElementType.Constructor ||
                        child.ElementType == ElementType.Destructor ||
                        child.ElementType == ElementType.Accessor)
                    {
                        // If the parent class is null, then this element is sitting outside of a class.
                        // This is illegal in C# so the code will not compile, but we still attempt to
                        // parse it. In this case there is no use of this prefixes since there is no class.
                        if (parentClass != null)
                        {
                            this.CheckClassMemberRulesForStatements(child, child, parentClass, members);
                        }
                    }
                    else
                    {
                        if (child.ElementType == ElementType.Class || child.ElementType == ElementType.Struct)
                        {
                            ClassBase elementContainer = child as ClassBase;
                            Debug.Assert(elementContainer != null, "The element is not a class.");

                            this.CheckClassMemberRulesForElements(child, elementContainer, members);
                        }
                        else if (!this.CheckClassMemberRulesForElements(child, parentClass, members))
                        {
                            return false;
                        }
                    }
                }
            }

            return true;
        }