diff --git a/ICSharpCode.Decompiler/Ast/AstBuilder.cs b/ICSharpCode.Decompiler/Ast/AstBuilder.cs index d1e58fe39..76fe00246 100644 --- a/ICSharpCode.Decompiler/Ast/AstBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstBuilder.cs @@ -172,7 +172,7 @@ namespace Decompiler } else if (type.IsNested) { AstType typeRef = CreateType(type.DeclaringType, typeAttributes, ref typeIndex); string namepart = ICSharpCode.NRefactory.TypeSystem.ReflectionHelper.SplitTypeParameterCountFromReflectionName(type.Name); - return new MemberType { Target = typeRef, MemberName = namepart }; + return new MemberType { Target = typeRef, MemberName = namepart }.WithAnnotation(type); } else { string ns = type.Namespace ?? string.Empty; string name = type.Name; @@ -190,7 +190,7 @@ namespace Decompiler for (int i = 1; i < parts.Length; i++) { nsType = new MemberType { Target = nsType, MemberName = parts[i] }; } - return new MemberType { Target = nsType, MemberName = name }; + return new MemberType { Target = nsType, MemberName = name }.WithAnnotation(type); } } } diff --git a/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs b/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs index 54fbc62c1..f5367b6eb 100644 --- a/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs +++ b/ICSharpCode.Decompiler/Ast/AstMetodBodyBuilder.cs @@ -542,7 +542,7 @@ namespace Decompiler target = methodArgs[0]; methodArgs.RemoveAt(0); } else { - target = new Ast.IdentifierExpression(cecilMethod.DeclaringType.FullName); + target = new TypeReferenceExpression { Type = AstBuilder.ConvertType(cecilMethod.DeclaringType)}; } // TODO: Constructors are ignored @@ -552,10 +552,10 @@ namespace Decompiler // TODO: Hack, detect properties properly if (cecilMethod.Name.StartsWith("get_")) { - return target.Member(cecilMethod.Name.Remove(0, 4)); + return target.Member(cecilMethod.Name.Remove(0, 4)).WithAnnotation(cecilMethod); } else if (cecilMethod.Name.StartsWith("set_")) { return new Ast.AssignmentExpression( - target.Member(cecilMethod.Name.Remove(0, 4)), + target.Member(cecilMethod.Name.Remove(0, 4)).WithAnnotation(cecilMethod), methodArgs[0] ); } @@ -575,7 +575,7 @@ namespace Decompiler }*/ // Default invocation - return target.Invoke(cecilMethod.Name, methodArgs); + return target.Invoke(cecilMethod.Name, methodArgs).WithAnnotation(cecilMethod); case Code.Calli: throw new NotImplementedException(); case Code.Castclass: return arg1.CastTo(operandAsTypeRef); case Code.Ckfinite: throw new NotImplementedException(); diff --git a/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs b/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs new file mode 100644 index 000000000..729caba28 --- /dev/null +++ b/ICSharpCode.Decompiler/Ast/NRefactoryExtensions.cs @@ -0,0 +1,17 @@ +// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) +// This code is distributed under MIT X11 license (for details please see \doc\license.txt) + +using System; +using ICSharpCode.NRefactory.CSharp; + +namespace Decompiler +{ + static class NRefactoryExtensions + { + public static T WithAnnotation(this T node, object annotation) where T : AstNode + { + node.AddAnnotation(annotation); + return node; + } + } +} diff --git a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs index 3ed2038c8..46e17f33d 100644 --- a/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs +++ b/ICSharpCode.Decompiler/Ast/TextOutputFormatter.cs @@ -2,14 +2,18 @@ // This code is distributed under MIT X11 license (for details please see \doc\license.txt) using System; +using System.Collections.Generic; +using System.Linq; using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp; +using Mono.Cecil; namespace Decompiler { public class TextOutputFormatter : IOutputFormatter { readonly ITextOutput output; + readonly Stack nodeStack = new Stack(); public TextOutputFormatter(ITextOutput output) { @@ -20,7 +24,18 @@ namespace Decompiler public void WriteIdentifier(string identifier) { - output.Write(identifier); + AstNode node = nodeStack.Peek(); + MemberReference memberRef = node.Annotation(); + if (memberRef == null && node.Role == AstNode.Roles.TargetExpression + && (node.Parent is InvocationExpression || node.Parent is ObjectCreateExpression)) + { + memberRef = node.Parent.Annotation(); + } + + if (memberRef != null) + output.WriteReference(identifier, memberRef); + else + output.Write(identifier); } public void WriteKeyword(string keyword) @@ -40,7 +55,8 @@ namespace Decompiler public void OpenBrace(BraceStyle style) { - output.MarkFoldStart(); + if (nodeStack.OfType().Count() <= 1) + output.MarkFoldStart(); output.WriteLine(" {"); output.Indent(); } @@ -49,7 +65,8 @@ namespace Decompiler { output.Unindent(); output.Write('}'); - output.MarkFoldEnd(); + if (nodeStack.OfType().Count() <= 1) + output.MarkFoldEnd(); } public void Indent() @@ -85,5 +102,16 @@ namespace Decompiler break; } } + + public void StartNode(AstNode node) + { + nodeStack.Push(node); + } + + public void EndNode(AstNode node) + { + if (nodeStack.Pop() != node) + throw new InvalidOperationException(); + } } } diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 535430039..2ace1aa02 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -52,6 +52,7 @@ + diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs index f05be52cf..71e3b5d35 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/Ast/AstNode.cs @@ -448,6 +448,8 @@ namespace ICSharpCode.NRefactory.CSharp { if (annotation == null) throw new ArgumentNullException("annotation"); + if (this.IsNull) + throw new InvalidOperationException("Cannot add annotations to the null node"); retry: // Retry until successful object oldAnnotation = Interlocked.CompareExchange(ref this.annotations, annotation, null); if (oldAnnotation == null) { diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/IOutputFormatter.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/IOutputFormatter.cs index 3aff02b5f..ac1966296 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/IOutputFormatter.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/IOutputFormatter.cs @@ -10,6 +10,9 @@ namespace ICSharpCode.NRefactory.CSharp /// public interface IOutputFormatter { + void StartNode(AstNode node); + void EndNode(AstNode node); + /// /// Writes an identifier. /// If the identifier conflicts with a keyword, the output visitor will diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs index 0e487ea3f..12fea7d59 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/OutputVisitor.cs @@ -67,6 +67,7 @@ namespace ICSharpCode.NRefactory.CSharp WriteSpecialsUpToNode(node); currentContainerNode = node; positionStack.Push(node.FirstChild); + formatter.StartNode(node); } object EndNode(AstNode node) @@ -76,6 +77,7 @@ namespace ICSharpCode.NRefactory.CSharp Debug.Assert(pos == null || pos.Parent == node); WriteSpecials(pos, null); currentContainerNode = node.Parent; + formatter.EndNode(node); return null; } #endregion diff --git a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/TextWriterOutputFormatter.cs b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/TextWriterOutputFormatter.cs index e14d1032c..f8c1340e5 100644 --- a/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/TextWriterOutputFormatter.cs +++ b/NRefactory/ICSharpCode.NRefactory/CSharp/OutputVisitor/TextWriterOutputFormatter.cs @@ -107,5 +107,13 @@ namespace ICSharpCode.NRefactory.CSharp break; } } + + public virtual void StartNode(AstNode node) + { + } + + public virtual void EndNode(AstNode node) + { + } } }