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 
19 namespace clang {
20 
21 namespace ento {
22 
23 SimpleConstraintManager::~SimpleConstraintManager() {}
24 
25 ProgramStateRef 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 
44 ProgramStateRef SimpleConstraintManager::assume(ProgramStateRef State,
45                                                 NonLoc Cond, bool Assumption) {
46   State = assumeAux(State, Cond, Assumption);
47   if (NotifyAssumeClients && SU)
48     return SU->processAssume(State, Cond, Assumption);
49   return State;
50 }
51 
52 ProgramStateRef 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.getAsSymExpr();
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 
94 ProgramStateRef 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.getAsSymExpr();
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