Esempio n. 1
0
    /// <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           
    }
Esempio n. 2
0
 /// <summary>
 /// <para>
 /// Serializes the expressions in toSerialize to an attribute determined by ctor, as if they come from module containingModule.
 /// Uses the SourceContext information of <param name="sc">sc</param> for the source context for the attribute.
 /// </para>
 /// <para><code>
 /// requires ctor != null &amp;&amp; sc != null;
 /// </code></para>
 /// <para><code>
 /// requires ctor.DeclaringType &lt;: Microsoft.Contracts.AttributeWithContext;
 /// </code></para>
 /// </summary>
 /// <returns></returns>
 public static AttributeNode SerializeExpressions(InstanceInitializer/*!*/ ctor, ExpressionList dontSerialize, ExpressionList toSerialize, SourceContext/*!*/ sc, Module containingModule) {
   MemberBinding attrBinding = new MemberBinding(null, ctor);
   ExpressionList args = new ExpressionList();
   if (dontSerialize != null) {
     foreach (Expression e in dontSerialize) {
       args.Add(e);
     }
   }
   if (toSerialize != null) {
     foreach (Expression e in toSerialize) {
       ContractSerializer cs = new ContractSerializer(containingModule);
       cs.Visit(e);
       string val = cs.SerializedContract;
       args.Add(new Literal(val, SystemTypes.String));
     }
   }
   if (sc.SourceText != null) {
     args.Add(new NamedArgument(Identifier.For("Filename"), new Literal(sc.Document.Name, SystemTypes.String)));
     args.Add(new NamedArgument(Identifier.For("StartLine"), new Literal(sc.StartLine, SystemTypes.Int32)));
     args.Add(new NamedArgument(Identifier.For("StartColumn"), new Literal(sc.StartColumn, SystemTypes.Int32)));
     args.Add(new NamedArgument(Identifier.For("EndLine"), new Literal(sc.EndLine, SystemTypes.Int32)));
     args.Add(new NamedArgument(Identifier.For("EndColumn"), new Literal(sc.EndColumn, SystemTypes.Int32)));
     args.Add(new NamedArgument(Identifier.For("SourceText"), new Literal(sc.SourceText, SystemTypes.String)));
   }
   return new AttributeNode(attrBinding, args, (AttributeTargets)0);
 }    
Esempio n. 3
0
 public virtual StatementList SerializeAssertion(Module currentModule, Expression condition, string message, SourceContext sourceContext, string methodName){
   Method method;
   bool useTwoArgumentCalls = true;
   if (methodName == "AssumeStatement") {
     method = this.GetTypeView(SystemTypes.AssertHelpers).GetMethod(Identifier.For(methodName), SystemTypes.String);
   } else {
     method = this.GetTypeView(SystemTypes.AssertHelpers).GetMethod(Identifier.For(methodName), SystemTypes.String, SystemTypes.String);
     #region Delete when LKG > 7301
     if (method == null) {
       method = this.GetTypeView(SystemTypes.AssertHelpers).GetMethod(Identifier.For(methodName), SystemTypes.String);
       useTwoArgumentCalls = false;
     }
     #endregion
   }
   ExpressionList el = Checker.SplitConjuncts(condition);
   StatementList sl = new StatementList();
   if (method == null) return sl;
   for (int j = 0, m = el.Count; j < m; j++) {
     Expression e_prime = el[j];
     ContractSerializer serializer = new ContractSerializer(currentModule, this.currentClosureLocal);
     serializer.Visit(e_prime);
     string conditionText = serializer.SerializedContract;
     ExpressionList args = new ExpressionList(new Literal(conditionText, SystemTypes.String));
     if (methodName != "AssumeStatement" && useTwoArgumentCalls) { // assume is a unary method
       if (string.IsNullOrEmpty(message)){
         // Can't have the source context passed in to the method in case the expression has been
         // split into different top level conjuncts.
         if (e_prime.SourceContext.Document != null) {
           args.Add(new Literal(e_prime.SourceContext.SourceText, SystemTypes.String));
         } else {
           args.Add(new Literal("Unknown source context", SystemTypes.String));
         }
       } else {
         args.Add(new Literal(message, SystemTypes.String));
       }
     }
     sl.Add(new ExpressionStatement(new MethodCall(new MemberBinding(null, method), args, NodeType.Call, SystemTypes.Void, sourceContext), sourceContext));
   }
   return sl;
 }