A collection of collections of objects that augment the type signature of a method with additional information that describe the contract between calling method and called method.
Inheritance: IMethodContract
Beispiel #1
0
 /// <summary>
 /// Accumulates all elements from <paramref name="sourceContract"/> into <paramref name="targetContract"/>
 /// </summary>
 /// <param name="targetContract">Contract which is target of accumulator</param>
 /// <param name="sourceContract">Contract which is source of accumulator</param>
 public static void AddMethodContract(MethodContract targetContract, IMethodContract sourceContract) {
   targetContract.Locations.AddRange(sourceContract.Locations);
   targetContract.Preconditions.AddRange(sourceContract.Preconditions);
   targetContract.Postconditions.AddRange(sourceContract.Postconditions);
   targetContract.ThrownExceptions.AddRange(sourceContract.ThrownExceptions);
   targetContract.IsPure |= sourceContract.IsPure; // need the disjunction
   return;
 }
Beispiel #2
0
        public override void TraverseChildren(IMethodDefinition method)
        {
            if (!MemberHelper.IsVisibleOutsideAssembly(method))
            {
                return;
            }
            var returnType = method.Type;

            if (returnType == this.host.PlatformType.SystemVoid ||
                returnType.IsEnum ||
                returnType.IsValueType
                )
            {
                return;
            }

            var newContract = new Microsoft.Cci.MutableContracts.MethodContract();
            var post        = new List <IPostcondition>();
            var p           = new Microsoft.Cci.MutableContracts.Postcondition()
            {
                Condition = new NotEquality()
                {
                    LeftOperand = new ReturnValue()
                    {
                        Type = returnType,
                    },
                    RightOperand = new CompileTimeConstant()
                    {
                        Type  = returnType,
                        Value = null,
                    },
                    Type = this.host.PlatformType.SystemBoolean,
                },
                OriginalSource = "result != null",
            };

            post.Add(p);
            newContract.Postconditions = post;

            var contract = this.contractProvider.GetMethodContractFor(method);

            if (contract != null)
            {
                Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(newContract, contract);
            }
            this.contractProvider.AssociateMethodWithContract(method, newContract);

            base.TraverseChildren(method);
        }
 /// <summary>
 /// Mutates the <paramref name="methodContract"/> by removing any contracts that violate any of the rules
 /// about contracts, e.g., preconditions mentioning a member that is more restrictive than the method containing
 /// the precondition.
 /// TODO: Return a list of errors.
 /// </summary>
 public static void CheckMethodContract(IMetadataHost host, IMethodDefinition method, MethodContract methodContract) {
   var reqs = methodContract.Preconditions;
   var newReqs = new List<IPrecondition>(methodContract.Preconditions.Count);
   foreach (var p in reqs) {
     var contractExpression = p.Condition;
     var v = Visibility.MostRestrictiveVisibility(host, contractExpression);
     var currentVisibility = method.Visibility;
     var intersection = TypeHelper.VisibilityIntersection(v, currentVisibility);
     if (intersection == currentVisibility) {
       newReqs.Add(p);
     } else {
       // TODO!! BUGBUG!! Need to signal an error, not just silently not add the precondition!
     }
   }
   methodContract.Preconditions = newReqs;
 }
            public override void TraverseChildren(IMethodDefinition method)
            {
                // inject only in visible method
                if(!MemberHelper.IsVisibleOutsideAssembly(method))
                    return;

                // inject only in methods that return a reference type
                var returnType = method.Type;
                if(returnType == this.host.PlatformType.SystemVoid
                  || returnType.IsValueType)
                    return;

                // create new postcondition
                // Contract.Ensures(Contract.Result<T>() != null);
                var newContract = new MethodContract
                {
                    Postconditions = new List<IPostcondition> {
                        new Postcondition {
                          // !=
                          Condition = new NotEquality {
                            // result
                            LeftOperand = new ReturnValue { Type = returnType, },
                            // null
                            RightOperand = new CompileTimeConstant {
                              Type = returnType,
                              Value = null,
                            },
                            Type = this.host.PlatformType.SystemBoolean,
                          },
                          // description
                          OriginalSource = "result != null",
                        }
                      }
                };

                // merge existing contracts, if any
                var contract = this.contractProvider.GetMethodContractFor(method);
                if(contract != null)
                {
                    ContractHelper.AddMethodContract(newContract,contract);
                }
                // store new contracts
                this.host.Event(CcsEventLevel.Message,"ensures not null: {0}",method);
                this.contractProvider.AssociateMethodWithContract(method,newContract);
            }
