public static bool MethodIsOwned(Method m) {
   if (m == null) return false;
   return m.GetAttribute(SystemTypes.RepAttribute) != null || m.GetAttribute(SystemTypes.PeerAttribute) != null;
 }
 public static bool MethodIsRep(Method m) {
   if (m == null) return false;
   AttributeNode attr = m.GetAttribute(SystemTypes.RepAttribute);
   return (attr != null);
 }
 public static bool MethodIsElementCollection(Method m) {
   if (m == null) return false;
   return m.GetAttribute(SystemTypes.ElementCollectionAttribute) != null;
 }
 /// <summary>
 /// Returns true iff method is marked [Element] or is the [] getter or method is marked ElementCollection.
 /// </summary>
 private bool MethodIsElementOrElementCollection(Method method) {
   if (method == null) return false;
   if (method.GetAttribute(SystemTypes.ElementAttribute) != null)
     return true;
   if ((method.DeclaringType != null && (method.DeclaringType.IsAssignableTo(SystemTypes.IEnumerable) || checker.HasEnumerablePattern(method.DeclaringType))) &&
        method.IsPropertyGetter && method.Name.ToString().Equals(StandardIds.getItem.ToString()))
     return true;
   if (method.GetAttribute(SystemTypes.ElementCollectionAttribute) != null)
     return true;
   return false;
 }
 // Note: second parameter is just optimiziation for the case when we do know that m's spec contains method call(s)
 private int RecursionTerminationValue(Method m, bool doMethodCallCheck) {
   if (m == null) return System.Int32.MaxValue;
   AttributeNode attr = m.GetAttribute(SystemTypes.RecursionTerminationAttribute);
   if (attr == null) { // recursion termination not specified
     if (!doMethodCallCheck)
       return System.Int32.MaxValue;
     else {
       CallAndResultVisitor visitor = new CallAndResultVisitor(this.checker);
       if (m.Contract != null) {
         foreach (Ensures ens in m.Contract.Ensures) {
           visitor.HasCall = false;
           visitor.VisitExpression(ens.PostCondition);
           if (visitor.HasCall)
             return System.Int32.MaxValue; // method spec contains call
         }
         foreach (Requires req in m.Contract.Requires) {
           visitor.HasCall = false;
           visitor.VisitExpression(req.Condition);
           if (visitor.HasCall)
             return System.Int32.MaxValue; // method spec contains call
         }
       }
       return 0; // did not find call in method spec
     }
   }
   ExpressionList exprs = attr.Expressions;
   if (exprs == null || exprs.Count == 0) return 0; // default value for attribute w/o param
   Expression arg = exprs[0];
   Literal lit = arg as Literal;
   if (lit != null && lit.Value is int)
     return (int)lit.Value;
   return System.Int32.MaxValue;
 }
