Browse Source

implement InsertMissingTokensDecorator

newNRILSpyDebugger
Siegfried Pammer 12 years ago
parent
commit
78e7fc45a9
  1. 31
      src/Libraries/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs
  2. 2
      src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  3. 16
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs
  4. 45
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs
  5. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs
  6. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs
  7. 6
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs
  8. 7
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs
  9. 1
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj
  10. 12
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs
  11. 102
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs
  12. 89
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/ITokenWriter.cs
  13. 112
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertMissingTokensDecorator.cs
  14. 21
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertRequiredSpacesDecorator.cs
  15. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertSpecialsDecorator.cs
  16. 127
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/TextWriterOutputFormatter.cs
  17. 87
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertMissingTokensDecoratorTests.cs
  18. 90
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ConsistencyChecker.cs
  19. 77
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseSelfTests.cs
  20. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

31
src/Libraries/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs → src/Libraries/ICSharpCode.Decompiler/Ast/TextTokenWriter.cs

@ -27,7 +27,7 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast namespace ICSharpCode.Decompiler.Ast
{ {
public class TextTokenWriter : ITokenWriter public class TextTokenWriter : TokenWriter
{ {
readonly ITextOutput output; readonly ITextOutput output;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>(); readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Ast
this.output = output; this.output = output;
} }
public void WriteIdentifier(Identifier identifier) public override void WriteIdentifier(Identifier identifier)
{ {
var definition = GetCurrentDefinition(); var definition = GetCurrentDefinition();
if (definition != null) { if (definition != null) {
@ -160,12 +160,12 @@ namespace ICSharpCode.Decompiler.Ast
return null; return null;
} }
public void WriteKeyword(Role role, string keyword) public override void WriteKeyword(Role role, string keyword)
{ {
output.Write(keyword); output.Write(keyword);
} }
public void WriteToken(Role role, string token) public override void WriteToken(Role role, string token)
{ {
// Attach member reference to token only if there's no identifier in the current node. // Attach member reference to token only if there's no identifier in the current node.
MemberReference memberRef = GetCurrentMemberReference(); MemberReference memberRef = GetCurrentMemberReference();
@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Ast
output.Write(token); output.Write(token);
} }
public void Space() public override void Space()
{ {
output.Write(' '); output.Write(' ');
} }
@ -203,17 +203,17 @@ namespace ICSharpCode.Decompiler.Ast
braceLevelWithinType--; braceLevelWithinType--;
} }
public void Indent() public override void Indent()
{ {
output.Indent(); output.Indent();
} }
public void Unindent() public override void Unindent()
{ {
output.Unindent(); output.Unindent();
} }
public void NewLine() public override void NewLine()
{ {
if (lastUsingDeclaration) { if (lastUsingDeclaration) {
output.MarkFoldEnd(); output.MarkFoldEnd();
@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.Ast
output.WriteLine(); output.WriteLine();
} }
public void WriteComment(CommentType commentType, string content) public override void WriteComment(CommentType commentType, string content)
{ {
switch (commentType) { switch (commentType) {
case CommentType.SingleLine: case CommentType.SingleLine:
@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.Ast
} }
} }
public void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument) public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{ {
// pre-processor directive must start on its own line // pre-processor directive must start on its own line
output.Write('#'); output.Write('#');
@ -267,7 +267,12 @@ namespace ICSharpCode.Decompiler.Ast
output.WriteLine(); output.WriteLine();
} }
public void WritePrimitiveValue(object value) public override void WritePrimitiveValue(object value, string literalValue = null)
{
}
public override void WritePrimitiveType(string type)
{ {
} }
@ -275,7 +280,7 @@ namespace ICSharpCode.Decompiler.Ast
Stack<TextLocation> startLocations = new Stack<TextLocation>(); Stack<TextLocation> startLocations = new Stack<TextLocation>();
Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>(); Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public void StartNode(AstNode node) public override void StartNode(AstNode node)
{ {
if (nodeStack.Count == 0) { if (nodeStack.Count == 0) {
if (IsUsingDeclaration(node)) { if (IsUsingDeclaration(node)) {
@ -303,7 +308,7 @@ namespace ICSharpCode.Decompiler.Ast
return node is UsingDeclaration || node is UsingAliasDeclaration; return node is UsingDeclaration || node is UsingAliasDeclaration;
} }
public void EndNode(AstNode node) public override void EndNode(AstNode node)
{ {
if (nodeStack.Pop() != node) if (nodeStack.Pop() != node)
throw new InvalidOperationException(); throw new InvalidOperationException();

2
src/Libraries/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -60,7 +60,7 @@
<Compile Include="Ast\DecompilerContext.cs" /> <Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.cs" /> <Compile Include="Ast\NameVariables.cs" />
<Compile Include="Ast\NRefactoryExtensions.cs" /> <Compile Include="Ast\NRefactoryExtensions.cs" />
<Compile Include="Ast\TextOutputFormatter.cs" /> <Compile Include="Ast\TextTokenWriter.cs" />
<Compile Include="Ast\Transforms\AddCheckedBlocks.cs" /> <Compile Include="Ast\Transforms\AddCheckedBlocks.cs" />
<Compile Include="Ast\Transforms\CombineQueryExpressions.cs" /> <Compile Include="Ast\Transforms\CombineQueryExpressions.cs" />
<Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" /> <Compile Include="Ast\Transforms\ContextTrackingVisitor.cs" />

16
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/AstNode.cs

@ -406,6 +406,8 @@ namespace ICSharpCode.NRefactory.CSharp
if (child == null || child.IsNull) if (child == null || child.IsNull)
return; return;
ThrowIfFrozen(); ThrowIfFrozen();
if (child == this)
throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
if (child.parent != null) if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child"); throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen) if (child.IsFrozen)
@ -413,6 +415,20 @@ namespace ICSharpCode.NRefactory.CSharp
AddChildUnsafe (child, role); AddChildUnsafe (child, role);
} }
public void AddChildWithExistingRole<T> (T child) where T : AstNode
{
if (child == null || child.IsNull)
return;
ThrowIfFrozen();
if (child == this)
throw new ArgumentException ("Cannot add a node to itself as a child.", "child");
if (child.parent != null)
throw new ArgumentException ("Node is already used in another tree.", "child");
if (child.IsFrozen)
throw new ArgumentException ("Cannot add a frozen node.", "child");
AddChildUnsafe (child, child.Role);
}
/// <summary> /// <summary>
/// Adds a child without performing any safety checks. /// Adds a child without performing any safety checks.
/// </summary> /// </summary>

45
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/CSharpModifierToken.cs

@ -169,5 +169,50 @@ namespace ICSharpCode.NRefactory.CSharp
throw new NotSupportedException("Invalid value for Modifiers"); throw new NotSupportedException("Invalid value for Modifiers");
} }
} }
public static Modifiers GetModifierValue(string modifier)
{
switch (modifier) {
case "private":
return Modifiers.Private;
case "internal":
return Modifiers.Internal;
case "protected":
return Modifiers.Protected;
case "public":
return Modifiers.Public;
case "abstract":
return Modifiers.Abstract;
case "virtual":
return Modifiers.Virtual;
case "sealed":
return Modifiers.Sealed;
case "static":
return Modifiers.Static;
case "override":
return Modifiers.Override;
case "readonly":
return Modifiers.Readonly;
case "const":
return Modifiers.Const;
case "new":
return Modifiers.New;
case "partial":
return Modifiers.Partial;
case "extern":
return Modifiers.Extern;
case "volatile":
return Modifiers.Volatile;
case "unsafe":
return Modifiers.Unsafe;
case "async":
return Modifiers.Async;
case "any":
// even though it's used for pattern matching only, 'any' needs to be in this list to be usable in the AST
return Modifiers.Any;
default:
throw new NotSupportedException("Invalid value for Modifiers");
}
}
} }
} }

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/NullReferenceExpression.cs

