예제 #1
0
        /// <summary>
        /// Gets the list of partial elements with the same fully qualified name as this element.
        /// </summary>
        /// <param name="element">The element to find partial partners of.</param>
        /// <returns>Returns the collection of partial elements of this type.</returns>
        /// <remarks>If this is not a partial element, this property returns null.</remarks>
        public ICollection <Element> GetPartialElements(Element element)
        {
            Param.RequireNotNull(element, "element");

            if (element.ContainsModifier(TokenType.Partial))
            {
                [email protected]();

                try
                {
                    List <Element> partialElementList;

                    if (this.partialElements.TryGetValue(element.FullyQualifiedName, out partialElementList))
                    {
                        return(partialElementList.AsReadOnly());
                    }
                }
                finally
                {
                    [email protected]();
                }
            }

            return(Element.EmptyElementArray);
        }
예제 #2
0
        /// <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;
        }
예제 #4
0
        /// <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>
        /// 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;
        }
예제 #6
0
        private bool CompareItems(Element first, Element 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.
                Element 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)
                {
                    // Check the access modifiers to see if they are in the correct order.
                    if (first.AccessModifierType > second.AccessModifierType)
                    {
                        // 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.DeclaresAccessModifier && first.ElementType != ElementType.Method && first.ContainsModifier(TokenType.Partial)) ||
                            (!second.DeclaresAccessModifier && second.ElementType != ElementType.Method && second.ContainsModifier(TokenType.Partial)))
                        {
                            // Make sure to use the line number of the partial element which does not contain
                            // an access modifier.
                            Element elementWithoutAccessModifier = first;
                            if (first.DeclaresAccessModifier || !first.ContainsModifier(TokenType.Partial))
                            {
                                elementWithoutAccessModifier = second;
                            }

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

                        return false;
                    }
                    else if (first.AccessModifierType == second.AccessModifierType)
                    {
                        bool firstConstant = false;
                        bool firstReadonly = false;

                        Field firstVariable = first as Field;
                        Field secondVariable = second as Field;

                        if (firstVariable != null && secondVariable != null)
                        {
                            firstConstant = firstVariable.Const;
                            firstReadonly = firstVariable.Readonly;
                                
                            // Check to make sure that constant and readonly items 
                            // come before non-constant, non-readonly items
                            if ((secondVariable.Const || secondVariable.Readonly) && 
                                !(firstVariable.Const || firstVariable.Readonly))
                            {
                                this.AddViolation(
                                    first, 
                                    invalidElement.LineNumber,
                                    Rules.ConstantsMustAppearBeforeFields, 
                                    OrderingRules.AccessModifierTypeString(first.AccessModifierType),
                                    first.FriendlyPluralTypeText,
                                    OrderingRules.AccessModifierTypeString(second.AccessModifierType),
                                    second.FriendlyPluralTypeText);

                                return false;
                            }
                        }

                        // Check to make sure that static items come before non-static items but after
                        // const and readonly items
                        if (second.ContainsModifier(TokenType.Static) && 
                            !(first.ContainsModifier(TokenType.Static) || firstConstant || firstReadonly))
                        {
                            this.AddViolation(
                                first, 
                                invalidElement.LineNumber,
                                Rules.StaticElementsMustAppearBeforeInstanceElements, 
                                OrderingRules.AccessModifierTypeString(first.AccessModifierType),
                                first.FriendlyPluralTypeText,
                                OrderingRules.AccessModifierTypeString(second.AccessModifierType),
                                second.FriendlyPluralTypeText);

                            return false;
                        }
                    }
                }
            }
            
            return true;
        }
        /// <summary>
        /// Gets the list of partial elements with the same fully qualified name as this element.
        /// </summary>
        /// <param name="element">The element to find partial partners of.</param>
        /// <returns>Returns the collection of partial elements of this type.</returns>
        /// <remarks>If this is not a partial element, this property returns null.</remarks>
        public ICollection<Element> GetPartialElements(Element element)
        {
            Param.RequireNotNull(element, "element");

            if (element.ContainsModifier(TokenType.Partial))
            {
                [email protected]();

                try
                {
                    List<Element> partialElementList;

                    if (this.partialElements.TryGetValue(element.FullyQualifiedName, out partialElementList))
                    {
                        return partialElementList.AsReadOnly();
                    }
                }
                finally
                {
                    [email protected]();
                }
            }

            return Element.EmptyElementArray;
        }
