Cppcheck
vfvalue.h
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 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 //---------------------------------------------------------------------------
20 #ifndef vfvalueH
21 #define vfvalueH
22 //---------------------------------------------------------------------------
23 
24 #include "config.h"
25 #include "mathlib.h"
26 
27 #include <cassert>
28 #include <cmath>
29 #include <functional>
30 #include <list>
31 #include <string>
32 #include <type_traits>
33 #include <utility>
34 #include <vector>
35 
36 class Token;
37 
38 namespace ValueFlow
39 {
41  public:
42  using ErrorPathItem = std::pair<const Token *, std::string>;
43  using ErrorPath = std::list<ErrorPathItem>;
44  enum class Bound { Upper, Lower, Point };
45 
46  explicit Value(long long val = 0, Bound b = Bound::Point) :
47  bound(b),
48  intvalue(val),
49  varvalue(val),
50  wideintvalue(val)
51  {}
52  Value(const Token* c, long long val, Bound b = Bound::Point);
53 
54  static Value unknown() {
55  Value v;
56  v.valueType = ValueType::UNINIT;
57  return v;
58  }
59 
60  bool equalValue(const ValueFlow::Value& rhs) const {
61  if (valueType != rhs.valueType)
62  return false;
63  switch (valueType) {
64  case ValueType::INT:
65  case ValueType::CONTAINER_SIZE:
66  case ValueType::BUFFER_SIZE:
67  case ValueType::ITERATOR_START:
68  case ValueType::ITERATOR_END:
69  if (intvalue != rhs.intvalue)
70  return false;
71  break;
72  case ValueType::TOK:
73  if (tokvalue != rhs.tokvalue)
74  return false;
75  break;
76  case ValueType::FLOAT:
77  if (floatValue > rhs.floatValue || floatValue < rhs.floatValue || std::signbit(floatValue) != std::signbit(rhs.floatValue))
78  return false;
79  break;
80  case ValueType::MOVED:
81  if (moveKind != rhs.moveKind)
82  return false;
83  break;
84  case ValueType::UNINIT:
85  break;
86  case ValueType::LIFETIME:
87  if (tokvalue != rhs.tokvalue)
88  return false;
89  break;
90  case ValueType::SYMBOLIC:
91  if (!sameToken(tokvalue, rhs.tokvalue))
92  return false;
93  if (intvalue != rhs.intvalue)
94  return false;
95  break;
96  }
97  return true;
98  }
99 
100  template<class T, class F>
101  static void visitValue(T& self, F f) {
102  switch (self.valueType) {
103  case ValueType::INT:
104  case ValueType::SYMBOLIC:
105  case ValueType::BUFFER_SIZE:
106  case ValueType::CONTAINER_SIZE:
107  case ValueType::ITERATOR_START:
108  case ValueType::ITERATOR_END: {
109  f(self.intvalue);
110  break;
111  }
112  case ValueType::FLOAT: {
113  f(self.floatValue);
114  break;
115  }
116  case ValueType::UNINIT:
117  case ValueType::TOK:
118  case ValueType::LIFETIME:
119  case ValueType::MOVED:
120  break;
121  }
122  }
123 
124  struct compareVisitor {
125  struct innerVisitor {
126  template<class Compare, class T, class U>
127  void operator()(bool& result, Compare compare, T x, U y) const {
128  result = compare(x, y);
129  }
130  };
131  template<class Compare, class T>
132  void operator()(bool& result, const Value& rhs, Compare compare, T x) const {
133  visitValue(rhs,
134  std::bind(innerVisitor{}, std::ref(result), std::move(compare), x, std::placeholders::_1));
135  }
136  };
137 
138  template<class Compare>
139  bool compareValue(const Value& rhs, Compare compare) const {
140  assert((!this->isSymbolicValue() && !rhs.isSymbolicValue()) ||
141  (this->valueType == rhs.valueType && sameToken(this->tokvalue, rhs.tokvalue)));
142  bool result = false;
143  visitValue(
144  *this,
145  std::bind(compareVisitor{}, std::ref(result), std::ref(rhs), std::move(compare), std::placeholders::_1));
146  return result;
147  }
148 
149  bool operator==(const Value &rhs) const {
150  if (!equalValue(rhs))
151  return false;
152 
153  return varvalue == rhs.varvalue &&
154  condition == rhs.condition &&
155  varId == rhs.varId &&
156  conditional == rhs.conditional &&
157  defaultArg == rhs.defaultArg &&
158  indirect == rhs.indirect &&
159  valueKind == rhs.valueKind;
160  }
161 
162  bool operator!=(const Value &rhs) const {
163  return !(*this == rhs);
164  }
165 
166  template<class T, REQUIRES("T must be an arithmetic type", std::is_arithmetic<T> )>
167  bool equalTo(const T& x) const {
168  bool result = false;
169  visitValue(*this, std::bind(equalVisitor{}, std::ref(result), x, std::placeholders::_1));
170  return result;
171  }
172 
173  void decreaseRange() {
174  if (bound == Bound::Lower)
175  visitValue(*this, increment{});
176  else if (bound == Bound::Upper)
177  visitValue(*this, decrement{});
178  }
179 
180  void invertBound() {
181  if (bound == Bound::Lower)
182  bound = Bound::Upper;
183  else if (bound == Bound::Upper)
184  bound = Bound::Lower;
185  }
186 
187  void invertRange() {
188  invertBound();
189  decreaseRange();
190  }
191 
192  void assumeCondition(const Token* tok);
193 
194  std::string infoString() const;
195 
196  std::string toString() const;
197 
198  enum class ValueType {
199  INT,
200  TOK,
201  FLOAT,
202  MOVED,
203  UNINIT,
204  CONTAINER_SIZE,
205  LIFETIME,
206  BUFFER_SIZE,
207  ITERATOR_START,
208  ITERATOR_END,
209  SYMBOLIC
210  } valueType = ValueType::INT;
211  bool isIntValue() const {
212  return valueType == ValueType::INT;
213  }
214  bool isTokValue() const {
215  return valueType == ValueType::TOK;
216  }
217  bool isFloatValue() const {
218  return valueType == ValueType::FLOAT;
219  }
220  bool isMovedValue() const {
221  return valueType == ValueType::MOVED;
222  }
223  bool isUninitValue() const {
224  return valueType == ValueType::UNINIT;
225  }
226  bool isContainerSizeValue() const {
227  return valueType == ValueType::CONTAINER_SIZE;
228  }
229  bool isLifetimeValue() const {
230  return valueType == ValueType::LIFETIME;
231  }
232  bool isBufferSizeValue() const {
233  return valueType == ValueType::BUFFER_SIZE;
234  }
235  bool isIteratorValue() const {
236  return valueType == ValueType::ITERATOR_START || valueType == ValueType::ITERATOR_END;
237  }
238  bool isIteratorStartValue() const {
239  return valueType == ValueType::ITERATOR_START;
240  }
241  bool isIteratorEndValue() const {
242  return valueType == ValueType::ITERATOR_END;
243  }
244  bool isSymbolicValue() const {
245  return valueType == ValueType::SYMBOLIC;
246  }
247 
248  bool isLocalLifetimeValue() const {
249  return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Local;
250  }
251 
252  bool isArgumentLifetimeValue() const {
253  return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::Argument;
254  }
255 
257  return valueType == ValueType::LIFETIME && lifetimeScope == LifetimeScope::SubFunction;
258  }
259 
260  bool isNonValue() const {
261  return isMovedValue() || isUninitValue() || isLifetimeValue();
262  }
263 
264  /** The value bound */
265  Bound bound = Bound::Point;
266 
267  /** int value (or sometimes bool value?) */
268  long long intvalue{};
269 
270  /** token value - the token that has the value. this is used for pointer aliases, strings, etc. */
271  const Token* tokvalue{};
272 
273  /** float value */
274  double floatValue{};
275 
276  /** For calculated values - variable value that calculated value depends on */
277  long long varvalue{};
278 
279  /** Condition that this value depends on */
280  const Token* condition{};
281 
283 
285 
286  /** For calculated values - varId that calculated value depends on */
287  nonneg int varId{};
288 
289  /** value relies on safe checking */
290  bool safe{};
291 
292  /** Conditional value */
293  bool conditional{};
294 
295  /** Value is is from an expanded macro */
296  bool macro{};
297 
298  /** Is this value passed as default parameter to the function? */
299  bool defaultArg{};
300 
301  int indirect{};
302 
303  /** kind of moved */
304  enum class MoveKind { NonMovedVariable, MovedVariable, ForwardedVariable } moveKind = MoveKind::NonMovedVariable;
305 
306  /** Path id */
308 
309  /** int value before implicit truncation */
310  long long wideintvalue{};
311 
312  std::vector<std::string> subexpressions;
313 
314  // Set to where a lifetime is captured by value
315  const Token* capturetok{};
316 
317  enum class LifetimeKind {
318  // Pointer points to a member of lifetime
319  Object,
320  // A member of object points to the lifetime
321  SubObject,
322  // Lambda has captured lifetime(similar to SubObject)
323  Lambda,
324  // Iterator points to the lifetime of a container(similar to Object)
325  Iterator,
326  // A pointer that holds the address of the lifetime
327  Address
328  } lifetimeKind = LifetimeKind::Object;
329 
330  enum class LifetimeScope { Local, Argument, SubFunction, ThisPointer, ThisValue } lifetimeScope = LifetimeScope::Local;
331 
332  static const char* toString(MoveKind moveKind);
333  static const char* toString(LifetimeKind lifetimeKind);
334  static const char* toString(LifetimeScope lifetimeScope);
335  static const char* toString(Bound bound);
336 
337  /** How known is this value */
338  enum class ValueKind {
339  /** This value is possible, other unlisted values may also be possible */
340  Possible,
341  /** Only listed values are possible */
342  Known,
343  /** Inconclusive */
344  Inconclusive,
345  /** Listed values are impossible */
346  Impossible
347  } valueKind = ValueKind::Possible;
348 
349  void setKnown() {
350  valueKind = ValueKind::Known;
351  }
352 
353  bool isKnown() const {
354  return valueKind == ValueKind::Known;
355  }
356 
357  void setPossible() {
358  valueKind = ValueKind::Possible;
359  }
360 
361  bool isPossible() const {
362  return valueKind == ValueKind::Possible;
363  }
364 
365  bool isImpossible() const {
366  return valueKind == ValueKind::Impossible;
367  }
368 
369  void setImpossible() {
370  valueKind = ValueKind::Impossible;
371  }
372 
373  void setInconclusive(bool inconclusive = true) {
374  if (inconclusive)
375  valueKind = ValueKind::Inconclusive;
376  }
377 
378  bool isInconclusive() const {
379  return valueKind == ValueKind::Inconclusive;
380  }
381 
383  if (isKnown())
384  valueKind = ValueKind::Possible;
385  }
386 
387  bool errorSeverity() const {
388  return !condition && !defaultArg;
389  }
390 
391  static bool sameToken(const Token* tok1, const Token* tok2);
392 
393  private:
394  struct equalVisitor {
395  template<class T, class U>
396  void operator()(bool& result, T x, U y) const {
397  result = !(x > y || x < y);
398  }
399  };
400 
401  struct increment {
402  template<class T>
403  void operator()(T& x) const {
404  x++;
405  }
406  };
407  struct decrement {
408  template<class T>
409  void operator()(T& x) const {
410  x--;
411  }
412  };
413  };
414 }
415 
416 #endif // vfvalueH
long long bigint
Definition: mathlib.h:68
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
void setImpossible()
Definition: vfvalue.h:369
bool equalTo(const T &x) const
Definition: vfvalue.h:167
void decreaseRange()
Definition: vfvalue.h:173
bool isArgumentLifetimeValue() const
Definition: vfvalue.h:252
bool isIntValue() const
Definition: vfvalue.h:211
bool isSymbolicValue() const
Definition: vfvalue.h:244
bool isTokValue() const
Definition: vfvalue.h:214
void invertBound()
Definition: vfvalue.h:180
ErrorPath debugPath
Definition: vfvalue.h:284
enum ValueFlow::Value::ValueType valueType
void changeKnownToPossible()
Definition: vfvalue.h:382
bool isIteratorValue() const
Definition: vfvalue.h:235
ErrorPath errorPath
Definition: vfvalue.h:282
bool isMovedValue() const
Definition: vfvalue.h:220
bool isFloatValue() const
Definition: vfvalue.h:217
bool errorSeverity() const
Definition: vfvalue.h:387
bool conditional
Conditional value.
Definition: vfvalue.h:293
ValueKind
How known is this value.
Definition: vfvalue.h:338
bool isLifetimeValue() const
Definition: vfvalue.h:229
long long varvalue
For calculated values - variable value that calculated value depends on.
Definition: vfvalue.h:277
bool defaultArg
Is this value passed as default parameter to the function?
Definition: vfvalue.h:299
bool isImpossible() const
Definition: vfvalue.h:365
double floatValue
float value
Definition: vfvalue.h:274
bool isUninitValue() const
Definition: vfvalue.h:223
bool isKnown() const
Definition: vfvalue.h:353
static void visitValue(T &self, F f)
Definition: vfvalue.h:101
static Value unknown()
Definition: vfvalue.h:54
const Token * condition
Condition that this value depends on.
Definition: vfvalue.h:280
const Token * tokvalue
token value - the token that has the value.
Definition: vfvalue.h:271
long long intvalue
int value (or sometimes bool value?)
Definition: vfvalue.h:268
nonneg int varId
For calculated values - varId that calculated value depends on.
Definition: vfvalue.h:287
bool isBufferSizeValue() const
Definition: vfvalue.h:232
void setPossible()
Definition: vfvalue.h:357
bool isNonValue() const
Definition: vfvalue.h:260
bool operator!=(const Value &rhs) const
Definition: vfvalue.h:162
enum ValueFlow::Value::ValueKind valueKind
bool equalValue(const ValueFlow::Value &rhs) const
Definition: vfvalue.h:60
void invertRange()
Definition: vfvalue.h:187
bool isLocalLifetimeValue() const
Definition: vfvalue.h:248
bool operator==(const Value &rhs) const
Definition: vfvalue.h:149
Value(long long val=0, Bound b=Bound::Point)
Definition: vfvalue.h:46
bool isContainerSizeValue() const
Definition: vfvalue.h:226
std::list< ErrorPathItem > ErrorPath
Definition: vfvalue.h:43
std::pair< const Token *, std::string > ErrorPathItem
Definition: vfvalue.h:42
enum ValueFlow::Value::MoveKind moveKind
void setInconclusive(bool inconclusive=true)
Definition: vfvalue.h:373
void setKnown()
Definition: vfvalue.h:349
bool isSubFunctionLifetimeValue() const
Definition: vfvalue.h:256
bool isIteratorStartValue() const
Definition: vfvalue.h:238
bool isIteratorEndValue() const
Definition: vfvalue.h:241
bool isInconclusive() const
Definition: vfvalue.h:378
MoveKind
kind of moved
Definition: vfvalue.h:304
bool isPossible() const
Definition: vfvalue.h:361
bool compareValue(const Value &rhs, Compare compare) const
Definition: vfvalue.h:139
std::vector< std::string > subexpressions
Definition: vfvalue.h:312
Value type.
std::string toString(Color c)
Definition: color.cpp:54
#define REQUIRES(msg,...)
Definition: config.h:124
#define CPPCHECKLIB
Definition: config.h:35
#define nonneg
Definition: config.h:138
void operator()(bool &result, Compare compare, T x, U y) const
Definition: vfvalue.h:127
void operator()(bool &result, const Value &rhs, Compare compare, T x) const
Definition: vfvalue.h:132
void operator()(T &x) const
Definition: vfvalue.h:409
void operator()(bool &result, T x, U y) const
Definition: vfvalue.h:396
void operator()(T &x) const
Definition: vfvalue.h:403