@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.location = value;
}
public override TextLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new TextLocation (location.Line, location.Column + "null".Length); return new TextLocation (location.Line, location.Column + "null".Length);

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Expressions/PrimitiveExpression.cs

@ -42,6 +42,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.startLocation = value;
}
string literalValue; string literalValue;
TextLocation? endLocation; TextLocation? endLocation;
public override TextLocation EndLocation { public override TextLocation EndLocation {

6
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/Identifier.cs

@ -83,6 +83,12 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.startLocation = value;
}
const uint verbatimBit = 1u << AstNodeFlagsUsedBits; const uint verbatimBit = 1u << AstNodeFlagsUsedBits;
public bool IsVerbatim { public bool IsVerbatim {

7
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/Ast/PrimitiveType.cs

@ -71,6 +71,13 @@ namespace ICSharpCode.NRefactory.CSharp
return location; return location;
} }
} }
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.location = value;
}
public override TextLocation EndLocation { public override TextLocation EndLocation {
get { get {
return new TextLocation (location.Line, location.Column + keyword.Length); return new TextLocation (location.Line, location.Column + keyword.Length);

1
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/ICSharpCode.NRefactory.CSharp.csproj

@ -207,6 +207,7 @@
<Compile Include="Formatter\Indent.cs" /> <Compile Include="Formatter\Indent.cs" />
<Compile Include="OutputVisitor\CodeDomConvertVisitor.cs" /> <Compile Include="OutputVisitor\CodeDomConvertVisitor.cs" />
<Compile Include="OutputVisitor\CSharpAmbience.cs" /> <Compile Include="OutputVisitor\CSharpAmbience.cs" />
<Compile Include="OutputVisitor\InsertMissingTokensDecorator.cs" />
<Compile Include="OutputVisitor\InsertParenthesesVisitor.cs" /> <Compile Include="OutputVisitor\InsertParenthesesVisitor.cs" />
<Compile Include="OutputVisitor\InsertRequiredSpacesDecorator.cs" /> <Compile Include="OutputVisitor\InsertRequiredSpacesDecorator.cs" />
<Compile Include="OutputVisitor\CSharpOutputVisitor.cs" /> <Compile Include="OutputVisitor\CSharpOutputVisitor.cs" />

12
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpAmbience.cs

@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp
return writer.ToString(); return writer.ToString();
} }
public void ConvertEntity(IEntity entity, ITokenWriter writer, CSharpFormattingOptions formattingPolicy) public void ConvertEntity(IEntity entity, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
if (entity == null) if (entity == null)
throw new ArgumentNullException("entity"); throw new ArgumentNullException("entity");
@ -160,7 +160,7 @@ namespace ICSharpCode.NRefactory.CSharp
return astBuilder; return astBuilder;
} }
void WriteTypeDeclarationName(ITypeDefinition typeDef, ITokenWriter writer, CSharpFormattingOptions formattingPolicy) void WriteTypeDeclarationName(ITypeDefinition typeDef, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
TypeSystemAstBuilder astBuilder = CreateAstBuilder(); TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(typeDef); EntityDeclaration node = astBuilder.ConvertEntity(typeDef);
@ -178,7 +178,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
void WriteMemberDeclarationName(IMember member, ITokenWriter writer, CSharpFormattingOptions formattingPolicy) void WriteMemberDeclarationName(IMember member, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
TypeSystemAstBuilder astBuilder = CreateAstBuilder(); TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(member); EntityDeclaration node = astBuilder.ConvertEntity(member);
@ -235,7 +235,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
void PrintModifiers(Modifiers modifiers, ITokenWriter writer) void PrintModifiers(Modifiers modifiers, TokenWriter writer)
{ {
foreach (var m in CSharpModifierToken.AllModifiers) { foreach (var m in CSharpModifierToken.AllModifiers) {
if ((modifiers & m) == m) { if ((modifiers & m) == m) {
@ -245,7 +245,7 @@ namespace ICSharpCode.NRefactory.CSharp
} }
} }
void WriteQualifiedName(string name, ITokenWriter writer, CSharpFormattingOptions formattingPolicy) void WriteQualifiedName(string name, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
var node = AstType.Create(name); var node = AstType.Create(name);
var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy); var outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
@ -270,7 +270,7 @@ namespace ICSharpCode.NRefactory.CSharp
return astType.ToString(); return astType.ToString();
} }
public void ConvertType(IType type, ITokenWriter writer, CSharpFormattingOptions formattingPolicy) public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
TypeSystemAstBuilder astBuilder = CreateAstBuilder(); TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstType astType = astBuilder.ConvertType(type); AstType astType = astBuilder.ConvertType(type);

102
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/CSharpOutputVisitor.cs

@ -34,7 +34,7 @@ namespace ICSharpCode.NRefactory.CSharp
/// </summary> /// </summary>
public class CSharpOutputVisitor : IAstVisitor public class CSharpOutputVisitor : IAstVisitor
{ {
readonly ITokenWriter writer; readonly TokenWriter writer;
readonly CSharpFormattingOptions policy; readonly CSharpFormattingOptions policy;
readonly Stack<AstNode> containerStack = new Stack<AstNode> (); readonly Stack<AstNode> containerStack = new Stack<AstNode> ();
@ -46,11 +46,11 @@ namespace ICSharpCode.NRefactory.CSharp
if (formattingPolicy == null) { if (formattingPolicy == null) {
throw new ArgumentNullException ("formattingPolicy"); throw new ArgumentNullException ("formattingPolicy");
} }
this.writer = new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new TextWriterTokenWriter(textWriter))); this.writer = TokenWriter.Create(textWriter);
this.policy = formattingPolicy; this.policy = formattingPolicy;
} }
public CSharpOutputVisitor (ITokenWriter writer, CSharpFormattingOptions formattingPolicy) public CSharpOutputVisitor (TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{ {
if (writer == null) { if (writer == null) {
throw new ArgumentNullException ("writer"); throw new ArgumentNullException ("writer");
@ -828,7 +828,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression) public void VisitNamedArgumentExpression(NamedArgumentExpression namedArgumentExpression)
{ {
StartNode(namedArgumentExpression); StartNode(namedArgumentExpression);
namedArgumentExpression.NameToken.AcceptVisitor(this); WriteIdentifier(namedArgumentExpression.NameToken);
WriteToken(Roles.Colon); WriteToken(Roles.Colon);
Space(); Space();
namedArgumentExpression.Expression.AcceptVisitor(this); namedArgumentExpression.Expression.AcceptVisitor(this);
@ -838,7 +838,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitNamedExpression(NamedExpression namedExpression) public void VisitNamedExpression(NamedExpression namedExpression)
{ {
StartNode(namedExpression); StartNode(namedExpression);
namedExpression.NameToken.AcceptVisitor(this); WriteIdentifier(namedExpression.NameToken);
Space(); Space();
WriteToken(Roles.Assign); WriteToken(Roles.Assign);
Space(); Space();
@ -849,7 +849,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression) public void VisitNullReferenceExpression(NullReferenceExpression nullReferenceExpression)
{ {
StartNode(nullReferenceExpression); StartNode(nullReferenceExpression);
WriteKeyword("null", nullReferenceExpression.Role); writer.WritePrimitiveValue(null);
EndNode(nullReferenceExpression); EndNode(nullReferenceExpression);
} }
@ -904,11 +904,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitPrimitiveExpression(PrimitiveExpression primitiveExpression) public void VisitPrimitiveExpression(PrimitiveExpression primitiveExpression)
{ {
StartNode(primitiveExpression); StartNode(primitiveExpression);
if (!string.IsNullOrEmpty(primitiveExpression.LiteralValue)) { writer.WritePrimitiveValue(primitiveExpression.Value, primitiveExpression.LiteralValue);
writer.WriteToken(primitiveExpression.Role, primitiveExpression.LiteralValue);
} else {
writer.WritePrimitiveValue(primitiveExpression.Value);
}
EndNode(primitiveExpression); EndNode(primitiveExpression);
} }
#endregion #endregion
@ -1028,7 +1024,7 @@ namespace ICSharpCode.NRefactory.CSharp
Space(); Space();
WriteKeyword(QueryContinuationClause.IntoKeywordRole); WriteKeyword(QueryContinuationClause.IntoKeywordRole);
Space(); Space();
queryContinuationClause.IdentifierToken.AcceptVisitor(this); WriteIdentifier(queryContinuationClause.IdentifierToken);
EndNode(queryContinuationClause); EndNode(queryContinuationClause);
} }
@ -1038,7 +1034,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteKeyword(QueryFromClause.FromKeywordRole); WriteKeyword(QueryFromClause.FromKeywordRole);
queryFromClause.Type.AcceptVisitor(this); queryFromClause.Type.AcceptVisitor(this);
Space(); Space();
queryFromClause.IdentifierToken.AcceptVisitor(this); WriteIdentifier(queryFromClause.IdentifierToken);
Space(); Space();
WriteKeyword(QueryFromClause.InKeywordRole); WriteKeyword(QueryFromClause.InKeywordRole);
Space(); Space();
@ -1051,7 +1047,7 @@ namespace ICSharpCode.NRefactory.CSharp
StartNode(queryLetClause); StartNode(queryLetClause);
WriteKeyword(QueryLetClause.LetKeywordRole); WriteKeyword(QueryLetClause.LetKeywordRole);
Space(); Space();
queryLetClause.IdentifierToken.AcceptVisitor(this); WriteIdentifier(queryLetClause.IdentifierToken);
Space(policy.SpaceAroundAssignment); Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign); WriteToken(Roles.Assign);
Space(policy.SpaceAroundAssignment); Space(policy.SpaceAroundAssignment);
@ -1184,7 +1180,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteKeyword(Roles.DelegateKeyword); WriteKeyword(Roles.DelegateKeyword);
delegateDeclaration.ReturnType.AcceptVisitor(this); delegateDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
delegateDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(delegateDeclaration.NameToken);
WriteTypeParameters(delegateDeclaration.TypeParameters); WriteTypeParameters(delegateDeclaration.TypeParameters);
Space(policy.SpaceBeforeDelegateDeclarationParentheses); Space(policy.SpaceBeforeDelegateDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(delegateDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis(delegateDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
@ -1234,7 +1230,7 @@ namespace ICSharpCode.NRefactory.CSharp
braceStyle = policy.ClassBraceStyle; braceStyle = policy.ClassBraceStyle;
break; break;
} }
typeDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(typeDeclaration.NameToken);
WriteTypeParameters(typeDeclaration.TypeParameters); WriteTypeParameters(typeDeclaration.TypeParameters);
if (typeDeclaration.BaseTypes.Any()) { if (typeDeclaration.BaseTypes.Any()) {
Space(); Space();
@ -1302,7 +1298,7 @@ namespace ICSharpCode.NRefactory.CSharp
Space(); Space();
WriteKeyword(Roles.AliasKeyword); WriteKeyword(Roles.AliasKeyword);
Space(); Space();
externAliasDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(externAliasDeclaration.NameToken);
Semicolon(); Semicolon();
EndNode(externAliasDeclaration); EndNode(externAliasDeclaration);
} }
@ -1350,7 +1346,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitBreakStatement(BreakStatement breakStatement) public void VisitBreakStatement(BreakStatement breakStatement)
{ {
StartNode(breakStatement); StartNode(breakStatement);
WriteKeyword("break"); WriteKeyword("break", BreakStatement.BreakKeywordRole);
Semicolon(); Semicolon();
EndNode(breakStatement); EndNode(breakStatement);
} }
@ -1366,7 +1362,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitContinueStatement(ContinueStatement continueStatement) public void VisitContinueStatement(ContinueStatement continueStatement)
{ {
StartNode(continueStatement); StartNode(continueStatement);
WriteKeyword("continue"); WriteKeyword("continue", ContinueStatement.ContinueKeywordRole);
Semicolon(); Semicolon();
EndNode(continueStatement); EndNode(continueStatement);
} }
@ -1427,7 +1423,7 @@ namespace ICSharpCode.NRefactory.CSharp
Space(policy.SpacesWithinForeachParentheses); Space(policy.SpacesWithinForeachParentheses);
foreachStatement.VariableType.AcceptVisitor(this); foreachStatement.VariableType.AcceptVisitor(this);
Space(); Space();
foreachStatement.VariableNameToken.AcceptVisitor(this); WriteIdentifier(foreachStatement.VariableNameToken);
WriteKeyword(ForeachStatement.InKeywordRole); WriteKeyword(ForeachStatement.InKeywordRole);
Space(); Space();
foreachStatement.InExpression.AcceptVisitor(this); foreachStatement.InExpression.AcceptVisitor(this);
@ -1665,7 +1661,7 @@ namespace ICSharpCode.NRefactory.CSharp
catchClause.Type.AcceptVisitor(this); catchClause.Type.AcceptVisitor(this);
if (!string.IsNullOrEmpty(catchClause.VariableName)) { if (!string.IsNullOrEmpty(catchClause.VariableName)) {
Space(); Space();
catchClause.VariableNameToken.AcceptVisitor(this); WriteIdentifier(catchClause.VariableNameToken);
} }
Space(policy.SpacesWithinCatchParentheses); Space(policy.SpacesWithinCatchParentheses);
RPar(); RPar();
@ -1762,13 +1758,13 @@ namespace ICSharpCode.NRefactory.CSharp
WriteAttributes(accessor.Attributes); WriteAttributes(accessor.Attributes);
WriteModifiers(accessor.ModifierTokens); WriteModifiers(accessor.ModifierTokens);
if (accessor.Role == PropertyDeclaration.GetterRole) { if (accessor.Role == PropertyDeclaration.GetterRole) {
WriteKeyword("get"); WriteKeyword("get", PropertyDeclaration.GetKeywordRole);
} else if (accessor.Role == PropertyDeclaration.SetterRole) { } else if (accessor.Role == PropertyDeclaration.SetterRole) {
WriteKeyword("set"); WriteKeyword("set", PropertyDeclaration.SetKeywordRole);
} else if (accessor.Role == CustomEventDeclaration.AddAccessorRole) { } else if (accessor.Role == CustomEventDeclaration.AddAccessorRole) {
WriteKeyword("add"); WriteKeyword("add", CustomEventDeclaration.AddKeywordRole);
} else if (accessor.Role == CustomEventDeclaration.RemoveAccessorRole) { } else if (accessor.Role == CustomEventDeclaration.RemoveAccessorRole) {
WriteKeyword("remove"); WriteKeyword("remove", CustomEventDeclaration.RemoveKeywordRole);
} }
WriteMethodBody(accessor.Body); WriteMethodBody(accessor.Body);
EndNode(accessor); EndNode(accessor);
@ -1780,12 +1776,10 @@ namespace ICSharpCode.NRefactory.CSharp
WriteAttributes(constructorDeclaration.Attributes); WriteAttributes(constructorDeclaration.Attributes);
WriteModifiers(constructorDeclaration.ModifierTokens); WriteModifiers(constructorDeclaration.ModifierTokens);
TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration; TypeDeclaration type = constructorDeclaration.Parent as TypeDeclaration;
var nameToken = constructorDeclaration.NameToken; if (type != null && type.Name != constructorDeclaration.Name)
if (!nameToken.IsNull) WriteIdentifier((Identifier)type.NameToken.Clone());
StartNode(nameToken); else
WriteIdentifier(type != null ? type.NameToken : constructorDeclaration.NameToken); WriteIdentifier(constructorDeclaration.NameToken);
if (!nameToken.IsNull)
EndNode(nameToken);
Space(policy.SpaceBeforeConstructorDeclarationParentheses); Space(policy.SpaceBeforeConstructorDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis(constructorDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
if (!constructorDeclaration.Initializer.IsNull) { if (!constructorDeclaration.Initializer.IsNull) {
@ -1818,12 +1812,10 @@ namespace ICSharpCode.NRefactory.CSharp
WriteModifiers(destructorDeclaration.ModifierTokens); WriteModifiers(destructorDeclaration.ModifierTokens);
WriteToken(DestructorDeclaration.TildeRole); WriteToken(DestructorDeclaration.TildeRole);
TypeDeclaration type = destructorDeclaration.Parent as TypeDeclaration; TypeDeclaration type = destructorDeclaration.Parent as TypeDeclaration;
var nameToken = destructorDeclaration.NameToken; if (type != null && type.Name != destructorDeclaration.Name)
if (!nameToken.IsNull) WriteIdentifier((Identifier)type.NameToken.Clone());
StartNode(nameToken); else
WriteIdentifier(type != null ? type.NameToken : destructorDeclaration.NameToken); WriteIdentifier(destructorDeclaration.NameToken);
if (!nameToken.IsNull)
EndNode(nameToken);
Space(policy.SpaceBeforeConstructorDeclarationParentheses); Space(policy.SpaceBeforeConstructorDeclarationParentheses);
LPar(); LPar();
RPar(); RPar();
@ -1836,7 +1828,7 @@ namespace ICSharpCode.NRefactory.CSharp
StartNode(enumMemberDeclaration); StartNode(enumMemberDeclaration);
WriteAttributes(enumMemberDeclaration.Attributes); WriteAttributes(enumMemberDeclaration.Attributes);
WriteModifiers(enumMemberDeclaration.ModifierTokens); WriteModifiers(enumMemberDeclaration.ModifierTokens);
enumMemberDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(enumMemberDeclaration.NameToken);
if (!enumMemberDeclaration.Initializer.IsNull) { if (!enumMemberDeclaration.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment); Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign); WriteToken(Roles.Assign);
@ -1868,7 +1860,7 @@ namespace ICSharpCode.NRefactory.CSharp
customEventDeclaration.ReturnType.AcceptVisitor(this); customEventDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(customEventDeclaration.PrivateImplementationType); WritePrivateImplementationType(customEventDeclaration.PrivateImplementationType);
customEventDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(customEventDeclaration.NameToken);
OpenBrace(policy.EventBraceStyle); OpenBrace(policy.EventBraceStyle);
// output add/remove in their original order // output add/remove in their original order
foreach (AstNode node in customEventDeclaration.Children) { foreach (AstNode node in customEventDeclaration.Children) {
@ -1910,7 +1902,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer) public void VisitFixedVariableInitializer(FixedVariableInitializer fixedVariableInitializer)
{ {
StartNode(fixedVariableInitializer); StartNode(fixedVariableInitializer);
fixedVariableInitializer.NameToken.AcceptVisitor(this); WriteIdentifier(fixedVariableInitializer.NameToken);
if (!fixedVariableInitializer.CountExpression.IsNull) { if (!fixedVariableInitializer.CountExpression.IsNull) {
WriteToken(Roles.LBracket); WriteToken(Roles.LBracket);
Space(policy.SpacesWithinBrackets); Space(policy.SpacesWithinBrackets);
@ -1952,7 +1944,7 @@ namespace ICSharpCode.NRefactory.CSharp
methodDeclaration.ReturnType.AcceptVisitor(this); methodDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(methodDeclaration.PrivateImplementationType); WritePrivateImplementationType(methodDeclaration.PrivateImplementationType);
methodDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(methodDeclaration.NameToken);
WriteTypeParameters(methodDeclaration.TypeParameters); WriteTypeParameters(methodDeclaration.TypeParameters);
Space(policy.SpaceBeforeMethodDeclarationParentheses); Space(policy.SpaceBeforeMethodDeclarationParentheses);
WriteCommaSeparatedListInParenthesis(methodDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses); WriteCommaSeparatedListInParenthesis(methodDeclaration.Parameters, policy.SpaceWithinMethodDeclarationParentheses);
@ -2012,7 +2004,7 @@ namespace ICSharpCode.NRefactory.CSharp
Space(); Space();
} }
if (!string.IsNullOrEmpty(parameterDeclaration.Name)) { if (!string.IsNullOrEmpty(parameterDeclaration.Name)) {
parameterDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(parameterDeclaration.NameToken);
} }
if (!parameterDeclaration.DefaultExpression.IsNull) { if (!parameterDeclaration.DefaultExpression.IsNull) {
Space(policy.SpaceAroundAssignment); Space(policy.SpaceAroundAssignment);
@ -2031,7 +2023,7 @@ namespace ICSharpCode.NRefactory.CSharp
propertyDeclaration.ReturnType.AcceptVisitor(this); propertyDeclaration.ReturnType.AcceptVisitor(this);
Space(); Space();
WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType); WritePrivateImplementationType(propertyDeclaration.PrivateImplementationType);
propertyDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(propertyDeclaration.NameToken);
OpenBrace(policy.PropertyBraceStyle); OpenBrace(policy.PropertyBraceStyle);
// output get/set in their original order // output get/set in their original order
foreach (AstNode node in propertyDeclaration.Children) { foreach (AstNode node in propertyDeclaration.Children) {
@ -2050,7 +2042,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitVariableInitializer(VariableInitializer variableInitializer) public void VisitVariableInitializer(VariableInitializer variableInitializer)
{ {
StartNode(variableInitializer); StartNode(variableInitializer);
variableInitializer.NameToken.AcceptVisitor(this); WriteIdentifier(variableInitializer.NameToken);
if (!variableInitializer.Initializer.IsNull) { if (!variableInitializer.Initializer.IsNull) {
Space(policy.SpaceAroundAssignment); Space(policy.SpaceAroundAssignment);
WriteToken(Roles.Assign); WriteToken(Roles.Assign);
@ -2120,12 +2112,7 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitPrimitiveType(PrimitiveType primitiveType) public void VisitPrimitiveType(PrimitiveType primitiveType)
{ {
StartNode(primitiveType); StartNode(primitiveType);
WriteKeyword(primitiveType.Keyword); writer.WritePrimitiveType(primitiveType.Keyword);
if (primitiveType.Keyword == "new") {
// new() constraint
LPar();
RPar();
}
EndNode(primitiveType); EndNode(primitiveType);
} }
@ -2176,7 +2163,7 @@ namespace ICSharpCode.NRefactory.CSharp
default: default:
throw new NotSupportedException ("Invalid value for VarianceModifier"); throw new NotSupportedException ("Invalid value for VarianceModifier");
} }
typeParameterDeclaration.NameToken.AcceptVisitor(this); WriteIdentifier(typeParameterDeclaration.NameToken);
EndNode(typeParameterDeclaration); EndNode(typeParameterDeclaration);
} }
@ -2185,7 +2172,7 @@ namespace ICSharpCode.NRefactory.CSharp
StartNode(constraint); StartNode(constraint);
Space(); Space();
WriteKeyword(Roles.WhereKeyword); WriteKeyword(Roles.WhereKeyword);
WriteIdentifier(constraint.TypeParameter.IdentifierToken); constraint.TypeParameter.AcceptVisitor(this);
Space(); Space();
WriteToken(Roles.Colon); WriteToken(Roles.Colon);
Space(); Space();
@ -2197,9 +2184,9 @@ namespace ICSharpCode.NRefactory.CSharp
{ {
CSharpModifierToken mod = cSharpTokenNode as CSharpModifierToken; CSharpModifierToken mod = cSharpTokenNode as CSharpModifierToken;
if (mod != null) { if (mod != null) {
StartNode(mod); // ITokenWriter assumes that each node processed between a
WriteKeyword(CSharpModifierToken.GetModifierName(mod.Modifier)); // StartNode(parentNode)-EndNode(parentNode)-pair is a child of parentNode.
EndNode(mod); WriteKeyword(CSharpModifierToken.GetModifierName(mod.Modifier), cSharpTokenNode.Role);
} else { } else {
throw new NotSupportedException ("Should never visit individual tokens"); throw new NotSupportedException ("Should never visit individual tokens");
} }
@ -2207,9 +2194,10 @@ namespace ICSharpCode.NRefactory.CSharp
public void VisitIdentifier(Identifier identifier) public void VisitIdentifier(Identifier identifier)
{ {
StartNode(identifier); // Do not call StartNode and EndNode for Identifier, because they are handled by the ITokenWriter.
// ITokenWriter assumes that each node processed between a
// StartNode(parentNode)-EndNode(parentNode)-pair is a child of parentNode.
WriteIdentifier(identifier); WriteIdentifier(identifier);
EndNode(identifier);
} }
#endregion #endregion

89
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/ITokenWriter.cs

@ -17,110 +17,141 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.IO;
namespace ICSharpCode.NRefactory.CSharp namespace ICSharpCode.NRefactory.CSharp
{ {
public interface ITokenWriter public abstract class TokenWriter
{ {
void StartNode(AstNode node); public abstract void StartNode(AstNode node);
void EndNode(AstNode node); public abstract void EndNode(AstNode node);
/// <summary> /// <summary>
/// Writes an identifier. /// Writes an identifier.
/// </summary> /// </summary>
void WriteIdentifier(Identifier identifier); public abstract void WriteIdentifier(Identifier identifier);
/// <summary> /// <summary>
/// Writes a keyword to the output. /// Writes a keyword to the output.
/// </summary> /// </summary>
void WriteKeyword(Role role, string keyword); public abstract void WriteKeyword(Role role, string keyword);
/// <summary> /// <summary>
/// Writes a token to the output. /// Writes a token to the output.
/// </summary> /// </summary>
void WriteToken(Role role, string token); public abstract void WriteToken(Role role, string token);
/// <summary> /// <summary>
/// Writes a primitive/literal value /// Writes a primitive/literal value
/// </summary> /// </summary>
void WritePrimitiveValue(object value); public abstract void WritePrimitiveValue(object value, string literalValue = null);
void Space(); public abstract void WritePrimitiveType(string type);
void Indent();
void Unindent();
void NewLine();
void WriteComment(CommentType commentType, string content); public abstract void Space();
void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument); public abstract void Indent();
public abstract void Unindent();
public abstract void NewLine();
public abstract void WriteComment(CommentType commentType, string content);
public abstract void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument);
public static TokenWriter Create(TextWriter writer, string indentation = "\t")
{
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new TextWriterTokenWriter(writer) { IndentationString = indentation }));
}
public static TokenWriter CreateWriterThatSetsLocationsInAST(TextWriter writer, string indentation = "\t")
{
var target = new TextWriterTokenWriter(writer) { IndentationString = indentation };
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new InsertMissingTokensDecorator(target, target)));
}
public static TokenWriter WrapInWriterThatSetsLocationsInAST(TokenWriter writer, string indentation = "\t")
{
if (!(writer is ILocatable))
throw new InvalidOperationException("writer does not provide locations!");
return new InsertSpecialsDecorator(new InsertRequiredSpacesDecorator(new InsertMissingTokensDecorator(writer, (ILocatable)writer)));
}
}
public interface ILocatable
{
TextLocation Location { get; }
} }
public abstract class DecoratingTokenWriter : ITokenWriter public abstract class DecoratingTokenWriter : TokenWriter
{ {
ITokenWriter decoratedWriter; TokenWriter decoratedWriter;
protected DecoratingTokenWriter(ITokenWriter decoratedWriter) protected DecoratingTokenWriter(TokenWriter decoratedWriter)
{ {
if (decoratedWriter == null) if (decoratedWriter == null)
throw new ArgumentNullException("decoratedWriter"); throw new ArgumentNullException("decoratedWriter");
this.decoratedWriter = decoratedWriter; this.decoratedWriter = decoratedWriter;
} }
public virtual void StartNode(AstNode node) public override void StartNode(AstNode node)
{ {
decoratedWriter.StartNode(node); decoratedWriter.StartNode(node);
} }
public virtual void EndNode(AstNode node) public override void EndNode(AstNode node)
{ {
decoratedWriter.EndNode(node); decoratedWriter.EndNode(node);
} }
public virtual void WriteIdentifier(Identifier identifier) public override void WriteIdentifier(Identifier identifier)
{ {
decoratedWriter.WriteIdentifier(identifier); decoratedWriter.WriteIdentifier(identifier);
} }
public virtual void WriteKeyword(Role role, string keyword) public override void WriteKeyword(Role role, string keyword)
{ {
decoratedWriter.WriteKeyword(role, keyword); decoratedWriter.WriteKeyword(role, keyword);
} }
public virtual void WriteToken(Role role, string token) public override void WriteToken(Role role, string token)
{ {
decoratedWriter.WriteToken(role, token); decoratedWriter.WriteToken(role, token);
} }
public virtual void WritePrimitiveValue(object value) public override void WritePrimitiveValue(object value, string literalValue = null)
{
decoratedWriter.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{ {
decoratedWriter.WritePrimitiveValue(value); decoratedWriter.WritePrimitiveType(type);
} }
public virtual void Space() public override void Space()
{ {
decoratedWriter.Space(); decoratedWriter.Space();
} }
public virtual void Indent() public override void Indent()
{ {
decoratedWriter.Indent(); decoratedWriter.Indent();
} }
public virtual void Unindent() public override void Unindent()
{ {
decoratedWriter.Unindent(); decoratedWriter.Unindent();
} }
public virtual void NewLine() public override void NewLine()
{ {
decoratedWriter.NewLine(); decoratedWriter.NewLine();
} }
public virtual void WriteComment(CommentType commentType, string content) public override void WriteComment(CommentType commentType, string content)
{ {
decoratedWriter.WriteComment(commentType, content); decoratedWriter.WriteComment(commentType, content);
} }
public virtual void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument) public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{ {
decoratedWriter.WritePreProcessorDirective(type, argument); decoratedWriter.WritePreProcessorDirective(type, argument);
} }

112
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertMissingTokensDecorator.cs

@ -0,0 +1,112 @@
// Copyright (c) 2010-2013 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Linq;
namespace ICSharpCode.NRefactory.CSharp
{
class InsertMissingTokensDecorator : DecoratingTokenWriter
{
readonly Stack<List<AstNode>> nodes = new Stack<List<AstNode>>();
List<AstNode> currentList;
readonly ILocatable locationProvider;
public InsertMissingTokensDecorator(TokenWriter writer, ILocatable locationProvider)
: base(writer)
{
this.locationProvider = locationProvider;
currentList = new List<AstNode>();
}
public override void StartNode(AstNode node)
{
currentList.Add(node);
nodes.Push(currentList);
currentList = new List<AstNode>();
base.StartNode(node);
}
public override void EndNode(AstNode node)
{
System.Diagnostics.Debug.Assert(currentList != null);
foreach (var removable in node.Children.Where(n => n is CSharpTokenNode)) {
removable.Remove();
}
foreach (var child in currentList) {
System.Diagnostics.Debug.Assert(child.Parent == null || node == child.Parent);
child.Remove();
node.AddChildWithExistingRole(child);
}
currentList = nodes.Pop();
base.EndNode(node);
}
public override void WriteToken(Role role, string token)
{
CSharpTokenNode t = new CSharpTokenNode(locationProvider.Location, (TokenRole)role);
currentList.Add(t);
base.WriteToken(role, token);
}
public override void WriteKeyword(Role role, string keyword)
{
TextLocation start = locationProvider.Location;
CSharpTokenNode t = null;
if (role is TokenRole)
t = new CSharpTokenNode(start, (TokenRole)role);
else if (role == EntityDeclaration.ModifierRole)
t = new CSharpModifierToken(start, CSharpModifierToken.GetModifierValue(keyword));
else if (keyword == "this") {
ThisReferenceExpression node = nodes.Peek().LastOrDefault() as ThisReferenceExpression;
if (node != null)
node.Location = start;
}
if (t != null) currentList.Add(t);
base.WriteKeyword(role, keyword);
}
public override void WriteIdentifier(Identifier identifier)
{
identifier.SetStartLocation(locationProvider.Location);
currentList.Add(identifier);
base.WriteIdentifier(identifier);
}
public override void WritePrimitiveValue(object value, string literalValue = null)
{
Expression node = nodes.Peek().LastOrDefault() as Expression;
if (node is PrimitiveExpression) {
((PrimitiveExpression)node).SetStartLocation(locationProvider.Location);
}
if (node is NullReferenceExpression) {
((NullReferenceExpression)node).SetStartLocation(locationProvider.Location);
}
base.WritePrimitiveValue(value, literalValue);
}
public override void WritePrimitiveType(string type)
{
PrimitiveType node = nodes.Peek().LastOrDefault() as PrimitiveType;
if (node != null)
node.SetStartLocation(locationProvider.Location);
base.WritePrimitiveType(type);
}
}
}

21
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertRequiredSpacesDecorator.cs

@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp
Division Division
} }
public InsertRequiredSpacesDecorator(ITokenWriter writer) public InsertRequiredSpacesDecorator(TokenWriter writer)
: base(writer) : base(writer)
{ {
} }
@ -148,7 +148,7 @@ namespace ICSharpCode.NRefactory.CSharp
lastWritten = LastWritten.Whitespace; lastWritten = LastWritten.Whitespace;
} }
public override void WritePrimitiveValue(object value) public override void WritePrimitiveValue(object value, string literalValue = null)
{ {
base.WritePrimitiveValue(value); base.WritePrimitiveValue(value);
if (value == null || value is bool) if (value == null || value is bool)
@ -177,9 +177,18 @@ namespace ICSharpCode.NRefactory.CSharp
lastWritten = LastWritten.Other; lastWritten = LastWritten.Other;
} }
} }
}
public override void WritePrimitiveType(string type)
{
if (lastWritten == LastWritten.KeywordOrIdentifier) {
Space();
}
base.WritePrimitiveType(type);
if (type == "new") {
lastWritten = LastWritten.Other;
} else {
lastWritten = LastWritten.KeywordOrIdentifier;
}
}
}
} }

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertSpecialsDecorator.cs

@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp
readonly Stack<AstNode> positionStack = new Stack<AstNode>(); readonly Stack<AstNode> positionStack = new Stack<AstNode>();
int visitorWroteNewLine = 0; int visitorWroteNewLine = 0;
public InsertSpecialsDecorator(ITokenWriter writer) : base(writer) public InsertSpecialsDecorator(TokenWriter writer) : base(writer)
{ {
} }

127
src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/TextWriterOutputFormatter.cs

@ -26,20 +26,21 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary> /// <summary>
/// Writes C# code into a TextWriter. /// Writes C# code into a TextWriter.
/// </summary> /// </summary>
public class TextWriterTokenWriter : ITokenWriter public class TextWriterTokenWriter : TokenWriter, ILocatable
{ {
readonly TextWriter textWriter; readonly TextWriter textWriter;
int indentation; int indentation;
bool needsIndent = true; bool needsIndent = true;
bool isAtStartOfLine = true; bool isAtStartOfLine = true;
int line, column;
public int Indentation { public int Indentation {
get { get { return this.indentation; }
return this.indentation; set { this.indentation = value; }
}
set {
this.indentation = value;
} }
public TextLocation Location {
get { return new TextLocation(line, column + (needsIndent ? indentation * IndentationString.Length : 0)); }
} }
public string IndentationString { get; set; } public string IndentationString { get; set; }
@ -50,34 +51,42 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentNullException("textWriter"); throw new ArgumentNullException("textWriter");
this.textWriter = textWriter; this.textWriter = textWriter;
this.IndentationString = "\t"; this.IndentationString = "\t";
this.line = 1;
this.column = 1;
} }
public void WriteIdentifier(Identifier identifier) public override void WriteIdentifier(Identifier identifier)
{ {
WriteIndentation(); WriteIndentation();
if (identifier.IsVerbatim) if (identifier.IsVerbatim) {
textWriter.Write('@'); textWriter.Write('@');
column++;
}
textWriter.Write(identifier.Name); textWriter.Write(identifier.Name);
column += identifier.Name.Length;
isAtStartOfLine = false; isAtStartOfLine = false;
} }
public void WriteKeyword(Role role, string keyword) public override void WriteKeyword(Role role, string keyword)
{ {
WriteIndentation(); WriteIndentation();
column += keyword.Length;
textWriter.Write(keyword); textWriter.Write(keyword);
isAtStartOfLine = false; isAtStartOfLine = false;
} }
public void WriteToken(Role role, string token) public override void WriteToken(Role role, string token)
{ {
WriteIndentation(); WriteIndentation();
column += token.Length;
textWriter.Write(token); textWriter.Write(token);
isAtStartOfLine = false; isAtStartOfLine = false;
} }
public void Space() public override void Space()
{ {
WriteIndentation(); WriteIndentation();
column++;
textWriter.Write(' '); textWriter.Write(' ');
} }
@ -88,33 +97,37 @@ namespace ICSharpCode.NRefactory.CSharp
for (int i = 0; i < indentation; i++) { for (int i = 0; i < indentation; i++) {
textWriter.Write(this.IndentationString); textWriter.Write(this.IndentationString);
} }
column += indentation * IndentationString.Length;
} }
} }
public void NewLine() public override void NewLine()
{ {
textWriter.WriteLine(); textWriter.WriteLine();
column = 1;
line++;
needsIndent = true; needsIndent = true;
isAtStartOfLine = true; isAtStartOfLine = true;
} }
public void Indent() public override void Indent()
{ {
indentation++; indentation++;
} }
public void Unindent() public override void Unindent()
{ {
indentation--; indentation--;
} }
public void WriteComment(CommentType commentType, string content) public override void WriteComment(CommentType commentType, string content)
{ {
WriteIndentation(); WriteIndentation();
switch (commentType) { switch (commentType) {
case CommentType.SingleLine: case CommentType.SingleLine:
textWriter.Write("//"); textWriter.Write("//");
textWriter.WriteLine(content); textWriter.WriteLine(content);
column += 2 + content.Length;
needsIndent = true; needsIndent = true;
isAtStartOfLine = true; isAtStartOfLine = true;
break; break;
@ -122,31 +135,59 @@ namespace ICSharpCode.NRefactory.CSharp
textWriter.Write("/*"); textWriter.Write("/*");
textWriter.Write(content); textWriter.Write(content);
textWriter.Write("*/"); textWriter.Write("*/");
column += 2;
UpdateEndLocation(content, ref line, ref column);
column += 2;
isAtStartOfLine = false; isAtStartOfLine = false;
break; break;
case CommentType.Documentation: case CommentType.Documentation:
textWriter.Write("///"); textWriter.Write("///");
textWriter.WriteLine(content); textWriter.WriteLine(content);
column += 3 + content.Length;
needsIndent = true; needsIndent = true;
isAtStartOfLine = true; isAtStartOfLine = true;
break; break;
default: default:
textWriter.Write(content); textWriter.Write(content);
column += content.Length;
break; break;
} }
} }
public void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument) static void UpdateEndLocation(string content, ref int line, ref int column)
{
if (string.IsNullOrEmpty(content))
return;
for (int i = 0; i < content.Length; i++) {
char ch = content[i];
switch (ch) {
case '\r':
if (i + 1 < content.Length && content[i + 1] == '\n')
i++;
goto case '\n';
case '\n':
line++;
column = 0;
break;
}
column++;
}
}
public override void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument)
{ {
// pre-processor directive must start on its own line // pre-processor directive must start on its own line
if (!isAtStartOfLine) if (!isAtStartOfLine)
NewLine(); NewLine();
WriteIndentation(); WriteIndentation();
textWriter.Write('#'); textWriter.Write('#');
textWriter.Write(type.ToString().ToLowerInvariant()); string directive = type.ToString().ToLowerInvariant();
textWriter.Write(directive);
column += 1 + directive.Length;
if (!string.IsNullOrEmpty(argument)) { if (!string.IsNullOrEmpty(argument)) {
textWriter.Write(' '); textWriter.Write(' ');
textWriter.Write(argument); textWriter.Write(argument);
column += 1 + argument.Length;
} }
NewLine(); NewLine();
} }
@ -159,42 +200,61 @@ namespace ICSharpCode.NRefactory.CSharp
return writer.ToString(); return writer.ToString();
} }
public void WritePrimitiveValue(object value) public override void WritePrimitiveValue(object value, string literalValue = null)
{ {
if (literalValue != null) {
textWriter.Write(literalValue);
column += literalValue.Length;
return;
}
if (value == null) { if (value == null) {
// usually NullReferenceExpression should be used for this, but we'll handle it anyways // usually NullReferenceExpression should be used for this, but we'll handle it anyways
textWriter.Write("null"); textWriter.Write("null");
column += 4;
return; return;
} }
if (value is bool) { if (value is bool) {
if ((bool)value) { if ((bool)value) {
textWriter.Write("true"); textWriter.Write("true");
column += 4;
} else { } else {
textWriter.Write("false"); textWriter.Write("false");
column += 5;
} }
return; return;
} }
if (value is string) { if (value is string) {
textWriter.Write("\"" + ConvertString(value.ToString()) + "\""); string tmp = "\"" + ConvertString(value.ToString()) + "\"";
column += tmp.Length;
textWriter.Write(tmp);
} else if (value is char) { } else if (value is char) {
textWriter.Write("'" + ConvertCharLiteral((char)value) + "'"); string tmp = "'" + ConvertCharLiteral((char)value) + "'";
column += tmp.Length;
textWriter.Write(tmp);
} else if (value is decimal) { } else if (value is decimal) {
textWriter.Write(((decimal)value).ToString(NumberFormatInfo.InvariantInfo) + "m"); string str = ((decimal)value).ToString(NumberFormatInfo.InvariantInfo) + "m";
column += str.Length;
textWriter.Write(str);
} else if (value is float) { } else if (value is float) {
float f = (float)value; float f = (float)value;
if (float.IsInfinity(f) || float.IsNaN(f)) { if (float.IsInfinity(f) || float.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions; // Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators. // but we still support writing these to make life easier for code generators.
textWriter.Write("float"); textWriter.Write("float");
column += 5;
WriteToken(Roles.Dot, "."); WriteToken(Roles.Dot, ".");
if (float.IsPositiveInfinity(f)) { if (float.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity"); textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (float.IsNegativeInfinity(f)) { } else if (float.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity"); textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else { } else {
textWriter.Write("NaN"); textWriter.Write("NaN");
column += 3;
} }
return; return;
} }
@ -203,21 +263,28 @@ namespace ICSharpCode.NRefactory.CSharp
// (again, not a primitive expression, but it's better to handle // (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators) // the special case here than to do it in all code generators)
textWriter.Write("-"); textWriter.Write("-");
column++;
} }
textWriter.Write(f.ToString("R", NumberFormatInfo.InvariantInfo) + "f"); var str = f.ToString("R", NumberFormatInfo.InvariantInfo) + "f";
column += str.Length;
textWriter.Write(str);
} else if (value is double) { } else if (value is double) {
double f = (double)value; double f = (double)value;
if (double.IsInfinity(f) || double.IsNaN(f)) { if (double.IsInfinity(f) || double.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions; // Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators. // but we still support writing these to make life easier for code generators.
textWriter.Write("double"); textWriter.Write("double");
textWriter.Write("."); column += 6;
WriteToken(Roles.Dot, ".");
if (double.IsPositiveInfinity(f)) { if (double.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity"); textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (double.IsNegativeInfinity(f)) { } else if (double.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity"); textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else { } else {
textWriter.Write("NaN"); textWriter.Write("NaN");
column += 3;
} }
return; return;
} }
@ -312,7 +379,17 @@ namespace ICSharpCode.NRefactory.CSharp
return sb.ToString(); return sb.ToString();
} }
public virtual void StartNode(AstNode node) public override void WritePrimitiveType(string type)
{
textWriter.Write(type);
column += type.Length;
if (type == "new") {
textWriter.Write("()");
column += 2;
}
}
public override void StartNode(AstNode node)
{ {
// Write out the indentation, so that overrides of this method // Write out the indentation, so that overrides of this method
// can rely use the current output length to identify the position of the node // can rely use the current output length to identify the position of the node
@ -320,7 +397,7 @@ namespace ICSharpCode.NRefactory.CSharp
WriteIndentation(); WriteIndentation();
} }
public virtual void EndNode(AstNode node) public override void EndNode(AstNode node)
{ {
} }
} }

