private bool ExtractFromClump(StatementList contractClump, Method method, GatherLocals gatherLocals, RequiresList Preconditions, EnsuresList Postconditions, RequiresList validations, EnsuresList modelPostconditions, SourceContext defaultContext, Method originalMethod, Block contractInitializer, ref HelperMethods.StackDepthTracker dupStackTracker) { // set the state so that the contract clump is used for extraction (as opposed to the method body as it used to) StatementList stmts = contractClump; int beginning = 0; int n = stmts.Count; int seginning = HelperMethods.FindNextRealStatement(((Block) stmts[beginning]).Statements, 0); bool endContractFound = false; bool postConditionFound = false; SourceContext currentSourceContext; for (int i = beginning; i < n; i++) { Block b = (Block) stmts[i]; if (b == null) continue; for (int j = 0, m = b.Statements == null ? 0 : b.Statements.Count; j < m; j++) { if (dupStackTracker.IsValid && dupStackTracker.Depth >= 0) { b.Statements[j] = dupStackTracker.Visit(b.Statements[j]); } Statement s = b.Statements[j]; if (s == null) continue; Block currentClump; Throw t = null; t = s as Throw; Method calledMethod = HelperMethods.IsMethodCall(s); if ((t != null || (calledMethod != null && calledMethod.DeclaringType != null && calledMethod.DeclaringType != this.contractNodes.ContractClass && HelperMethods.IsVoidType(calledMethod.ReturnType) && !this.contractNodes.IsContractOrValidatorOrAbbreviatorMethod(calledMethod)))) { // Treat throw statements as (part of) a precondition // don't accept "throw ..." unless it comes in the "precondition section" // then treat the current clump as a precondition, but need to massage it a bit: // all branches to the block just after the throw should be modified to be branches to // a new manufactured block that sets a fresh local to "true". The // throw itself should be changed to set the same local to "false". That way the // clump can be treated as the value of precondition (because the branch polarity has // already been negated as part of the code gen). // This test was supposed to be a sanity check that the current block contained // only "throw ..." or else "nop; throw ...". But I've also seen "ThrowHelper.Throw(...); nop", // so I'm just going to comment this out for now. //if (!((m == 1 && j == 0) || (m == 2 && j == 1))) { // Preconditions = new RequiresList(); // Postconditions = new EnsuresList(); // return; // throw new ExtractorException(); //} Expression exception; // The clump being extracted may contain code/blocks that represent (part of) // the expression that is being thrown (if the original throw expression had // control flow in it from boolean expressions and/or ternary expressions). b.Statements[j] = null; // wipe out throw statement currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); int currentClumpLength = i - beginning + 1; // there better be a next block because that must have been the target for all of the branches // that didn't cause the throw to happen if (!(i < n - 1)) { this.HandleError(method, 1027, "Malformed contract.", s.SourceContext); return false; } Block nextBlock = (Block) stmts[i + 1]; // cast succeeds because body is clump Local valueOfPrecondition = new Local(Identifier.For("_preConditionHolds"), SystemTypes.Boolean); Block preconditionHolds = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.True))); ReplaceBranchTarget rbt = new ReplaceBranchTarget(nextBlock, preconditionHolds); rbt.VisitBlock(currentClump); int ILOffset; CountPopExpressions cpe = new CountPopExpressions(); currentSourceContext = s.SourceContext; cpe.Visit(s); if (0 < cpe.PopOccurrences) { // then there is a set of blocks that represent the exception: the Reader // was not able to decompile it back into an expression. Extract the set // from the current clump and make it into a block expression // Find the last block that has a branch to "preconditionHolds". After that are all of the blocks // that represent the evaluation of the exception int branchBlockIndex = currentClumpLength - 2; // can't be the current block: that has the throw in it while (0 <= branchBlockIndex) { Block possibleBranchBlock = currentClump.Statements[branchBlockIndex] as Block; Branch br = possibleBranchBlock.Statements[possibleBranchBlock.Statements.Count - 1] as Branch; if (br != null && br.Target == preconditionHolds) { break; } branchBlockIndex--; } if (branchBlockIndex < 0) { this.HandleError(method, 1028, "Malformed exception constructor in contract.", defaultContext); return false; } Block exceptionBlock = new Block(HelperMethods.ExtractClump(currentClump.Statements, branchBlockIndex + 1, 0, currentClumpLength - 1, ((Block) currentClump.Statements[currentClumpLength - 1]).Statements.Count - 1)); exceptionBlock.Statements.Add(new ExpressionStatement(t.Expression)); SourceContext sctx = ((Block) exceptionBlock.Statements[0]).Statements[0].SourceContext; if (sctx.IsValid) { currentSourceContext = sctx; } else { SourceContext tmp; bool foundContext = HelperMethods.GetLastSourceContext(exceptionBlock.Statements, out tmp); if (foundContext) currentSourceContext = tmp; } if (!CheckClump(method, gatherLocals, currentSourceContext, exceptionBlock)) return false; exception = new BlockExpression(exceptionBlock, SystemTypes.Exception); ILOffset = t.ILOffset; } else { currentSourceContext = s.SourceContext; if (t != null) { // then the statement is "throw ..." exception = t.Expression; ILOffset = t.ILOffset; } else { ExpressionStatement throwHelperCall = s as ExpressionStatement; Debug.Assert(throwHelperCall != null); exception = throwHelperCall.Expression; ILOffset = s.ILOffset; } exception.SourceContext = currentSourceContext; SourceContext tmp; bool foundContext = HelperMethods.GetLastSourceContext(currentClump.Statements, out tmp); if (foundContext) currentSourceContext = tmp; } Block returnValueOfPrecondition = new Block(new StatementList(new ExpressionStatement(valueOfPrecondition))); Statement extraAssumeFalse = this.ExtraAssumeFalseOnThrow(); Block preconditionFails = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False), extraAssumeFalse, new Branch(null, returnValueOfPrecondition, true, false, false))); //Block preconditionFails = new Block(new StatementList(new AssignmentStatement(valueOfPrecondition, Literal.False), new Branch(null, returnValueOfPrecondition, true, false, false))); currentClump.Statements.Add(preconditionFails); // replace throw statement currentClump.Statements.Add(preconditionHolds); currentClump.Statements.Add(returnValueOfPrecondition); if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; BlockExpression be = new BlockExpression(currentClump, SystemTypes.Boolean); be.SourceContext = currentSourceContext; var ro = new RequiresOtherwise(be, exception); ro.ILOffset = ILOffset; ro.SourceContext = currentSourceContext; if (postConditionFound) { HandleError(originalMethod, 1013, "Precondition found after postcondition.", currentSourceContext); return false; } validations.Add(ro); var req = new RequiresPlain(be, FindExceptionThrown.Find(exception)); req.IsFromValidation = true; req.ILOffset = ro.ILOffset; req.SourceContext = ro.SourceContext; Preconditions.Add(req); } else { if (contractNodes.IsContractMethod(calledMethod)) { // Treat calls to contract methods if (endContractFound) { HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } if (contractNodes.IsEndContract(calledMethod)) { endContractFound = true; continue; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; Expression arg = mc.Operands[0]; arg.SourceContext = s.SourceContext; MethodContractElement mce; currentSourceContext = s.SourceContext; Expression condition; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement condition = arg; } else { b.Statements[j] = new ExpressionStatement(arg); // construct a clump from // methodBody.Statements[beginning].Statements[seginning] to // methodBody.Statements[i].Statements[j] currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; BlockExpression be = new BlockExpression(currentClump); condition = be; } condition.SourceContext = currentSourceContext; if (contractNodes.IsPlainPrecondition(calledMethod)) { var req = new RequiresPlain(condition); contractNodes.IsRequiresWithException(calledMethod, out req.ExceptionType); mce = req; } else if (this.contractNodes.IsPostcondition(calledMethod)) { mce = new EnsuresNormal(condition); } else if (contractNodes.IsExceptionalPostcondition(calledMethod)) { EnsuresExceptional ee = new EnsuresExceptional(condition); // Extract the type of exception. ee.Type = calledMethod.TemplateArguments[0]; mce = ee; } else { throw new InvalidOperationException("Cannot recognize contract method"); } mce.SourceContext = currentSourceContext; mce.ILOffset = mc.ILOffset; if (1 < mc.Operands.Count) { var candidate = SanitizeUserMessage(method, mc.Operands[1], currentSourceContext); mce.UserMessage = candidate; } if (2 < mc.Operands.Count) { Literal lit = mc.Operands[2] as Literal; if (lit != null) { mce.SourceConditionText = lit; } } // determine Model status mce.UsesModels = CodeInspector.UsesModel(mce.Assertion, this.contractNodes); // Check context rules switch (mce.NodeType) { case NodeType.RequiresPlain: if (postConditionFound) { this.HandleError(originalMethod, 1014, "Precondition found after postcondition.", currentSourceContext); return false; } if (mce.UsesModels) { this.HandleError(originalMethod, 1073, "Preconditions may not refer to model members.", currentSourceContext); return false; } var rp = (RequiresPlain) mce; Preconditions.Add(rp); validations.Add(rp); // also add to the internal validation list break; // TODO: check visibility of post conditions based on visibility of possible implementation case NodeType.EnsuresNormal: case NodeType.EnsuresExceptional: Ensures ensures = (Ensures) mce; if (mce.UsesModels) { if (this.IncludeModels) { modelPostconditions.Add(ensures); } } else { Postconditions.Add(ensures); } postConditionFound = true; break; } } else if (ContractNodes.IsValidatorMethod(calledMethod)) { // Treat calls to Contract validators if (endContractFound) { this.HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; var memberBinding = (MemberBinding) mc.Callee; currentSourceContext = s.SourceContext; Statement validation; Block validationPrefix; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement validation = s; validationPrefix = null; } else { // The clump may contain multiple statements ending in the validator call. // to extract the code as Requires<E>, we need to keep the statements preceeding // the validator call, as they may contain local initialization etc. These should go // into the first Requires<E> that the validator expands to. This way, if there are // no Requires<E> expanded from the validator, then the statements can be omitted. // At the same time, the statements won't be duplicated when validations are emitted. // // If the validator call contains any pops, then the extraction must fail saying it // is too complicated. // must null out statement with call before extract clump b.Statements[j] = null; // we have a copy in mc, s validationPrefix = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(validationPrefix, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (CountPopExpressions.Count(mc) > 0) { this.HandleError(method, 1071, "Arguments to contract validator call are too complicated. Please simplify.", currentSourceContext); return false; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, validationPrefix)) return false; validation = new Block(new StatementList(validationPrefix, s)); validation.SourceContext = currentSourceContext; } var ro = new RequiresOtherwise(null, new BlockExpression(new Block(new StatementList(validation)))); validations.Add(ro); CopyValidatorContracts( method, calledMethod, memberBinding.TargetObject, mc.Operands, Preconditions, currentSourceContext, validationPrefix); } else if (ContractNodes.IsAbbreviatorMethod(calledMethod)) { // Treat calls to Contract abbreviators if (endContractFound) { this.HandleError(originalMethod, 1012, "Contract call found after prior EndContractBlock.", s.SourceContext); break; } MethodCall mc = ((ExpressionStatement) s).Expression as MethodCall; var memberBinding = (MemberBinding) mc.Callee; currentSourceContext = s.SourceContext; if (beginning == i && seginning == j) { // Deal with the simple case: the reader decompiled the call into a single statement // nothing to do. All is in the call and its arguments } else { // The clump may contain multiple statements ending in the abbreviator call. // We need to keep the statements preceeding the abbreviator call and add them to the // contract initializer block. The reason we cannot add them to the first expansion contract // of the abbreviator is that the abbreviator may give rise to closure initialization which will // be hoisted into the closure initializer block. This closure initializer may refer to the // locals initialized by the present statement sequence, so it must precede it. // // If the abbreviator call contains any pops, then the extraction must fail saying it // is too complicated. // grab prefix of clump minus last call statement. // must null out current call statement before we extract clump (ow. it stays in body) b.Statements[j] = null; currentClump = new Block(HelperMethods.ExtractClump(stmts, beginning, seginning, i, j)); if (!currentSourceContext.IsValid) { // then a good source context has not been found yet. Grovel around in the clump // to see if there is a better one SourceContext sctx; if (HelperMethods.FindContext(currentClump, currentSourceContext, out sctx)) currentSourceContext = sctx; } if (CountPopExpressions.Count(mc) > 0) { this.HandleError(method, 1070, "Arguments to contract abbreviator call are too complicated. Please simplify.", currentSourceContext); return false; } if (!CheckClump(originalMethod, gatherLocals, currentSourceContext, currentClump)) return false; if (HelperMethods.IsNonTrivial(currentClump)) { contractInitializer.Statements.Add(currentClump); } } CopyAbbreviatorContracts(method, calledMethod, memberBinding.TargetObject, mc.Operands, Preconditions, Postconditions, currentSourceContext, validations, contractInitializer); } else { // important to continue here and accumulate blocks/statements for next contract! if (i == beginning && j == seginning && s.NodeType == NodeType.Nop) { // nop following contract is often associated with previous code, so skip it seginning = j + 1; } continue; } } // Re-initialize current state after contract has been found beginning = i; seginning = j + 1; //seginning = HelperMethods.FindNextRealStatement(((Block)stmts[i]).Statements, j + 1); if (seginning < 0) seginning = 0; //b = (Block)stmts[i]; // IMPORTANT! Need this to keep "b" in sync } } if (this.verbose) { Console.WriteLine("\tNumber of Preconditions: " + Preconditions.Count); Console.WriteLine("\tNumber of Postconditions: " + Postconditions.Count); } return true; }
/// <summary> /// </summary> /// <param name="validationContractInitializer">possibly empty initializer from closures in validators. Must be added as prefix to first requires</param> /// <param name="validationPrefix">Possibly empty statement list of code preceeding validator call. Must be added to first /// requires.</param> private void MoveValidatorRequires(Method targetMethod, RequiresList requiresList, RequiresList Preconditions, SourceContext useSite, Block validationContractInitializer, Block validationPrefix) { bool isFromValidation = true; if (requiresList == null) return; foreach (RequiresPlain req in requiresList) { if (!req.DefSite.IsValid) { req.DefSite = req.SourceContext; } req.SourceContext = useSite; req.IsFromValidation = isFromValidation; // mark that we copied this from a validator when necessary // re-sanitize user message for this context req.UserMessage = SanitizeUserMessage(targetMethod, req.UserMessage, useSite); // check if first requires and add prefixes if (HelperMethods.IsNonTrivial(validationPrefix)) { req.Condition = new BlockExpression( new Block(new StatementList(validationPrefix, new ExpressionStatement(req.Condition)))); validationPrefix = null; } if (HelperMethods.IsNonTrivial(validationContractInitializer)) { req.Condition = new BlockExpression( new Block(new StatementList(validationContractInitializer, new ExpressionStatement(req.Condition)))); validationContractInitializer = null; } Preconditions.Add(req); } }
private void MoveAbbreviatorRequires(Method targetMethod, RequiresList requiresList, RequiresList Preconditions, RequiresList validations, SourceContext useSite) { Contract.Requires(validations != null); if (requiresList == null) return; foreach (RequiresPlain req in requiresList) { if (!req.DefSite.IsValid) { req.DefSite = req.SourceContext; } req.SourceContext = useSite; req.IsFromValidation = false; // re-sanitize user message for this context req.UserMessage = SanitizeUserMessage(targetMethod, req.UserMessage, useSite); Preconditions.Add(req); validations.Add(req); // we keep everything on both lists so we can emit for validation or standard } }
// Instead of overriding VisitRequiresPlain or VisitRequiresOtherwise, just process the list. // Almost all of the code is the same for both plain and otherwise requires. // This could be done by overriding VisitRequires -- but would depend upon introducing // a VisitRequires method in StandardVisitor. public override RequiresList VisitRequiresList(RequiresList Requires){ // add a default precondition here and not earlier in the pipeline so it doesn't confuse // the contract inheritance checks. // REVIEW: probably better to add it earlier and have a HasCompilerGeneratedSignature on it // so it can be ignored in the inheritance checks. bool addDefaultPrecondition = this.currentMethod != null && !this.currentMethod.IsStatic && !this.currentMethod.IsAbstract && this.currentMethod.Body != null && this.currentMethod.Body.Statements != null && !(this.currentMethod.HasCompilerGeneratedSignature && !this.currentMethod.Name.Name.StartsWith("get_") && !this.currentMethod.Name.Name.StartsWith("set_")) && this.currentMethod.NodeType != NodeType.InstanceInitializer && this.currentMethod.NodeType != NodeType.StaticInitializer && (this.currentType != null && this.currentType.Contract != null && this.currentType.Contract.FramePropertyGetter != null) && this.currentMethod.GetAttribute(SystemTypes.NoDefaultContractAttribute) == null ; RequiresList newRequires = new RequiresList(); if (addDefaultPrecondition){ Method frameGetter = this.currentType.Contract.FramePropertyGetter; Method m = null; // We used to use "get_CanStartWriting" for non-virtual methods. But Rustan and I decided // that it should be fine to use the transitive one for all methods. It is more liberal // but still prevents re-entrance into a method in a frame that is exposed. m = SystemTypes.Guard.GetMethod(Identifier.For("get_CanStartWritingTransitively"), null); // default precondition is (as normalized IR): // requires this.get_FrameGuard().get_CanStartWriting(); if it is a non-virtual method // requires this.get_FrameGuard().get_CanStartWritingTransitively(); if it is a virtual method if (frameGetter != null && m != null){ SourceContext sc = this.currentMethod.Name.SourceContext; MethodCall getFrameGuard = new MethodCall(new MemberBinding(this.currentThisParameter, frameGetter), null, NodeType.MethodCall, SystemTypes.Guard, sc); Requires r = new RequiresOtherwise( new MethodCall( new MemberBinding(getFrameGuard,m), null, NodeType.MethodCall, SystemTypes.Boolean), new Construct(new MemberBinding(null, SystemTypes.RequiresException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal("The target object of this call must be exposable.", SystemTypes.String)), SystemTypes.RequiresException) ); r.SourceContext = sc; newRequires.Add(r); } } if ((this.currentMethod.IsPublic || this.currentMethod.IsFamilyOrAssembly) && !(this.currentCompilation != null && this.currentCompilation.CompilerParameters != null && ((CompilerOptions)this.currentCompilation.CompilerParameters).DisableNullParameterValidation)){ ParameterList parameters = this.currentMethod.Parameters; for (int i = 0, n = parameters == null ? 0 : parameters.Count; i < n; i++){ Parameter parameter = parameters[i]; if (parameter != null && !parameter.IsOut && this.typeSystem.IsNonNullType(parameter.Type)){ RequiresOtherwise r; Reference rtype = parameter.Type as Reference; if (rtype == null) { TypeNode parameterType = TypeNode.StripModifier(parameter.Type, SystemTypes.NonNullType); Expression e = null; if (this.useGenerics && (parameterType is TypeParameter || parameterType is ClassParameter)) { e = new BinaryExpression(parameter, new MemberBinding(null, parameterType), NodeType.Box, SystemTypes.Object, parameter.SourceContext); } else { e = new ParameterBinding(parameter, parameter.SourceContext); } r = new RequiresOtherwise( new BinaryExpression(e, new Literal(null, TypeNode.StripModifiers(parameter.Type)), NodeType.Ne, SystemTypes.Boolean, parameter.SourceContext), new Construct(new MemberBinding(null, SystemTypes.ArgumentNullException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal(parameter.Name.Name, SystemTypes.String)), SystemTypes.ArgumentNullException)); } else { // have to perform deref r = new RequiresOtherwise( new BinaryExpression(new AddressDereference(new ParameterBinding(parameter, parameter.SourceContext), rtype.ElementType), new Literal(null, TypeNode.StripModifiers(rtype.ElementType)), NodeType.Ne, SystemTypes.Boolean, parameter.SourceContext), new Construct(new MemberBinding(null, SystemTypes.ArgumentNullException.GetConstructor(SystemTypes.String)), new ExpressionList(new Literal(parameter.Name.Name, SystemTypes.String)), SystemTypes.ArgumentNullException)); } r.SourceContext = parameter.SourceContext; newRequires.Add(r); } } } for (int i = 0, n = Requires == null ? 0 : Requires.Count; i < n; i++){ newRequires.Add(Requires[i]); } if (newRequires.Count == 0) return Requires; Block preConditionBlock = new Block(new StatementList()); preConditionBlock.HasLocals = true; for (int i = 0, n = newRequires.Count; i < n; i++) { Requires r = newRequires[i]; if (r == null) continue; if (r.Condition == null) continue; // Code generation for preconditions needs to be such that the // data flow analysis will "see" the consequences. If the value // of the precondition is assigned to a local, then the information // is lost. // // try { // if re goto pre_i_holds; // } // catch { throw new ErrorDuringPreConditionEvaluation(...); } // throw new PreConditionException(...); // pre_i_holds: nop bool noAllocationAllowed = this.currentMethod.GetAttribute(SystemTypes.BartokNoHeapAllocationAttribute) != null; Local exceptionDuringPreCondition = new Local(Identifier.For("SS$exceptionDuringPreCondition" + i),SystemTypes.Exception); Local exceptionDuringPreCondition3 = new Local(Identifier.For("SS$objectExceptionDuringPreCondition" + i),SystemTypes.Object); Expression cond = r.Condition; string condition = cond != null && cond.SourceContext.SourceText != null && cond.SourceContext.SourceText.Length > 0 ? cond.SourceContext.SourceText : "<unknown condition>"; Expression ec2; Expression ec3; if (noAllocationAllowed) { ec2 = ec3 = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("InvalidContract"))); } else { MemberBinding excBinding2 = new MemberBinding(null, SystemTypes.InvalidContractException.GetConstructor(SystemTypes.String, SystemTypes.Exception)); MemberBinding excBinding3 = new MemberBinding(null, SystemTypes.InvalidContractException.GetConstructor(SystemTypes.String)); string msg2 = "Exception occurred during evaluation of precondition '" + condition + "' in method '" + currentMethod.FullName + "'"; ec2 = new Construct(excBinding2, new ExpressionList(new Literal(msg2, SystemTypes.String), exceptionDuringPreCondition)); ec3 = new Construct(excBinding3, new ExpressionList(new Literal(msg2, SystemTypes.String))); } #region If the precondition fails, throw an exception Expression throwExpression = null; #region Create the expression to throw. Deal with different subtypes of Requires if (noAllocationAllowed) { throwExpression = new MemberBinding(null, SystemTypes.PreAllocatedExceptions.GetField(Identifier.For("Requires"))); } else { if (r is RequiresPlain) { MemberBinding excBinding = new MemberBinding(null, SystemTypes.RequiresException.GetConstructor(SystemTypes.String)); Construct ec = new Construct(excBinding, new ExpressionList()); string msg = "Precondition '" + condition + "' violated from method '" + currentMethod.FullName + "'"; ec.Operands.Add(new Literal(msg, SystemTypes.String)); throwExpression = ec; } else if (r is RequiresOtherwise) { RequiresOtherwise otherwise = (RequiresOtherwise)r; if (otherwise.ThrowException is Literal) { // it was "requires P otherwise E" where E is a type name of an exception class Literal l = (Literal)otherwise.ThrowException; Class exceptionClass = (Class)l.Value; MemberBinding excBinding = new MemberBinding(null, this.GetTypeView(exceptionClass).GetConstructor()); // what to do if there is no nullary constructor? I guess that should have been checked in the context checker Construct ec = new Construct(excBinding, new ExpressionList()); throwExpression = ec; } else { // it was "requires P otherwise new E(...)" (or some other expression whose value is an exception) throwExpression = this.VisitExpression(otherwise.ThrowException); } } else { Debug.Assert(false, "Expecting only RequiresOtherwise and RequiresPlain as subtypes of Requires"); } } #endregion Throw t = new Throw(throwExpression,r.SourceContext); #endregion Block pre_i_holds = new Block(); //CatchList cl = new CatchList(2); //cl.Add(new Catch(new Block(new StatementList(new Throw(ec2,r.Condition.SourceContext))),exceptionDuringPreCondition,SystemTypes.Exception)); //cl.Add(new Catch(new Block(new StatementList(new Throw(ec3,r.Condition.SourceContext))),exceptionDuringPreCondition3,SystemTypes.Object)); //Try tryPre = new Try(new Block(new StatementList(new If(r.Condition,new Block(new StatementList(new Branch(null,pre_i_holds))),null))),cl,null,null,null); //preConditionBlock.Statements.Add(tryPre); preConditionBlock.Statements.Add(new If(r.Condition,new Block(new StatementList(new Branch(null,pre_i_holds))),null)); preConditionBlock.Statements.Add(t); preConditionBlock.Statements.Add(pre_i_holds); } preConditionBlock = this.VisitBlock(preConditionBlock); this.currentContractPrelude.Statements.Add(preConditionBlock); return Requires; }