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
19namespace clang {
20
21namespace ento {
22
23SimpleConstraintManager::~SimpleConstraintManager() {}
24
25ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
26                                                DefinedSVal Cond,
27                                                bool Assumption) {
28  // If we have a Loc value, cast it to a bool NonLoc first.
29  if (Optional<Loc> LV = Cond.getAs<Loc>()) {
30    SValBuilder &SVB = State->getStateManager().getSValBuilder();
31    QualType T;
32    const MemRegion *MR = LV->getAsRegion();
33    if (const TypedRegion *TR = dyn_cast_or_null<TypedRegion>(MR))
34      T = TR->getLocationType();
35    else
36      T = SVB.getContext().VoidPtrTy;
37
38    Cond = SVB.evalCast(*LV, SVB.getContext().BoolTy, T).castAs<DefinedSVal>();
39  }
40
41  return assume(State, Cond.castAs<NonLoc>(), Assumption);
42}
43
44ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
45                                                NonLoc Cond, bool Assumption) {
46  State = assumeAux(State, Cond, Assumption);
47  if (NotifyAssumeClients && EE)
48    return EE->processAssume(State, Cond, Assumption);
49  return State;
50}
51
52ProgramStateRef SimpleConstraintManager::assumeAux(ProgramStateRef State,
53                                                   NonLoc Cond,
54                                                   bool Assumption) {
55
56  // We cannot reason about SymSymExprs, and can only reason about some
57  // SymIntExprs.
58  if (!canReasonAbout(Cond)) {
59    // Just add the constraint to the expression without trying to simplify.
60    SymbolRef Sym = Cond.getAsSymbol();
61    assert(Sym);
62    return assumeSymUnsupported(State, Sym, Assumption);
63  }
64
65  switch (Cond.getSubKind()) {
66  default:
67    llvm_unreachable("'Assume' not implemented for this NonLoc");
68
69  case nonloc::SymbolValKind: {
70    nonloc::SymbolVal SV = Cond.castAs<nonloc::SymbolVal>();
71    SymbolRef Sym = SV.getSymbol();
72    assert(Sym);
73    return assumeSym(State, Sym, Assumption);
74  }
75
76  case nonloc::ConcreteIntKind: {
77    bool b = Cond.castAs<nonloc::ConcreteInt>().getValue() != 0;
78    bool isFeasible = b ? Assumption : !Assumption;
79    return isFeasible ? State : nullptr;
80  }
81
82  case nonloc::PointerToMemberKind: {
83    bool IsNull = !Cond.castAs<nonloc::PointerToMember>().isNullMemberPointer();
84    bool IsFeasible = IsNull ? Assumption : !Assumption;
85    return IsFeasible ? State : nullptr;
86  }
87
88  case nonloc::LocAsIntegerKind:
89    return assume(State, Cond.castAs<nonloc::LocAsInteger>().getLoc(),
90                  Assumption);
91  } // end switch
92}
93
94ProgramStateRef SimpleConstraintManager::assumeInclusiveRange(
95    ProgramStateRef State, NonLoc Value, const llvm::APSInt &From,
96    const llvm::APSInt &To, bool InRange) {
97
98  assert(From.isUnsigned() == To.isUnsigned() &&
99         From.getBitWidth() == To.getBitWidth() &&
100         "Values should have same types!");
101
102  if (!canReasonAbout(Value)) {
103    // Just add the constraint to the expression without trying to simplify.
104    SymbolRef Sym = Value.getAsSymbol();
105    assert(Sym);
106    return assumeSymInclusiveRange(State, Sym, From, To, InRange);
107  }
108
109  switch (Value.getSubKind()) {
110  default:
111    llvm_unreachable("'assumeInclusiveRange' is not implemented"
112                     "for this NonLoc");
113
114  case nonloc::LocAsIntegerKind:
115  case nonloc::SymbolValKind: {
116    if (SymbolRef Sym = Value.getAsSymbol())
117      return assumeSymInclusiveRange(State, Sym, From, To, InRange);
118    return State;
119  } // end switch
120
121  case nonloc::ConcreteIntKind: {
122    const llvm::APSInt &IntVal = Value.castAs<nonloc::ConcreteInt>().getValue();
123    bool IsInRange = IntVal >= From && IntVal <= To;
124    bool isFeasible = (IsInRange == InRange);
125    return isFeasible ? State : nullptr;
126  }
127  } // end switch
128}
129
130} // end of namespace ento
131
132} // end of namespace clang
133