/// <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); }
/// <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> /// 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; }
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; }
/// <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); } } } }
/// <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); } } }
/// <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; }
/// <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"); } } } } }