Browse Source

Fixed some issues with code round-tripping; and added unit tests for some parser failures.

newNRvisualizers
Daniel Grunwald 14 years ago
parent
commit
a71670f2bc
  1. 64
      ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  2. 14
      ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs
  3. 13
      ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs
  4. 1
      ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs
  5. 36
      ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs
  6. 45
      ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs
  7. 1
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs
  8. 2
      ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs
  9. 2
      ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj
  10. 0
      ICSharpCode.NRefactory/TypeSystem/SpecialType.cs

64
ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -211,20 +211,29 @@ namespace ICSharpCode.NRefactory.CSharp
} }
/// <summary> /// <summary>
/// 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
/// </summary> /// </summary>
void OptionalComma() void OptionalComma()
{ {
// Look for the role between the current position and the nextNode. // Look if there's a comma after the current node, and insert it if it exists.
for (AstNode pos = positionStack.Peek(); pos != null; pos = pos.NextSibling) { AstNode pos = positionStack.Peek();
if (pos.Role == AstNode.Roles.Comma) { while (pos != null && pos.NodeType == NodeType.Whitespace)
Comma(null, noSpaceAfterComma: true); pos = pos.NextSibling;
break; if (pos != null && pos.Role == AstNode.Roles.Comma)
} else if (pos.NodeType != NodeType.Whitespace) { Comma(null, noSpaceAfterComma: true);
// only skip over whitespace and comma nodes }
break;
} /// <summary>
} /// Writes an optional semicolon, e.g. at the end of a type or namespace declaration.
/// </summary>
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<AstNode> list) void WriteCommaSeparatedList (IEnumerable<AstNode> list)
@ -362,7 +371,7 @@ namespace ICSharpCode.NRefactory.CSharp
void RPar () void RPar ()
{ {
WriteToken (")", AstNode.Roles.LPar); WriteToken (")", AstNode.Roles.RPar);
} }
/// <summary> /// <summary>
@ -595,10 +604,27 @@ namespace ICSharpCode.NRefactory.CSharp
public object VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression, object data) public object VisitArrayInitializerExpression (ArrayInitializerExpression arrayInitializerExpression, object data)
{ {
StartNode (arrayInitializerExpression); 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); 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<Expression> elements) void PrintInitializerElements(AstNodeCollection<Expression> elements)
{ {
BraceStyle style; BraceStyle style;
@ -617,6 +643,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
node.AcceptVisitor(this, null); node.AcceptVisitor(this, null);
} }
OptionalComma();
NewLine(); NewLine();
CloseBrace(style); CloseBrace(style);
} }
@ -902,7 +929,6 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
StartNode (anonymousTypeCreateExpression); StartNode (anonymousTypeCreateExpression);
WriteKeyword ("new"); WriteKeyword ("new");
Space ();
PrintInitializerElements(anonymousTypeCreateExpression.Initializers); PrintInitializerElements(anonymousTypeCreateExpression.Initializers);
return EndNode (anonymousTypeCreateExpression); return EndNode (anonymousTypeCreateExpression);
} }
@ -1327,9 +1353,10 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
StartNode (attribute); StartNode (attribute);
attribute.Type.AcceptVisitor (this, data); 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); WriteCommaSeparatedListInParenthesis (attribute.Arguments, policy.SpaceWithinMethodCallParentheses);
}
return EndNode (attribute); return EndNode (attribute);
} }
@ -1379,6 +1406,7 @@ namespace ICSharpCode.NRefactory.CSharp
foreach (var member in namespaceDeclaration.Members) foreach (var member in namespaceDeclaration.Members)
member.AcceptVisitor (this, data); member.AcceptVisitor (this, data);
CloseBrace (policy.NamespaceBraceStyle); CloseBrace (policy.NamespaceBraceStyle);
OptionalSemicolon ();
NewLine (); NewLine ();
return EndNode (namespaceDeclaration); return EndNode (namespaceDeclaration);
} }
@ -1438,6 +1466,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
CloseBrace (braceStyle); CloseBrace (braceStyle);
OptionalSemicolon ();
NewLine (); NewLine ();
return EndNode (typeDeclaration); return EndNode (typeDeclaration);
} }
@ -1867,6 +1896,7 @@ namespace ICSharpCode.NRefactory.CSharp
public object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data) public object VisitVariableDeclarationStatement (VariableDeclarationStatement variableDeclarationStatement, object data)
{ {
StartNode (variableDeclarationStatement); StartNode (variableDeclarationStatement);
WriteModifiers (variableDeclarationStatement.GetChildrenByRole (VariableDeclarationStatement.ModifierRole));
variableDeclarationStatement.Type.AcceptVisitor (this, data); variableDeclarationStatement.Type.AcceptVisitor (this, data);
Space (); Space ();
WriteCommaSeparatedList (variableDeclarationStatement.Variables); WriteCommaSeparatedList (variableDeclarationStatement.Variables);

14
ICSharpCode.NRefactory.Tests/CSharp/CSharpOutputVisitorTests.cs

@ -65,5 +65,19 @@ namespace ICSharpCode.NRefactory.CSharp
AssertOutput("enum DisplayFlags\n{\n$D = 4\n}\n", type); 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);
}
} }
} }

