/// <summary> /// Initializes a new instance of the <see cref="CSharpOverLoopInstruction"/> class. /// </summary> /// <param name="context">The creation context.</param> /// <param name="parentFeature">The parent feature.</param> /// <param name="source">The Easly instruction from which the C# instruction is created.</param> protected CSharpOverLoopInstruction(ICSharpContext context, ICSharpFeature parentFeature, IOverLoopInstruction source) : base(context, parentFeature, source) { OverList = CSharpExpression.Create(context, (IExpression)source.OverList); LoopInstructions = CSharpScope.Create(context, parentFeature, (IScope)source.LoopInstructions); foreach (IName Name in source.IndexerList) { string IndexerName = Name.ValidText.Item; IScopeAttributeFeature IndexerFeature = Source.InnerLoopScope[IndexerName]; ICSharpScopeAttributeFeature NewIndexer = CSharpScopeAttributeFeature.Create(context, ParentFeature.Owner, IndexerFeature); IndexerList.Add(NewIndexer); } if (source.ExitEntityName.IsAssigned) { ExitEntityName = ((IIdentifier)source.ExitEntityName.Item).ValidText.Item; } foreach (IAssertion Item in Source.InvariantList) { ICSharpAssertion NewAssertion = CSharpAssertion.Create(context, Item); InvariantList.Add(NewAssertion); } }
public override void VisitTypeNode(TypeNode typeNode) { if (typeNode == null) { return; } // we might have copied this type already if (this.duplicatedMembers[typeNode.UniqueKey] != null) { return; } TypeNode targetType = typeNode.FindShadow(this.targetAssembly); if (targetType != null) { if (targetType.Contract == null) { targetType.Contract = new TypeContract(targetType, true); } this.outOfBandDuplicator.TargetType = targetType; if (typeNode.Contract != null) { InvariantList duplicatedInvariants = this.outOfBandDuplicator.VisitInvariantList(typeNode.Contract.Invariants); targetType.Contract.Invariants = duplicatedInvariants; } CopyAttributesWithoutDuplicateUnlessAllowMultiple(targetType, typeNode); base.VisitTypeNode(typeNode); } else { // target type does not exist. Copy it if (typeNode.DeclaringType != null) { // nested types are members and have been handled by CopyMissingMembers } else { this.outOfBandDuplicator.VisitTypeNode(typeNode); } } }
/// <summary> /// Initializes a new instance of the <see cref="CSharpForLoopInstruction"/> class. /// </summary> /// <param name="context">The creation context.</param> /// <param name="parentFeature">The parent feature.</param> /// <param name="source">The Easly instruction from which the C# instruction is created.</param> protected CSharpForLoopInstruction(ICSharpContext context, ICSharpFeature parentFeature, IForLoopInstruction source) : base(context, parentFeature, source) { foreach (IEntityDeclaration Declaration in source.EntityDeclarationList) { ICSharpScopeAttributeFeature NewDeclaration = CSharpScopeAttributeFeature.Create(context, parentFeature.Owner, Declaration.ValidEntity.Item); EntityDeclarationList.Add(NewDeclaration); } foreach (IInstruction Instruction in source.InitInstructionList) { ICSharpInstruction NewInstruction = Create(context, parentFeature, Instruction); InitInstructionList.Add(NewInstruction); } WhileCondition = CSharpExpression.Create(context, (IExpression)source.WhileCondition); foreach (IInstruction Instruction in source.LoopInstructionList) { ICSharpInstruction NewInstruction = Create(context, parentFeature, Instruction); LoopInstructionList.Add(NewInstruction); } foreach (IInstruction Instruction in source.IterationInstructionList) { ICSharpInstruction NewInstruction = Create(context, parentFeature, Instruction); IterationInstructionList.Add(NewInstruction); } if (source.Variant.IsAssigned) { VariantExpression = CSharpExpression.Create(context, (IExpression)source.Variant.Item); } foreach (IAssertion Item in Source.InvariantList) { ICSharpAssertion NewAssertion = CSharpAssertion.Create(context, Item); InvariantList.Add(NewAssertion); } }
public void CheckInvariants(TypeNode t, InvariantList invariants) { Contract.Requires(invariants != null); this.assignmentFound = false; foreach (var i in invariants) { if (i == null) continue; this.lastSourceContext = i.SourceContext; this.CurrentMethod = i; this.Visit(i); Contract.Assume(this.CurrentMethod != null); if (this.assignmentFound) { this.errorHandler( new Error(1003, "Malformed contract. Found Invariant after assignment in method '" + this.CurrentMethod.FullName + "'.", i.SourceContext)); break; } } }
private void ExtractIndividualInvariants(TypeNode type, InvariantList result, Method invariantMethod) { if (invariantMethod == null || invariantMethod.Body == null || invariantMethod.Body.Statements == null || invariantMethod.Body.Statements.Count == 0) { return; } Block invariantMethodBody = invariantMethod.Body; int n = invariantMethodBody.Statements.Count; int beginning = 0; while (beginning < invariantMethodBody.Statements.Count && invariantMethodBody.Statements[beginning] is PreambleBlock) { beginning++; } for (int i = beginning; i < n; i++) { Block b = (Block) invariantMethodBody.Statements[i]; int seginning = 0; for (int j = 0, m = b.Statements == null ? 0 : b.Statements.Count; j < m; j++) { ExpressionStatement s = b.Statements[j] as ExpressionStatement; if (s == null) continue; Literal invariantName; Literal sourceText; Expression invariantCondition = this.contractNodes.IsInvariant(s, out invariantName, out sourceText); if (invariantCondition == null) { Method called = HelperMethods.IsMethodCall(s); if (called != null) { if (HelperMethods.IsVoidType(called.ReturnType)) { this.CallErrorFound(new Error(1045, "Invariant methods must be a sequence of calls to Contract.Invariant(...)", s.SourceContext)); return; } } continue; } // construct a clump from // invariantMethodBody.Statements[beginning].Statements[seginning] to // invariantMethodBody.Statements[i].Statements[j] Block currentClump = new Block(HelperMethods.ExtractClump(invariantMethodBody.Statements, beginning, seginning, i, j)); BlockExpression be = new BlockExpression(currentClump, SystemTypes.Void); Invariant inv = new Invariant(type, be, invariantMethod.Name.Name); inv.UserMessage = invariantName; inv.SourceConditionText = sourceText; SourceContext sctx; if (HelperMethods.FindContext(currentClump, s.SourceContext, out sctx)) { inv.SourceContext = sctx; inv.Condition.SourceContext = sctx; } inv.ILOffset = s.ILOffset; inv.UsesModels = CodeInspector.UsesModel(inv.Condition, this.contractNodes); if (inv.UsesModels) { this.HandleError(invariantMethod, 1072, "Invariants cannot refer to model members.", sctx); } else { result.Add(inv); } // Re-initialize current state beginning = i; seginning = j + 1; b = (Block) invariantMethodBody.Statements[i]; // IMPORTANT! Need this to keep "b" in sync } } }
public virtual InvariantList VisitInvariantList(InvariantList invariants){ if (invariants == null) return null; for (int i = 0, n = invariants.Count; i < n; i++) invariants[i] = this.VisitInvariant(invariants[i]); return invariants; }
public override void VisitTypeNode(TypeNode typeNode) { if (typeNode == null) return; if (HelperMethods.IsContractTypeForSomeOtherType(typeNode, this.rewriterNodes) != null) { return; } Method savedInvariantMethod = this.InvariantMethod; Field savedReentrancyFlag = this.ReentrancyFlag; this.InvariantMethod = null; this.ReentrancyFlag = null; var savedState = this.currentState; this.currentState = new CurrentState(typeNode); var savedEmitFlags = this.AdaptRuntimeOptionsBasedOnAttributes(typeNode.Attributes); try { if (this.Emit(RuntimeContractEmitFlags.Invariants) && rewriterNodes.InvariantMethod != null) { InvariantList userWrittenInvariants = typeNode.Contract == null ? null : typeNode.Contract.Invariants; Class asClass = typeNode as Class; Field baseReentrancyFlag; Method baseInvariantMethod = FindAndInstantiateBaseClassInvariantMethod(asClass, out baseReentrancyFlag); if ((userWrittenInvariants != null && 0 < userWrittenInvariants.Count) || baseInvariantMethod != null) { Field reEntrancyFlag = null; var isStructWithExplicitLayout = IsStructWithExplicitLayout(typeNode as Struct); if (isStructWithExplicitLayout) { this.HandleError(new Warning(1044, String.Format("Struct '{0}' has explicit layout and an invariant. Invariant recursion guards will not be emitted and evaluation of invariants may occur too eagerly.", typeNode.FullName), new SourceContext())); } else { #region Find or create re-entrancy flag to the class if (baseReentrancyFlag != null) { // grab base reEntrancyFlag reEntrancyFlag = baseReentrancyFlag; } else { FieldFlags reentrancyFlagProtection; if (typeNode.IsSealed) { reentrancyFlagProtection = FieldFlags.Private | FieldFlags.CompilerControlled; } else if (this.InheritInvariantsAcrossAssemblies) { reentrancyFlagProtection = FieldFlags.Family | FieldFlags.CompilerControlled; } else { reentrancyFlagProtection = FieldFlags.FamANDAssem | FieldFlags.CompilerControlled; } reEntrancyFlag = new Field(typeNode, null, reentrancyFlagProtection, Identifier.For("$evaluatingInvariant$"), SystemTypes.Boolean, null); RewriteHelper.TryAddCompilerGeneratedAttribute(reEntrancyFlag); RewriteHelper.TryAddDebuggerBrowsableNeverAttribute(reEntrancyFlag); typeNode.Members.Add(reEntrancyFlag); } #endregion Add re-entrancy flag to the class } Block newBody = new Block(new StatementList(3)); // newBody ::= // if (this.$evaluatingInvariant$){ // return (true); // don't really return true since this is a void method, but it means the invariant is assumed to hold // this.$evaluatingInvariant$ := true; // try{ // <evaluate invariants and call base invariant method> // } finally { // this.$evaluatingInvariant$ := false; // } Method invariantMethod = new Method( typeNode, new AttributeList(), Identifier.For("$InvariantMethod$"), null, SystemTypes.Void, newBody); RewriteHelper.TryAddCompilerGeneratedAttribute(invariantMethod); invariantMethod.CallingConvention = CallingConventionFlags.HasThis; if (this.InheritInvariantsAcrossAssemblies) invariantMethod.Flags = MethodFlags.Family | MethodFlags.Virtual; else invariantMethod.Flags = MethodFlags.FamANDAssem | MethodFlags.Virtual; invariantMethod.Attributes.Add(new AttributeNode(new MemberBinding(null, this.runtimeContracts.ContractNodes.InvariantMethodAttribute.GetConstructor()), null)); #region call base class invariant if (baseInvariantMethod != null) { newBody.Statements.Add( new ExpressionStatement( new MethodCall( new MemberBinding(invariantMethod.ThisParameter, baseInvariantMethod), null, NodeType.Call, SystemTypes.Void))); } #endregion #region Add re-entrancy test to the method Block invariantExit = new Block(); if (reEntrancyFlag != null) { Block reEntrancyTest = new Block(new StatementList()); reEntrancyTest.Statements.Add( new Branch(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), invariantExit)); reEntrancyTest.Statements.Add( new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.True) ); newBody.Statements.Add(reEntrancyTest); } #endregion Add re-entrancy test to the method Block invariantChecks = new Block(new StatementList()); if (userWrittenInvariants != null) { #region Filter out invariants that aren't runtime checkable var filteredInvariants = new InvariantList(); foreach (var i in userWrittenInvariants) { if (!EmitInvariant(i, this.skipQuantifiers)) continue; filteredInvariants.Add(i); } #endregion Filter out invariants that aren't runtime checkable #region Duplicate the invariants // need to duplicate the invariants so they aren't shared Duplicator d = new Duplicator(typeNode.DeclaringModule, typeNode); InvariantList duplicatedInvariants = d.VisitInvariantList(filteredInvariants); // F: seems to have the invariant duplictedInvariants != null Contract.Assume(duplicatedInvariants != null); #endregion Duplicate the invariants #region Rewrite the body of the invariant method // then we need to replace calls to Contract.Invariant with calls to Contract.RewriterInvariant // in the body of the invariant method RewriteInvariant rc = new RewriteInvariant(this.runtimeContracts); rc.VisitInvariantList(duplicatedInvariants); #endregion Rewrite the body of the invariant method for (int i = 0, n = duplicatedInvariants.Count; i < n; i++) { Expression e = duplicatedInvariants[i].Condition; var blockExpr = e as BlockExpression; if (blockExpr != null) { invariantChecks.Statements.Add(blockExpr.Block); } else { invariantChecks.Statements.Add(new ExpressionStatement(e)); } } } Block finallyB = new Block(new StatementList(1)); if (reEntrancyFlag != null) { finallyB.Statements.Add( new AssignmentStatement(new MemberBinding(invariantMethod.ThisParameter, reEntrancyFlag), Literal.False) ); } this.cleanUpCodeCoverage.VisitBlock(invariantChecks); Block b = RewriteHelper.CreateTryFinallyBlock(invariantMethod, invariantChecks, finallyB); newBody.Statements.Add(b); newBody.Statements.Add(invariantExit); newBody.Statements.Add(new Return()); // set the field "this.InvariantMethod" to this one so it is used in calls within each method // but don't add it yet to the class so it doesn't get visited! this.InvariantMethod = invariantMethod; this.ReentrancyFlag = reEntrancyFlag; } } base.VisitTypeNode(typeNode); // Now add invariant method to the class if (this.InvariantMethod != null) { typeNode.Members.Add(this.InvariantMethod); } return; } finally { this.InvariantMethod = savedInvariantMethod; this.ReentrancyFlag = savedReentrancyFlag; this.currentState = savedState; this.contractEmitFlags = savedEmitFlags; } }
public virtual void VisitInvariantList(InvariantList invariants) { if (invariants == null) return; for (int i = 0, n = invariants.Count; i < n; i++) this.VisitInvariant(invariants[i]); }
public override InvariantList VisitInvariantList(InvariantList Invariants){ if (Invariants == null) return null; return base.VisitInvariantList(Invariants.Clone()); }
public virtual InvariantList VisitInvariantList(InvariantList Invariants1, InvariantList Invariants2){ if (Invariants1 == null) return null; for (int i = 0, n = Invariants1.Count, m = Invariants2 == null ? 0 : Invariants2.Count; i < n; i++){ //^ assert Invariants2 != null; if (i >= m) Invariants1[i] = this.VisitInvariant(Invariants1[i], null); else Invariants1[i] = this.VisitInvariant(Invariants1[i], Invariants2[i]); } return Invariants1; }
/// <summary> /// Implements the runtime check for invariants of class C. Also implements the runtime check for modelfields. /// ensures: If c declares invariants or modelfields, then c.Contract.InvariantMethod contains their runtime checking code; /// Adds the CheckInvariant method to c.Members if it wasn't a member already. /// </summary> void ImplementCheckInvariantMethod(Class c) { // c is the class to which all of this code is going to get attached to. Method m = null; #region Get a handle m on the invariant method, create one if necessary if (c.Contract == null || c.Contract.InvariantMethod == null) { Method invariantMethod = new Method( c, new AttributeList(), Identifier.For("SpecSharp::CheckInvariant"), new ParameterList(new Parameter(Identifier.For("throwException"), SystemTypes.Boolean)), SystemTypes.Boolean, null); invariantMethod.CallingConvention = CallingConventionFlags.HasThis; invariantMethod.Flags = MethodFlags.Private; m = invariantMethod; } else m = c.Contract.InvariantMethod; #endregion Get a handle on the invariant method, create one if necessary StatementList stmts = new StatementList(); #region Create code for all of the invariants, implicit and explicit. Add that code to stmts. Parameter throwException = m.Parameters[0]; InvariantList consolidatedInvariants = new InvariantList(); InvariantList invariants = c.Contract == null ? null : c.Contract.Invariants; for (int i = 0, n = invariants == null ? 0 : invariants.Count; i < n; i++) if (!invariants[i].IsStatic) consolidatedInvariants.Add(invariants[i]); // InterfaceList ifaces = this.GetTypeView(c).Interfaces; InterfaceList ifaces = c.Interfaces; for (int i = 0, n = ifaces.Count; i < n; i++){ Interface iface = ifaces[i]; if (iface == null) continue; GatherInheritedInstanceInvariants(iface, consolidatedInvariants); } for (int i = 0; i < consolidatedInvariants.Count; i++){ Invariant inv = consolidatedInvariants[i]; stmts.Add(new If(new UnaryExpression(inv.Condition, NodeType.LogicalNot, SystemTypes.Boolean), new Block(new StatementList( new If(throwException, new Block(new StatementList( new Throw(new Construct(new MemberBinding(null, SystemTypes.ObjectInvariantException.GetConstructor()), null, SystemTypes.ObjectInvariantException), inv.SourceContext) )), new Block(new StatementList(new Return(Literal.False)))))), null)); } #endregion #region Create code for all of the modelfields defined by c. Add that code to stmts. StatementList mfStats = new StatementList(); ExpressionList modifiesList = new ExpressionList(); // synthesize modifies clause foreach (ModelfieldContract mfC in c.Contract.ModelfieldContracts) { //Add the following code to the method: // if (!E) { // <mfC.Modelfield> = value(mfC.Witness); // if (!E) throw exception; // } //where E is the conjunction of (1) all satisfies clauses of the contract, and (2) all satisfies clauses of overridden contracts in superclasses. //Note that satisifes clauses of contracts implemented by mfC (i.e., contracts in interfaces) have been copied to mfC. //Note that if f in C overrides f in D, and f in D overrides f in E, then f in C overrides f in E. Expression E = Literal.True; for (ModelfieldContract currentMfC = mfC; currentMfC != null; currentMfC = currentMfC.NearestOverriddenContract) { foreach (Expression satClause in currentMfC.SatisfiesList) { if (satClause == null) continue; //error will have been dealt with elsewhere E = new BinaryExpression(satClause, E, NodeType.LogicalAnd, SystemTypes.Boolean); } } Expression notE = new UnaryExpression(E, NodeType.LogicalNot, SystemTypes.Boolean); #region create the if statement //Start with the creation of the body of the if. MemberBinding lhs = new MemberBinding(new This(c), mfC.Modelfield); Statement setF = new AssignmentStatement(lhs, mfC.Witness); modifiesList.Add(lhs); // synthesize modifies clause String mfAsString = mfC.Modelfield.FullName; MemberBinding exc = new MemberBinding(null,SystemTypes.ModelfieldException.GetConstructor(SystemTypes.String)); Construct exception = new Construct(exc, new ExpressionList(new Literal(mfAsString,SystemTypes.String)), SystemTypes.ModelfieldException); Block innerIfBody = new Block(new StatementList( new If(throwException, new Block(new StatementList( new Throw(exception, mfC.Modelfield.SourceContext) )), new Block(new StatementList(new Return(Literal.False)))))); Statement innerIf = new If(notE, innerIfBody, null); StatementList body = new StatementList(); body.Add(setF); body.Add(innerIf); Statement outerIf = new If(notE, new Block(body), null); #endregion mfStats.Add(outerIf); } #endregion #region If c declares invariants or modelfields, then add a contract to c if it has none, and make sure that m is c's InvariantMethod. if (stmts.Count > 0 || mfStats.Count > 0) { Duplicator dup = new Duplicator(this.currentModule, this.currentType); dup.DuplicateFor[throwException.UniqueKey] = throwException; stmts = dup.VisitStatementList(stmts); mfStats = dup.VisitStatementList(mfStats); m.Body = new Block(stmts); m.Body.Statements.Add(new Block(mfStats)); //The model field code should be wrapped in a ContractMarkerException block, but I can't get it to work m.Body.Statements.Add(new Return(Literal.True)); m.Body.HasLocals = true; //who knows? there might be locals in the invariants or model fields (quantifier bound variables). #region Slap on NoDefaultContract and (what is roughly the equivalent of) a requires this.PreValid. //I doubt if this is still needed //No need for a runtime check of this precondition though, so directly add an attribute. //Bit of a hack, but there does not seem to be a really good place to do this. InstanceInitializer ndCtor = SystemTypes.NoDefaultContractAttribute.GetConstructor(); if (ndCtor != null) m.Attributes.Add(new AttributeNode(new MemberBinding(null, ndCtor), null, AttributeTargets.Method)); TypeNode guard = SystemTypes.Guard; if (guard != null) { Method method = guard.GetMethod(Identifier.For("FrameIsPrevalid"), SystemTypes.Object, SystemTypes.Type); if (method != null) { This t = new This(c); Expression req = new MethodCall( new MemberBinding(null, method), new ExpressionList(t, new UnaryExpression(new Literal(t.Type, SystemTypes.Type), NodeType.Typeof, OptionalModifier.For(SystemTypes.NonNullType, SystemTypes.Type)))); // Place it in the method contract so downstream tools that are in the compiler pipeline see it if (m.Contract == null) { m.Contract = new MethodContract(m); } if (m.Contract.Requires == null) { m.Contract.Requires = new RequiresList(1); } m.Contract.Requires.Add(new RequiresPlain(req)); m.Contract.Modifies = modifiesList; // needed for model fields // Since this happens after contracts are serialized, serialize the precondition and stick it in the method's attributes. ContractSerializer cs = new ContractSerializer(this.currentModule); cs.Visit(req); string val = cs.SerializedContract; InstanceInitializer ctor = SystemTypes.RequiresAttribute.GetConstructor(SystemTypes.String); MemberBinding attrBinding = new MemberBinding(null, ctor); ExpressionList args = new ExpressionList(); args.Add(new Literal(val, SystemTypes.String)); AttributeNode a = new AttributeNode(attrBinding, args, (AttributeTargets)0); m.Attributes.Add(a); if (modifiesList.Count > 0) { ctor = SystemTypes.ModifiesAttribute.GetConstructor(SystemTypes.String); for (int i = 0, n = modifiesList.Count; i < n; i++) { Expression e = modifiesList[i]; a = Checker.SerializeExpression(ctor, e, this.currentModule); m.Attributes.Add(a); } } } } #endregion if (c.Contract == null) { c.Contract = new TypeContract(c); c.Contract.DeclaringType = c; } if (c.Contract.InvariantMethod == null) { c.Contract.InvariantMethod = m; c.Members.Add(m); } //else assert (m == c.Contract.InvairantMethod) } #endregion }
void GatherInheritedInstanceInvariants(Interface iface, InvariantList invs){ if (iface == null) return; if (iface.Contract != null && iface.Contract.InvariantCount > 0){ for (int i = 0, n = iface.Contract.Invariants.Count; i < n; i++){ if (!iface.Contract.Invariants[i].IsStatic) invs.Add(iface.Contract.Invariants[i]); } } // InterfaceList iface_ifaces = this.GetTypeView(iface).Interfaces; InterfaceList iface_ifaces = iface.Interfaces; for (int i = 0, n = iface_ifaces == null ? 0 : iface_ifaces.Count; i < n; i++){ GatherInheritedInstanceInvariants(iface_ifaces[i],invs); } return; }
public EventingVisitor(Action<InvariantList> visitInvariantList) { VisitedInvariantList += visitInvariantList; } public event Action<InvariantList> VisitedInvariantList; public override InvariantList VisitInvariantList(InvariantList invariants) { if (VisitedInvariantList != null) VisitedInvariantList(invariants); return base.VisitInvariantList(invariants); }