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. 10
      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. 104
      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. 23
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertRequiredSpacesDecorator.cs
  15. 2
      src/Libraries/NRefactory/ICSharpCode.NRefactory.CSharp/OutputVisitor/InsertSpecialsDecorator.cs
  16. 129
      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; @@ -27,7 +27,7 @@ using Mono.Cecil;
namespace ICSharpCode.Decompiler.Ast
{
public class TextTokenWriter : ITokenWriter
public class TextTokenWriter : TokenWriter
{
readonly ITextOutput output;
readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -47,7 +47,7 @@ namespace ICSharpCode.Decompiler.Ast
this.output = output;
}
public void WriteIdentifier(Identifier identifier)
public override void WriteIdentifier(Identifier identifier)
{
var definition = GetCurrentDefinition();
if (definition != null) {
@ -160,12 +160,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -160,12 +160,12 @@ namespace ICSharpCode.Decompiler.Ast
return null;
}
public void WriteKeyword(Role role, string keyword)
public override void WriteKeyword(Role role, string 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.
MemberReference memberRef = GetCurrentMemberReference();
@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -176,7 +176,7 @@ namespace ICSharpCode.Decompiler.Ast
output.Write(token);
}
public void Space()
public override void Space()
{
output.Write(' ');
}
@ -203,17 +203,17 @@ namespace ICSharpCode.Decompiler.Ast @@ -203,17 +203,17 @@ namespace ICSharpCode.Decompiler.Ast
braceLevelWithinType--;
}
public void Indent()
public override void Indent()
{
output.Indent();
}
public void Unindent()
public override void Unindent()
{
output.Unindent();
}
public void NewLine()
public override void NewLine()
{
if (lastUsingDeclaration) {
output.MarkFoldEnd();
@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -223,7 +223,7 @@ namespace ICSharpCode.Decompiler.Ast
output.WriteLine();
}
public void WriteComment(CommentType commentType, string content)
public override void WriteComment(CommentType commentType, string content)
{
switch (commentType) {
case CommentType.SingleLine:
@ -255,7 +255,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -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
output.Write('#');
@ -267,7 +267,12 @@ namespace ICSharpCode.Decompiler.Ast @@ -267,7 +267,12 @@ namespace ICSharpCode.Decompiler.Ast
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 @@ -275,7 +280,7 @@ namespace ICSharpCode.Decompiler.Ast
Stack<TextLocation> startLocations = new Stack<TextLocation>();
Stack<MethodDebugSymbols> symbolsStack = new Stack<MethodDebugSymbols>();
public void StartNode(AstNode node)
public override void StartNode(AstNode node)
{
if (nodeStack.Count == 0) {
if (IsUsingDeclaration(node)) {
@ -303,7 +308,7 @@ namespace ICSharpCode.Decompiler.Ast @@ -303,7 +308,7 @@ namespace ICSharpCode.Decompiler.Ast
return node is UsingDeclaration || node is UsingAliasDeclaration;
}
public void EndNode(AstNode node)
public override void EndNode(AstNode node)
{
if (nodeStack.Pop() != node)
throw new InvalidOperationException();

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

@ -60,7 +60,7 @@ @@ -60,7 +60,7 @@
<Compile Include="Ast\DecompilerContext.cs" />
<Compile Include="Ast\NameVariables.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\CombineQueryExpressions.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 @@ -406,6 +406,8 @@ namespace ICSharpCode.NRefactory.CSharp
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)
@ -413,6 +415,20 @@ namespace ICSharpCode.NRefactory.CSharp @@ -413,6 +415,20 @@ namespace ICSharpCode.NRefactory.CSharp
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>
/// Adds a child without performing any safety checks.
/// </summary>

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

@ -169,5 +169,50 @@ namespace ICSharpCode.NRefactory.CSharp @@ -169,5 +169,50 @@ namespace ICSharpCode.NRefactory.CSharp
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");
}
}
}
}

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

@ -1,6 +1,6 @@ @@ -1,6 +1,6 @@
//
// NullReferenceExpression.cs
//
//
// Author:
// Mike Krüger <mkrueger@novell.com>
//
@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp @@ -38,6 +38,12 @@ namespace ICSharpCode.NRefactory.CSharp
}
}
internal void SetStartLocation(TextLocation value)
{
ThrowIfFrozen();
this.location = value;
}
public override TextLocation EndLocation {
get {
return new TextLocation (location.Line, location.Column + "null".Length);
@ -57,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -57,7 +63,7 @@ namespace ICSharpCode.NRefactory.CSharp
{
visitor.VisitNullReferenceExpression (this);
}
public override T AcceptVisitor<T> (IAstVisitor<T> visitor)
{
return visitor.VisitNullReferenceExpression (this);

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

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

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

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

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

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

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

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

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

@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -41,7 +41,7 @@ namespace ICSharpCode.NRefactory.CSharp
return writer.ToString();
}
public void ConvertEntity(IEntity entity, ITokenWriter writer, CSharpFormattingOptions formattingPolicy)
public void ConvertEntity(IEntity entity, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
if (entity == null)
throw new ArgumentNullException("entity");
@ -160,7 +160,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -160,7 +160,7 @@ namespace ICSharpCode.NRefactory.CSharp
return astBuilder;
}
void WriteTypeDeclarationName(ITypeDefinition typeDef, ITokenWriter writer, CSharpFormattingOptions formattingPolicy)
void WriteTypeDeclarationName(ITypeDefinition typeDef, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
EntityDeclaration node = astBuilder.ConvertEntity(typeDef);
@ -178,7 +178,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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();
EntityDeclaration node = astBuilder.ConvertEntity(member);
@ -235,7 +235,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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) {
if ((modifiers & m) == m) {
@ -245,7 +245,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -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 outputVisitor = new CSharpOutputVisitor(writer, formattingPolicy);
@ -270,7 +270,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -270,7 +270,7 @@ namespace ICSharpCode.NRefactory.CSharp
return astType.ToString();
}
public void ConvertType(IType type, ITokenWriter writer, CSharpFormattingOptions formattingPolicy)
public void ConvertType(IType type, TokenWriter writer, CSharpFormattingOptions formattingPolicy)
{
TypeSystemAstBuilder astBuilder = CreateAstBuilder();
AstType astType = astBuilder.ConvertType(type);

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

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

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

@ -17,110 +17,141 @@ @@ -17,110 +17,141 @@
// DEALINGS IN THE SOFTWARE.
using System;
using System.IO;
namespace ICSharpCode.NRefactory.CSharp
{
public interface ITokenWriter
public abstract class TokenWriter
{
void StartNode(AstNode node);
void EndNode(AstNode node);
public abstract void StartNode(AstNode node);
public abstract void EndNode(AstNode node);
/// <summary>
/// Writes an identifier.
/// </summary>
void WriteIdentifier(Identifier identifier);
public abstract void WriteIdentifier(Identifier identifier);
/// <summary>
/// Writes a keyword to the output.
/// </summary>
void WriteKeyword(Role role, string keyword);
public abstract void WriteKeyword(Role role, string keyword);
/// <summary>
/// Writes a token to the output.
/// </summary>
void WriteToken(Role role, string token);
public abstract void WriteToken(Role role, string token);
/// <summary>
/// Writes a primitive/literal value
/// </summary>
void WritePrimitiveValue(object value);
public abstract void WritePrimitiveValue(object value, string literalValue = null);
void Space();
void Indent();
void Unindent();
void NewLine();
public abstract void WritePrimitiveType(string type);
void WriteComment(CommentType commentType, string content);
void WritePreProcessorDirective(PreProcessorDirectiveType type, string argument);
public abstract void Space();
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)
throw new ArgumentNullException("decoratedWriter");
this.decoratedWriter = decoratedWriter;
}
public virtual void StartNode(AstNode node)
public override void StartNode(AstNode node)
{
decoratedWriter.StartNode(node);
}
public virtual void EndNode(AstNode node)
public override void EndNode(AstNode node)
{
decoratedWriter.EndNode(node);
}
public virtual void WriteIdentifier(Identifier identifier)
public override void WriteIdentifier(Identifier identifier)
{
decoratedWriter.WriteIdentifier(identifier);
}
public virtual void WriteKeyword(Role role, string keyword)
public override void WriteKeyword(Role role, string 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);
}
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();
}
public virtual void Indent()
public override void Indent()
{
decoratedWriter.Indent();
}
public virtual void Unindent()
public override void Unindent()
{
decoratedWriter.Unindent();
}
public virtual void NewLine()
public override void NewLine()
{
decoratedWriter.NewLine();
}
public virtual void WriteComment(CommentType commentType, string content)
public override void WriteComment(CommentType commentType, string 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);
}

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

@ -0,0 +1,112 @@ @@ -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);
}
}
}

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

