1//== SimpleConstraintManager.cpp --------------------------------*- C++ -*--==//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9//  This file defines SimpleConstraintManager, a class that provides a
10//  simplified constraint manager interface, compared to ConstraintManager.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/StaticAnalyzer/Core/PathSensitive/SimpleConstraintManager.h"
15#include "clang/StaticAnalyzer/Core/PathSensitive/APSIntType.h"
16#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
17#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
18#include <optional>
19
20namespace clang {
21
22namespace ento {
23
24SimpleConstraintManager::~SimpleConstraintManager() {}
25
26ProgramStateRef SimpleConstraintManager::assumeInternal(ProgramStateRef State,
27                                                        DefinedSVal Cond,
28                                                        bool Assumption) {
29  // If we have a Loc value, cast it to a bool NonLoc first.
30  if (std::optional<Loc> LV = Cond.getAs<Loc>()) {
31    SValBuilder &SVB = State->getStateManager().getSValBuilder();
32    QualType T;
33    const MemRegion *MR = LV->getAsRegion();
34    if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
35      T = TR->getLocationType();
36    else
37      T = SVB.getContext().VoidPtrTy;
38
39    Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
40  }
41
42  return assume(State, Cond.castAs<NonLoc>(), Assumption);
43}
44
45ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
46                                                NonLoc Cond, bool Assumption) {
47  State = assumeAux(State, Cond, Assumption);
48  if (EE)
49    return EE->processAssume(State, Cond, Assumption);
50  return State;
51}
52
53ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
54                                                   NonLoc Cond,
55                                                   bool Assumption) {
56
57  // We cannot reason about SymSymExprs, and can only reason about some
58  // SymIntExprs.
59  if (!canReasonAbout(Cond)) {
60    // Just add the constraint to the expression without trying to simplify.
61    SymbolRef Sym = Cond.getAsSymbol();
62    assert(Sym);
63    return assumeSymUnsupported(State, Sym, Assumption);
64  }
65
66  switch (Cond.getKind()) {
67  default:
68    llvm_unreachable("'Assume' not implemented for this NonLoc");
69
70  case nonloc::SymbolValKind: {
71    nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
72    SymbolRef Sym = SV.getSymbol();
73    assert(Sym);
74    return assumeSym(State, Sym, Assumption);
75  }
76
77  case nonloc::ConcreteIntKind: {
78    bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
79    bool isFeasible = b ? Assumption : !Assumption;
80    return isFeasible ? State : nullptr;
81  }
82
83  case nonloc::PointerToMemberKind: {
84    bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer();
85    bool IsFeasible = IsNull ? Assumption : !Assumption;
86    return IsFeasible ? State : nullptr;
87  }
88
89  case nonloc::LocAsIntegerKind:
90    return assumeInternal(State, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
91                          Assumption);
92  } // end switch
93}
94
95ProgramStateRef SimpleConstraintManager::assumeInclusiveRangeInternal(
96    ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
97    const llvm::APSInt &To, bool InRange) {
98
99  assert(From.isUnsigned() == To.isUnsigned() &&
100         From.getBitWidth() == To.getBitWidth() &&
101         "Values should have same types!");
102
103  if (!canReasonAbout(Value)) {
104    // Just add the constraint to the expression without trying to simplify.
105    SymbolRef Sym = Value.getAsSymbol();
106    assert(Sym);
107    return assumeSymInclusiveRange(State, Sym, From, To, InRange);
108  }
109
110  switch (Value.getKind()) {
111  default:
112    llvm_unreachable("'assumeInclusiveRange' is not implemented"
113                     "for this NonLoc");
114
115  case nonloc::LocAsIntegerKind:
116  case nonloc::SymbolValKind: {
117    if (SymbolRef Sym = Value.getAsSymbol())
118      return assumeSymInclusiveRange(State, Sym, From, To, InRange);
119    return State;
120  } // end switch
121
122  case nonloc::ConcreteIntKind: {
123    const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue();
124    bool IsInRange = IntVal >= From && IntVal <= To;
125    bool isFeasible = (IsInRange == InRange);
126    return isFeasible ? State : nullptr;
127  }
128  } // end switch
129}
130
131} // end of namespace ento
132
133} // end of namespace clang
134