static MethodBody CreateTestMethod (params OpCode [] opcodes)
		{
			var method = new MethodDefinition {
				Name = "function",
			};

			var il = method.Body.GetILProcessor ();

			foreach (var opcode in opcodes)
				il.Emit (opcode);

			return method.Body;
		}
		HashSet<ILVariable> localVariablesToDefine = new HashSet<ILVariable>(); // local variables that are missing a definition
		
		/// <summary>
		/// Creates the body for the method definition.
		/// </summary>
		/// <param name="methodDef">Method definition to decompile.</param>
		/// <param name="context">Decompilation context.</param>
		/// <param name="parameters">Parameter declarations of the method being decompiled.
		/// These are used to update the parameter names when the decompiler generates names for the parameters.</param>
		/// <param name="localVariables">Local variables storage that will be filled/updated with the local variables.</param>
		/// <returns>Block for the method body</returns>
		public static BlockStatement CreateMethodBody(MethodDefinition methodDef,
		                                              DecompilerContext context,
		                                              IEnumerable<ParameterDeclaration> parameters = null,
		                                              /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>> localVariables = null)
		{
			if (localVariables == null)
				localVariables = new /*Concurrent*/Dictionary<int, IEnumerable<ILVariable>>();
			
			MethodDefinition oldCurrentMethod = context.CurrentMethod;
			Debug.Assert(oldCurrentMethod == null || oldCurrentMethod == methodDef);
			context.CurrentMethod = methodDef;
			try {
				AstMethodBodyBuilder builder = new AstMethodBodyBuilder();
				builder.methodDef = methodDef;
				builder.context = context;
				builder.typeSystem = methodDef.Module.TypeSystem;
				return builder.CreateMethodBody(parameters, localVariables);
			} finally {
				context.CurrentMethod = oldCurrentMethod;
			}
		}
		public static void WriteMethodBody (TextWriter writer, MethodDefinition method)
		{
			var body = method.Body;

			WriteVariables (writer, body);

			foreach (Instruction instruction in body.Instructions) {
				var sequence_point = instruction.SequencePoint;
				if (sequence_point != null) {
					writer.Write ('\t');
					WriteSequencePoint (writer, sequence_point);
					writer.WriteLine ();
				}

				writer.Write ('\t');
				WriteInstruction (writer, instruction);
				writer.WriteLine ();
			}

			WriteExceptionHandlers (writer, body);
		}
		public static string FormatMethodBody (MethodDefinition method)
		{
			var writer = new StringWriter ();
			WriteMethodBody (writer, method);
			return writer.ToString ();
		}
		public void RemoveOverrideMapping (MethodDefinition method)
		{
			Overrides.Remove (method.token.RID);
		}
		public bool TryGetOverrideMapping (MethodDefinition method, out MetadataToken [] mapping)
		{
			return Overrides.TryGetValue (method.token.RID, out mapping);
		}
		public void AddMethodDefinition (MethodDefinition method)
		{
			Methods [method.token.RID - 1] = method;
		}
		ILBlock ConvertFinallyBlock(MethodDefinition finallyMethod)
		{
			ILBlock block = CreateILAst(finallyMethod);
			// Get rid of assignment to state
			FieldReference stfld;
			List<ILExpression> args;
			if (block.Body.Count > 0 && block.Body[0].Match(ILCode.Stfld, out stfld, out args)) {
				if (GetFieldDefinition(stfld) == stateField && args[0].MatchThis())
					block.Body.RemoveAt(0);
			}
			// Convert ret to endfinally
			foreach (ILExpression expr in block.EnumerateSelfAndChildrenRecursive().OfType<ILExpression>()) {
				if (expr.Code == ILCode.Ret)
					expr.Code = ILCode.Endfinally;
			}
			return block;
		}
		void ConstructExceptionTable()
		{
			disposeMethod = enumeratorType.Methods.FirstOrDefault(m => m.Name == "System.IDisposable.Dispose");
			ILBlock ilMethod = CreateILAst(disposeMethod);
			
			finallyMethodToStateInterval = new Dictionary<MethodDefinition, Interval>();
			
			InitStateRanges(ilMethod.Body[0]);
			AssignStateRanges(ilMethod.Body, ilMethod.Body.Count, forDispose: true);
			
			// Now look at the finally blocks:
			foreach (var tryFinally in ilMethod.EnumerateSelfAndChildrenRecursive().OfType<ILTryCatchBlock>()) {
				Interval interval = ranges[tryFinally.TryBlock.Body[0]].ToEnclosingInterval();
				var finallyBody = tryFinally.FinallyBlock.Body;
				if (finallyBody.Count != 2)
					throw new YieldAnalysisFailedException();
				ILExpression call = finallyBody[0] as ILExpression;
				if (call == null || call.Code != ILCode.Call || call.Arguments.Count != 1)
					throw new YieldAnalysisFailedException();
				if (!call.Arguments[0].MatchThis())
					throw new YieldAnalysisFailedException();
				if (!finallyBody[1].Match(ILCode.Endfinally))
					throw new YieldAnalysisFailedException();
				
				MethodDefinition mdef = GetMethodDefinition(call.Operand as MethodReference);
				if (mdef == null || finallyMethodToStateInterval.ContainsKey(mdef))
					throw new YieldAnalysisFailedException();
				finallyMethodToStateInterval.Add(mdef, interval);
			}
			ranges = null;
		}
		bool MatchEnumeratorCreationNewObj(ILExpression expr, out MethodDefinition ctor)
		{
			// newobj(CurrentType/...::.ctor, ldc.i4(-2))
			ctor = null;
			if (expr.Code != ILCode.Newobj || expr.Arguments.Count != 1)
				return false;
			if (expr.Arguments[0].Code != ILCode.Ldc_I4)
				return false;
			int initialState = (int)expr.Arguments[0].Operand;
			if (!(initialState == -2 || initialState == 0))
				return false;
			ctor = GetMethodDefinition(expr.Operand as MethodReference);
			if (ctor == null || ctor.DeclaringType.DeclaringType != context.CurrentType)
				return false;
			return IsCompilerGeneratorEnumerator(ctor.DeclaringType);
		}
		public static ILMethodAst Build(MethodDefinition methodDef, bool optimize)
		{
            if (methodDef.Body.Instructions.Count == 0)
            {
                return ILMethodAst.Empty;
            }
            else
            {
                var ilastBuilder = new ILMethodAstBuilder(methodDef, optimize);
                List<ByteCode> body = ilastBuilder.StackAnalysis(methodDef);
                List<ILNode> ast = ilastBuilder.ConvertToAst(body, new HashSet<ExceptionHandler>(methodDef.Body.ExceptionHandlers));

                return new ILMethodAst(ilastBuilder.parameterList, ast);
            }
        }
 private ILMethodAstBuilder(MethodDefinition methodDef, bool optimize)
 {
     this.methodDef = methodDef;
     this.optimize = optimize;
 }
		public void RemoveInstruction ()
		{
			var object_ref = new TypeReference ("System", "Object", null, null, false);
			var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);
			var body = new MethodBody (method);

			var il = body.GetILProcessor ();

			var first = il.Create (OpCodes.Nop);
			var second = il.Create (OpCodes.Nop);
			var third = il.Create (OpCodes.Nop);

			body.Instructions.Add (first);
			body.Instructions.Add (second);
			body.Instructions.Add (third);

			Assert.IsNull (first.Previous);
			Assert.AreEqual (second, first.Next);
			Assert.AreEqual (first, second.Previous);
			Assert.AreEqual (third, second.Next);
			Assert.AreEqual (second, third.Previous);
			Assert.IsNull (third.Next);

			body.Instructions.Remove (second);

			Assert.IsNull (first.Previous);
			Assert.AreEqual (third, first.Next);
			Assert.AreEqual (first, third.Previous);
			Assert.IsNull (third.Next);
		}
		static void AssertCode (string expected, MethodDefinition method)
		{
			Assert.IsTrue (method.HasBody);
			Assert.IsNotNull (method.Body);

			Assert.AreEqual (Normalize (expected), Normalize (Formatter.FormatMethodBody (method)));
		}
		/// <summary>
		/// Creates ILAst for the specified method, optimized up to before the 'YieldReturn' step.
		/// </summary>
		ILBlock CreateILAst(MethodDefinition method)
		{
			if (method == null || !method.HasBody)
				throw new YieldAnalysisFailedException();
			
			ILBlock ilMethod = new ILBlock();
            var astBuilder = ILMethodAstBuilder.Build(method, true);
			ilMethod.Body = astBuilder.Nodes.ToList();
			ILAstOptimizer optimizer = new ILAstOptimizer();
			optimizer.Optimize(context, ilMethod, ILAstOptimizationStep.YieldReturn);
			return ilMethod;
		}
		public void InsertParameterIndex ()
		{
			var object_ref = new TypeReference ("System", "Object", null, null, false);
			var method = new MethodDefinition ("foo", MethodAttributes.Static, object_ref);

			var x = new ParameterDefinition ("x", ParameterAttributes.None, object_ref);
			var y = new ParameterDefinition ("y", ParameterAttributes.None, object_ref);
			var z = new ParameterDefinition ("y", ParameterAttributes.None, object_ref);

			method.Parameters.Add (x);
			method.Parameters.Add (z);

			Assert.AreEqual (0, x.Index);
			Assert.AreEqual (-1, y.Index);
			Assert.AreEqual (1, z.Index);

			method.Parameters.Insert (1, y);

			Assert.AreEqual (0, x.Index);
			Assert.AreEqual (1, y.Index);
			Assert.AreEqual (2, z.Index);
		}
		static PropertyDefinition GetIndexer(MethodDefinition cecilMethodDef)
		{
			TypeDefinition typeDef = cecilMethodDef.DeclaringType;
			string indexerName = null;
			foreach (CustomAttribute ca in typeDef.CustomAttributes) {
				if (ca.Constructor.FullName == "System.Void System.Reflection.DefaultMemberAttribute::.ctor(System.String)") {
					indexerName = ca.ConstructorArguments.Single().Value as string;
					break;
				}
			}
			if (indexerName == null)
				return null;
			foreach (PropertyDefinition prop in typeDef.Properties) {
				if (prop.Name == indexerName) {
					if (prop.GetMethod == cecilMethodDef || prop.SetMethod == cecilMethodDef)
						return prop;
				}
			}
			return null;
		}