@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -49,7 +49,7 @@ namespace ICSharpCode.NRefactory.CSharp
Division
}
public InsertRequiredSpacesDecorator(ITokenWriter writer)
public InsertRequiredSpacesDecorator(TokenWriter writer)
: base(writer)
{
}
@ -148,7 +148,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -148,7 +148,7 @@ namespace ICSharpCode.NRefactory.CSharp
lastWritten = LastWritten.Whitespace;
}
public override void WritePrimitiveValue(object value)
public override void WritePrimitiveValue(object value, string literalValue = null)
{
base.WritePrimitiveValue(value);
if (value == null || value is bool)
@ -177,9 +177,18 @@ namespace ICSharpCode.NRefactory.CSharp @@ -177,9 +177,18 @@ namespace ICSharpCode.NRefactory.CSharp
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 @@ -29,7 +29,7 @@ namespace ICSharpCode.NRefactory.CSharp
readonly Stack<AstNode> positionStack = new Stack<AstNode>();
int visitorWroteNewLine = 0;
public InsertSpecialsDecorator(ITokenWriter writer) : base(writer)
public InsertSpecialsDecorator(TokenWriter writer) : base(writer)
{
}

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

@ -26,20 +26,21 @@ namespace ICSharpCode.NRefactory.CSharp @@ -26,20 +26,21 @@ namespace ICSharpCode.NRefactory.CSharp
/// <summary>
/// Writes C# code into a TextWriter.
/// </summary>
public class TextWriterTokenWriter : ITokenWriter
public class TextWriterTokenWriter : TokenWriter, ILocatable
{
readonly TextWriter textWriter;
int indentation;
bool needsIndent = true;
bool isAtStartOfLine = true;
int line, column;
public int Indentation {
get {
return this.indentation;
}
set {
this.indentation = value;
}
get { return this.indentation; }
set { this.indentation = value; }
}
public TextLocation Location {
get { return new TextLocation(line, column + (needsIndent ? indentation * IndentationString.Length : 0)); }
}
public string IndentationString { get; set; }
@ -50,34 +51,42 @@ namespace ICSharpCode.NRefactory.CSharp @@ -50,34 +51,42 @@ namespace ICSharpCode.NRefactory.CSharp
throw new ArgumentNullException("textWriter");
this.textWriter = textWriter;
this.IndentationString = "\t";
this.line = 1;
this.column = 1;
}
public void WriteIdentifier(Identifier identifier)
public override void WriteIdentifier(Identifier identifier)
{
WriteIndentation();
if (identifier.IsVerbatim)
if (identifier.IsVerbatim) {
textWriter.Write('@');
column++;
}
textWriter.Write(identifier.Name);
column += identifier.Name.Length;
isAtStartOfLine = false;
}
public void WriteKeyword(Role role, string keyword)
public override void WriteKeyword(Role role, string keyword)
{
WriteIndentation();
column += keyword.Length;
textWriter.Write(keyword);
isAtStartOfLine = false;
}
public void WriteToken(Role role, string token)
public override void WriteToken(Role role, string token)
{
WriteIndentation();
column += token.Length;
textWriter.Write(token);
isAtStartOfLine = false;
}
public void Space()
public override void Space()
{
WriteIndentation();
column++;
textWriter.Write(' ');
}
@ -88,33 +97,37 @@ namespace ICSharpCode.NRefactory.CSharp @@ -88,33 +97,37 @@ namespace ICSharpCode.NRefactory.CSharp
for (int i = 0; i < indentation; i++) {
textWriter.Write(this.IndentationString);
}
column += indentation * IndentationString.Length;
}
}
public void NewLine()
public override void NewLine()
{
textWriter.WriteLine();
column = 1;
line++;
needsIndent = true;
isAtStartOfLine = true;
}
public void Indent()
public override void Indent()
{
indentation++;
}
public void Unindent()
public override void Unindent()
{
indentation--;
}
public void WriteComment(CommentType commentType, string content)
public override void WriteComment(CommentType commentType, string content)
{
WriteIndentation();
switch (commentType) {
case CommentType.SingleLine:
textWriter.Write("//");
textWriter.WriteLine(content);
column += 2 + content.Length;
needsIndent = true;
isAtStartOfLine = true;
break;
@ -122,31 +135,59 @@ namespace ICSharpCode.NRefactory.CSharp @@ -122,31 +135,59 @@ namespace ICSharpCode.NRefactory.CSharp
textWriter.Write("/*");
textWriter.Write(content);
textWriter.Write("*/");
column += 2;
UpdateEndLocation(content, ref line, ref column);
column += 2;
isAtStartOfLine = false;
break;
case CommentType.Documentation:
textWriter.Write("///");
textWriter.WriteLine(content);
column += 3 + content.Length;
needsIndent = true;
isAtStartOfLine = true;
break;
default:
textWriter.Write(content);
column += content.Length;
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
if (!isAtStartOfLine)
NewLine();
WriteIndentation();
textWriter.Write('#');
textWriter.Write(type.ToString().ToLowerInvariant());
string directive = type.ToString().ToLowerInvariant();
textWriter.Write(directive);
column += 1 + directive.Length;
if (!string.IsNullOrEmpty(argument)) {
textWriter.Write(' ');
textWriter.Write(argument);
column += 1 + argument.Length;
}
NewLine();
}
@ -159,42 +200,61 @@ namespace ICSharpCode.NRefactory.CSharp @@ -159,42 +200,61 @@ namespace ICSharpCode.NRefactory.CSharp
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) {
// usually NullReferenceExpression should be used for this, but we'll handle it anyways
textWriter.Write("null");
column += 4;
return;
}
if (value is bool) {
if ((bool)value) {
textWriter.Write("true");
column += 4;
} else {
textWriter.Write("false");
column += 5;
}
return;
}
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) {
textWriter.Write("'" + ConvertCharLiteral((char)value) + "'");
string tmp = "'" + ConvertCharLiteral((char)value) + "'";
column += tmp.Length;
textWriter.Write(tmp);
} 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) {
float f = (float)value;
if (float.IsInfinity(f) || float.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators.
textWriter.Write("float");
column += 5;
WriteToken(Roles.Dot, ".");
if (float.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (float.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
}
return;
}
@ -203,21 +263,28 @@ namespace ICSharpCode.NRefactory.CSharp @@ -203,21 +263,28 @@ namespace ICSharpCode.NRefactory.CSharp
// (again, not a primitive expression, but it's better to handle
// the special case here than to do it in all code generators)
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) {
double f = (double)value;
if (double.IsInfinity(f) || double.IsNaN(f)) {
// Strictly speaking, these aren't PrimitiveExpressions;
// but we still support writing these to make life easier for code generators.
textWriter.Write("double");
textWriter.Write(".");
column += 6;
WriteToken(Roles.Dot, ".");
if (double.IsPositiveInfinity(f)) {
textWriter.Write("PositiveInfinity");
column += "PositiveInfinity".Length;
} else if (double.IsNegativeInfinity(f)) {
textWriter.Write("NegativeInfinity");
column += "NegativeInfinity".Length;
} else {
textWriter.Write("NaN");
column += 3;
}
return;
}
@ -312,7 +379,17 @@ namespace ICSharpCode.NRefactory.CSharp @@ -312,7 +379,17 @@ namespace ICSharpCode.NRefactory.CSharp
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
// can rely use the current output length to identify the position of the node
@ -320,7 +397,7 @@ namespace ICSharpCode.NRefactory.CSharp @@ -320,7 +397,7 @@ namespace ICSharpCode.NRefactory.CSharp
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 @@ @@ -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 @@ @@ -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 @@ -67,89 +67,20 @@ namespace ICSharpCode.NRefactory.CSharp.Parser
}
#region ParseAndCheckPositions
string currentFileName;
ReadOnlyDocument currentDocument;
[Test, Ignore("Positions still are incorrect in several cases")]
public void ParseAndCheckPositions()
{
CSharpParser parser = new CSharpParser();
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);
if (parser.HasErrors)
continue;
this.currentFileName = fileName;
CheckPositionConsistency(syntaxTree);
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);
ConsistencyChecker.CheckPositionConsistency(syntaxTree, fileName, currentDocument);
ConsistencyChecker.CheckMissingTokens(syntaxTree, fileName, currentDocument);
}
Assert.IsTrue(assertion, "Expected whitespace between " + startNode.GetType () +":" + whitespaceStart + " and " + endNode.GetType () + ":" + whitespaceEnd
+ ", but got '" + text + "' (in " + currentFileName + " parent:" + startNode.Parent.GetType () +")");
}
#endregion
}

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

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

Loading…
Cancel
Save