Beispiel #5
0
 /// <summary>
 /// Visits the specified method contract.
 /// </summary>
 /// <param name="methodContract">The method contract.</param>
 /// <returns></returns>
 protected virtual IMethodContract DeepCopy(MethodContract methodContract) {
   methodContract.Allocates = this.DeepCopy(methodContract.Allocates);
   methodContract.Frees = this.DeepCopy(methodContract.Frees);
   methodContract.ModifiedVariables = this.DeepCopy(methodContract.ModifiedVariables);
   methodContract.Postconditions = this.DeepCopy(methodContract.Postconditions);
   methodContract.Preconditions = this.DeepCopy(methodContract.Preconditions);
   methodContract.Reads = this.DeepCopy(methodContract.Reads);
   methodContract.ThrownExceptions = this.DeepCopy(methodContract.ThrownExceptions);
   methodContract.Writes = this.DeepCopy(methodContract.Writes);
   return methodContract;
 }
Beispiel #6
0
        /// <summary>
        /// Returns the method contract, if any, that has been associated with the given object. Returns null if no association exits.
        /// </summary>
        /// <param name="method">An object that might have been associated with a method contract. This can be any kind of object.</param>
        /// <returns></returns>
        /*?*/
        public IMethodContract GetMethodContractFor(object method)
        {
            if (this.methodsBeingExtracted.Contains(method)) {
            // hit a cycle while chasing validators/abbreviators
            // TODO: signal error
            return null;
              } else {
            this.methodsBeingExtracted.Add(method);
              }

              try {

            IMethodContract contract = this.underlyingContractProvider.GetMethodContractFor(method);
            if (contract != null) return contract == ContractDummy.MethodContract ? null : contract;

            MethodContract result = new MethodContract();
            IMethodContract primaryContract = this.primaryExtractor.GetMethodContractFor(method);
            bool found = false;
            if (primaryContract != null) {
              found = true;
              Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(result, primaryContract);
            }
            if (this.oobExtractors != null) {
              foreach (var oobProvider in this.oobExtractors) {

            IMethodReference methodReference = method as IMethodReference;
            if (methodReference == null) continue; // REVIEW: Is there anything else it could be and still find a contract for it?

            MappingMutator primaryToOobMapper = this.mapperForPrimaryToOob[oobProvider];
            var oobMethod = primaryToOobMapper.Map(methodReference);

            if (oobMethod == null) continue;

            var oobContract = oobProvider.GetMethodContractFor(oobMethod);

            if (oobContract == null) continue;

            MappingMutator oobToPrimaryMapper = this.mapperForOobToPrimary[oobProvider];
            oobContract = oobToPrimaryMapper.Map(oobContract);

            var sps = new Microsoft.Cci.MutableContracts.SubstituteParameters(this.host, oobMethod.ResolvedMethod, methodReference.ResolvedMethod);
            oobContract = sps.Visit(oobContract);

            Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(result, oobContract);
            found = true;

              }
            }

            // always cache so we don't try to extract more than once
            if (found) {
              this.underlyingContractProvider.AssociateMethodWithContract(method, result);
            } else {
              this.underlyingContractProvider.AssociateMethodWithContract(method, ContractDummy.MethodContract);
              result = null;
            }
            return result;
              } finally {
            this.methodsBeingExtracted.RemoveAt(this.methodsBeingExtracted.Count - 1);
              }
        }
        /// <summary>
        /// Adds the rsd contract to the method, it is added as a postcondition where the rsd field of the type is less than or equal to limit
        /// </summary>
        protected FieldDefinition AddRsdContractToMethod(IMethodDefinition method, ITypeReference type, string rsdName, IExpression limit, IExpression cond)
        {
            var rsdField = GetRsdField(method, rsdName, type);

            var newContract = new Microsoft.Cci.MutableContracts.MethodContract();
            var postconditions = new List<IPostcondition>();

            var limitCondition = new LessThanOrEqual()
            {
                LeftOperand = new BoundExpression()
                {
                    Definition = rsdField,
                    Type = rsdField.Type
                },
                RightOperand = limit,
                Type = _host.PlatformType.SystemBoolean,
            };

            var int32Type = new PlatformType(_host).SystemInt32;

            if (cond != null)
            {
                //cond ==> tmp <= limit =~=
                //!cond || tmp <= limit =~=
                //!cond ? tmp <= limit : true
                postconditions.Add(
                    new Microsoft.Cci.MutableContracts.PostCondition()
                    {
                        Condition = new Conditional()
                        {
                            Condition = new LogicalNot() { Operand = cond },
                            Type = int32Type,
                            ResultIfTrue = new CompileTimeConstant() { Type = int32Type, Value = 1 },
                            ResultIfFalse = limitCondition
                        },
                        OriginalSource = "!cond ? rsd <= limit : true",
                    }
                );
            }
            else
            {
                postconditions.Add(
                    new Microsoft.Cci.MutableContracts.PostCondition()
                    {
                        Condition = limitCondition,
                        OriginalSource = "rsd <= limit",
                    }
                );
            }

            newContract.Postconditions = postconditions;

            var contract = _contractProvider.GetMethodContractFor(method);
            if (contract != null)
            {
                Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(newContract, contract);
            }
            _contractProvider.AssociateMethodWithContract(method, newContract);

            return rsdField;
        }