87
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/InsertMissingTokensDecoratorTests.cs

@ -0,0 +1,87 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using System.Linq;
using System.Text;
using ICSharpCode.NRefactory.Editor;
using NUnit.Framework;
using ICSharpCode.NRefactory.CSharp.Parser;
namespace ICSharpCode.NRefactory.CSharp
{
/// <summary>
/// Description of InsertMissingTokensDecoratorTests.
/// </summary>
[TestFixture]
public class InsertMissingTokensDecoratorTests
{
string[] fileNames;
[TestFixtureSetUp]
public void SetUp()
{
string path = Path.GetFullPath (Path.Combine ("..", ".."));
if (!File.Exists(Path.Combine(path, "NRefactory.sln")))
throw new InvalidOperationException("Test cannot find the NRefactory source code in " + path);
fileNames = Directory.GetFiles(path, "*.cs", SearchOption.AllDirectories);
}
static void RemoveTokens(AstNode node)
{
foreach (var child in node.Descendants) {
if (child is CSharpTokenNode && !(child is CSharpModifierToken))
child.Remove();
else if (child.NodeType == NodeType.Whitespace)
child.Remove();
}
}
void AssertOutput(AstNode node)
{
RemoveTokens(node);
StringWriter w = new StringWriter();
w.NewLine = "\n";
node.AcceptVisitor(new CSharpOutputVisitor(TokenWriter.CreateWriterThatSetsLocationsInAST(w), FormattingOptionsFactory.CreateSharpDevelop()));
var doc = new ReadOnlyDocument(w.ToString());
ConsistencyChecker.CheckMissingTokens(node, "test.cs", doc);
ConsistencyChecker.CheckPositionConsistency(node, "test.cs", doc);
}
[Test]
public void SimpleClass()
{
var code = @"class Test
{
}
";
var unit = SyntaxTree.Parse(code);
AssertOutput(unit);
}
[Test]
public void SimpleMethod()
{
var code = @"class Test
{
void A ()
{
}
}
";
var unit = SyntaxTree.Parse(code);
AssertOutput(unit);
}
[Test]
public void SelfTest()
{
foreach (var file in fileNames) {
Console.WriteLine("processing {0}...", file);
var node = SyntaxTree.Parse(File.ReadAllText(file), file);
AssertOutput(node);
}
}
}
}