13
ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/ArrayCreateExpressionTests.cs

@ -17,6 +17,7 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using NUnit.Framework; using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser.Expression namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
@ -145,5 +146,17 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
} }
}}); }});
} }
[Test]
public void ArrayInitializerWithCommaAtEnd()
{
var ace = ParseUtilCSharp.ParseExpression<ArrayCreateExpression>("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());
}
} }
} }

1
ICSharpCode.NRefactory.Tests/CSharp/Parser/Expression/MemberReferenceExpressionTests.cs

@ -67,6 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.Expression
"Namespace.Subnamespace.SomeClass<string>.myField", "Namespace.Subnamespace.SomeClass<string>.myField",
new MemberReferenceExpression { new MemberReferenceExpression {
Target = new IdentifierExpression("Namespace").Member("Subnamespace"), Target = new IdentifierExpression("Namespace").Member("Subnamespace"),
MemberName = "SomeClass",
TypeArguments = { new PrimitiveType("string") } TypeArguments = { new PrimitiveType("string") }
}.Member("myField") }.Member("myField")
); );

36
ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/PreprocessorDirectiveTests.cs

@ -35,15 +35,16 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.GeneralScope
}"; }";
NamespaceDeclaration ns = ParseUtilCSharp.ParseGlobal<NamespaceDeclaration>(program); NamespaceDeclaration ns = ParseUtilCSharp.ParseGlobal<NamespaceDeclaration>(program);
Assert.AreEqual(0, ns.Members.Count); Assert.AreEqual(0, ns.Members.Count);
Assert.AreEqual(7, ns.Children.Count());
Assert.AreEqual(AstNode.Roles.Keyword, ns.Children.ElementAt(0).Role); Assert.AreEqual(new Role[] {
Assert.AreEqual(AstNode.Roles.Identifier, ns.Children.ElementAt(1).Role); AstNode.Roles.Keyword,
Assert.AreEqual(AstNode.Roles.LBrace, ns.Children.ElementAt(2).Role); AstNode.Roles.Identifier,
Assert.AreEqual(AstNode.Roles.PreProcessorDirective, ns.Children.ElementAt(3).Role); AstNode.Roles.LBrace,
Assert.AreEqual(AstNode.Roles.Comment, ns.Children.ElementAt(4).Role); AstNode.Roles.PreProcessorDirective,
Assert.AreEqual(AstNode.Roles.PreProcessorDirective, ns.Children.ElementAt(5).Role); AstNode.Roles.Comment,
Assert.AreEqual(AstNode.Roles.RBrace, ns.Children.ElementAt(6).Role); AstNode.Roles.PreProcessorDirective,
AstNode.Roles.RBrace
}, ns.Children.Select(c => c.Role).ToArray());
var pp = ns.GetChildrenByRole(AstNode.Roles.PreProcessorDirective); 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, 2), pp.First().StartLocation);
Assert.AreEqual(new TextLocation(2, 15), pp.First().EndLocation); Assert.AreEqual(new TextLocation(2, 15), pp.First().EndLocation);
var c = ns.GetChildByRole(AstNode.Roles.Comment); var comment = ns.GetChildByRole(AstNode.Roles.Comment);
Assert.AreEqual(CommentType.InactiveCode, c.CommentType); Assert.AreEqual(CommentType.InactiveCode, comment.CommentType);
Assert.AreEqual(new TextLocation(3, 1), c.StartLocation); Assert.AreEqual(new TextLocation(3, 1), comment.StartLocation);
Assert.AreEqual(new TextLocation(4, 2), c.EndLocation); Assert.AreEqual(new TextLocation(4, 2), comment.EndLocation);
Assert.AreEqual("\tclass A {}\n\t", c.Content.Replace("\r", "")); Assert.AreEqual("\tclass A {}\n\t", comment.Content.Replace("\r", ""));
Assert.AreEqual(PreProcessorDirectiveType.Endif, pp.Last().Type); Assert.AreEqual(PreProcessorDirectiveType.Endif, pp.Last().Type);
Assert.AreEqual(string.Empty, pp.Last().Argument); Assert.AreEqual(string.Empty, pp.Last().Argument);
Assert.AreEqual(new TextLocation(4, 2), pp.First().StartLocation); Assert.AreEqual(new TextLocation(4, 2), pp.First().StartLocation);
Assert.AreEqual(new TextLocation(4, 8), pp.First().EndLocation); Assert.AreEqual(new TextLocation(4, 8), pp.First().EndLocation);
} }
[Test]
public void PragmaWarning()
{
string program = "#pragma warning disable 809";
var ppd = ParseUtilCSharp.ParseGlobal<PreProcessorDirective>(program);
Assert.AreEqual(PreProcessorDirectiveType.Pragma, ppd.Type);
Assert.AreEqual("warning disable 809", ppd.Argument);
}
} }
} }

