/src/cppcheck/lib/programmemory.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- C++ -*- |
2 | | * Cppcheck - A tool for static C/C++ code analysis |
3 | | * Copyright (C) 2007-2024 Cppcheck team. |
4 | | * |
5 | | * This program is free software: you can redistribute it and/or modify |
6 | | * it under the terms of the GNU General Public License as published by |
7 | | * the Free Software Foundation, either version 3 of the License, or |
8 | | * (at your option) any later version. |
9 | | * |
10 | | * This program is distributed in the hope that it will be useful, |
11 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
12 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
13 | | * GNU General Public License for more details. |
14 | | * |
15 | | * You should have received a copy of the GNU General Public License |
16 | | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
17 | | */ |
18 | | |
19 | | #ifndef GUARD_PROGRAMMEMORY_H |
20 | | #define GUARD_PROGRAMMEMORY_H |
21 | | |
22 | | #include "config.h" |
23 | | #include "mathlib.h" |
24 | | #include "vfvalue.h" // needed for alias |
25 | | |
26 | | #include <cstddef> |
27 | | #include <functional> |
28 | | #include <map> |
29 | | #include <memory> |
30 | | #include <string> |
31 | | #include <unordered_map> |
32 | | #include <utility> |
33 | | #include <vector> |
34 | | |
35 | | class Scope; |
36 | | class Token; |
37 | | class Settings; |
38 | | |
39 | | // Class used to handle heterogeneous lookup in unordered_map(since we can't use C++20 yet) |
40 | | struct ExprIdToken { |
41 | | const Token* tok = nullptr; |
42 | | nonneg int exprid = 0; |
43 | | |
44 | | ExprIdToken() = default; |
45 | | // cppcheck-suppress noExplicitConstructor |
46 | | // NOLINTNEXTLINE(google-explicit-constructor) |
47 | | ExprIdToken(const Token* tok); |
48 | | // TODO: Make this constructor only available from ProgramMemory |
49 | | // cppcheck-suppress noExplicitConstructor |
50 | | // NOLINTNEXTLINE(google-explicit-constructor) |
51 | 45.1k | ExprIdToken(nonneg int exprid) : exprid(exprid) {} |
52 | | |
53 | | nonneg int getExpressionId() const; |
54 | | |
55 | 30.7k | bool operator==(const ExprIdToken& rhs) const { |
56 | 30.7k | return getExpressionId() == rhs.getExpressionId(); |
57 | 30.7k | } |
58 | | |
59 | 0 | bool operator<(const ExprIdToken& rhs) const { |
60 | 0 | return getExpressionId() < rhs.getExpressionId(); |
61 | 0 | } |
62 | | |
63 | | template<class T, class U> |
64 | | friend bool operator!=(const T& lhs, const U& rhs) |
65 | 1.02k | { |
66 | 1.02k | return !(lhs == rhs); |
67 | 1.02k | } |
68 | | |
69 | | template<class T, class U> |
70 | | friend bool operator<=(const T& lhs, const U& rhs) |
71 | | { |
72 | | return !(lhs > rhs); |
73 | | } |
74 | | |
75 | | template<class T, class U> |
76 | | friend bool operator>(const T& lhs, const U& rhs) |
77 | | { |
78 | | return rhs < lhs; |
79 | | } |
80 | | |
81 | | template<class T, class U> |
82 | | friend bool operator>=(const T& lhs, const U& rhs) |
83 | | { |
84 | | return !(lhs < rhs); |
85 | | } |
86 | | |
87 | 0 | const Token& operator*() const NOEXCEPT { |
88 | 0 | return *tok; |
89 | 0 | } |
90 | | |
91 | 0 | const Token* operator->() const NOEXCEPT { |
92 | 0 | return tok; |
93 | 0 | } |
94 | | |
95 | | struct Hash { |
96 | | std::size_t operator()(ExprIdToken etok) const; |
97 | | }; |
98 | | }; |
99 | | |
100 | | struct CPPCHECKLIB ProgramMemory { |
101 | | using Map = std::unordered_map<ExprIdToken, ValueFlow::Value, ExprIdToken::Hash>; |
102 | | |
103 | 4.19k | ProgramMemory() : mValues(new Map()) {} |
104 | | |
105 | 100 | explicit ProgramMemory(Map values) : mValues(new Map(std::move(values))) {} |
106 | | |
107 | | void setValue(const Token* expr, const ValueFlow::Value& value); |
108 | | const ValueFlow::Value* getValue(nonneg int exprid, bool impossible = false) const; |
109 | | |
110 | | bool getIntValue(nonneg int exprid, MathLib::bigint& result) const; |
111 | | void setIntValue(const Token* expr, MathLib::bigint value, bool impossible = false); |
112 | | |
113 | | bool getContainerSizeValue(nonneg int exprid, MathLib::bigint& result) const; |
114 | | bool getContainerEmptyValue(nonneg int exprid, MathLib::bigint& result) const; |
115 | | void setContainerSizeValue(const Token* expr, MathLib::bigint value, bool isEqual = true); |
116 | | |
117 | | void setUnknown(const Token* expr); |
118 | | |
119 | | bool getTokValue(nonneg int exprid, const Token*& result) const; |
120 | | bool hasValue(nonneg int exprid); |
121 | | |
122 | | const ValueFlow::Value& at(nonneg int exprid) const; |
123 | | ValueFlow::Value& at(nonneg int exprid); |
124 | | |
125 | | void erase_if(const std::function<bool(const ExprIdToken&)>& pred); |
126 | | |
127 | | void swap(ProgramMemory &pm) NOEXCEPT; |
128 | | |
129 | | void clear(); |
130 | | |
131 | | bool empty() const; |
132 | | |
133 | | void replace(ProgramMemory pm); |
134 | | |
135 | 1.93k | Map::const_iterator begin() const { |
136 | 1.93k | return mValues->cbegin(); |
137 | 1.93k | } |
138 | | |
139 | 1.93k | Map::const_iterator end() const { |
140 | 1.93k | return mValues->cend(); |
141 | 1.93k | } |
142 | | |
143 | 0 | friend bool operator==(const ProgramMemory& x, const ProgramMemory& y) { |
144 | 0 | return x.mValues == y.mValues; |
145 | 0 | } |
146 | | |
147 | 0 | friend bool operator!=(const ProgramMemory& x, const ProgramMemory& y) { |
148 | 0 | return x.mValues != y.mValues; |
149 | 0 | } |
150 | | |
151 | | private: |
152 | | void copyOnWrite(); |
153 | | |
154 | | std::shared_ptr<Map> mValues; |
155 | | }; |
156 | | |
157 | | struct ProgramMemoryState { |
158 | | ProgramMemory state; |
159 | | std::map<nonneg int, const Token*> origins; |
160 | | const Settings& settings; |
161 | | |
162 | | explicit ProgramMemoryState(const Settings& s); |
163 | | |
164 | | void replace(ProgramMemory pm, const Token* origin = nullptr); |
165 | | |
166 | | void addState(const Token* tok, const ProgramMemory::Map& vars); |
167 | | |
168 | | void assume(const Token* tok, bool b, bool isEmpty = false); |
169 | | |
170 | | void removeModifiedVars(const Token* tok); |
171 | | |
172 | | ProgramMemory get(const Token* tok, const Token* ctx, const ProgramMemory::Map& vars) const; |
173 | | }; |
174 | | |
175 | | std::vector<ValueFlow::Value> execute(const Scope* scope, ProgramMemory& pm, const Settings& settings); |
176 | | |
177 | | void execute(const Token* expr, |
178 | | ProgramMemory& programMemory, |
179 | | MathLib::bigint* result, |
180 | | bool* error, |
181 | | const Settings& settings); |
182 | | |
183 | | /** |
184 | | * Is condition always false when variable has given value? |
185 | | * \param condition top ast token in condition |
186 | | * \param pm program memory |
187 | | */ |
188 | | bool conditionIsFalse(const Token* condition, ProgramMemory pm, const Settings& settings); |
189 | | |
190 | | /** |
191 | | * Is condition always true when variable has given value? |
192 | | * \param condition top ast token in condition |
193 | | * \param pm program memory |
194 | | */ |
195 | | bool conditionIsTrue(const Token* condition, ProgramMemory pm, const Settings& settings); |
196 | | |
197 | | /** |
198 | | * Get program memory by looking backwards from given token. |
199 | | */ |
200 | | ProgramMemory getProgramMemory(const Token* tok, const Token* expr, const ValueFlow::Value& value, const Settings& settings); |
201 | | |
202 | | ValueFlow::Value evaluateLibraryFunction(const std::unordered_map<nonneg int, ValueFlow::Value>& args, |
203 | | const std::string& returnValue, |
204 | | const Settings& settings, |
205 | | bool cpp); |
206 | | |
207 | | #endif |
208 | | |
209 | | |
210 | | |