/// <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; }
/// <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 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> /// Checks the order of any using directives found under this element. /// </summary> /// <param name="element">The element containing the using directives.</param> private void CheckOrderOfUsingDirectivesUnderElement(Element element) { Param.AssertNotNull(element, "element"); // Add each of the using directives to an array. List<UsingDirective> usings = null; for (Element childElement = element.FindFirstChildElement(); childElement != null; childElement = childElement.FindNextSiblingElement()) { if (childElement.ElementType == ElementType.UsingDirective) { if (usings == null) { usings = new List<UsingDirective>(); } usings.Add((UsingDirective)childElement); } else if (childElement.ElementType != ElementType.ExternAliasDirective) { break; } } if (usings != null) { this.CheckOrderOfUsingDirectivesInList(usings); } }
/// <summary> /// Checks the order of using directives within the document. /// </summary> /// <param name="rootElement">The root element containing the using directives.</param> private void CheckUsingDirectiveOrder(Element rootElement) { Param.AssertNotNull(rootElement, "rootElement"); if (!rootElement.Generated) { this.CheckOrderOfUsingDirectivesUnderElement(rootElement); // Find any namespace elements within this element. for (Element childElement = rootElement.FindFirstChildElement(); childElement != null; childElement = childElement.FindNextSiblingElement()) { if (childElement.ElementType == ElementType.Namespace) { this.CheckUsingDirectiveOrder(childElement); } } } }
/// <summary> /// Checks the placement of statements within the given element. /// </summary> /// <param name="element">The element to check.</param> private void CheckStatementFormattingRulesForElement(Element element) { Param.AssertNotNull(element, "element"); if (!element.Generated) { if (element.ElementType == ElementType.EmptyElement) { this.AddViolation(element, element.LineNumber, Rules.CodeMustNotContainEmptyStatements); } else { this.CheckStatementFormattingRulesForStatements(element, element); for (Element child = element.FindFirstChildElement(); child != null; child = child.FindNextSiblingElement()) { this.CheckStatementFormattingRulesForElement(child); } } } }
/// <summary> /// Checks the spacing of child elements of the given element, to ensure that elements /// are separated by a blank line. /// </summary> /// <param name="element">The element being visited.</param> private void CheckChildElementSpacing(Element element) { Param.AssertNotNull(element, "element"); Element previousElement = null; if (element.Children.ElementCount > 0) { for (Element childElement = element.FindFirstChildElement(); childElement != null; childElement = childElement.FindNextSiblingElement()) { // Check the line spacing between the two elements if: // - There was a previous element // - AND neither of the elements are generated // - AND the previous element and the current element are of different types // - - OR the current element has a header // - - OR the previous element spans multiple lines // - - OR the elements are not using directives, extern alias directives, accessors, enum items, or fields. if (previousElement != null && !previousElement.Generated && !childElement.Generated && (previousElement.ElementType != childElement.ElementType || childElement.Header != null || previousElement.Location.LineSpan > 1 || (childElement.ElementType != ElementType.UsingDirective && childElement.ElementType != ElementType.ExternAliasDirective && childElement.ElementType != ElementType.Accessor && childElement.ElementType != ElementType.EnumItem && childElement.ElementType != ElementType.Field))) { // The start line of this element is the first line of the header if there is one, // or the first line of the element itself if there is no header. int startLine = childElement.LineNumber; if (childElement.Header != null) { startLine = childElement.Header.LineNumber; } if (startLine == previousElement.Location.EndPoint.LineNumber || startLine == previousElement.Location.EndPoint.LineNumber + 1) { this.AddViolation(childElement, Rules.ElementsMustBeSeparatedByBlankLine); } } previousElement = childElement; } } }