Exemple #1
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;
    }
Exemple #2
0
 private AttributeNode GetPurityAttribute(Method method) {
   if (method == null || method.Attributes == null) return null;
   return method.GetAttributeFromSelfOrDeclaringMember(SystemTypes.PureAttribute);
 }