90
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ConsistencyChecker.cs

@ -0,0 +1,90 @@
// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
using System;
using System.IO;
using ICSharpCode.NRefactory.Editor;
using NUnit.Framework;
namespace ICSharpCode.NRefactory.CSharp.Parser
{
/// <summary>
/// Provides utilities to check whether positions and/or tokens in an AST are valid.
/// </summary>
public static class ConsistencyChecker
{
static void PrintNode (AstNode node)
{
Console.WriteLine ("Parent:" + node.GetType ());
Console.WriteLine ("Children:");
foreach (var c in node.Children)
Console.WriteLine (c.GetType () +" at:"+ c.StartLocation +"-"+ c.EndLocation + " Role: "+ c.Role);
Console.WriteLine ("----");
}
public static void CheckPositionConsistency (AstNode node, string currentFileName, IDocument currentDocument = null)
{
if (currentDocument == null)
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName));
string comment = "(" + node.GetType ().Name + " at " + node.StartLocation + " in " + currentFileName + ")";
var pred = node.StartLocation <= node.EndLocation;
if (!pred)
PrintNode (node);
Assert.IsTrue(pred, "StartLocation must be before EndLocation " + comment);
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
bool assertion = child.StartLocation >= prevNodeEnd;
if (!assertion) {
PrintNode (prevNode);
PrintNode (node);
}
Assert.IsTrue(assertion, currentFileName + ": Child " + child.GetType () +" (" + child.StartLocation + ")" +" must start after previous sibling " + prevNode.GetType () + "(" + prevNode.StartLocation + ")");
CheckPositionConsistency(child, currentFileName, currentDocument);
prevNodeEnd = child.EndLocation;
prevNode = child;
}
Assert.IsTrue(prevNodeEnd <= node.EndLocation, "Last child must end before parent node ends " + comment);
}
public static void CheckMissingTokens(AstNode node, string currentFileName, IDocument currentDocument = null)
{
if (currentDocument == null)
currentDocument = new ReadOnlyDocument(File.ReadAllText(currentFileName));
if (node is CSharpTokenNode) {
Assert.IsNull(node.FirstChild, "Token nodes should not have children");
} else {
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
CheckWhitespace(prevNode, prevNodeEnd, child, child.StartLocation, currentFileName, currentDocument);
CheckMissingTokens(child, currentFileName, currentDocument);
prevNode = child;
prevNodeEnd = child.EndLocation;
}
CheckWhitespace(prevNode, prevNodeEnd, node, node.EndLocation, currentFileName, currentDocument);
}
}
static void CheckWhitespace(AstNode startNode, TextLocation whitespaceStart, AstNode endNode, TextLocation whitespaceEnd, string currentFileName, IDocument currentDocument)
{
Assert.Greater(whitespaceStart.Line, 0);
Assert.Greater(whitespaceStart.Column, 0);
Assert.Greater(whitespaceEnd.Line, 0);
Assert.Greater(whitespaceEnd.Column, 0);
if (whitespaceStart == whitespaceEnd || startNode == endNode)
return;
int start = currentDocument.GetOffset(whitespaceStart.Line, whitespaceStart.Column);
int end = currentDocument.GetOffset(whitespaceEnd.Line, whitespaceEnd.Column);
string text = currentDocument.GetText(start, end - start);
bool assertion = string.IsNullOrWhiteSpace(text);
if (!assertion) {
if (startNode.Parent != endNode.Parent)
PrintNode (startNode.Parent);
PrintNode (endNode.Parent);
}
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")");
}
}
}

