Example #1
0
    public override Expression VisitMethodCall(MethodCall call) {
      if (call == null) return null;
      MemberBinding mb = call.Callee as MemberBinding;
      Method m = mb == null ? null : mb.BoundMember as Method;
      if (m != null && !this.typeSystem.insideUnsafeCode) {
        bool badMethod = m.ReturnType is Pointer;
        for (int i = 0, n = m.Parameters == null ? 0 : m.Parameters.Count; i < n; i++) {
          Parameter p = m.Parameters[i];
          if (p == null) continue;
          if (p.Type is Pointer) { badMethod = true; break; }
        }
        if (badMethod && call.SourceContext.Document != null) {
          this.HandleError(call, Error.UnsafeNeeded);
          return null;
        }
      }
      #region Pure methods that have an out parameter cannot be used in a contract
      // This is checked here and not where ref parameters are checked (VisitMethod)
      // because we want to allow pure methods to have out parameters for use in purity
      // analysis. It is just that Boogie doesn't generate the right axioms, etc. for
      // pure methods that have out parameters. So for now, just don't allow them in
      // contracts.
      if ((insideMethodContract || insideInvariant || insideAssertOrAssume)
        && m != null && !m.IsPropertyGetter
        && (m.IsPure || m.IsConfined || m.IsStateIndependent)) {
        // don't check property getters: they already will have an error if they have out parameters.
        for (int i = 0, n = m.Parameters == null ? 0 : m.Parameters.Count; i < n; i++) {
          Parameter p = m.Parameters[i];
          if (p.IsOut) {
            this.HandleError(p, Error.PureMethodWithOutParamUsedInContract);
          }
        }
      }
      #endregion


      // if any two arguments Might Return Newly Allocated Object then method must be marked NoReferenceComparison
      if ((insideMethodContract || insideInvariant || insideAssertOrAssume) && m != null && mb != null) {
        int MRNAOargs = 0;
        MightReturnNewlyAllocatedObjectVisitor visitor = new MightReturnNewlyAllocatedObjectVisitor(this);
        this.TransferStateTo(visitor);
        visitor.CurrentMethod = this.currentMethod;
        // receiver
        visitor.Visit(mb);
        if (visitor.IsMRNAO)
          MRNAOargs++;
        else // parameters          
          for (int i = 0, n = call.Operands == null ? 0 : call.Operands.Count; i < n; i++) {
            Expression exp = call.Operands[i];
            visitor.IsMRNAO = false;
            visitor.Visit(exp);
            if (visitor.IsMRNAO) {
              MRNAOargs++;
            }
          }
        if (MRNAOargs > 1 && m.GetAttribute(SystemTypes.NoReferenceComparisonAttribute) == null) {
          this.HandleError(call, Error.MethodShouldBeMarkedNoReferenceComparison, m.Name.ToString());
          return null;
        }

      }

      return base.VisitMethodCall(call);
    }