/// <summary> /// Writes a starting region directive. /// </summary> /// <param name="element">Region element.</param> protected override void WriteRegionBeginDirective(RegionElement element) { StringBuilder builder = new StringBuilder(DefaultBlockLength); builder.Append(VBSymbol.Preprocessor); builder.Append(VBKeyword.Region); builder.Append(" \""); builder.Append(element.Name); builder.Append('"'); WriteIndented(builder.ToString()); }
/// <summary> /// Writes an ending region directive. /// </summary> /// <param name="element">Region element.</param> protected override void WriteRegionEndDirective(RegionElement element) { StringBuilder builder = new StringBuilder(DefaultBlockLength); builder.Append(VBSymbol.Preprocessor); builder.Append(VBKeyword.End); builder.Append(' '); builder.Append(VBKeyword.Region); if (Configuration.Formatting.Regions.EndRegionNameEnabled) { builder.Append(" '"); builder.Append(element.Name); } WriteIndented(builder.ToString()); }
public void InsertNullTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Name; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.Field, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert a non-null element // FieldElement field1 = new FieldElement(); field1.Name = "newField"; sortedInserter.InsertElement(regionElement, field1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); // // Insert a null element // FieldElement field2 = null; sortedInserter.InsertElement(regionElement, field2); Assert.AreEqual(1, regionElement.Children.Count, "Element should not have been inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); }
/// <summary> /// Arranges the specified code element into the parent. /// </summary> /// <param name="parentElement">Parent element to arrange within.</param> /// <param name="codeElement">Code element to arrange.</param> public void ArrangeElement(ICodeElement parentElement, ICodeElement codeElement) { InitializeChildrenArranger(); if (codeElement != null) { RegionElement region = null; string regionName = _regionConfiguration.Name; bool directivesEnabled = _regionConfiguration.DirectivesEnabled; foreach (ICodeElement childElement in parentElement.Children) { RegionElement regionElement = childElement as RegionElement; if (regionElement != null && regionElement.Name == regionName) { region = regionElement; break; } } if (region == null) { region = new RegionElement(); region.Name = regionName; region.DirectivesEnabled = directivesEnabled; if (parentElement.Children.Count == 0) { parentElement.AddChild(region); } else { // // Determine where to insert the new region // int insertIndex = 0; int compareIndex = _levelRegions.IndexOf(region.Name); for (int siblingIndex = 0; siblingIndex < parentElement.Children.Count; siblingIndex++) { RegionElement siblingRegion = parentElement.Children[siblingIndex] as RegionElement; if (siblingRegion != null) { insertIndex = siblingIndex; int siblingCompareIndex = _levelRegions.IndexOf(siblingRegion.Name); if (compareIndex <= siblingCompareIndex) { break; } else { insertIndex++; } } else { insertIndex++; } } parentElement.InsertChild(insertIndex, region); } } _childrenArranger.ArrangeElement(region, codeElement); } }
public void MoveUsingsToNamespaceTest() { List<ICodeElement> codeElements = new List<ICodeElement>(); UsingElement using1 = new UsingElement(); using1.Name = "System"; using1.IsMovable = true; codeElements.Add(using1); // Nested region and groups RegionElement region = new RegionElement(); region.Name = "Region"; codeElements.Add(region); GroupElement group = new GroupElement(); group.Name = "Group"; region.AddChild(group); UsingElement using2 = new UsingElement(); using2.Name = "System.IO"; using2.IsMovable = true; group.AddChild(using2); NamespaceElement namespaceElement = new NamespaceElement(); namespaceElement.Name = "TestNamespace"; codeElements.Add(namespaceElement); UsingElement using3 = new UsingElement(); using3.Name = "System.Collections"; using3.IsMovable = true; namespaceElement.AddChild(using3); TypeElement class1 = new TypeElement(); class1.Name = "Class1"; namespaceElement.AddChild(class1); TypeElement class2 = new TypeElement(); class2.Name = "Class2"; namespaceElement.AddChild(class2); CodeConfiguration configuration = CodeConfiguration.Default.Clone() as CodeConfiguration; CodeArranger arranger; // // Move to namespace. // configuration.Formatting.Usings.MoveTo = CodeLevel.Namespace; arranger = new CodeArranger(configuration); ReadOnlyCollection<ICodeElement> arranged = arranger.Arrange(codeElements.AsReadOnly()); Assert.AreEqual(2, arranged.Count, "After arranging, an unexpected number of elements were returned."); NamespaceElement namespaceElementTest = arranged[1] as NamespaceElement; Assert.IsNotNull(namespaceElementTest, "Expected a namespace element."); Assert.AreEqual(2, namespaceElementTest.Children.Count, "After arranging, an unexpected number of namespace elements were returned."); GroupElement namespaceGroup = namespaceElementTest.Children[0] as GroupElement; Assert.IsNotNull(namespaceGroup); GroupElement innerGroup = namespaceGroup.Children[0] as GroupElement; Assert.AreEqual("System", innerGroup.Children[0].Name); Assert.AreEqual("System.Collections", innerGroup.Children[1].Name); Assert.AreEqual("System.IO", innerGroup.Children[2].Name); RegionElement typeRegion = namespaceElementTest.Children[1] as RegionElement; Assert.IsNotNull(typeRegion); Assert.AreEqual("Class1", typeRegion.Children[0].Name); Assert.AreEqual("Class2", typeRegion.Children[1].Name); }
public void InsertByTypeTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Type; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.Method, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert an element with a mid alphabet return type. // MethodElement method1 = new MethodElement(); method1.Name = "DoSomething"; method1.Type = "Nullable<DateTime>"; sortedInserter.InsertElement(regionElement, method1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(method1), "Element was not inserted at the correct index."); // // Insert an element that should be sorted toward the end // MethodElement method2 = new MethodElement(); method2.Name = "DoSomething"; method2.Type = "Type"; sortedInserter.InsertElement(regionElement, method2); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(method1), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(method2), "Element is not at the correct index."); // // Insert an element that should be sorted toward the beginning // MethodElement method3 = new MethodElement(); method3.Name = "DoSomething"; method3.Type = "IEnumerable"; sortedInserter.InsertElement(regionElement, method3); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(method3), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(method1), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(method2), "Element is not at the correct index."); }
public void InsertByNameTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Name; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.Field, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert an element with a mid alphabet name. // FieldElement field1 = new FieldElement(); field1.Name = "newField"; sortedInserter.InsertElement(regionElement, field1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); // // Insert an element that should be sorted toward the end // FieldElement field2 = new FieldElement(); field2.Name = "zooField"; sortedInserter.InsertElement(regionElement, field2); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); // // Insert an element that should be sorted toward the beginning // FieldElement field3 = new FieldElement(); field3.Name = "booField"; sortedInserter.InsertElement(regionElement, field3); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); }
/// <summary> /// Parses a region from the preprocessor line. /// </summary> /// <param name="line">Region start line.</param> /// <returns>A region element for the line.</returns> private RegionElement ParseRegion(string line) { RegionElement regionElement; string regionName = line.Substring(VBKeyword.Region.Length).Trim(' ', '"'); if (string.IsNullOrEmpty(regionName)) { this.OnParseError("Expected region name"); } regionElement = new RegionElement(); regionElement.Name = regionName; return regionElement; }
public void InsertByElementTypeTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.ElementType; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.NotSpecified, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert an element with a middle access. // ConstructorElement constructor = new ConstructorElement(); constructor.Name = "SomeClass"; constructor.Access = CodeAccess.Public; sortedInserter.InsertElement(regionElement, constructor); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(constructor), "Element was not inserted at the correct index."); // // Insert an element that should be sorted toward the end // MethodElement methodElement = new MethodElement(); methodElement.Name = "SomeMethod"; methodElement.Access = CodeAccess.Public; sortedInserter.InsertElement(regionElement, methodElement); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(constructor), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(methodElement), "Element is not at the correct index."); // // Insert an element that should be sorted toward the beginning // FieldElement fieldElement = new FieldElement(); fieldElement.Name = "someField"; fieldElement.Access = CodeAccess.Private; sortedInserter.InsertElement(regionElement, fieldElement); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(fieldElement), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(constructor), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(methodElement), "Element is not at the correct index."); }
public void InsertByAccessAndNameTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Access; sortBy.Direction = SortDirection.Ascending; SortBy innerSortBy = new SortBy(); innerSortBy.By = ElementAttributeType.Name; innerSortBy.Direction = SortDirection.Ascending; sortBy.InnerSortBy = innerSortBy; SortedInserter sortedInserter = new SortedInserter(ElementType.Field, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert elements with middle access. // FieldElement field1 = new FieldElement(); field1.Access = CodeAccess.Protected | CodeAccess.Internal; field1.Name = "newField"; sortedInserter.InsertElement(regionElement, field1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); FieldElement field2 = new FieldElement(); field2.Access = CodeAccess.Protected | CodeAccess.Internal; field2.Name = "gooField"; sortedInserter.InsertElement(regionElement, field2); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field2), "Element was not inserted at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); // // Insert an element that should be sorted toward the end // FieldElement field3 = new FieldElement(); field3.Access = CodeAccess.Public; field3.Name = "zooField"; sortedInserter.InsertElement(regionElement, field3); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field2), "Element was not inserted at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); FieldElement field4 = new FieldElement(); field4.Access = CodeAccess.Public; field4.Name = "tooField"; sortedInserter.InsertElement(regionElement, field4); Assert.AreEqual(4, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field2), "Element was not inserted at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field4), "Element is not at the correct index."); Assert.AreEqual(3, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); // // Insert an element that should be sorted toward the beginning // FieldElement field5 = new FieldElement(); field5.Access = CodeAccess.Private; field5.Name = "booField"; sortedInserter.InsertElement(regionElement, field5); Assert.AreEqual(5, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field5), "Element was not inserted at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field2), "Element was not inserted at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); Assert.AreEqual(3, regionElement.Children.IndexOf(field4), "Element is not at the correct index."); Assert.AreEqual(4, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); FieldElement field6 = new FieldElement(); field6.Access = CodeAccess.Private; field6.Name = "fooField"; sortedInserter.InsertElement(regionElement, field6); Assert.AreEqual(6, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field5), "Element was not inserted at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field6), "Element was not inserted at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field2), "Element was not inserted at the correct index."); Assert.AreEqual(3, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); Assert.AreEqual(4, regionElement.Children.IndexOf(field4), "Element is not at the correct index."); Assert.AreEqual(5, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); }
public void InsertByAccessTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Access; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.Field, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert an element with a middle access. // FieldElement field1 = new FieldElement(); field1.Access = CodeAccess.Protected | CodeAccess.Internal; sortedInserter.InsertElement(regionElement, field1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); // // Insert an element that should be sorted toward the end // FieldElement field2 = new FieldElement(); field2.Access = CodeAccess.Public; sortedInserter.InsertElement(regionElement, field2); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); // // Insert an element that should be sorted toward the beginning // FieldElement field3 = new FieldElement(); field3.Access = CodeAccess.Private; sortedInserter.InsertElement(regionElement, field3); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); }
/// <summary> /// Parses a collection of elements. /// </summary> /// <param name="parentElement">Parent element for context.</param> /// <returns>Parsed code elements.</returns> private List<ICodeElement> ParseElements(ICodeElement parentElement) { List<ICodeElement> codeElements = new List<ICodeElement>(); List<ICommentElement> comments = new List<ICommentElement>(); List<AttributeElement> attributes = new List<AttributeElement>(); Stack<ICodeElement> enclosingElementStack = new Stack<ICodeElement>(); StringBuilder elementBuilder = new StringBuilder(DefaultBlockLength); char nextChar; while (TryReadChar()) { switch (CurrentChar) { // // Comments // case CSharpSymbol.BeginComment: nextChar = NextChar; if (nextChar == CSharpSymbol.BeginComment) { CommentElement commentLine = ParseCommentLine(); string commentDirectiveRegionName = GetCommentDirectiveText(commentLine, Configuration.Formatting.Regions.CommentDirectiveBeginPattern, "Name"); if (commentDirectiveRegionName != null) { PushComments(codeElements, comments); RegionElement regionElement = new RegionElement(); regionElement.Name = commentDirectiveRegionName; enclosingElementStack.Push(regionElement); } else { commentDirectiveRegionName = GetCommentDirectiveText(commentLine, Configuration.Formatting.Regions.CommentDirectiveEndPattern, "Name"); if (commentDirectiveRegionName != null) { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.Region) { this.OnParseError("Unmatched end region directive"); } ICodeElement enclosingElement = enclosingElementStack.Pop(); // // Add any processed comments to the region or condition directive. // if (comments.Count > 0) { foreach (ICommentElement commentElement in comments) { enclosingElement.AddChild(commentElement); } comments.Clear(); } // // Are we processing a nested region or condition directive? // if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(enclosingElement); } else { codeElements.Add(enclosingElement); } } else { comments.Add(commentLine); } } } else if (nextChar == CSharpSymbol.BlockCommentModifier) { CommentElement commentBlock = ParseCommentBlock(); comments.Add(commentBlock); } else { elementBuilder.Append(CurrentChar); } break; // // Preprocessor // case CSharpSymbol.Preprocessor: // // TODO: Parse pragma directives // string line = ReadLine().Trim(); if (line.StartsWith(CSharpKeyword.Region, StringComparison.Ordinal)) { PushComments(codeElements, comments); RegionElement regionElement = ParseRegion(line); enclosingElementStack.Push(regionElement); } else if (line.StartsWith(CSharpKeyword.If, StringComparison.Ordinal) || line.StartsWith(CSharpKeyword.Else, StringComparison.Ordinal) || line.StartsWith(CSharpKeyword.Elif, StringComparison.Ordinal)) { bool isIf; ConditionDirectiveElement conditionDirective = ParseConditionDirective(line.Trim(), out isIf); if (isIf) { enclosingElementStack.Push(conditionDirective); } else { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective) { this.OnParseError("Expected 'if' preprocessor directive."); } else { ConditionDirectiveElement previousCondition = enclosingElementStack.Peek() as ConditionDirectiveElement; while (previousCondition.ElseCondition != null) { previousCondition = previousCondition.ElseCondition; } // // Add the condition to the end of the condition linked list // previousCondition.ElseCondition = conditionDirective; } } } else if (line.StartsWith(CSharpKeyword.EndRegion, StringComparison.Ordinal) || line.StartsWith(CSharpKeyword.EndIf, StringComparison.Ordinal)) { ICodeElement enclosingElement = null; // // If we don't have an element of the same type on the stack, then // we've got a mismatch for the closing directive. // if (line.StartsWith(CSharpKeyword.EndRegion, StringComparison.Ordinal)) { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.Region) { this.OnParseError("Unmatched end region directive"); } } else if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective) { this.OnParseError("Unmatched #endif"); } enclosingElement = enclosingElementStack.Pop(); // // Add any processed comments to the region or condition directive. // if (comments.Count > 0) { foreach (ICommentElement commentElement in comments) { enclosingElement.AddChild(commentElement); } comments.Clear(); } // // If there are any attributes not associated with an element (e.g. // a condition directive containing only an attribute, then // throw an error as this is currently not supported. // if (enclosingElement.ElementType == ElementType.ConditionDirective && attributes.Count > 0) { this.OnParseError("Cannot arrange files with preprocessor directives containing attributes unassociated to an element"); } // // Are we processing a nested region or condition directive? // if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(enclosingElement); } else { codeElements.Add(enclosingElement); } } else { this.OnParseError( "Cannot arrange files with preprocessor directives " + "other than #region, #endregion and conditional compilation directives"); } break; // // Attribute // case CSharpSymbol.BeginAttribute: nextChar = NextChar; // // Parse array definition // if (elementBuilder.Length > 0) { EatWhiteSpace(); nextChar = NextChar; if (nextChar == CSharpSymbol.EndAttribute) { // Array type EatChar(CSharpSymbol.EndAttribute); elementBuilder.Append(CSharpSymbol.BeginAttribute); elementBuilder.Append(CSharpSymbol.EndAttribute); elementBuilder.Append(' '); } else { string nestedText = ParseNestedText( CSharpSymbol.BeginAttribute, CSharpSymbol.EndAttribute, false, true); elementBuilder.Append(CSharpSymbol.BeginAttribute); elementBuilder.Append(nestedText); elementBuilder.Append(CSharpSymbol.EndAttribute); } } else { // // Parse attribute // AttributeElement attributeElement = ParseAttribute(comments.AsReadOnly()); attributes.Add(attributeElement); codeElements.Add(attributeElement); comments.Clear(); } break; // // Trim generics // case CSharpSymbol.BeginGeneric: string elementText = elementBuilder.ToString(); if (elementBuilder.Length > 0 && !(elementText.Trim().EndsWith(CSharpKeyword.Operator, StringComparison.Ordinal))) { string nestedText = ParseNestedText( CSharpSymbol.BeginGeneric, CSharpSymbol.EndGeneric, false, true); // // Trim whitespace preceding type parameters // TrimTrailingWhiteSpace(elementBuilder); elementBuilder.Append(CSharpSymbol.BeginGeneric); elementBuilder.Append(nestedText); elementBuilder.Append(CSharpSymbol.EndGeneric); } else { elementBuilder.Append(CurrentChar); } break; case CSharpSymbol.Nullable: TrimTrailingWhiteSpace(elementBuilder); elementBuilder.Append(CurrentChar); break; // Eat any unneeded whitespace case ' ': case '\n': case '\r': case '\t': if (elementBuilder.Length > 0 && elementBuilder[elementBuilder.Length - 1] != ' ') { elementBuilder.Append(' '); } break; default: elementBuilder.Append(CurrentChar); nextChar = NextChar; if (char.IsWhiteSpace(nextChar) || CSharpSymbol.IsCSharpSymbol(CurrentChar)) { // // Try to parse a code element // ICodeElement element = TryParseElement( parentElement, elementBuilder, comments.AsReadOnly(), attributes.AsReadOnly()); if (element != null) { if (element is CommentedElement) { UsingElement usingElement = element as UsingElement; // // If this is the first using statement, then don't attach // header comments to the element. // if (usingElement != null && parentElement == null && codeElements.Count == 0) { foreach (ICommentElement commentElement in usingElement.HeaderComments) { if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(commentElement); } else { codeElements.Add(commentElement); } } usingElement.ClearHeaderCommentLines(); } comments.Clear(); } if (enclosingElementStack.Count > 0) { ICodeElement enclosingElement = enclosingElementStack.Peek(); if (enclosingElement.ElementType == ElementType.ConditionDirective) { ConditionDirectiveElement conditionDirective = enclosingElement as ConditionDirectiveElement; while (conditionDirective.ElseCondition != null) { conditionDirective = conditionDirective.ElseCondition; } enclosingElement = conditionDirective; } enclosingElement.AddChild(element); } else { codeElements.Add(element); } elementBuilder = new StringBuilder(DefaultBlockLength); if (element is IAttributedElement) { foreach (AttributeElement attribute in attributes) { codeElements.Remove(attribute); } attributes = new List<AttributeElement>(); } } } break; } char nextCh = NextChar; // // Elements should capture closing block characters // if (nextCh == CSharpSymbol.EndBlock) { break; } } if (comments.Count > 0) { for (int commentIndex = 0; commentIndex < comments.Count; commentIndex++) { ICommentElement comment = comments[commentIndex]; codeElements.Insert(commentIndex, comment); } } // // Make sure that all region elements and preprocessor directives have been closed // if (enclosingElementStack.Count > 0) { if (enclosingElementStack.Peek().ElementType == ElementType.Region) { this.OnParseError( string.Format( CultureInfo.InvariantCulture, "Missing end region directive for '{0}'", enclosingElementStack.Peek().Name)); } else { this.OnParseError("Expected #endif"); } } if (elementBuilder.Length > 0) { this.OnParseError( string.Format( Thread.CurrentThread.CurrentCulture, "Unhandled element text '{0}'", elementBuilder)); } return codeElements; }
/// <summary> /// Parses a region from the preprocessor line. /// </summary> /// <param name="line">Line of text containing the region to parse.</param> /// <returns>A region element.</returns> private static RegionElement ParseRegion(string line) { RegionElement regionElement; string regionName = line.Substring(CSharpKeyword.Region.Length).Trim(); // A region name is not required, so allow empty string regionElement = new RegionElement(); regionElement.Name = regionName; return regionElement; }
/// <summary> /// Processes a region element. /// </summary> /// <param name="element">Region code element.</param> public void VisitRegionElement(RegionElement element) { RegionStyle regionStyle = _configuration.Formatting.Regions.Style; if (regionStyle == RegionStyle.Default) { // Use the default region style regionStyle = RegionStyle.Directive; } if (regionStyle == RegionStyle.NoDirective || !element.DirectivesEnabled) { CodeWriter.WriteVisitElements(element.Children, Writer, this); } else { if (regionStyle == RegionStyle.Directive) { WriteRegionBeginDirective(element); } else if (regionStyle == RegionStyle.CommentDirective) { CommentElement commentDirective = new CommentElement( string.Format( CultureInfo.InvariantCulture, Configuration.Formatting.Regions.CommentDirectiveBeginFormat, element.Name).TrimEnd()); VisitCommentElement(commentDirective); } Writer.WriteLine(); WriteChildren(element); if (element.Children.Count > 0) { Writer.WriteLine(); } if (regionStyle == RegionStyle.Directive) { WriteRegionEndDirective(element); } else if (regionStyle == RegionStyle.CommentDirective) { string regionName = string.Empty; if (Configuration.Formatting.Regions.EndRegionNameEnabled) { regionName = element.Name; } CommentElement commentDirective = new CommentElement( string.Format( CultureInfo.InvariantCulture, Configuration.Formatting.Regions.CommentDirectiveEndFormat, regionName).TrimEnd()); VisitCommentElement(commentDirective); } } }
public void InsertByNoneTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.None; sortBy.Direction = SortDirection.Ascending; SortedInserter sortedInserter = new SortedInserter(ElementType.Field, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // With no criteria specified, elements should just be inserted // at the end of the collection. // FieldElement field1 = new FieldElement(); field1.Name = "zooField"; sortedInserter.InsertElement(regionElement, field1); Assert.AreEqual(1, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element was not inserted at the correct index."); FieldElement field2 = new FieldElement(); field1.Name = "newField"; sortedInserter.InsertElement(regionElement, field2); Assert.AreEqual(2, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); FieldElement field3 = new FieldElement(); field1.Name = "booField"; sortedInserter.InsertElement(regionElement, field3); Assert.AreEqual(3, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(field1), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(field2), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(field3), "Element is not at the correct index."); }
/// <summary> /// Writes an ending region directive. /// </summary> /// <param name="element">The region element.</param> protected abstract void WriteRegionEndDirective(RegionElement element);
public void InsertByTypeElementTypeDescendingTest() { SortBy sortBy = new SortBy(); sortBy.By = ElementAttributeType.Type; sortBy.Direction = SortDirection.Descending; SortedInserter sortedInserter = new SortedInserter(ElementType.Type, sortBy); // // Create a parent element // RegionElement regionElement = new RegionElement(); Assert.AreEqual(0, regionElement.Children.Count, "Parent element should not have any children."); // // Insert an element with a mid value. // TypeElement type1 = new TypeElement(); type1.Name = "Type1"; type1.Type = TypeElementType.Structure; sortedInserter.InsertElement(regionElement, type1); // // Insert an element that should be sorted toward the end // TypeElement type2 = new TypeElement(); type2.Name = "Type2"; type2.Type = TypeElementType.Class; sortedInserter.InsertElement(regionElement, type2); // // Insert an element that should be sorted toward the middle // TypeElement type3 = new TypeElement(); type3.Name = "Type3"; type3.Type = TypeElementType.Interface; sortedInserter.InsertElement(regionElement, type3); // // Insert an element that should be sorted toward the beginning // TypeElement type4 = new TypeElement(); type4.Name = "Type4"; type4.Type = TypeElementType.Enum; sortedInserter.InsertElement(regionElement, type4); Assert.AreEqual(4, regionElement.Children.Count, "Element was not inserted into the parent."); Assert.AreEqual(0, regionElement.Children.IndexOf(type4), "Element is not at the correct index."); Assert.AreEqual(1, regionElement.Children.IndexOf(type3), "Element is not at the correct index."); Assert.AreEqual(2, regionElement.Children.IndexOf(type1), "Element is not at the correct index."); Assert.AreEqual(3, regionElement.Children.IndexOf(type2), "Element is not at the correct index."); }
/// <summary> /// Parses elements from the current point in the stream. /// </summary> /// <param name="parentElement">Parent element</param> /// <returns>A list of parsed code elements.</returns> private List<ICodeElement> ParseElements(ICodeElement parentElement) { List<ICodeElement> codeElements = new List<ICodeElement>(); List<ICommentElement> comments = new List<ICommentElement>(); List<AttributeElement> attributes = new List<AttributeElement>(); Stack<ICodeElement> enclosingElementStack = new Stack<ICodeElement>(); StringBuilder elementBuilder = new StringBuilder(DefaultBlockLength); char nextChar; bool end = false; bool lineContinuation = false; while (TryReadChar() && !end) { switch (CurrentChar) { // // Comments // case VBSymbol.BeginComment: CommentElement commentLine = ParseCommentLine(); string commentDirectiveRegionName = GetCommentDirectiveText(commentLine, Configuration.Formatting.Regions.CommentDirectiveBeginPattern, "Name"); if (commentDirectiveRegionName != null) { PushComments(codeElements, comments); RegionElement regionElement = new RegionElement(); regionElement.Name = commentDirectiveRegionName; enclosingElementStack.Push(regionElement); } else { commentDirectiveRegionName = GetCommentDirectiveText(commentLine, Configuration.Formatting.Regions.CommentDirectiveEndPattern, "Name"); if (commentDirectiveRegionName != null) { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.Region) { this.OnParseError("Unmatched end region directive"); } ICodeElement enclosingElement = enclosingElementStack.Pop(); // // Add any processed comments to the region or condition directive. // if (comments.Count > 0) { foreach (ICommentElement commentElement in comments) { enclosingElement.AddChild(commentElement); } comments.Clear(); } // // Are we processing a nested region or condition directive? // if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(enclosingElement); } else { codeElements.Add(enclosingElement); } } else { comments.Add(commentLine); } } break; // // Preprocessor // case VBSymbol.Preprocessor: // // TODO: Parse additional preprocessor directives. // string line = ReadLine().Trim(); string[] words = line.Split(WhiteSpaceCharacters, StringSplitOptions.RemoveEmptyEntries); if (words.Length > 0 && VBKeyword.Normalize(words[0]) == VBKeyword.Region) { PushComments(codeElements, comments); RegionElement regionElement = ParseRegion(line); enclosingElementStack.Push(regionElement); } else if (words.Length > 0 && (VBKeyword.Normalize(words[0]) == VBKeyword.If || VBKeyword.Normalize(words[0]) == VBKeyword.Else || VBKeyword.Normalize(words[0]) == VBKeyword.ElseIf)) { bool isIf; ConditionDirectiveElement conditionDirective = ParseConditionDirective(line.Trim(), out isIf); if (isIf) { enclosingElementStack.Push(conditionDirective); } else { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective) { this.OnParseError("Expected 'If' preprocessor directive."); } else { ConditionDirectiveElement previousCondition = enclosingElementStack.Peek() as ConditionDirectiveElement; while (previousCondition.ElseCondition != null) { previousCondition = previousCondition.ElseCondition; } // Add the condition to the end of the condition linked list previousCondition.ElseCondition = conditionDirective; } } } else if (words.Length > 1 && VBKeyword.Normalize(words[0]) == VBKeyword.End && (VBKeyword.Normalize(words[1]) == VBKeyword.Region || VBKeyword.Normalize(words[1]) == VBKeyword.If)) { ICodeElement enclosingElement = null; if (VBKeyword.Normalize(words[1]) == VBKeyword.Region) { if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.Region) { this.OnParseError("Unmatched end region directive"); } } else if (enclosingElementStack.Count == 0 || enclosingElementStack.Peek().ElementType != ElementType.ConditionDirective) { this.OnParseError("Unmatched #End If"); } enclosingElement = enclosingElementStack.Pop(); // // If there are any attributes not associated with an element (e.g. // a condition directive containing only an attribute, then // throw an error as this is currently not supported. // if (enclosingElement.ElementType == ElementType.ConditionDirective && attributes.Count > 0) { this.OnParseError("Cannot arrange files with preprocessor directives containing attributes unassociated to an element"); } if (comments.Count > 0) { foreach (ICommentElement commentElement in comments) { enclosingElement.AddChild(commentElement); } comments.Clear(); } if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(enclosingElement); } else { codeElements.Add(enclosingElement); } } else { this.OnParseError( "Cannot arrange files with preprocessor directives " + "other than #Region, #End Region and conditional compilation directives"); } break; // // Attribute // case VBSymbol.BeginAttribute: nextChar = NextChar; // // Parse attribute // AttributeElement attributeElement = ParseAttribute(comments.AsReadOnly()); attributes.Add(attributeElement); codeElements.Add(attributeElement); comments.Clear(); break; case VBSymbol.LineContinuation: if (IsWhiteSpace(PreviousChar) && IsWhiteSpace(NextChar)) { lineContinuation = true; } else { elementBuilder.Append(CurrentChar); } break; // Eat any unneeded whitespace case ' ': case '\n': case '\r': case '\t': case ':': if (elementBuilder.Length > 0) { string processedText = elementBuilder.ToString().Trim(); if (CurrentChar == '\n') { if (!lineContinuation) { this.OnParseError( string.Format( Thread.CurrentThread.CurrentCulture, "Unhandled element text '{0}'", processedText)); } else { lineContinuation = false; } } if (elementBuilder[elementBuilder.Length - 1] != ' ') { elementBuilder.Append(' '); } } break; default: elementBuilder.Append(CurrentChar); string upperElementText = elementBuilder.ToString().ToUpperInvariant(); nextChar = NextChar; if (upperElementText == VBKeyword.End.ToUpperInvariant()) { end = true; elementBuilder = new StringBuilder(DefaultBlockLength); } else if (upperElementText == VBKeyword.Rem.ToUpperInvariant() && nextChar == ' ') { CommentElement remCommentLine = ParseCommentLine(); comments.Add(remCommentLine); elementBuilder = new StringBuilder(DefaultBlockLength); } else if (upperElementText == VBKeyword.Option.ToUpperInvariant() && IsWhiteSpace(nextChar)) { ICodeElement optionElement = ParseOption(comments.AsReadOnly()); comments.Clear(); codeElements.Add(optionElement); elementBuilder = new StringBuilder(DefaultBlockLength); } else { if (char.IsWhiteSpace(nextChar) || VBSymbol.IsVBSymbol(CurrentChar)) { string elementText = VBKeyword.Normalize(elementBuilder.ToString()); bool isImplements = elementText.StartsWith( VBKeyword.Implements, StringComparison.OrdinalIgnoreCase); bool isInherits = !isImplements && elementText.StartsWith( VBKeyword.Inherits, StringComparison.OrdinalIgnoreCase); TypeElement typeElement = parentElement as TypeElement; if ((isImplements || isInherits) && typeElement != null) { InterfaceReferenceType referenceType = InterfaceReferenceType.None; if (isInherits) { referenceType = InterfaceReferenceType.Class; } else if (isImplements) { referenceType = InterfaceReferenceType.Interface; } do { EatWhiteSpace(WhiteSpaceTypes.SpaceAndTab); if (NextChar == VBSymbol.AliasSeparator) { EatChar(VBSymbol.AliasSeparator); } string typeName = CaptureTypeName(); InterfaceReference interfaceReference = new InterfaceReference(typeName, referenceType); typeElement.AddInterface(interfaceReference); EatWhiteSpace(WhiteSpaceTypes.SpaceAndTab); } while (NextChar == VBSymbol.AliasSeparator); elementBuilder = new StringBuilder(DefaultBlockLength); } else { // // Try to parse a code element // ICodeElement element = TryParseElement(parentElement, elementBuilder, comments.AsReadOnly(), attributes.AsReadOnly()); if (element != null) { if (element is CommentedElement) { UsingElement usingElement = element as UsingElement; // // If this is the first using statement, then don't attach // header comments to the element. // if (usingElement != null && parentElement == null && codeElements.Count == 0) { foreach (ICommentElement commentElement in usingElement.HeaderComments) { if (enclosingElementStack.Count > 0) { enclosingElementStack.Peek().AddChild(commentElement); } else { codeElements.Add(commentElement); } } usingElement.ClearHeaderCommentLines(); } comments.Clear(); } if (enclosingElementStack.Count > 0) { ICodeElement enclosingElement = enclosingElementStack.Peek(); if (enclosingElement.ElementType == ElementType.ConditionDirective) { ConditionDirectiveElement conditionDirective = enclosingElement as ConditionDirectiveElement; while (conditionDirective.ElseCondition != null) { conditionDirective = conditionDirective.ElseCondition; } enclosingElement = conditionDirective; } enclosingElement.AddChild(element); } else { codeElements.Add(element); } elementBuilder = new StringBuilder(DefaultBlockLength); if (element is IAttributedElement) { foreach (AttributeElement attribute in attributes) { codeElements.Remove(attribute); } attributes = new List<AttributeElement>(); } } } } } break; } char nextCh = NextChar; } if (comments.Count > 0) { for (int commentIndex = 0; commentIndex < comments.Count; commentIndex++) { ICommentElement comment = comments[commentIndex]; codeElements.Insert(commentIndex, comment); } } // // Make sure that all region elements have been closed // if (enclosingElementStack.Count > 0) { if (enclosingElementStack.Peek().ElementType == ElementType.Region) { this.OnParseError( string.Format( CultureInfo.InvariantCulture, "Missing end region directive for '{0}'", enclosingElementStack.Peek().Name)); } else { this.OnParseError("Expected #End If"); } } if (elementBuilder.Length > 0) { this.OnParseError( string.Format( Thread.CurrentThread.CurrentCulture, "Unhandled element text '{0}'", elementBuilder)); } return codeElements; }
public void DefaultArrangeUsingsInRegionTest() { CodeArranger arranger = new CodeArranger(CodeConfiguration.Default); List<ICodeElement> codeElements = new List<ICodeElement>(); RegionElement regionElement = new RegionElement(); regionElement.Name = "Using Directives"; UsingElement usingElement1 = new UsingElement(); usingElement1.Name = "System"; regionElement.AddChild(usingElement1); UsingElement usingElement2 = new UsingElement(); usingElement2.Name = "System.Text"; regionElement.AddChild(usingElement2); codeElements.Add(regionElement); ReadOnlyCollection<ICodeElement> arranged = arranger.Arrange(codeElements.AsReadOnly()); // // Verify using statements were stripped from the region // Assert.AreEqual(1, arranged.Count, "An unexpected number of root elements were returned from Arrange."); GroupElement groupElement = arranged[0] as GroupElement; Assert.IsNotNull(groupElement, "Expected a group element."); Assert.AreEqual("Namespace", groupElement.Name); groupElement = groupElement.Children[0] as GroupElement; Assert.IsNotNull(groupElement, "Expected a group element."); Assert.AreEqual("System", groupElement.Name); foreach (ICodeElement arrangedElement in groupElement.Children) { Assert.IsTrue(arrangedElement is UsingElement, "Expected a using element."); } }