mirror of https://github.com/icsharpcode/ILSpy.git
				
				
			
			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
						
					
					
				
			
		
		
	
	
							356 lines
						
					
					
						
							12 KiB
						
					
					
				// Copyright (c) 2014 Daniel Grunwald | 
						|
//  | 
						|
// 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; | 
						|
 | 
						|
using ICSharpCode.Decompiler.CSharp.Resolver; | 
						|
using ICSharpCode.Decompiler.CSharp.Syntax; | 
						|
using ICSharpCode.Decompiler.IL; | 
						|
using ICSharpCode.Decompiler.Semantics; | 
						|
using ICSharpCode.Decompiler.TypeSystem; | 
						|
 | 
						|
namespace ICSharpCode.Decompiler.CSharp | 
						|
{ | 
						|
	// Annotations: | 
						|
	//  * AstNodes should be annotated with the corresponding ILInstruction | 
						|
	//  * AstNodes referring to other entities should be annotated with the IEntity | 
						|
	//  * Expression type information is currently only available in the ExpressionBuilder, but we might | 
						|
	//    change 'WithTypeInfo()' to use an annotation in the future | 
						|
	//  * IntroduceUnsafeModifier.PointerArithmeticAnnotation is placed on arithmetic operators that operate | 
						|
	//    on pointers. | 
						|
	//    TODO: actually, we could use the type info instead? | 
						|
	//  * AddCheckedBlocks.CheckedAnnotation / AddCheckedBlocks.UnCheckedAnnotation is used on | 
						|
	//    checked/unchecked integer arithmetic | 
						|
	//    TODO: here the info is also redundant, we could peek at the BinaryNumericInstruction instead | 
						|
	//          but on the other hand, some unchecked casts are not backed by any BinaryNumericInstruction | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Currently unused; we'll probably use the LdToken ILInstruction as annotation instead when LdToken | 
						|
	/// support gets reimplemented. | 
						|
	/// </summary> | 
						|
	public class LdTokenAnnotation { } | 
						|
 | 
						|
	public static class AnnotationExtensions | 
						|
	{ | 
						|
		internal static ExpressionWithILInstruction WithILInstruction(this Expression expression, | 
						|
			ILInstruction instruction) | 
						|
		{ | 
						|
			expression.AddAnnotation(instruction); | 
						|
			return new ExpressionWithILInstruction(expression); | 
						|
		} | 
						|
 | 
						|
		internal static ExpressionWithILInstruction WithILInstruction(this Expression expression, | 
						|
			IEnumerable<ILInstruction> instructions) | 
						|
		{ | 
						|
			foreach (var inst in instructions) | 
						|
				expression.AddAnnotation(inst); | 
						|
			return new ExpressionWithILInstruction(expression); | 
						|
		} | 
						|
 | 
						|
		internal static ExpressionWithILInstruction WithoutILInstruction(this Expression expression) | 
						|
		{ | 
						|
			return new ExpressionWithILInstruction(expression); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedStatement WithILInstruction(this Statement statement, | 
						|
			ILInstruction instruction) | 
						|
		{ | 
						|
			statement.AddAnnotation(instruction); | 
						|
			return new TranslatedStatement(statement); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedStatement WithILInstruction(this Statement statement, | 
						|
			IEnumerable<ILInstruction> instructions) | 
						|
		{ | 
						|
			foreach (var inst in instructions) | 
						|
				statement.AddAnnotation(inst); | 
						|
			return new TranslatedStatement(statement); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedStatement WithoutILInstruction(this Statement statement) | 
						|
		{ | 
						|
			return new TranslatedStatement(statement); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedExpression WithILInstruction(this ExpressionWithResolveResult expression, | 
						|
			ILInstruction instruction) | 
						|
		{ | 
						|
			expression.Expression.AddAnnotation(instruction); | 
						|
			return new TranslatedExpression(expression.Expression, expression.ResolveResult); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedExpression WithILInstruction(this ExpressionWithResolveResult expression, | 
						|
			IEnumerable<ILInstruction> instructions) | 
						|
		{ | 
						|
			foreach (var inst in instructions) | 
						|
				expression.Expression.AddAnnotation(inst); | 
						|
			return new TranslatedExpression(expression.Expression, expression.ResolveResult); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedExpression WithILInstruction(this TranslatedExpression expression, | 
						|
			ILInstruction instruction) | 
						|
		{ | 
						|
			expression.Expression.AddAnnotation(instruction); | 
						|
			return expression; | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedExpression WithoutILInstruction(this ExpressionWithResolveResult expression) | 
						|
		{ | 
						|
			return new TranslatedExpression(expression.Expression, expression.ResolveResult); | 
						|
		} | 
						|
 | 
						|
		internal static ExpressionWithResolveResult WithRR(this Expression expression, | 
						|
			ResolveResult resolveResult) | 
						|
		{ | 
						|
			expression.AddAnnotation(resolveResult); | 
						|
			return new ExpressionWithResolveResult(expression, resolveResult); | 
						|
		} | 
						|
 | 
						|
		internal static TranslatedExpression WithRR(this ExpressionWithILInstruction expression, | 
						|
			ResolveResult resolveResult) | 
						|
		{ | 
						|
			expression.Expression.AddAnnotation(resolveResult); | 
						|
			return new TranslatedExpression(expression, resolveResult); | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Retrieves the <see cref="ISymbol"/> associated with this AstNode, or null if no symbol | 
						|
		/// is associated with the node. | 
						|
		/// </summary> | 
						|
		public static ISymbol GetSymbol(this AstNode node) | 
						|
		{ | 
						|
			var rr = node.Annotation<ResolveResult>(); | 
						|
			if (rr is MethodGroupResolveResult) | 
						|
			{ | 
						|
				// delegate construction? | 
						|
				var newObj = node.Annotation<NewObj>(); | 
						|
				if (newObj != null) | 
						|
				{ | 
						|
					var funcptr = newObj.Arguments.ElementAtOrDefault(1); | 
						|
					if (funcptr is LdFtn ldftn) | 
						|
					{ | 
						|
						return ldftn.Method; | 
						|
					} | 
						|
					else if (funcptr is LdVirtFtn ldVirtFtn) | 
						|
					{ | 
						|
						return ldVirtFtn.Method; | 
						|
					} | 
						|
				} | 
						|
				var ldVirtDelegate = node.Annotation<LdVirtDelegate>(); | 
						|
				if (ldVirtDelegate != null) | 
						|
				{ | 
						|
					return ldVirtDelegate.Method; | 
						|
				} | 
						|
			} | 
						|
			return rr?.GetSymbol(); | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Retrieves the <see cref="ResolveResult"/> associated with this <see cref="AstNode"/>, | 
						|
		/// or <see cref="ErrorResolveResult.UnknownError"/> if no resolve result is associated with the node. | 
						|
		/// </summary> | 
						|
		public static ResolveResult GetResolveResult(this AstNode node) | 
						|
		{ | 
						|
			return node.Annotation<ResolveResult>() ?? ErrorResolveResult.UnknownError; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Retrieves the <see cref="ILVariable"/> associated with this <see cref="IdentifierExpression"/>, | 
						|
		/// or <c>null</c> if no variable is associated with this identifier. | 
						|
		/// </summary> | 
						|
		public static ILVariable GetILVariable(this IdentifierExpression expr) | 
						|
		{ | 
						|
			if (expr.Annotation<ResolveResult>() is ILVariableResolveResult rr) | 
						|
				return rr.Variable; | 
						|
			else | 
						|
				return null; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Retrieves the <see cref="ILVariable"/> associated with this <see cref="VariableInitializer"/>, | 
						|
		/// or <c>null</c> if no variable is associated with this initializer. | 
						|
		/// </summary> | 
						|
		public static ILVariable GetILVariable(this VariableInitializer vi) | 
						|
		{ | 
						|
			if (vi.Annotation<ResolveResult>() is ILVariableResolveResult rr) | 
						|
				return rr.Variable; | 
						|
			else | 
						|
				return null; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Retrieves the <see cref="ILVariable"/> associated with this <see cref="ForeachStatement"/>, | 
						|
		/// or <c>null</c> if no variable is associated with this foreach statement. | 
						|
		/// </summary> | 
						|
		public static ILVariable GetILVariable(this ForeachStatement loop) | 
						|
		{ | 
						|
			if (loop.Annotation<ResolveResult>() is ILVariableResolveResult rr) | 
						|
				return rr.Variable; | 
						|
			else | 
						|
				return null; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Adds an <see cref="ILVariable"/> to this initializer. | 
						|
		/// </summary> | 
						|
		public static VariableInitializer WithILVariable(this VariableInitializer vi, ILVariable v) | 
						|
		{ | 
						|
			vi.AddAnnotation(new ILVariableResolveResult(v, v.Type)); | 
						|
			return vi; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Adds an <see cref="ILVariable"/> to this foreach statement. | 
						|
		/// </summary> | 
						|
		public static ForeachStatement WithILVariable(this ForeachStatement loop, ILVariable v) | 
						|
		{ | 
						|
			loop.AddAnnotation(new ILVariableResolveResult(v, v.Type)); | 
						|
			return loop; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Copies all annotations from <paramref name="other"/> to <paramref name="node"/>. | 
						|
		/// </summary> | 
						|
		public static T CopyAnnotationsFrom<T>(this T node, AstNode other) where T : AstNode | 
						|
		{ | 
						|
			foreach (object annotation in other.Annotations) | 
						|
			{ | 
						|
				node.AddAnnotation(annotation); | 
						|
			} | 
						|
			return node; | 
						|
		} | 
						|
 | 
						|
		/// <summary> | 
						|
		/// Copies all <see cref="ILInstruction"/> annotations from <paramref name="other"/> | 
						|
		/// to <paramref name="node"/>. | 
						|
		/// </summary> | 
						|
		public static T CopyInstructionsFrom<T>(this T node, AstNode other) where T : AstNode | 
						|
		{ | 
						|
			foreach (object annotation in other.Annotations.OfType<ILInstruction>()) | 
						|
			{ | 
						|
				node.AddAnnotation(annotation); | 
						|
			} | 
						|
			return node; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Represents a reference to a local variable. | 
						|
	/// </summary> | 
						|
	public class ILVariableResolveResult : ResolveResult | 
						|
	{ | 
						|
		public readonly ILVariable Variable; | 
						|
 | 
						|
		public ILVariableResolveResult(ILVariable v) : base(v.Type) | 
						|
		{ | 
						|
			this.Variable = v; | 
						|
		} | 
						|
 | 
						|
		public ILVariableResolveResult(ILVariable v, IType type) : base(type) | 
						|
		{ | 
						|
			this.Variable = v ?? throw new ArgumentNullException(nameof(v)); | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates a <see cref="ForeachStatement"/> with the instructions for the GetEnumerator, MoveNext | 
						|
	/// and get_Current calls. | 
						|
	/// </summary> | 
						|
	public class ForeachAnnotation | 
						|
	{ | 
						|
		public readonly ILInstruction GetEnumeratorCall; | 
						|
		public readonly ILInstruction MoveNextCall; | 
						|
		public readonly ILInstruction GetCurrentCall; | 
						|
 | 
						|
		public ForeachAnnotation(ILInstruction getEnumeratorCall, ILInstruction moveNextCall, | 
						|
			ILInstruction getCurrentCall) | 
						|
		{ | 
						|
			GetEnumeratorCall = getEnumeratorCall; | 
						|
			MoveNextCall = moveNextCall; | 
						|
			GetCurrentCall = getCurrentCall; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates the top-level block statement of a function | 
						|
	/// with the implicitly executed return/yield break. | 
						|
	/// </summary> | 
						|
	public class ImplicitReturnAnnotation | 
						|
	{ | 
						|
		public readonly Leave Leave; | 
						|
 | 
						|
		public ImplicitReturnAnnotation(Leave leave) | 
						|
		{ | 
						|
			this.Leave = leave; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates an expression when an implicit user-defined conversion was omitted. | 
						|
	/// </summary> | 
						|
	public class ImplicitConversionAnnotation | 
						|
	{ | 
						|
		public readonly ConversionResolveResult ConversionResolveResult; | 
						|
		public IType TargetType => ConversionResolveResult.Type; | 
						|
 | 
						|
		public ImplicitConversionAnnotation(ConversionResolveResult conversionResolveResult) | 
						|
		{ | 
						|
			this.ConversionResolveResult = conversionResolveResult; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates a QueryGroupClause with the ILFunctions of each (implicit lambda) expression. | 
						|
	/// </summary> | 
						|
	public class QueryGroupClauseAnnotation | 
						|
	{ | 
						|
		public readonly ILFunction KeyLambda; | 
						|
		public readonly ILFunction ProjectionLambda; | 
						|
 | 
						|
		public QueryGroupClauseAnnotation(ILFunction key, ILFunction projection) | 
						|
		{ | 
						|
			this.KeyLambda = key; | 
						|
			this.ProjectionLambda = projection; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates a QueryJoinClause with the ILFunctions of each (implicit lambda) expression. | 
						|
	/// </summary> | 
						|
	public class QueryJoinClauseAnnotation | 
						|
	{ | 
						|
		public readonly ILFunction OnLambda; | 
						|
		public readonly ILFunction EqualsLambda; | 
						|
 | 
						|
		public QueryJoinClauseAnnotation(ILFunction on, ILFunction equals) | 
						|
		{ | 
						|
			this.OnLambda = on; | 
						|
			this.EqualsLambda = equals; | 
						|
		} | 
						|
	} | 
						|
 | 
						|
	/// <summary> | 
						|
	/// Annotates an out DirectionExpression if the out variable can be declared implicitly typed. | 
						|
	/// </summary> | 
						|
	public class UseImplicitlyTypedOutAnnotation | 
						|
	{ | 
						|
		public static readonly UseImplicitlyTypedOutAnnotation Instance = new UseImplicitlyTypedOutAnnotation(); | 
						|
	} | 
						|
}
 | 
						|
 |