//===- ConstraintManager.h - Constraints on symbolic values. ----*- C++ -*-===//
 
//
 
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 
// See https://llvm.org/LICENSE.txt for license information.
 
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
//
 
//===----------------------------------------------------------------------===//
 
//
 
//  This file defined the interface to manage constraints on symbolic values.
 
//
 
//===----------------------------------------------------------------------===//
 
 
 
#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
 
#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H
 
 
 
#include "clang/Basic/LLVM.h"
 
#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState_Fwd.h"
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 
#include "clang/StaticAnalyzer/Core/PathSensitive/SymExpr.h"
 
#include "llvm/Support/SaveAndRestore.h"
 
#include <memory>
 
#include <optional>
 
#include <utility>
 
 
 
namespace llvm {
 
 
 
class APSInt;
 
 
 
} // namespace llvm
 
 
 
namespace clang {
 
namespace ento {
 
 
 
class ProgramStateManager;
 
class ExprEngine;
 
class SymbolReaper;
 
 
 
class ConditionTruthVal {
 
  std::optional<bool> Val;
 
 
 
public:
 
  /// Construct a ConditionTruthVal indicating the constraint is constrained
 
  /// to either true or false, depending on the boolean value provided.
 
  ConditionTruthVal(bool constraint) : Val(constraint) {}
 
 
 
  /// Construct a ConstraintVal indicating the constraint is underconstrained.
 
  ConditionTruthVal() = default;
 
 
 
  /// \return Stored value, assuming that the value is known.
 
  /// Crashes otherwise.
 
  bool getValue() const {
 
    return *Val;
 
  }
 
 
 
  /// Return true if the constraint is perfectly constrained to 'true'.
 
  bool isConstrainedTrue() const { return Val && *Val; }
 
 
 
  /// Return true if the constraint is perfectly constrained to 'false'.
 
  bool isConstrainedFalse() const { return Val && !*Val; }
 
 
 
  /// Return true if the constrained is perfectly constrained.
 
  bool isConstrained() const { return Val.has_value(); }
 
 
 
  /// Return true if the constrained is underconstrained and we do not know
 
  /// if the constraint is true of value.
 
  bool isUnderconstrained() const { return !Val.has_value(); }
 
};
 
 
 
class ConstraintManager {
 
public:
 
  ConstraintManager() = default;
 
  virtual ~ConstraintManager();
 
 
 
  virtual bool haveEqualConstraints(ProgramStateRef S1,
 
                                    ProgramStateRef S2) const = 0;
 
 
 
  ProgramStateRef assume(ProgramStateRef state, DefinedSVal Cond,
 
                         bool Assumption);
 
 
 
  using ProgramStatePair = std::pair<ProgramStateRef, ProgramStateRef>;
 
 
 
  /// Returns a pair of states (StTrue, StFalse) where the given condition is
 
  /// assumed to be true or false, respectively.
 
  /// (Note that these two states might be equal if the parent state turns out
 
  /// to be infeasible. This may happen if the underlying constraint solver is
 
  /// not perfectly precise and this may happen very rarely.)
 
  ProgramStatePair assumeDual(ProgramStateRef State, DefinedSVal Cond);
 
 
 
  ProgramStateRef assumeInclusiveRange(ProgramStateRef State, NonLoc Value,
 
                                       const llvm::APSInt &From,
 
                                       const llvm::APSInt &To, bool InBound);
 
 
 
  /// Returns a pair of states (StInRange, StOutOfRange) where the given value
 
  /// is assumed to be in the range or out of the range, respectively.
 
  /// (Note that these two states might be equal if the parent state turns out
 
  /// to be infeasible. This may happen if the underlying constraint solver is
 
  /// not perfectly precise and this may happen very rarely.)
 
  ProgramStatePair assumeInclusiveRangeDual(ProgramStateRef State, NonLoc Value,
 
                                            const llvm::APSInt &From,
 
                                            const llvm::APSInt &To);
 
 
 
  /// If a symbol is perfectly constrained to a constant, attempt
 
  /// to return the concrete value.
 
  ///
 
  /// Note that a ConstraintManager is not obligated to return a concretized
 
  /// value for a symbol, even if it is perfectly constrained.
 
  /// It might return null.
 
  virtual const llvm::APSInt* getSymVal(ProgramStateRef state,
 
                                        SymbolRef sym) const {
 
    return nullptr;
 
  }
 
 
 
  /// Scan all symbols referenced by the constraints. If the symbol is not
 
  /// alive, remove it.
 
  virtual ProgramStateRef removeDeadBindings(ProgramStateRef state,
 
                                                 SymbolReaper& SymReaper) = 0;
 
 
 
  virtual void printJson(raw_ostream &Out, ProgramStateRef State,
 
                         const char *NL, unsigned int Space,
 
                         bool IsDot) const = 0;
 
 
 
  virtual void printValue(raw_ostream &Out, ProgramStateRef State,
 
                          SymbolRef Sym) {}
 
 
 
  /// Convenience method to query the state to see if a symbol is null or
 
  /// not null, or if neither assumption can be made.
 
  ConditionTruthVal isNull(ProgramStateRef State, SymbolRef Sym) {
 
    return checkNull(State, Sym);
 
  }
 
 
 
protected:
 
  /// A helper class to simulate the call stack of nested assume calls.
 
  class AssumeStackTy {
 
  public:
 
    void push(const ProgramState *S) { Aux.push_back(S); }
 
    void pop() { Aux.pop_back(); }
 
    bool contains(const ProgramState *S) const {
 
      return llvm::is_contained(Aux, S);
 
    }
 
 
 
  private:
 
    llvm::SmallVector<const ProgramState *, 4> Aux;
 
  };
 
  AssumeStackTy AssumeStack;
 
 
 
  virtual ProgramStateRef assumeInternal(ProgramStateRef state,
 
                                         DefinedSVal Cond, bool Assumption) = 0;
 
 
 
  virtual ProgramStateRef assumeInclusiveRangeInternal(ProgramStateRef State,
 
                                                       NonLoc Value,
 
                                                       const llvm::APSInt &From,
 
                                                       const llvm::APSInt &To,
 
                                                       bool InBound) = 0;
 
 
 
  /// canReasonAbout - Not all ConstraintManagers can accurately reason about
 
  ///  all SVal values.  This method returns true if the ConstraintManager can
 
  ///  reasonably handle a given SVal value.  This is typically queried by
 
  ///  ExprEngine to determine if the value should be replaced with a
 
  ///  conjured symbolic value in order to recover some precision.
 
  virtual bool canReasonAbout(SVal X) const = 0;
 
 
 
  /// Returns whether or not a symbol is known to be null ("true"), known to be
 
  /// non-null ("false"), or may be either ("underconstrained").
 
  virtual ConditionTruthVal checkNull(ProgramStateRef State, SymbolRef Sym);
 
 
 
  template <typename AssumeFunction>
 
  ProgramStatePair assumeDualImpl(ProgramStateRef &State,
 
                                  AssumeFunction &Assume);
 
};
 
 
 
std::unique_ptr<ConstraintManager>
 
CreateRangeConstraintManager(ProgramStateManager &statemgr,
 
                             ExprEngine *exprengine);
 
 
 
std::unique_ptr<ConstraintManager>
 
CreateZ3ConstraintManager(ProgramStateManager &statemgr,
 
                          ExprEngine *exprengine);
 
 
 
} // namespace ento
 
} // namespace clang
 
 
 
#endif // LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_CONSTRAINTMANAGER_H