Beispiel #8
0
 private static MethodContract FilterUserMessageAndLegacyPreconditions(IContractAwareHost host, IMethodContract contract, ITypeDefinition typeDefinition, bool keepLegacy) {
   var mc = new MethodContract(contract);
   mc.Postconditions = FilterUserMessage(host, contract.Postconditions, typeDefinition);
   mc.Preconditions = FilterUserMessageAndLegacyPreconditions(host, contract.Preconditions, typeDefinition, keepLegacy);
   mc.ThrownExceptions = FilterUserMessage(host, contract.ThrownExceptions, typeDefinition);
   return mc;
 }
Beispiel #9
0
    /// <summary>
    /// Returns a method contract containing the 'effective' contract for the given
    /// method definition. The effective contract contains all contracts for the method:
    /// any that it has on its own, as well as all those inherited from any methods
    /// that it overrides or interface methods that it implements (either implicitly
    /// or explicitly).
    /// All parameters in inherited contracts are substituted for by
    /// the method's own parameters.
    /// If there are no contracts, then it returns null.
    /// Any preconditions that were written as legacy-preconditions or calls to Requires&lt;E&gt; are
    /// included iff <paramref name="keepLegacyPreconditions"/>.
    /// </summary>
    public static IMethodContract GetMethodContractForIncludingInheritedContracts(IContractAwareHost host, IMethodDefinition methodDefinition, bool keepLegacyPreconditions = true) {
      MethodContract cumulativeContract = new MethodContract();
      bool atLeastOneContract = false;
      IMethodContract/*?*/ mc = ContractHelper.GetMethodContractFor(host, methodDefinition);
      if (mc != null) {
        Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, mc);
        atLeastOneContract = true;
      }
      #region Overrides of base class methods
      if (!methodDefinition.IsNewSlot) { // REVIEW: Is there a better test?
        IMethodDefinition overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(methodDefinition) as IMethodDefinition;
        while (overriddenMethod != null && !(overriddenMethod is Dummy)) {
          IMethodContract/*?*/ overriddenContract = ContractHelper.GetMethodContractFor(host, overriddenMethod);
          if (overriddenContract != null) {

            overriddenContract = CopyContractIntoNewContext(host, overriddenContract, methodDefinition, overriddenMethod);
            overriddenContract = FilterUserMessageAndLegacyPreconditions(host, overriddenContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions);

            // if the method is generic, then need to specialize the contract to have the same method type parameters as the method
            if (methodDefinition.IsGeneric) {
              var d = new Dictionary<uint, ITypeReference>();
              IteratorHelper.Zip(overriddenMethod.GenericParameters, methodDefinition.GenericParameters, (i, j) => d.Add(i.InternedKey, j));
              var cs = new CodeSpecializer(host, d);
              overriddenContract = cs.Rewrite(overriddenContract);
            }

            Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, overriddenContract);
            atLeastOneContract = true;
          }
          overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(overriddenMethod) as IMethodDefinition;
        }
      }
      #endregion Overrides of base class methods
      #region Implicit interface implementations
      foreach (IMethodDefinition ifaceMethod in ContractHelper.GetAllImplicitlyImplementedInterfaceMethods(methodDefinition)) {
        IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod);
        if (ifaceContract == null) continue;
        ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod);
        ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions);
        Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract);
        atLeastOneContract = true;
      }
      #endregion Implicit interface implementations
      #region Explicit interface implementations and explicit method overrides
      foreach (IMethodReference ifaceMethodRef in MemberHelper.GetExplicitlyOverriddenMethods(methodDefinition)) {
        IMethodDefinition/*?*/ ifaceMethod = ifaceMethodRef.ResolvedMethod;
        if (ifaceMethod == null) continue;
        IMethodContract/*?*/ ifaceContract = ContractHelper.GetMethodContractFor(host, ifaceMethod);
        if (ifaceContract == null) continue;
        ifaceContract = CopyContractIntoNewContext(host, ifaceContract, methodDefinition, ifaceMethod);
        ifaceContract = FilterUserMessageAndLegacyPreconditions(host, ifaceContract, methodDefinition.ContainingTypeDefinition, keepLegacyPreconditions);
        Microsoft.Cci.MutableContracts.ContractHelper.AddMethodContract(cumulativeContract, ifaceContract);
        atLeastOneContract = true;
      }
      #endregion Explicit interface implementations and explicit method overrides
      return atLeastOneContract ? cumulativeContract : null;
    }
