/ILSpy/VB/VBTextOutputFormatter.cs

http://github.com/icsharpcode/ILSpy · C# · 254 lines · 176 code · 32 blank · 46 comment · 48 complexity · e9dbc40a91c6ff93d0bc17d0dab5b055 MD5 · raw file

  1. // Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2. //
  3. // Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4. // software and associated documentation files (the "Software"), to deal in the Software
  5. // without restriction, including without limitation the rights to use, copy, modify, merge,
  6. // publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7. // to whom the Software is furnished to do so, subject to the following conditions:
  8. //
  9. // The above copyright notice and this permission notice shall be included in all copies or
  10. // substantial portions of the Software.
  11. //
  12. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  13. // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  14. // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  15. // FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  16. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  17. // DEALINGS IN THE SOFTWARE.
  18. using System;
  19. using System.Collections.Generic;
  20. using ICSharpCode.Decompiler;
  21. using ICSharpCode.Decompiler.ILAst;
  22. using ICSharpCode.NRefactory.VB;
  23. using ICSharpCode.NRefactory.VB.Ast;
  24. using Mono.Cecil;
  25. namespace ICSharpCode.ILSpy.VB
  26. {
  27. /// <summary>
  28. /// Description of VBTextOutputFormatter.
  29. /// </summary>
  30. public class VBTextOutputFormatter : IOutputFormatter
  31. {
  32. readonly ITextOutput output;
  33. readonly Stack<AstNode> nodeStack = new Stack<AstNode>();
  34. bool firstImport, lastImport;
  35. public VBTextOutputFormatter(ITextOutput output)
  36. {
  37. if (output == null)
  38. throw new ArgumentNullException("output");
  39. this.output = output;
  40. }
  41. public void StartNode(AstNode node)
  42. {
  43. // var ranges = node.Annotation<List<ILRange>>();
  44. // if (ranges != null && ranges.Count > 0)
  45. // {
  46. // // find the ancestor that has method mapping as annotation
  47. // if (node.Ancestors != null && node.Ancestors.Count() > 0)
  48. // {
  49. // var n = node.Ancestors.FirstOrDefault(a => a.Annotation<MemberMapping>() != null);
  50. // if (n != null) {
  51. // MemberMapping mapping = n.Annotation<MemberMapping>();
  52. //
  53. // // add all ranges
  54. // foreach (var range in ranges) {
  55. // mapping.MemberCodeMappings.Add(new SourceCodeMapping {
  56. // ILInstructionOffset = range,
  57. // SourceCodeLine = output.CurrentLine,
  58. // MemberMapping = mapping
  59. // });
  60. // }
  61. // }
  62. // }
  63. // }
  64. if (nodeStack.Count == 0) {
  65. if (node is ImportsStatement) {
  66. firstImport = !(node.PrevSibling is ImportsStatement);
  67. lastImport = !(node.NextSibling is ImportsStatement);
  68. } else {
  69. firstImport = false;
  70. lastImport = false;
  71. }
  72. }
  73. nodeStack.Push(node);
  74. }
  75. public void EndNode(AstNode node)
  76. {
  77. if (nodeStack.Pop() != node)
  78. throw new InvalidOperationException();
  79. }
  80. public void WriteIdentifier(string identifier)
  81. {
  82. var definition = GetCurrentDefinition();
  83. if (definition != null) {
  84. output.WriteDefinition(identifier, definition);
  85. return;
  86. }
  87. object memberRef = GetCurrentMemberReference();
  88. if (memberRef != null) {
  89. output.WriteReference(identifier, memberRef);
  90. return;
  91. }
  92. definition = GetCurrentLocalDefinition();
  93. if (definition != null) {
  94. output.WriteDefinition(identifier, definition);
  95. return;
  96. }
  97. memberRef = GetCurrentLocalReference();
  98. if (memberRef != null) {
  99. output.WriteReference(identifier, memberRef, true);
  100. return;
  101. }
  102. if (firstImport) {
  103. output.MarkFoldStart(defaultCollapsed: true);
  104. firstImport = false;
  105. }
  106. output.Write(identifier);
  107. }
  108. MemberReference GetCurrentMemberReference()
  109. {
  110. AstNode node = nodeStack.Peek();
  111. MemberReference memberRef = node.Annotation<MemberReference>();
  112. if (memberRef == null && node.Role == AstNode.Roles.TargetExpression && (node.Parent is InvocationExpression || node.Parent is ObjectCreationExpression)) {
  113. memberRef = node.Parent.Annotation<MemberReference>();
  114. }
  115. return memberRef;
  116. }
  117. object GetCurrentLocalReference()
  118. {
  119. AstNode node = nodeStack.Peek();
  120. ILVariable variable = node.Annotation<ILVariable>();
  121. if (variable != null) {
  122. if (variable.OriginalParameter != null)
  123. return variable.OriginalParameter;
  124. //if (variable.OriginalVariable != null)
  125. // return variable.OriginalVariable;
  126. return variable;
  127. }
  128. return null;
  129. }
  130. object GetCurrentLocalDefinition()
  131. {
  132. AstNode node = nodeStack.Peek();
  133. var parameterDef = node.Annotation<ParameterDefinition>();
  134. if (parameterDef != null)
  135. return parameterDef;
  136. if (node is VariableInitializer || node is CatchBlock || node is ForEachStatement) {
  137. var variable = node.Annotation<ILVariable>();
  138. if (variable != null) {
  139. if (variable.OriginalParameter != null)
  140. return variable.OriginalParameter;
  141. //if (variable.OriginalVariable != null)
  142. // return variable.OriginalVariable;
  143. return variable;
  144. } else {
  145. }
  146. }
  147. return null;
  148. }
  149. object GetCurrentDefinition()
  150. {
  151. if (nodeStack == null || nodeStack.Count == 0)
  152. return null;
  153. var node = nodeStack.Peek();
  154. if (IsDefinition(node))
  155. return node.Annotation<MemberReference>();
  156. node = node.Parent;
  157. if (IsDefinition(node))
  158. return node.Annotation<MemberReference>();
  159. return null;
  160. }
  161. public void WriteKeyword(string keyword)
  162. {
  163. output.Write(keyword);
  164. }
  165. public void WriteToken(string token)
  166. {
  167. // Attach member reference to token only if there's no identifier in the current node.
  168. MemberReference memberRef = GetCurrentMemberReference();
  169. if (memberRef != null && nodeStack.Peek().GetChildByRole(AstNode.Roles.Identifier).IsNull)
  170. output.WriteReference(token, memberRef);
  171. else
  172. output.Write(token);
  173. }
  174. public void Space()
  175. {
  176. output.Write(' ');
  177. }
  178. public void Indent()
  179. {
  180. output.Indent();
  181. }
  182. public void Unindent()
  183. {
  184. output.Unindent();
  185. }
  186. public void NewLine()
  187. {
  188. if (lastImport) {
  189. output.MarkFoldEnd();
  190. lastImport = false;
  191. }
  192. output.WriteLine();
  193. }
  194. public void WriteComment(bool isDocumentation, string content)
  195. {
  196. if (isDocumentation)
  197. output.Write("'''");
  198. else
  199. output.Write("'");
  200. output.WriteLine(content);
  201. }
  202. public void MarkFoldStart()
  203. {
  204. output.MarkFoldStart();
  205. }
  206. public void MarkFoldEnd()
  207. {
  208. output.MarkFoldEnd();
  209. }
  210. private static bool IsDefinition(AstNode node)
  211. {
  212. return
  213. node is FieldDeclaration ||
  214. node is ConstructorDeclaration ||
  215. node is EventDeclaration ||
  216. node is DelegateDeclaration ||
  217. node is OperatorDeclaration||
  218. node is MemberDeclaration ||
  219. node is TypeDeclaration;
  220. }
  221. }
  222. }