예제 #8
0
        /// <summary>
        /// Checks to see if the element is unnecessary.
        /// </summary>
        /// <param name="element">The element to check.</param>
        private void CheckForEmptyElements(Element element)
        {
            Param.AssertNotNull(element, "element");

            if (!element.Generated)
            {
                if (element.ElementType == ElementType.Constructor && element.ContainsModifier(TokenType.Static))
                {
                    if (IsEmptyElement(element))
                    {
                        this.AddViolation(element, Rules.RemoveUnnecessaryCode, element.FriendlyTypeText);
                    }
                }
            }
        }
예제 #9
0
        /// <summary>
        /// Verifies that elements have access modifiers.
        /// </summary>
        /// <param name="element">The element to check.</param>
        private void CheckForAccessModifier(Element element)
        {
            Param.AssertNotNull(element, "element");

            if (element.ElementType == ElementType.Method ||
                element.ElementType == ElementType.Property ||
                element.ElementType == ElementType.Indexer ||
                element.ElementType == ElementType.Event)
            {
                // A Method, property, indexer or event must have access an modifier unless it
                // is an explicit implementation of an interface member, in which case it is public by
                // default and you are not allowed to specify an access modifier. Partial methods are not allowed
                // to have access modifier so we skip those as well.
                if (!element.DeclaresAccessModifier && !element.ContainsModifier(TokenType.Partial))
                {
                    if (element.Name.IndexOf(".", StringComparison.Ordinal) == -1 ||
                        element.Name.StartsWith("this.", StringComparison.Ordinal))
                    {
                        this.AddViolation(element, Rules.AccessModifierMustBeDeclared, element.FriendlyTypeText);
                    }
                }
            }
            else if (element.ElementType == ElementType.Class ||
                element.ElementType == ElementType.Field ||
                element.ElementType == ElementType.Enum ||
                element.ElementType == ElementType.Struct ||
                element.ElementType == ElementType.Interface ||
                element.ElementType == ElementType.Delegate)
            {
                if (!element.DeclaresAccessModifier)
                {
                    this.AddViolation(element, Rules.AccessModifierMustBeDeclared, element.FriendlyTypeText);
                }
            }
            else if (element.ElementType == ElementType.Constructor)
            {
                // If a constructor is not static it must have an access modifier.
                if (!element.DeclaresAccessModifier && !element.ContainsModifier(TokenType.Static))
                {
                    this.AddViolation(element, Rules.AccessModifierMustBeDeclared, element.FriendlyTypeText);
                }
            }
        }
