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