private void EmitCheckExceptionBody(Method checkExceptionMethod, List <EnsuresExceptional> exceptionalPostconditions) { Contract.Requires(checkExceptionMethod != null); Contract.Requires(exceptionalPostconditions != null); Contract.Requires(exceptionalPostconditions.Count > 0); // We emit the following method: // bool CheckException(Exception e) { // var ex = e as C1; // if (ex != null) { // EnsuresOnThrow(predicate) // } // else { // var ex2 = e as AggregateException; // if (ex2 != null) { // ex2.Handle(CheckException); // } // } // // // Method always returns true. This is by design! // // We need to check all exceptions in the AggregateException // // and fail in EnsuresOnThrow if the postcondition is not met. // return true; // handled var body = checkExceptionMethod.Body.Statements; var returnBlock = new Block(new StatementList()); foreach (var e in exceptionalPostconditions) { // The catchBlock contains the catchBody, and then // an empty block that is used in the EH. // TODO ST: name is confusing because there is no catch blocks in this method! Block catchBlock = new Block(new StatementList()); // local is: var ex1 = e as C1; Local localEx = new Local(e.Type); body.Add( new AssignmentStatement(localEx, new BinaryExpression(checkExceptionMethod.Parameters[0], new MemberBinding(null, e.Type), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(localEx, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); // call Contract.EnsuresOnThrow ExpressionList args = new ExpressionList(); args.Add(e.PostCondition); args.Add(e.UserMessage ?? Literal.Null); args.Add(e.SourceConditionText ?? Literal.Null); args.Add(localEx); var checks = new StatementList(); checks.Add( new ExpressionStatement( new MethodCall( new MemberBinding(null, this.rewriter.RuntimeContracts.EnsuresOnThrowMethod), args, NodeType.Call, SystemTypes.Void), e.SourceContext)); this.rewriter.CleanUpCodeCoverage.VisitStatementList(checks); // TODO ST: actually I can't see this recursion guard check in the resulting IL!! rewriter.EmitRecursionGuardAroundChecks(checkExceptionMethod, catchBlock, checks); catchBlock.Statements.Add(new Branch(null, returnBlock)); } // recurse on AggregateException itself { // var ae = e as AggregateException; // if (ae != null) { // ae.Handle(this.CheckException); // } Block catchBlock = new Block(new StatementList()); var aggregateType = aggregateExceptionType.Value; // var ex2 = e as AggregateException; Local localEx2 = new Local(aggregateType); body.Add( new AssignmentStatement(localEx2, new BinaryExpression( checkExceptionMethod.Parameters[0], new MemberBinding(null, aggregateType), NodeType.Isinst))); Block skipBlock = new Block(); body.Add(new Branch(new UnaryExpression(localEx2, NodeType.LogicalNot), skipBlock)); body.Add(catchBlock); body.Add(skipBlock); var funcType = func2Type.Value; funcType = funcType.GetTemplateInstance(this.rewriter.AssemblyBeingRewritten, SystemTypes.Exception, SystemTypes.Boolean); var handleMethod = aggregateType.GetMethod(Identifier.For("Handle"), funcType); var funcLocal = new Local(funcType); var ldftn = new UnaryExpression( new MemberBinding(null, checkExceptionMethod), NodeType.Ldftn, CoreSystemTypes.IntPtr); catchBlock.Statements.Add( new AssignmentStatement(funcLocal, new Construct( new MemberBinding(null, funcType.GetConstructor(SystemTypes.Object, SystemTypes.IntPtr)), new ExpressionList(checkExceptionMethod.ThisParameter, ldftn)))); catchBlock.Statements.Add( new ExpressionStatement(new MethodCall(new MemberBinding(localEx2, handleMethod), new ExpressionList(funcLocal)))); } // add return true to CheckException method body.Add(returnBlock); body.Add(new Return(Literal.True)); }