Exemplo n.º 1
0
 public override Expression VisitBinaryExpression(BinaryExpression binaryExpression) {
   Expression result = base.VisitBinaryExpression(binaryExpression);
   SpecSharpCompilerOptions options = this.currentOptions as SpecSharpCompilerOptions;
   if (options != null && options.CheckContractAdmissibility) {
     if ((insideMethodContract || insideInvariant) &&
         (binaryExpression.NodeType == NodeType.Eq || binaryExpression.NodeType == NodeType.Ne) &&
           binaryExpression.Operand1 != null && binaryExpression.Operand1.Type != null &&
           !binaryExpression.Operand1.Type.IsValueType) {
       MightReturnNewlyAllocatedObjectVisitor visitor = new MightReturnNewlyAllocatedObjectVisitor(this);
       this.TransferStateTo(visitor);
       visitor.CurrentMethod = this.currentMethod;
       visitor.VisitExpression(binaryExpression.Operand1);
       if (visitor.IsMRNAO) {
         visitor.IsMRNAO = false;
         visitor.VisitExpression(binaryExpression.Operand2);
         if (visitor.IsMRNAO)
           this.HandleError(binaryExpression, Error.BothOperandsOfReferenceComparisonMightBeNewlyAllocated);
       }
     }
   }
   return result;
 }
Exemplo n.º 2
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);
    }