예제 #10
0
        /// <summary>
        /// Determines whether the given element is a non-public, static extern element with a DllImport attribute.
        /// </summary>
        /// <param name="element">The element to check.</param>
        /// <returns>Returns true if the element is a non-public, static extern element.</returns>
        private static bool IsNonPublicStaticExternDllImport(Element element)
        {
            Param.AssertNotNull(element, "element");

            // If the method is not public, then it is not a valid DllImport.
            var actualAccess = element.ActualAccessLevel;
            if (actualAccess == AccessModifierType.Public)
            {
                return false;
            }

            // If the method is not static and extern, then it is not a valid DllImport.
            if (!element.ContainsModifier(TokenType.Static) ||
                !element.ContainsModifier(TokenType.Extern))
            {
                return false;
            }

            // Look for a DllImport attribute.
            if (element.Attributes != null)
            {
                foreach (StyleCop.CSharp.CodeModel.Attribute attribute in element.Attributes)
                {
                    if (attribute.AttributeExpressions != null)
                    {
                        foreach (AttributeExpression attributeExpression in attribute.AttributeExpressions)
                        {
                            for (MethodInvocationExpression innerMethod = attributeExpression.FindFirstChild<MethodInvocationExpression>(); 
                                innerMethod != null; 
                                innerMethod = innerMethod.FindNextSibling<MethodInvocationExpression>())
                            {
                                Expression name = innerMethod.Name;
                                if (name != null)
                                {
                                    Token startOfName = name.FindFirstDescendentToken();

                                    if (startOfName != null)
                                    {
                                        if (name.MatchTokensFrom(startOfName, "DllImport") ||
                                            name.MatchTokensFrom(startOfName, "DllImportAttribute") ||
                                            name.MatchTokensFrom(startOfName, "System", ".", "Runtime", ".", "InteropServices", ".", "DllImport") ||
                                            name.MatchTokensFrom(startOfName, "System", ".", "Runtime", ".", "InteropServices", ".", "DllImportAttribute"))
                                        {
                                            // The method is a public, static, extern DllImport.
                                            return true;
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return false;
        }
예제 #11
0
        /// <summary>
        /// Checks the generic type parameters of a header for consistancy with the item the header belongs to.
        /// </summary>
        /// <param name="element">The element to check.</param>
        /// <param name="formattedDocs">The formatted Xml document that comprises the header.</param>
        private void CheckGenericTypeParams(Element element, XmlDocument formattedDocs)
        {
            Param.AssertNotNull(element, "element");
            Param.AssertNotNull(formattedDocs, "formattedDocs");

            List<string> types = DocumentationRules.ExtractGenericTypeList(element.Name);
            if (types != null && types.Count > 0)
            {
                // Go through each type and make sure there is a header for it.
                XmlNodeList paramNodes = formattedDocs.SelectNodes("root/typeparam");
                if (paramNodes == null || paramNodes.Count == 0)
                {
                    // If this is a partial class and the header contains a content tag rather
                    // than a summary tag, then assume that the typeparams are documented on
                    // another part of the partial class, and ignore this.
                    bool isPartial = element.ContainsModifier(TokenType.Partial);
                    if (!isPartial || formattedDocs.SelectSingleNode("root/summary") != null || formattedDocs.SelectSingleNode("root/content") == null)
                    {
                        if (isPartial)
                        {
                            // Output a special message for partial classes which explains about content tags.
                            this.AddViolation(element, Rules.GenericTypeParametersMustBeDocumentedPartialClass, element.FriendlyTypeText);
                        }
                        else
                        {
                            this.AddViolation(element, Rules.GenericTypeParametersMustBeDocumented, element.FriendlyTypeText);
                        }
                    }
                }
                else
                {
                    for (int i = 0; i < paramNodes.Count; ++i)
                    {
                        XmlNode paramNode = paramNodes[i];
                        if (types.Count <= i)
                        {
                            this.AddViolation(element, Rules.GenericTypeParameterDocumentationMustMatchTypeParameters, element.FriendlyTypeText);
                            break;
                        }
                        else
                        {
                            XmlNode attrib = paramNode.Attributes.GetNamedItem("name");
                            if (attrib == null || attrib.Value.Length == 0)
                            {
                                this.AddViolation(element, Rules.GenericTypeParameterDocumentationMustDeclareParameterName);
                            }
                            else if (attrib.Value != types[i])
                            {
                                this.AddViolation(element, Rules.GenericTypeParameterDocumentationMustMatchTypeParameters, element.FriendlyTypeText);
                                break;
                            }
                        }
                    }

                    // If the element has more parameters than param tags.
                    if (types.Count > paramNodes.Count)
                    {
                        this.AddViolation(element, Rules.GenericTypeParameterDocumentationMustMatchTypeParameters, element.FriendlyTypeText);
                    }

                    // Make sure none of the parameters is empty.
                    foreach (XmlNode paramNode in paramNodes)
                    {
                        if (paramNode.InnerText == null || paramNode.InnerText.Length == 0)
                        {
                            this.AddViolation(element, Rules.GenericTypeParameterDocumentationMustHaveText, paramNode.OuterXml);
                        }
                        else
                        {
                            this.CheckDocumentationValidity(element, element.LineNumber, paramNode, "typeparam");
                        }
                    }
                }
            }
        }