You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

356 lines
12 KiB

  1. // Copyright (c) 2014 Daniel Grunwald
  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 System.Linq;
  21. using ICSharpCode.Decompiler.CSharp.Resolver;
  22. using ICSharpCode.Decompiler.CSharp.Syntax;
  23. using ICSharpCode.Decompiler.IL;
  24. using ICSharpCode.Decompiler.Semantics;
  25. using ICSharpCode.Decompiler.TypeSystem;
  26. namespace ICSharpCode.Decompiler.CSharp
  27. {
  28. // Annotations:
  29. // * AstNodes should be annotated with the corresponding ILInstruction
  30. // * AstNodes referring to other entities should be annotated with the IEntity
  31. // * Expression type information is currently only available in the ExpressionBuilder, but we might
  32. // change 'WithTypeInfo()' to use an annotation in the future
  33. // * IntroduceUnsafeModifier.PointerArithmeticAnnotation is placed on arithmetic operators that operate
  34. // on pointers.
  35. // TODO: actually, we could use the type info instead?
  36. // * AddCheckedBlocks.CheckedAnnotation / AddCheckedBlocks.UnCheckedAnnotation is used on
  37. // checked/unchecked integer arithmetic
  38. // TODO: here the info is also redundant, we could peek at the BinaryNumericInstruction instead
  39. // but on the other hand, some unchecked casts are not backed by any BinaryNumericInstruction
  40. /// <summary>
  41. /// Currently unused; we'll probably use the LdToken ILInstruction as annotation instead when LdToken
  42. /// support gets reimplemented.
  43. /// </summary>
  44. public class LdTokenAnnotation { }
  45. public static class AnnotationExtensions
  46. {
  47. internal static ExpressionWithILInstruction WithILInstruction(this Expression expression,
  48. ILInstruction instruction)
  49. {
  50. expression.AddAnnotation(instruction);
  51. return new ExpressionWithILInstruction(expression);
  52. }
  53. internal static ExpressionWithILInstruction WithILInstruction(this Expression expression,
  54. IEnumerable<ILInstruction> instructions)
  55. {
  56. foreach (var inst in instructions)
  57. expression.AddAnnotation(inst);
  58. return new ExpressionWithILInstruction(expression);
  59. }
  60. internal static ExpressionWithILInstruction WithoutILInstruction(this Expression expression)
  61. {
  62. return new ExpressionWithILInstruction(expression);
  63. }
  64. internal static TranslatedStatement WithILInstruction(this Statement statement,
  65. ILInstruction instruction)
  66. {
  67. statement.AddAnnotation(instruction);
  68. return new TranslatedStatement(statement);
  69. }
  70. internal static TranslatedStatement WithILInstruction(this Statement statement,
  71. IEnumerable<ILInstruction> instructions)
  72. {
  73. foreach (var inst in instructions)
  74. statement.AddAnnotation(inst);
  75. return new TranslatedStatement(statement);
  76. }
  77. internal static TranslatedStatement WithoutILInstruction(this Statement statement)
  78. {
  79. return new TranslatedStatement(statement);
  80. }
  81. internal static TranslatedExpression WithILInstruction(this ExpressionWithResolveResult expression,
  82. ILInstruction instruction)
  83. {
  84. expression.Expression.AddAnnotation(instruction);
  85. return new TranslatedExpression(expression.Expression, expression.ResolveResult);
  86. }
  87. internal static TranslatedExpression WithILInstruction(this ExpressionWithResolveResult expression,
  88. IEnumerable<ILInstruction> instructions)
  89. {
  90. foreach (var inst in instructions)
  91. expression.Expression.AddAnnotation(inst);
  92. return new TranslatedExpression(expression.Expression, expression.ResolveResult);
  93. }
  94. internal static TranslatedExpression WithILInstruction(this TranslatedExpression expression,
  95. ILInstruction instruction)
  96. {
  97. expression.Expression.AddAnnotation(instruction);
  98. return expression;
  99. }
  100. internal static TranslatedExpression WithoutILInstruction(this ExpressionWithResolveResult expression)
  101. {
  102. return new TranslatedExpression(expression.Expression, expression.ResolveResult);
  103. }
  104. internal static ExpressionWithResolveResult WithRR(this Expression expression,
  105. ResolveResult resolveResult)
  106. {
  107. expression.AddAnnotation(resolveResult);
  108. return new ExpressionWithResolveResult(expression, resolveResult);
  109. }
  110. internal static TranslatedExpression WithRR(this ExpressionWithILInstruction expression,
  111. ResolveResult resolveResult)
  112. {
  113. expression.Expression.AddAnnotation(resolveResult);
  114. return new TranslatedExpression(expression, resolveResult);
  115. }
  116. /// <summary>
  117. /// Retrieves the <see cref="ISymbol"/> associated with this AstNode, or null if no symbol
  118. /// is associated with the node.
  119. /// </summary>
  120. public static ISymbol GetSymbol(this AstNode node)
  121. {
  122. var rr = node.Annotation<ResolveResult>();
  123. if (rr is MethodGroupResolveResult)
  124. {
  125. // delegate construction?
  126. var newObj = node.Annotation<NewObj>();
  127. if (newObj != null)
  128. {
  129. var funcptr = newObj.Arguments.ElementAtOrDefault(1);
  130. if (funcptr is LdFtn ldftn)
  131. {
  132. return ldftn.Method;
  133. }
  134. else if (funcptr is LdVirtFtn ldVirtFtn)
  135. {
  136. return ldVirtFtn.Method;
  137. }
  138. }
  139. var ldVirtDelegate = node.Annotation<LdVirtDelegate>();
  140. if (ldVirtDelegate != null)
  141. {
  142. return ldVirtDelegate.Method;
  143. }
  144. }
  145. return rr?.GetSymbol();
  146. }
  147. /// <summary>
  148. /// Retrieves the <see cref="ResolveResult"/> associated with this <see cref="AstNode"/>,
  149. /// or <see cref="ErrorResolveResult.UnknownError"/> if no resolve result is associated with the node.
  150. /// </summary>
  151. public static ResolveResult GetResolveResult(this AstNode node)
  152. {
  153. return node.Annotation<ResolveResult>() ?? ErrorResolveResult.UnknownError;
  154. }
  155. /// <summary>
  156. /// Retrieves the <see cref="ILVariable"/> associated with this <see cref="IdentifierExpression"/>,
  157. /// or <c>null</c> if no variable is associated with this identifier.
  158. /// </summary>
  159. public static ILVariable GetILVariable(this IdentifierExpression expr)
  160. {
  161. if (expr.Annotation<ResolveResult>() is ILVariableResolveResult rr)
  162. return rr.Variable;
  163. else
  164. return null;
  165. }
  166. /// <summary>
  167. /// Retrieves the <see cref="ILVariable"/> associated with this <see cref="VariableInitializer"/>,
  168. /// or <c>null</c> if no variable is associated with this initializer.
  169. /// </summary>
  170. public static ILVariable GetILVariable(this VariableInitializer vi)
  171. {
  172. if (vi.Annotation<ResolveResult>() is ILVariableResolveResult rr)
  173. return rr.Variable;
  174. else
  175. return null;
  176. }
  177. /// <summary>
  178. /// Retrieves the <see cref="ILVariable"/> associated with this <see cref="ForeachStatement"/>,
  179. /// or <c>null</c> if no variable is associated with this foreach statement.
  180. /// </summary>
  181. public static ILVariable GetILVariable(this ForeachStatement loop)
  182. {
  183. if (loop.Annotation<ResolveResult>() is ILVariableResolveResult rr)
  184. return rr.Variable;
  185. else
  186. return null;
  187. }
  188. /// <summary>
  189. /// Adds an <see cref="ILVariable"/> to this initializer.
  190. /// </summary>
  191. public static VariableInitializer WithILVariable(this VariableInitializer vi, ILVariable v)
  192. {
  193. vi.AddAnnotation(new ILVariableResolveResult(v, v.Type));
  194. return vi;
  195. }
  196. /// <summary>
  197. /// Adds an <see cref="ILVariable"/> to this foreach statement.
  198. /// </summary>
  199. public static ForeachStatement WithILVariable(this ForeachStatement loop, ILVariable v)
  200. {
  201. loop.AddAnnotation(new ILVariableResolveResult(v, v.Type));
  202. return loop;
  203. }
  204. /// <summary>
  205. /// Copies all annotations from <paramref name="other"/> to <paramref name="node"/>.
  206. /// </summary>
  207. public static T CopyAnnotationsFrom<T>(this T node, AstNode other) where T : AstNode
  208. {
  209. foreach (object annotation in other.Annotations)
  210. {
  211. node.AddAnnotation(annotation);
  212. }
  213. return node;
  214. }
  215. /// <summary>
  216. /// Copies all <see cref="ILInstruction"/> annotations from <paramref name="other"/>
  217. /// to <paramref name="node"/>.
  218. /// </summary>
  219. public static T CopyInstructionsFrom<T>(this T node, AstNode other) where T : AstNode
  220. {
  221. foreach (object annotation in other.Annotations.OfType<ILInstruction>())
  222. {
  223. node.AddAnnotation(annotation);
  224. }
  225. return node;
  226. }
  227. }
  228. /// <summary>
  229. /// Represents a reference to a local variable.
  230. /// </summary>
  231. public class ILVariableResolveResult : ResolveResult
  232. {
  233. public readonly ILVariable Variable;
  234. public ILVariableResolveResult(ILVariable v) : base(v.Type)
  235. {
  236. this.Variable = v;
  237. }
  238. public ILVariableResolveResult(ILVariable v, IType type) : base(type)
  239. {
  240. this.Variable = v ?? throw new ArgumentNullException(nameof(v));
  241. }
  242. }
  243. /// <summary>
  244. /// Annotates a <see cref="ForeachStatement"/> with the instructions for the GetEnumerator, MoveNext
  245. /// and get_Current calls.
  246. /// </summary>
  247. public class ForeachAnnotation
  248. {
  249. public readonly ILInstruction GetEnumeratorCall;
  250. public readonly ILInstruction MoveNextCall;
  251. public readonly ILInstruction GetCurrentCall;
  252. public ForeachAnnotation(ILInstruction getEnumeratorCall, ILInstruction moveNextCall,
  253. ILInstruction getCurrentCall)
  254. {
  255. GetEnumeratorCall = getEnumeratorCall;
  256. MoveNextCall = moveNextCall;
  257. GetCurrentCall = getCurrentCall;
  258. }
  259. }
  260. /// <summary>
  261. /// Annotates the top-level block statement of a function
  262. /// with the implicitly executed return/yield break.
  263. /// </summary>
  264. public class ImplicitReturnAnnotation
  265. {
  266. public readonly Leave Leave;
  267. public ImplicitReturnAnnotation(Leave leave)
  268. {
  269. this.Leave = leave;
  270. }
  271. }
  272. /// <summary>
  273. /// Annotates an expression when an implicit user-defined conversion was omitted.
  274. /// </summary>
  275. public class ImplicitConversionAnnotation
  276. {
  277. public readonly ConversionResolveResult ConversionResolveResult;
  278. public IType TargetType => ConversionResolveResult.Type;
  279. public ImplicitConversionAnnotation(ConversionResolveResult conversionResolveResult)
  280. {
  281. this.ConversionResolveResult = conversionResolveResult;
  282. }
  283. }
  284. /// <summary>
  285. /// Annotates a QueryGroupClause with the ILFunctions of each (implicit lambda) expression.
  286. /// </summary>
  287. public class QueryGroupClauseAnnotation
  288. {
  289. public readonly ILFunction KeyLambda;
  290. public readonly ILFunction ProjectionLambda;
  291. public QueryGroupClauseAnnotation(ILFunction key, ILFunction projection)
  292. {
  293. this.KeyLambda = key;
  294. this.ProjectionLambda = projection;
  295. }
  296. }
  297. /// <summary>
  298. /// Annotates a QueryJoinClause with the ILFunctions of each (implicit lambda) expression.
  299. /// </summary>
  300. public class QueryJoinClauseAnnotation
  301. {
  302. public readonly ILFunction OnLambda;
  303. public readonly ILFunction EqualsLambda;
  304. public QueryJoinClauseAnnotation(ILFunction on, ILFunction equals)
  305. {
  306. this.OnLambda = on;
  307. this.EqualsLambda = equals;
  308. }
  309. }
  310. /// <summary>
  311. /// Annotates an out DirectionExpression if the out variable can be declared implicitly typed.
  312. /// </summary>
  313. public class UseImplicitlyTypedOutAnnotation
  314. {
  315. public static readonly UseImplicitlyTypedOutAnnotation Instance = new UseImplicitlyTypedOutAnnotation();
  316. }
  317. }