Beispiel #10
0
    /// <summary>
    /// Given a method definition for a getter or setter that the compiler produced for an auto-property,
    /// mine the type contract and extract contracts from any invariants that mention the property.
    /// If the <paramref name="methodDefinition"/> is a getter, then the returned method contract contains
    /// only postconditions.
    /// If the <paramref name="methodDefinition"/> is a setter, then the returned method contract contains
    /// only preconditions.
    /// If an invariant does not mention the property, then it is not represented in the returned contract.
    /// </summary>
    /// <param name="host"></param>
    /// <param name="typeContract">
    /// This must be the type contract corresponding to the containing type of <paramref name="methodDefinition"/>.
    /// </param>
    /// <param name="methodDefinition">
    /// A method definition that should be a getter or setter for an auto-property. If it is not, then null is returned.
    /// </param>
    /// <returns>Either null or a method contract containing pre- or postconditions (mutually exclusive)
    /// mined from the invariants contained in the <paramref name="typeContract"/>.
    /// </returns>
    public static MethodContract/*?*/ GetAutoPropertyContract(IMetadataHost host, ITypeContract typeContract, IMethodDefinition methodDefinition) {
      // If the method was generated for an auto-property, then need to see if a contract can be derived by mining the invariant.
      if (!methodDefinition.IsSpecialName) return null;
      bool isPropertyGetter = methodDefinition.Name.Value.StartsWith("get_");
      bool isPropertySetter = methodDefinition.Name.Value.StartsWith("set_");
      //^ assume !(isPropertyGetter && isPropertySetter); // maybe neither, but never both!
      if (!ContractHelper.IsAutoPropertyMember(host, methodDefinition)) return null;
      IMethodDefinition getter = null;
      IMethodDefinition setter = null;
      // needs to have both a setter and a getter
      var ct = methodDefinition.ContainingTypeDefinition;
      if (isPropertyGetter) {
        getter = methodDefinition;
        var mms = ct.GetMatchingMembersNamed(host.NameTable.GetNameFor("set_" + methodDefinition.Name.Value.Substring(4)), false, md => ContractHelper.IsAutoPropertyMember(host, md));
        foreach (var mem in mms) {
          setter = mem as IMethodDefinition;
          break;
        }
      } else { // isPropertySetter
        setter = methodDefinition;
        var mms = ct.GetMatchingMembersNamed(host.NameTable.GetNameFor("get_" + methodDefinition.Name.Value.Substring(4)), false, md => ContractHelper.IsAutoPropertyMember(host, md));
        foreach (var mem in mms) {
          getter = mem as IMethodDefinition;
          break;
        }
      }

      // Silent error?
      if (getter == null || setter == null) return null;

      // If the auto-property inherits any contracts then it doesn't derive any from the invariant
      var inheritsContract = false;
      IMethodDefinition overriddenMethod = MemberHelper.GetImplicitlyOverriddenBaseClassMethod(getter) as IMethodDefinition;
      var isOverride = getter.IsNewSlot && overriddenMethod != null && !(overriddenMethod is Dummy);
      inheritsContract |= isOverride;
      if (!inheritsContract) {
        inheritsContract |= IteratorHelper.EnumerableIsNotEmpty(ContractHelper.GetAllImplicitlyImplementedInterfaceMethods(getter));
      }
      if (!inheritsContract) {
        inheritsContract |= IteratorHelper.EnumerableIsNotEmpty(MemberHelper.GetExplicitlyOverriddenMethods(getter));
      }

      if (inheritsContract) return null;

      if (typeContract == null) return null;
      MethodContract derivedMethodContract = null;
      if (isPropertyGetter) {
        var derivedPostConditions = new List<IPostcondition>();
        foreach (var i in typeContract.Invariants) {
          if (!MemberFinder.ExpressionContains(i.Condition, getter)) continue;

          var v = Visibility.MostRestrictiveVisibility(host, i.Condition);
          var currentVisibility = getter.Visibility;
          var intersection = TypeHelper.VisibilityIntersection(v, currentVisibility);
          if (intersection != currentVisibility) continue;

          derivedPostConditions.Add(
            new Postcondition() {
              Condition = ReplaceAutoPropGetter.MakeEnsures(host, getter, i.Condition),
              Description = i.Description,
              OriginalSource = i.OriginalSource,
              Locations = new List<ILocation>(i.Locations),
            });
        }
        if (0 < derivedPostConditions.Count) {
          derivedMethodContract = new MethodContract() {
            Postconditions = derivedPostConditions,
          };
        }
      } else { // isPropertySetter
        var derivedPreconditions = new List<IPrecondition>();
        foreach (var i in typeContract.Invariants) {
          if (!MemberFinder.ExpressionContains(i.Condition, getter)) continue;

          var v = Visibility.MostRestrictiveVisibility(host, i.Condition);
          var currentVisibility = setter.Visibility;
          var intersection = TypeHelper.VisibilityIntersection(v, currentVisibility);
          if (intersection != currentVisibility) continue;

          derivedPreconditions.Add(
            new Precondition() {
              Condition = ReplaceAutoPropGetter.MakeRequires(host, getter, setter, i.Condition),
              Description = i.Description,
              OriginalSource = i.OriginalSource,
              Locations = new List<ILocation>(i.Locations),
            });
        }
        if (0 < derivedPreconditions.Count) {
          derivedMethodContract = new MethodContract() {
            Preconditions = derivedPreconditions,
          };
        }
      }
      return derivedMethodContract;
    }