77
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/CSharp/Parser/ParseSelfTests.cs

@ -67,89 +67,20 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
} }
#region ParseAndCheckPositions #region ParseAndCheckPositions
string currentFileName;
ReadOnlyDocument currentDocument;
[Test, Ignore("Positions still are incorrect in several cases")] [Test, Ignore("Positions still are incorrect in several cases")]
public void ParseAndCheckPositions() public void ParseAndCheckPositions()
{ {
CSharpParser parser = new CSharpParser(); CSharpParser parser = new CSharpParser();
foreach (string fileName in fileNames) { foreach (string fileName in fileNames) {
this.currentDocument = new ReadOnlyDocument(File.ReadAllText(fileName)); var currentDocument = new ReadOnlyDocument(File.ReadAllText(fileName));
SyntaxTree syntaxTree = parser.Parse(currentDocument, fileName); SyntaxTree syntaxTree = parser.Parse(currentDocument, fileName);
if (parser.HasErrors) if (parser.HasErrors)
continue; continue;
this.currentFileName = fileName; ConsistencyChecker.CheckPositionConsistency(syntaxTree, fileName, currentDocument);
CheckPositionConsistency(syntaxTree); ConsistencyChecker.CheckMissingTokens(syntaxTree, fileName, currentDocument);
CheckMissingTokens(syntaxTree);
}
}
void PrintNode (AstNode node)
{
Console.WriteLine ("Parent:" + node.GetType ());
Console.WriteLine ("Children:");
foreach (var c in node.Children)
Console.WriteLine (c.GetType () +" at:"+ c.StartLocation +"-"+ c.EndLocation + " Role: "+ c.Role);
Console.WriteLine ("----");
}
void CheckPositionConsistency (AstNode node)
{
string comment = "(" + node.GetType ().Name + " at " + node.StartLocation + " in " + currentFileName + ")";
var pred = node.StartLocation <= node.EndLocation;
if (!pred)
PrintNode (node);
Assert.IsTrue(pred, "StartLocation must be before EndLocation " + comment);
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
bool assertion = child.StartLocation >= prevNodeEnd;
if (!assertion) {
PrintNode (prevNode);
PrintNode (node);
}
Assert.IsTrue(assertion, currentFileName + ": Child " + child.GetType () +" (" + child.StartLocation + ")" +" must start after previous sibling " + prevNode.GetType () + "(" + prevNode.StartLocation + ")");
CheckPositionConsistency(child);
prevNodeEnd = child.EndLocation;
prevNode = child;
}
Assert.IsTrue(prevNodeEnd <= node.EndLocation, "Last child must end before parent node ends " + comment);
}
void CheckMissingTokens(AstNode node)
{
if (node is CSharpTokenNode) {
Assert.IsNull(node.FirstChild, "Token nodes should not have children");
} else {
var prevNodeEnd = node.StartLocation;
var prevNode = node;
for (AstNode child = node.FirstChild; child != null; child = child.NextSibling) {
CheckWhitespace(prevNode, prevNodeEnd, child, child.StartLocation);
CheckMissingTokens(child);
prevNode = child;
prevNodeEnd = child.EndLocation;
}
CheckWhitespace(prevNode, prevNodeEnd, node, node.EndLocation);
}
}
void CheckWhitespace(AstNode startNode, TextLocation whitespaceStart, AstNode endNode, TextLocation whitespaceEnd)
{
if (whitespaceStart == whitespaceEnd || startNode == endNode)
return;
int start = currentDocument.GetOffset(whitespaceStart.Line, whitespaceStart.Column);
int end = currentDocument.GetOffset(whitespaceEnd.Line, whitespaceEnd.Column);
string text = currentDocument.GetText(start, end - start);
bool assertion = string.IsNullOrWhiteSpace(text);
if (!assertion) {
if (startNode.Parent != endNode.Parent)
PrintNode (startNode.Parent);
PrintNode (endNode.Parent);
} }
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")");
} }
#endregion #endregion
} }