45
ICSharpCode.NRefactory.Tests/CSharp/Parser/GeneralScope/TypeDeclarationTests.cs

@ -333,10 +333,47 @@ public abstract class MyClass : MyBase, Interface1, My.Test.Interface2
[Test] [Test]
public void EnumWithCommaAtEnd() public void EnumWithCommaAtEnd()
{ {
TypeDeclaration td = ParseUtilCSharp.ParseGlobal<TypeDeclaration>("enum MyEnum { A, B, }"); TypeDeclaration td = ParseUtilCSharp.ParseGlobal<TypeDeclaration>("enum MyEnum { A, }");
Assert.AreEqual(2, td.Members.Count); Assert.AreEqual(
Assert.AreEqual(AstNode.Roles.RBrace, td.LastChild.Role); new Role[] {
Assert.AreEqual(AstNode.Roles.Comma, td.LastChild.PrevSibling.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<TypeDeclaration>("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<TypeDeclaration>("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());
} }
} }
} }

1
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/IndexerDeclarationTests.cs

@ -59,6 +59,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
Identifier = "MyInterface", Identifier = "MyInterface",
TypeArguments = { new PrimitiveType("string") } TypeArguments = { new PrimitiveType("string") }
}, },
Name = "this",
Parameters = { Parameters = {
new ParameterDeclaration(new PrimitiveType("int"), "a"), new ParameterDeclaration(new PrimitiveType("int"), "a"),
new ParameterDeclaration(new PrimitiveType("string"), "b") new ParameterDeclaration(new PrimitiveType("string"), "b")

2
ICSharpCode.NRefactory.Tests/CSharp/Parser/TypeMembers/MethodDeclarationTests.cs

@ -167,6 +167,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
", ",
new TypeDeclaration { new TypeDeclaration {
ClassType = ClassType.Interface, ClassType = ClassType.Interface,
Name = "MyInterface",
Members = { Members = {
new MethodDeclaration { new MethodDeclaration {
ReturnType = new SimpleType("T"), ReturnType = new SimpleType("T"),
@ -192,6 +193,7 @@ namespace ICSharpCode.NRefactory.CSharp.Parser.TypeMembers
", ",
new TypeDeclaration { new TypeDeclaration {
ClassType = ClassType.Interface, ClassType = ClassType.Interface,
Name = "MyInterface",
Members = { Members = {
new MethodDeclaration { new MethodDeclaration {
ReturnType = new PrimitiveType("void"), ReturnType = new PrimitiveType("void"),

2
ICSharpCode.NRefactory/ICSharpCode.NRefactory.csproj

@ -197,7 +197,7 @@
<Compile Include="TypeSystem\IVariable.cs" /> <Compile Include="TypeSystem\IVariable.cs" />
<Compile Include="TypeSystem\PointerType.cs" /> <Compile Include="TypeSystem\PointerType.cs" />
<Compile Include="TypeSystem\ReflectionHelper.cs" /> <Compile Include="TypeSystem\ReflectionHelper.cs" />
<Compile Include="TypeSystem\SharedTypes.cs" /> <Compile Include="TypeSystem\SpecialType.cs" />
<Compile Include="Utils\7BitEncodedInts.cs" /> <Compile Include="Utils\7BitEncodedInts.cs" />
<Compile Include="Utils\BitVector16.cs" /> <Compile Include="Utils\BitVector16.cs" />
<Compile Include="Utils\BusyManager.cs" /> <Compile Include="Utils\BusyManager.cs" />

0
ICSharpCode.NRefactory/TypeSystem/SharedTypes.cs → ICSharpCode.NRefactory/TypeSystem/SpecialType.cs

Loading…
Cancel
Save