diff --git a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs index cb568dce25..754787408f 100644 --- a/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs +++ b/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs @@ -211,20 +211,29 @@ namespace ICSharpCode.NRefactory.CSharp } /// - /// Writes an optional comma, e.g. at the end of an enum declaration + /// Writes an optional comma, e.g. at the end of an enum declaration or in an array initializer /// void OptionalComma() { - // Look for the role between the current position and the nextNode. - for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) { - if (pos.Role == AstNode.Roles.Comma) { - Comma(null, noSpaceAfterComma: true); - break; - } else if (pos.NodeType != NodeType.Whitespace) { - // only skip over whitespace and comma nodes - break; - } - } + // Look if there's a comma after the current node, and insert it if it exists. + AstNode pos = positionStack.Peek(); + while (pos != null && pos.NodeType == NodeType.Whitespace) + pos = pos.NextSibling; + if (pos != null && pos.Role == AstNode.Roles.Comma) + Comma(null, noSpaceAfterComma: true); + } + + /// + /// Writes an optional semicolon, e.g. at the end of a type or namespace declaration. + /// + void OptionalSemicolon() + { + // Look if there's a semicolon after the current node, and insert it if it exists. + AstNode pos = positionStack.Peek(); + while (pos != null && pos.NodeType == NodeType.Whitespace) + pos = pos.NextSibling; + if (pos != null && pos.Role == AstNode.Roles.Semicolon) + Semicolon(); } void WriteCommaSeparatedList (IEnumerable list) @@ -362,7 +371,7 @@ namespace ICSharpCode.NRefactory.CSharp void RPar () { - WriteToken (")", AstNode.Roles.LPar); + WriteToken (")", AstNode.Roles.RPar); } /// @@ -595,10 +604,27 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression, object data) { StartNode (arrayInitializerExpression); - PrintInitializerElements(arrayInitializerExpression.Elements); + bool bracesAreOptional = arrayInitializerExpression.Elements.Count == 1 + && IsObjectInitializer(arrayInitializerExpression.Parent); + if (bracesAreOptional && arrayInitializerExpression.LBraceToken.IsNull) { + arrayInitializerExpression.Elements.Single().AcceptVisitor(this, data); + } else { + PrintInitializerElements(arrayInitializerExpression.Elements); + } return EndNode (arrayInitializerExpression); } - + + bool IsObjectInitializer(AstNode node) + { + if (!(node is ArrayInitializerExpression)) + return false; + if (node.Parent is ObjectCreateExpression) + return node.Role == ObjectCreateExpression.InitializerRole; + if (node.Parent is NamedExpression) + return node.Role == NamedExpression.Roles.Expression; + return false; + } + void PrintInitializerElements(AstNodeCollection elements) { BraceStyle style; @@ -617,6 +643,7 @@ namespace ICSharpCode.NRefactory.CSharp } node.AcceptVisitor(this, null); } + OptionalComma(); NewLine(); CloseBrace(style); } @@ -902,7 +929,6 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode (anonymousTypeCreateExpression); WriteKeyword ("new"); - Space (); PrintInitializerElements(anonymousTypeCreateExpression.Initializers); return EndNode (anonymousTypeCreateExpression); } @@ -1327,9 +1353,10 @@ namespace ICSharpCode.NRefactory.CSharp { StartNode (attribute); attribute.Type.AcceptVisitor (this, data); - Space (policy.SpaceBeforeMethodCallParentheses); - if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole (AstNode.Roles.LPar).IsNull) + if (attribute.Arguments.Count != 0 || !attribute.GetChildByRole (AstNode.Roles.LPar).IsNull) { + Space (policy.SpaceBeforeMethodCallParentheses); WriteCommaSeparatedListInParenthesis (attribute.Arguments, policy.SpaceWithinMethodCallParentheses); + } return EndNode (attribute); } @@ -1379,6 +1406,7 @@ namespace ICSharpCode.NRefactory.CSharp foreach (var member in namespaceDeclaration.Members) member.AcceptVisitor (this, data); CloseBrace (policy.NamespaceBraceStyle); + OptionalSemicolon (); NewLine (); return EndNode (namespaceDeclaration); } @@ -1438,6 +1466,7 @@ namespace ICSharpCode.NRefactory.CSharp } } CloseBrace (braceStyle); + OptionalSemicolon (); NewLine (); return EndNode (typeDeclaration); } @@ -1867,6 +1896,7 @@ namespace ICSharpCode.NRefactory.CSharp public object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) { StartNode (variableDeclarationStatement); + WriteModifiers (variableDeclarationStatement.GetChildrenByRole (VariableDeclarationStatement.ModifierRole)); variableDeclarationStatement.Type.AcceptVisitor (this, data); Space (); WriteCommaSeparatedList (variableDeclarationStatement.Variables); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs index d8661b44bd..2c2a217009 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs @@ -65,5 +65,19 @@ namespace ICSharpCode.NRefactory.CSharp AssertOutput("enum DisplayFlags\n{\n$D = 4\n}\n", type); } + + [Test] + public void InlineCommentAtEndOfCondition() + { + IfElseStatement condition = new IfElseStatement(); + condition.AddChild(new CSharpTokenNode(new TextLocation(1, 1), 2), IfElseStatement.IfKeywordRole); + condition.AddChild(new CSharpTokenNode(new TextLocation(1, 4), 1), IfElseStatement.Roles.LPar); + condition.AddChild(new IdentifierExpression("cond", new TextLocation(1, 5)), IfElseStatement.ConditionRole); + condition.AddChild(new Comment(CommentType.MultiLine, new TextLocation(1, 9), new TextLocation(1, 14)) { Content = "a" }, IfElseStatement.Roles.Comment); + condition.AddChild(new CSharpTokenNode(new TextLocation(1, 14), 1), IfElseStatement.Roles.RPar); + condition.AddChild(new ReturnStatement(), IfElseStatement.TrueRole); + + AssertOutput("if (cond/*a*/)\n$return;\n", condition); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs index bb96d1e5b8..34f87f3600 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs @@ -17,6 +17,7 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Linq; using NUnit.Framework; namespace ICSharpCode.NRefactory.CSharp.Parser.Expression @@ -145,5 +146,17 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression } }}); } + + [Test] + public void ArrayInitializerWithCommaAtEnd() + { + var ace = ParseUtilCSharp.ParseExpression("new [] { 1, }"); + Assert.AreEqual(new Role[] { + AstNode.Roles.LBrace, + AstNode.Roles.Expression, + AstNode.Roles.Comma, + AstNode.Roles.RBrace + }, ace.Initializer.Children.Select(c => c.Role).ToArray()); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs index dedbd83535..341158a3a1 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs @@ -67,6 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression "Namespace.Subnamespace.SomeClass.myField", new MemberReferenceExpression { Target = new IdentifierExpression("Namespace").Member("Subnamespace"), + MemberName = "SomeClass", TypeArguments = { new PrimitiveType("string") } }.Member("myField") ); diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs index 66aba60333..13f5aab200 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs @@ -35,15 +35,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope }"; NamespaceDeclaration ns = ParseUtilCSharp.ParseGlobal(program); Assert.AreEqual(0, ns.Members.Count); - Assert.AreEqual(7, ns.Children.Count()); - Assert.AreEqual(AstNode.Roles.Keyword, ns.Children.ElementAt(0).Role); - Assert.AreEqual(AstNode.Roles.Identifier, ns.Children.ElementAt(1).Role); - Assert.AreEqual(AstNode.Roles.LBrace, ns.Children.ElementAt(2).Role); - Assert.AreEqual(AstNode.Roles.PreProcessorDirective, ns.Children.ElementAt(3).Role); - Assert.AreEqual(AstNode.Roles.Comment, ns.Children.ElementAt(4).Role); - Assert.AreEqual(AstNode.Roles.PreProcessorDirective, ns.Children.ElementAt(5).Role); - Assert.AreEqual(AstNode.Roles.RBrace, ns.Children.ElementAt(6).Role); + Assert.AreEqual(new Role[] { + AstNode.Roles.Keyword, + AstNode.Roles.Identifier, + AstNode.Roles.LBrace, + AstNode.Roles.PreProcessorDirective, + AstNode.Roles.Comment, + AstNode.Roles.PreProcessorDirective, + AstNode.Roles.RBrace + }, ns.Children.Select(c => c.Role).ToArray()); var pp = ns.GetChildrenByRole(AstNode.Roles.PreProcessorDirective); @@ -53,16 +54,25 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope Assert.AreEqual(new TextLocation(2, 2), pp.First().StartLocation); Assert.AreEqual(new TextLocation(2, 15), pp.First().EndLocation); - var c = ns.GetChildByRole(AstNode.Roles.Comment); - Assert.AreEqual(CommentType.InactiveCode, c.CommentType); - Assert.AreEqual(new TextLocation(3, 1), c.StartLocation); - Assert.AreEqual(new TextLocation(4, 2), c.EndLocation); - Assert.AreEqual("\tclass A {}\n\t", c.Content.Replace("\r", "")); + var comment = ns.GetChildByRole(AstNode.Roles.Comment); + Assert.AreEqual(CommentType.InactiveCode, comment.CommentType); + Assert.AreEqual(new TextLocation(3, 1), comment.StartLocation); + Assert.AreEqual(new TextLocation(4, 2), comment.EndLocation); + Assert.AreEqual("\tclass A {}\n\t", comment.Content.Replace("\r", "")); Assert.AreEqual(PreProcessorDirectiveType.Endif, pp.Last().Type); Assert.AreEqual(string.Empty, pp.Last().Argument); Assert.AreEqual(new TextLocation(4, 2), pp.First().StartLocation); Assert.AreEqual(new TextLocation(4, 8), pp.First().EndLocation); } + + [Test] + public void PragmaWarning() + { + string program = "#pragma warning disable 809"; + var ppd = ParseUtilCSharp.ParseGlobal(program); + Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type); + Assert.AreEqual("warning disable 809", ppd.Argument); + } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs index 3349e7b06d..0aca3db0ee 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs @@ -333,10 +333,47 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2 [Test] public void EnumWithCommaAtEnd() { - TypeDeclaration td = ParseUtilCSharp.ParseGlobal("enum MyEnum { A, B, }"); - Assert.AreEqual(2, td.Members.Count); - Assert.AreEqual(AstNode.Roles.RBrace, td.LastChild.Role); - Assert.AreEqual(AstNode.Roles.Comma, td.LastChild.PrevSibling.Role); + TypeDeclaration td = ParseUtilCSharp.ParseGlobal("enum MyEnum { A, }"); + Assert.AreEqual( + new Role[] { + AstNode.Roles.Keyword, + AstNode.Roles.Identifier, + AstNode.Roles.LBrace, + TypeDeclaration.MemberRole, + AstNode.Roles.Comma, + AstNode.Roles.RBrace + }, td.Children.Select(c => c.Role).ToArray()); + } + + [Test] + public void EnumWithCommaAndSemicolonAtEnd() + { + TypeDeclaration td = ParseUtilCSharp.ParseGlobal("enum MyEnum { A, };"); + Assert.AreEqual( + new Role[] { + AstNode.Roles.Keyword, + AstNode.Roles.Identifier, + AstNode.Roles.LBrace, + TypeDeclaration.MemberRole, + AstNode.Roles.Comma, + AstNode.Roles.RBrace, + AstNode.Roles.Semicolon + }, td.Children.Select(c => c.Role).ToArray()); + } + + [Test] + public void EnumWithSemicolonAtEnd() + { + TypeDeclaration td = ParseUtilCSharp.ParseGlobal("enum MyEnum { A };"); + Assert.AreEqual( + new Role[] { + AstNode.Roles.Keyword, + AstNode.Roles.Identifier, + AstNode.Roles.LBrace, + TypeDeclaration.MemberRole, + AstNode.Roles.RBrace, + AstNode.Roles.Semicolon + }, td.Children.Select(c => c.Role).ToArray()); } } } diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs index 55f75091f2..4cabc1d2bf 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs @@ -59,6 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers Identifier = "MyInterface", TypeArguments = { new PrimitiveType("string") } }, + Name = "this", Parameters = { new ParameterDeclaration(new PrimitiveType("int"), "a"), new ParameterDeclaration(new PrimitiveType("string"), "b") diff --git a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs index 434b40dda3..463704d4ae 100644 --- a/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs +++ b/ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs @@ -167,6 +167,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers ", new TypeDeclaration { ClassType = ClassType.Interface, + Name = "MyInterface", Members = { new MethodDeclaration { ReturnType = new SimpleType("T"), @@ -192,6 +193,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers ", new TypeDeclaration { ClassType = ClassType.Interface, + Name = "MyInterface", Members = { new MethodDeclaration { ReturnType = new PrimitiveType("void"), diff --git a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj index 2d9f7e1ef5..635f488b51 100644 --- a/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj +++ b/ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj @@ -197,7 +197,7 @@ - + diff --git a/ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs b/ICSharpCode.NRefactory/TypeSystem/SpecialType.cs similarity index 100% rename from ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs rename to ICSharpCode.NRefactory/TypeSystem/SpecialType.cs