2
src/Libraries/NRefactory/ICSharpCode.NRefactory.Tests/ICSharpCode.NRefactory.Tests.csproj

@ -159,8 +159,10 @@
<Compile Include="CSharp\CSharpAmbienceTests.cs" /> <Compile Include="CSharp\CSharpAmbienceTests.cs" />
<Compile Include="CSharp\CodeDomConvertVisitorTests.cs" /> <Compile Include="CSharp\CodeDomConvertVisitorTests.cs" />
<Compile Include="CSharp\DepthFirstVisitorTests.cs" /> <Compile Include="CSharp\DepthFirstVisitorTests.cs" />
<Compile Include="CSharp\InsertMissingTokensDecoratorTests.cs" />
<Compile Include="CSharp\InsertParenthesesVisitorTests.cs" /> <Compile Include="CSharp\InsertParenthesesVisitorTests.cs" />
<Compile Include="CSharp\CSharpOutputVisitorTests.cs" /> <Compile Include="CSharp\CSharpOutputVisitorTests.cs" />
<Compile Include="CSharp\Parser\ConsistencyChecker.cs" />
<Compile Include="CSharp\Parser\Expression\AnonymousTypeCreateExpressionTests.cs" /> <Compile Include="CSharp\Parser\Expression\AnonymousTypeCreateExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\ObjectCreateExpressionTests.cs" /> <Compile Include="CSharp\Parser\Expression\ObjectCreateExpressionTests.cs" />
<Compile Include="CSharp\Parser\Expression\UndocumentedExpressionTests.cs" /> <Compile Include="CSharp\Parser\Expression\UndocumentedExpressionTests.cs" />

Loading…
Cancel
Save