Example #6
0
    public override Method VisitMethod(Method method) {
      if (method == null) return null;

      // Need to call base visitor so that contract inheritance has already happened
      Method result = base.VisitMethod(method);

      #region MustOverride
      if (method.GetAttribute(Runtime.MustOverrideAttribute) != null
        && !method.IsVirtual) {
        this.HandleError(method.Name, Error.MethodMarkedMustOverrideMustBeVirtual, this.GetMethodSignature(method));
      }
      #endregion
      #region Check constraints when the method overrides a virtual method or implements an interface method
      if ((method.ImplementedInterfaceMethods != null && method.ImplementedInterfaceMethods.Count > 0)
            || (method.ImplicitlyImplementedInterfaceMethods != null && method.ImplicitlyImplementedInterfaceMethods.Count > 0)
            || method.OverriddenMethod != null
            || (method.IsPropertyGetter && method.DeclaringMember.OverriddenMember != null)
        ) {
        #region Purity must be consistent
        AttributeNode purityMarker = null;
        Method otherMethod = null;
        for (int i = 0, n = method.ImplementedInterfaceMethods == null ? 0 : method.ImplementedInterfaceMethods.Count; i < n; i++) {
          Method m = method.ImplementedInterfaceMethods[i];
          if (m == null) continue;
          purityMarker = GetPurityAttribute(m);
          if (purityMarker != null) {
            otherMethod = m;
            break; // FIXME! if one is marked, all should be marked the same!!
          }
        }
        if (otherMethod == null) {
          for (int i = 0, n = method.ImplicitlyImplementedInterfaceMethods == null ? 0 : method.ImplicitlyImplementedInterfaceMethods.Count; i < n; i++) {
            Method m = method.ImplicitlyImplementedInterfaceMethods[i];
            if (m == null) continue;
            purityMarker = GetPurityAttribute(m);
            if (purityMarker != null) {
              otherMethod = m;
              break; // FIXME! if one is marked, all should be marked the same!!
            }
          }
        }
        if (otherMethod == null){
          if (method.OverriddenMethod != null) {
            purityMarker = GetPurityAttribute(method.OverriddenMethod);
            if (purityMarker != null) {
              otherMethod = method.OverriddenMethod;
            }
          }
        }
        if (otherMethod == null) {
          if (method.IsPropertyGetter && method.DeclaringMember.OverriddenMember != null) {
            Property p = method.DeclaringMember.OverriddenMember as Property;
            if (p != null) {
              purityMarker = GetPurityAttribute(p.Getter);
              if (purityMarker != null) {
                otherMethod = p.Getter;
              }
            }
          }
        }
        Method methodToComplainAbout = method;
        ProxyMethod pm = methodToComplainAbout as ProxyMethod;
        if (pm != null) {
          methodToComplainAbout = pm.ProxyFor;
        }
        if (purityMarker != null) {
          if (!PurityLessThanOrEqualTo(otherMethod, methodToComplainAbout)) {
            string marking;
            if (otherMethod.IsPure)
              marking = "[Pure]";
            else if (otherMethod.IsConfined)
              marking = "[Pure]";
            else //(otherMethod.IsStateIndependent)
              marking = "[Pure][Reads(ReadsAttribute.Reads.Nothing)]";
            this.HandleError(methodToComplainAbout.Name, Error.MethodInheritingPurityMustBeMarked,
              this.GetMethodSignature(methodToComplainAbout),
              this.GetMethodSignature(otherMethod),
              marking);
          }
        }
        #endregion Purity must be consistent
      }
      #endregion Check constraints when the method overrides a virtual method or implements an inteface method

      #region Additive
      AttributeNode attrNode = method.GetAttribute(SystemTypes.AdditiveAttribute);
      AttributeNode overridenAttr = null;
      bool isAdditive = IsAdditive(attrNode);
      if (isAdditive && attrNode != null) {
        if (attrNode.Target == AttributeTargets.ReturnValue) {
          if (method.ReturnType.IsValueType) {
            this.HandleError(attrNode, Error.AttributeAllowedOnlyOnReferenceTypeParameters, this.GetTypeName(attrNode.Type));
          }
        } else if (method.DeclaringType.IsValueType) {
          this.HandleError(attrNode, Error.AttributeAllowedOnlyOnReferenceTypeParameters, this.GetTypeName(attrNode.Type));
        } else if (method.IsStatic) {
          // don't need to check for whether method is a ctor (which would be an error) because
          // if the method is a ctor, then an error will already have been generated since
          // ctors are not listed as a valid target for [Additive]
          this.HandleError(method, Error.StaticMethodCannotBeMarkedWithAttribute, this.GetTypeName(SystemTypes.AdditiveAttribute));
        }
      }
      Method overriden = method.OverriddenMethod;
      if (overriden != null) {
        overridenAttr = overriden.GetAttribute(SystemTypes.AdditiveAttribute);
        if (IsAdditive(overridenAttr) != isAdditive)
          this.HandleError(method, Error.OverrideMethodNotMarkedWithAttribute, this.GetTypeName(SystemTypes.AdditiveAttribute));
      }
      #endregion
      #region Inside
      attrNode = method.GetAttribute(SystemTypes.InsideAttribute);
      overridenAttr = null;
      bool isInside = IsInside(attrNode);
      if (isInside && attrNode != null) {
        if (attrNode.Target == AttributeTargets.ReturnValue) {
          if (method.ReturnType.IsValueType) {
            this.HandleError(attrNode, Error.AttributeAllowedOnlyOnReferenceTypeParameters, this.GetTypeName(attrNode.Type));
          }
        } else if (method.DeclaringType.IsValueType) {
          this.HandleError(attrNode, Error.AttributeAllowedOnlyOnReferenceTypeParameters, this.GetTypeName(attrNode.Type));
        } else if (method.DeclaringType is Interface) {
          this.HandleError(attrNode, Error.AttributeNotAllowedOnInterfaceMethods, this.GetTypeName(attrNode.Type));
        } else if (method.IsVirtual) {
          this.HandleError(method, Error.VirtualMethodWithNonVirtualMethodAttribute, this.GetTypeName(SystemTypes.InsideAttribute));
        }
      }
      #endregion
      #region Captured
      attrNode = method.GetAttribute(SystemTypes.CapturedAttribute);
      overridenAttr = null;
      bool isCaptured = attrNode != null;
      if (isCaptured) {
        if (attrNode.Target != AttributeTargets.ReturnValue && method.DeclaringType.IsValueType) {
          // if its target is "return", then it will already have gotten an error for that
          // just because that isn't included in the valid targets for that attribute
          this.HandleError(attrNode, Error.AttributeAllowedOnlyOnReferenceTypeParameters, this.GetTypeName(attrNode.Type));
        }
      }
      overriden = method.OverriddenMethod;
      if (overriden != null) {
        overridenAttr = overriden.GetAttribute(SystemTypes.CapturedAttribute);
        if (overridenAttr != null && !isCaptured)
          this.HandleError(method, Error.OverrideMethodNotMarkedWithAttribute, this.GetTypeName(SystemTypes.CapturedAttribute));
      }
      #endregion
      #region Can't have both [Rep] and [Peer]
      bool isRep = method.GetAttribute(SystemTypes.RepAttribute) != null;
      bool isPeer = method.GetAttribute(SystemTypes.PeerAttribute) != null;
      if (isRep && isPeer) {
        this.HandleError(method, Error.ConflictingAttributes, this.GetTypeName(SystemTypes.RepAttribute),
          this.GetTypeName(SystemTypes.PeerAttribute));
      }
      #endregion

      #region NoReferenceComparison
      attrNode = method.GetAttribute(SystemTypes.NoReferenceComparisonAttribute);
      overridenAttr = null;
      if (overriden != null)
        overridenAttr = overriden.GetAttribute(SystemTypes.NoReferenceComparisonAttribute);
      if (attrNode == null && overridenAttr != null)
        this.HandleError(method, Error.NoReferenceComparisonAttrNotCopied, method.Name.ToString());
      else if (attrNode != null && !(method.IsPure || method.IsConfined || method.IsStateIndependent))
        this.HandleError(method, Error.NonPureMarkedNoReferenceComparison);
      else if (attrNode != null) {
        NoReferenceComparisonVisitor visitor = new NoReferenceComparisonVisitor(this);
        this.TransferStateTo(visitor);
        visitor.Visit(method.Body);
        if (!visitor.HasNoReferenceComparison)
          this.HandleError(method, Error.ViolatedNoReferenceComparison, method.Name.ToString());
      }
      #endregion
      #region ResultNotNewlyAllocated
      attrNode = method.GetAttribute(SystemTypes.ResultNotNewlyAllocatedAttribute);
      overridenAttr = null;
      if (overriden != null)
        overridenAttr = overriden.GetAttribute(SystemTypes.ResultNotNewlyAllocatedAttribute);
      if (attrNode == null && overridenAttr != null)
        this.HandleError(method, Error.ResultNotNewlyAllocatedAttrNotCopied, method.Name.ToString());
      else if (attrNode != null && !(method.IsPure || method.IsConfined || method.IsStateIndependent))
        this.HandleError(method, Error.NonPureMarkedResultNotNewlyAllocated);
      else if (attrNode != null && (method.ReturnType == null || method.ReturnType.IsValueType))
        this.HandleError(method, Error.NonRefTypeMethodMarkedResultNotNewlyAllocated);
      #endregion
      #region Pure methods cannot have ref parameters
      if (!method.IsPropertyGetter && (method.IsPure || method.IsConfined || method.IsStateIndependent)) {
        // don't check property getters: they already will have an error if they have out or ref parameters.
        for (int i = 0, n = method.Parameters == null ? 0 : method.Parameters.Count; i < n; i++) {
          Parameter p = method.Parameters[i];
          if (p.IsOut) continue;
          Reference r = p.Type as Reference;
          if (r != null) {
            this.HandleError(p, Error.PureMethodCannotHaveRefParam);
          }
        }
      }
      #endregion
      #region Pure methods cannot have modifies clauses
      if ((method.IsPure || method.IsConfined || method.IsStateIndependent) && method.Contract != null && method.Contract.Modifies != null && 0 < method.Contract.Modifies.Count) {
        this.HandleError(method, Error.PureMethodCannotHaveModifies);
      }
      #endregion Pure methods cannot have modifies clauses

      bool b;
      TypeNode returnType = method.ReturnType;
      if (returnType != null)
        returnType = returnType.StripOptionalModifiers(out b);
      if ((method.GetAttribute(SystemTypes.RepAttribute) != null || method.GetAttribute(SystemTypes.PeerAttribute) != null) && 
          !(returnType.IsReferenceType || (method.IsPropertyGetter && ((Property)method.DeclaringMember).Type.IsReferenceType)))
        this.HandleError(method, Error.BadUseOfOwnedOnMethod);
      else if (method.IsVirtual && !method.IsPropertyGetter && MemberIsRep(method)) // note: second conjunct mainly to get Boogie through
        this.HandleError(method, Error.UseOfRepOnVirtualMethod);

      #region Make sure purity attributes are used correctly
      AttributeNode pureAttr = method.GetAttributeFromSelfOrDeclaringMember(SystemTypes.PureAttribute);
      AttributeNode readsAttr = method.GetAttributeFromSelfOrDeclaringMember(SystemTypes.ReadsAttribute);
      if (readsAttr != null) {
        if (pureAttr == null) {
          this.HandleError(method, Error.ReadsWithoutPure);
        }
        Literal l = readsAttr.GetPositionalArgument(0) as Literal;
        // default ctor for Reads sets it to Owned
        Microsoft.Contracts.ReadsAttribute.Reads r =
          l == null ?
          Microsoft.Contracts.ReadsAttribute.Reads.Owned :
          (Microsoft.Contracts.ReadsAttribute.Reads)l.Value;
        switch (r) {
          case Microsoft.Contracts.ReadsAttribute.Reads.Everything:
            if (!method.IsPure)
              this.HandleError(method, Error.InconsistentPurityAttributes);
            break;
          case Microsoft.Contracts.ReadsAttribute.Reads.Nothing:
            if (!method.IsStateIndependent)
              this.HandleError(method, Error.InconsistentPurityAttributes);
            break;
          case Microsoft.Contracts.ReadsAttribute.Reads.Owned:
            if (!method.IsConfined)
              this.HandleError(method, Error.PureOwnedNotAllowed);
            break;
        }
      }
      #endregion Make sure purity attributes are used correctly

      return result;
    }