Cppcheck
astutils.cpp
Go to the documentation of this file.
1 /*
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 
20 //---------------------------------------------------------------------------
21 #include "astutils.h"
22 
23 #include "config.h"
24 #include "errortypes.h"
25 #include "findtoken.h"
26 #include "infer.h"
27 #include "library.h"
28 #include "mathlib.h"
29 #include "settings.h"
30 #include "symboldatabase.h"
31 #include "token.h"
32 #include "utils.h"
33 #include "valueflow.h"
34 #include "valueptr.h"
35 #include "vfvalue.h"
36 
37 #include "checkclass.h"
38 
39 #include <algorithm>
40 #include <cassert>
41 #include <functional>
42 #include <initializer_list>
43 #include <iterator>
44 #include <list>
45 #include <set>
46 #include <type_traits>
47 #include <unordered_map>
48 #include <utility>
49 
50 const Token* findExpression(const nonneg int exprid,
51  const Token* start,
52  const Token* end,
53  const std::function<bool(const Token*)>& pred)
54 {
55  if (exprid == 0)
56  return nullptr;
57  if (!precedes(start, end))
58  return nullptr;
59  for (const Token* tok = start; tok != end; tok = tok->next()) {
60  if (tok->exprId() != exprid)
61  continue;
62  if (pred(tok))
63  return tok;
64  }
65  return nullptr;
66 }
67 
68 static int findArgumentPosRecursive(const Token* tok, const Token* tokToFind, bool &found, nonneg int depth=0)
69 {
70  ++depth;
71  if (!tok || depth >= 100)
72  return -1;
73  if (tok->str() == ",") {
74  int res = findArgumentPosRecursive(tok->astOperand1(), tokToFind, found, depth);
75  if (res == -1)
76  return -1;
77  if (found)
78  return res;
79  const int argn = res;
80  res = findArgumentPosRecursive(tok->astOperand2(), tokToFind, found, depth);
81  if (res == -1)
82  return -1;
83  return argn + res;
84  }
85  if (tokToFind == tok)
86  found = true;
87  return 1;
88 }
89 
90 static int findArgumentPos(const Token* tok, const Token* tokToFind){
91  bool found = false;
92  const int argn = findArgumentPosRecursive(tok, tokToFind, found, 0);
93  if (found)
94  return argn - 1;
95  return -1;
96 }
97 
98 static int getArgumentPos(const Token* ftok, const Token* tokToFind){
99  const Token* tok = ftok;
100  if (Token::Match(tok, "%name% (|{"))
101  tok = ftok->next();
102  if (!Token::Match(tok, "(|{|["))
103  return -1;
104  const Token* startTok = tok->astOperand2();
105  if (!startTok && tok->next() != tok->link())
106  startTok = tok->astOperand1();
107  return findArgumentPos(startTok, tokToFind);
108 }
109 
110 std::vector<const Token*> astFlatten(const Token* tok, const char* op)
111 {
112  std::vector<const Token*> result;
113  astFlattenCopy(tok, op, std::back_inserter(result));
114  return result;
115 }
116 
117 std::vector<Token*> astFlatten(Token* tok, const char* op)
118 {
119  std::vector<Token*> result;
120  astFlattenCopy(tok, op, std::back_inserter(result));
121  return result;
122 }
123 
124 nonneg int astCount(const Token* tok, const char* op, int depth)
125 {
126  --depth;
127  if (!tok || depth < 0)
128  return 0;
129  if (tok->str() == op)
130  return astCount(tok->astOperand1(), op, depth) + astCount(tok->astOperand2(), op, depth);
131  return 1;
132 }
133 
134 bool astHasToken(const Token* root, const Token * tok)
135 {
136  if (!root)
137  return false;
138  while (tok->astParent() && tok != root)
139  tok = tok->astParent();
140  return root == tok;
141 }
142 
143 bool astHasVar(const Token * tok, nonneg int varid)
144 {
145  if (!tok)
146  return false;
147  if (tok->varId() == varid)
148  return true;
149  return astHasVar(tok->astOperand1(), varid) || astHasVar(tok->astOperand2(), varid);
150 }
151 
152 bool astHasExpr(const Token* tok, nonneg int exprid)
153 {
154  if (!tok)
155  return false;
156  if (tok->exprId() == exprid)
157  return true;
158  return astHasExpr(tok->astOperand1(), exprid) || astHasExpr(tok->astOperand2(), exprid);
159 }
160 
161 static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
162 {
163  if (!tok)
164  return false;
165  const ValueType *valueType = tok->valueType();
166  if (!valueType)
167  return false;
168  return valueType->type == ValueType::Type::CHAR && valueType->pointer == 0U && valueType->sign == sign;
169 }
170 
171 bool astIsSignedChar(const Token *tok)
172 {
173  return astIsCharWithSign(tok, ValueType::Sign::SIGNED);
174 }
175 
176 bool astIsUnknownSignChar(const Token *tok)
177 {
178  return astIsCharWithSign(tok, ValueType::Sign::UNKNOWN_SIGN);
179 }
180 
181 bool astIsGenericChar(const Token* tok)
182 {
183  return !astIsPointer(tok) && tok && tok->valueType() && (tok->valueType()->type == ValueType::Type::CHAR || tok->valueType()->type == ValueType::Type::WCHAR_T);
184 }
185 
186 bool astIsPrimitive(const Token* tok)
187 {
188  const ValueType* vt = tok ? tok->valueType() : nullptr;
189  if (!vt)
190  return false;
191  return vt->isPrimitive();
192 }
193 
194 bool astIsIntegral(const Token *tok, bool unknown)
195 {
196  const ValueType *vt = tok ? tok->valueType() : nullptr;
197  if (!vt)
198  return unknown;
199  return vt->isIntegral() && vt->pointer == 0U;
200 }
201 
202 bool astIsUnsigned(const Token* tok)
203 {
204  return tok && tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED;
205 }
206 
207 bool astIsFloat(const Token *tok, bool unknown)
208 {
209  const ValueType *vt = tok ? tok->valueType() : nullptr;
210  if (!vt)
211  return unknown;
212  return vt->type >= ValueType::Type::FLOAT && vt->pointer == 0U;
213 }
214 
215 bool astIsBool(const Token *tok)
216 {
217  return tok && (tok->isBoolean() || (tok->valueType() && tok->valueType()->type == ValueType::Type::BOOL && !tok->valueType()->pointer));
218 }
219 
220 bool astIsPointer(const Token *tok)
221 {
222  return tok && tok->valueType() && tok->valueType()->pointer;
223 }
224 
225 bool astIsSmartPointer(const Token* tok)
226 {
227  return tok && tok->valueType() && tok->valueType()->smartPointerTypeToken;
228 }
229 
231 {
232  if (!astIsSmartPointer(tok))
233  return false;
234  if (!tok->valueType()->smartPointer)
235  return false;
236  return tok->valueType()->smartPointer->unique;
237 }
238 
239 bool astIsIterator(const Token *tok)
240 {
241  return tok && tok->valueType() && tok->valueType()->type == ValueType::Type::ITERATOR;
242 }
243 
244 bool astIsContainer(const Token* tok) {
245  return getLibraryContainer(tok) != nullptr && !astIsIterator(tok);
246 }
247 
249 {
250  const Library::Container* container = getLibraryContainer(tok);
251  return container && !container->stdStringLike && !astIsIterator(tok);
252 }
253 
254 bool astIsContainerView(const Token* tok)
255 {
256  const Library::Container* container = getLibraryContainer(tok);
257  return container && !astIsIterator(tok) && container->view;
258 }
259 
260 bool astIsContainerOwned(const Token* tok) {
261  return astIsContainer(tok) && !astIsContainerView(tok);
262 }
263 
264 bool astIsContainerString(const Token* tok)
265 {
266  if (!tok)
267  return false;
268  if (!tok->valueType())
269  return false;
270  const Library::Container* container = tok->valueType()->container;
271  if (!container)
272  return false;
273  return container->stdStringLike;
274 }
275 
276 static const Token* getContainerFunction(const Token* tok)
277 {
278  if (!tok || !tok->valueType() || !tok->valueType()->container)
279  return nullptr;
280  const Token* parent = tok->astParent();
281  if (Token::Match(parent, ". %name% (") && astIsLHS(tok)) {
282  return parent->next();
283  }
284  return nullptr;
285 }
286 
288 {
289  const Token* ftok2 = getContainerFunction(tok);
290  if (ftok)
291  *ftok = ftok2;
292  if (!ftok2)
294  return tok->valueType()->container->getAction(ftok2->str());
295 }
296 
298 {
299  const Token* ftok2 = getContainerFunction(tok);
300  if (ftok)
301  *ftok = ftok2;
302  if (!ftok2)
304  return tok->valueType()->container->getYield(ftok2->str());
305 }
306 
307 Library::Container::Yield astFunctionYield(const Token* tok, const Settings& settings, const Token** ftok)
308 {
309  if (!tok)
311 
312  const auto* function = settings.library.getFunction(tok);
313  if (!function)
315 
316  if (ftok)
317  *ftok = tok;
318  return function->containerYield;
319 }
320 
322 {
323  return Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "(");
324 }
325 
326 std::string astCanonicalType(const Token *expr, bool pointedToType)
327 {
328  if (!expr)
329  return "";
330  std::pair<const Token*, const Token*> decl = Token::typeDecl(expr, pointedToType);
331  if (decl.first && decl.second) {
332  std::string ret;
333  for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) {
334  if (!Token::Match(type, "const|static"))
335  ret += type->str();
336  }
337  return ret;
338  }
339  return "";
340 }
341 
342 static bool match(const Token *tok, const std::string &rhs)
343 {
344  if (tok->str() == rhs)
345  return true;
346  if (!tok->varId() && tok->hasKnownIntValue() && std::to_string(tok->values().front().intvalue) == rhs)
347  return true;
348  return false;
349 }
350 
351 const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
352 {
353  if (!tok)
354  return nullptr;
355 
356  const Token *ret = nullptr;
357  if (tok->isComparisonOp()) {
358  if (tok->astOperand1() && match(tok->astOperand1(), rhs)) {
359  // Invert comparator
360  std::string s = tok->str();
361  if (s[0] == '>')
362  s[0] = '<';
363  else if (s[0] == '<')
364  s[0] = '>';
365  if (s == comp) {
366  ret = tok->astOperand2();
367  }
368  } else if (tok->str() == comp && tok->astOperand2() && match(tok->astOperand2(), rhs)) {
369  ret = tok->astOperand1();
370  }
371  } else if (comp == "!=" && rhs == "0") {
372  if (tok->str() == "!") {
373  ret = tok->astOperand1();
374  // handle (!(x==0)) as (x!=0)
375  astIsVariableComparison(ret, "==", "0", &ret);
376  } else
377  ret = tok;
378  } else if (comp == "==" && rhs == "0") {
379  if (tok->str() == "!") {
380  ret = tok->astOperand1();
381  // handle (!(x!=0)) as (x==0)
382  astIsVariableComparison(ret, "!=", "0", &ret);
383  }
384  }
385  while (ret && ret->str() == ".")
386  ret = ret->astOperand2();
387  if (ret && ret->str() == "=" && ret->astOperand1() && ret->astOperand1()->varId())
388  ret = ret->astOperand1();
389  else if (ret && ret->varId() == 0U)
390  ret = nullptr;
391  if (vartok)
392  *vartok = ret;
393  return ret;
394 }
395 
396 bool isVariableDecl(const Token* tok)
397 {
398  if (!tok)
399  return false;
400  const Variable* var = tok->variable();
401  if (!var)
402  return false;
403  if (var->nameToken() == tok)
404  return true;
405  const Token * const varDeclEndToken = var->declEndToken();
406  return Token::Match(varDeclEndToken, "; %var%") && varDeclEndToken->next() == tok;
407 }
408 
409 bool isStlStringType(const Token* tok)
410 {
411  return Token::Match(tok, "std :: string|wstring|u16string|u32string !!::") ||
412  (Token::simpleMatch(tok, "std :: basic_string <") && !Token::simpleMatch(tok->linkAt(3), "> ::"));
413 }
414 
415 bool isTemporary(const Token* tok, const Library* library, bool unknown)
416 {
417  if (!tok)
418  return false;
419  if (Token::simpleMatch(tok, "."))
420  return (tok->originalName() != "->" && isTemporary(tok->astOperand1(), library)) ||
421  isTemporary(tok->astOperand2(), library);
422  if (Token::Match(tok, ",|::"))
423  return isTemporary(tok->astOperand2(), library);
424  if (tok->isCast() || (tok->isCpp() && isCPPCast(tok)))
425  return isTemporary(tok->astOperand2(), library);
426  if (Token::Match(tok, ".|[|++|--|%name%|%assign%"))
427  return false;
428  if (tok->isUnaryOp("*"))
429  return false;
430  if (Token::Match(tok, "&|<<|>>") && isLikelyStream(tok->astOperand1()))
431  return false;
432  if (Token::simpleMatch(tok, "?")) {
433  const Token* branchTok = tok->astOperand2();
434  if (!branchTok->astOperand1() || !branchTok->astOperand1()->valueType())
435  return false;
436  if (!branchTok->astOperand2()->valueType())
437  return false;
438  return !branchTok->astOperand1()->valueType()->isTypeEqual(branchTok->astOperand2()->valueType());
439  }
440  if (Token::simpleMatch(tok, "(") && tok->astOperand1() &&
441  (tok->astOperand2() || Token::simpleMatch(tok->next(), ")"))) {
442  if (Token::simpleMatch(tok->astOperand1(), "typeid"))
443  return false;
444  if (tok->valueType()) {
445  if (tok->valueType()->pointer > 0) {
446  const Token* const parent = tok->astParent();
447  if (Token::simpleMatch(parent, "&"))
448  return true;
449  if (Token::simpleMatch(parent, "return") && parent->valueType()->reference != Reference::None &&
450  parent->valueType()->container && parent->valueType()->container->stdStringLike)
451  return true;
452  }
453  return tok->valueType()->reference == Reference::None && tok->valueType()->pointer == 0;
454  }
455  const Token* ftok = nullptr;
456  if (Token::simpleMatch(tok->previous(), ">") && tok->previous()->link())
457  ftok = tok->previous()->link()->previous();
458  else
459  ftok = tok->previous();
460  if (!ftok)
461  return false;
462  if (const Function * f = ftok->function())
463  return !Function::returnsReference(f, true);
464  if (ftok->type())
465  return true;
466  if (library) {
467  std::string returnType = library->returnValueType(ftok);
468  return !returnType.empty() && returnType.back() != '&';
469  }
470  return unknown;
471  }
472  if (tok->isCast())
473  return false;
474  // Currying a function is unknown in cppcheck
475  if (Token::simpleMatch(tok, "(") && Token::simpleMatch(tok->astOperand1(), "("))
476  return unknown;
477  if (Token::simpleMatch(tok, "{") && Token::simpleMatch(tok->astParent(), "return") && tok->astOperand1() &&
478  !tok->astOperand2())
479  return isTemporary(tok->astOperand1(), library);
480  return true;
481 }
482 
483 static bool isFunctionCall(const Token* tok)
484 {
485  if (Token::Match(tok, "%name% ("))
486  return true;
487  if (Token::Match(tok, "%name% <") && Token::simpleMatch(tok->next()->link(), "> ("))
488  return true;
489  if (Token::Match(tok, "%name% ::"))
490  return isFunctionCall(tok->tokAt(2));
491  return false;
492 }
493 
494 static bool hasToken(const Token * startTok, const Token * stopTok, const Token * tok)
495 {
496  for (const Token * tok2 = startTok; tok2 != stopTok; tok2 = tok2->next()) {
497  if (tok2 == tok)
498  return true;
499  }
500  return false;
501 }
502 
503 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
505 {
506  if (!tok)
507  return nullptr;
508  T* leftmostLeaf = tok;
509  while (leftmostLeaf->astOperand1())
510  leftmostLeaf = leftmostLeaf->astOperand1();
511  return leftmostLeaf->previous();
512 }
513 
515 {
517 }
519 {
521 }
522 
523 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
525 {
526  T * rightmostLeaf = tok;
527  if (!rightmostLeaf || !rightmostLeaf->astOperand1())
528  return nullptr;
529  do {
530  if (T* lam = findLambdaEndToken(rightmostLeaf)) {
531  rightmostLeaf = lam;
532  break;
533  }
534  if (rightmostLeaf->astOperand2() && precedes(rightmostLeaf, rightmostLeaf->astOperand2()))
535  rightmostLeaf = rightmostLeaf->astOperand2();
536  else if (rightmostLeaf->astOperand1() && precedes(rightmostLeaf, rightmostLeaf->astOperand1()))
537  rightmostLeaf = rightmostLeaf->astOperand1();
538  else
539  break;
540  } while (rightmostLeaf->astOperand1() || rightmostLeaf->astOperand2());
541  while (Token::Match(rightmostLeaf->next(), "]|)") && !hasToken(rightmostLeaf->next()->link(), rightmostLeaf->next(), tok))
542  rightmostLeaf = rightmostLeaf->next();
543  if (Token::Match(rightmostLeaf, "{|(|[") && rightmostLeaf->link())
544  rightmostLeaf = rightmostLeaf->link();
545  return rightmostLeaf->next();
546 }
547 
549 {
551 }
553 {
555 }
556 
557 const Token* astParentSkipParens(const Token* tok)
558 {
559  return astParentSkipParens(const_cast<Token*>(tok));
560 }
562 {
563  if (!tok)
564  return nullptr;
565  Token * parent = tok->astParent();
566  if (!Token::simpleMatch(parent, "("))
567  return parent;
568  if (parent->link() != nextAfterAstRightmostLeaf(tok))
569  return parent;
570  if (Token::Match(parent->previous(), "%name% (") ||
571  (Token::simpleMatch(parent->previous(), "> (") && parent->previous()->link()))
572  return parent;
573  return astParentSkipParens(parent);
574 }
575 
576 const Token* getParentMember(const Token * tok)
577 {
578  if (!tok)
579  return tok;
580  const Token * parent = tok->astParent();
581  if (!Token::simpleMatch(parent, "."))
582  return tok;
583  if (astIsRHS(tok)) {
584  if (Token::simpleMatch(parent->astOperand1(), "."))
585  return parent->astOperand1()->astOperand2();
586  return parent->astOperand1();
587  }
588  const Token * gparent = parent->astParent();
589  if (!Token::simpleMatch(gparent, ".") || gparent->astOperand2() != parent)
590  return tok;
591  if (gparent->astOperand1())
592  return gparent->astOperand1();
593  return tok;
594 }
595 
596 const Token* getParentLifetime(const Token* tok)
597 {
598  if (!tok)
599  return tok;
600  // Skipping checking for variable if its a pointer-to-member
601  if (!Token::simpleMatch(tok->previous(), ". *")) {
602  const Variable* var = tok->variable();
603  // TODO: Call getLifetimeVariable for deeper analysis
604  if (!var)
605  return tok;
606  if (var->isLocal() || var->isArgument())
607  return tok;
608  }
609  const Token* parent = getParentMember(tok);
610  if (parent != tok)
611  return getParentLifetime(parent);
612  return tok;
613 }
614 
615 static std::vector<const Token*> getParentMembers(const Token* tok)
616 {
617  if (!tok)
618  return {};
619  if (!Token::simpleMatch(tok->astParent(), "."))
620  return {tok};
621  const Token* parent = tok->astParent();
622  while (Token::simpleMatch(parent->astParent(), "."))
623  parent = parent->astParent();
624  std::vector<const Token*> result;
625  for (const Token* tok2 : astFlatten(parent, ".")) {
626  if (Token::simpleMatch(tok2, "(") && Token::simpleMatch(tok2->astOperand1(), ".")) {
627  std::vector<const Token*> sub = getParentMembers(tok2->astOperand1());
628  result.insert(result.end(), sub.cbegin(), sub.cend());
629  }
630  result.push_back(tok2);
631  }
632  return result;
633 }
634 
635 static const Token* getParentLifetimeObject(const Token* tok)
636 {
637  while (Token::simpleMatch(tok, "["))
638  tok = tok->astOperand1();
639  return tok;
640 }
641 
642 const Token* getParentLifetime(const Token* tok, const Library& library)
643 {
644  std::vector<const Token*> members = getParentMembers(tok);
645  if (members.size() < 2)
646  return tok;
647  // Find the first local variable, temporary, or array
648  auto it = std::find_if(members.crbegin(), members.crend(), [&](const Token* tok2) {
649  const Variable* var = tok2->variable();
650  if (var)
651  return var->isLocal() || var->isArgument();
652  if (Token::simpleMatch(tok2, "["))
653  return true;
654  return isTemporary(tok2, &library);
655  });
656  if (it == members.rend())
657  return tok;
658  // If any of the submembers are borrowed types then stop
659  if (std::any_of(it.base() - 1, members.cend() - 1, [&](const Token* tok2) {
660  const Token* obj = getParentLifetimeObject(tok2);
661  const Variable* var = obj->variable();
662  // Check for arrays first since astIsPointer will return true, but an array is not a borrowed type
663  if (var && var->isArray())
664  return false;
665  if (astIsPointer(obj) || astIsContainerView(obj) || astIsIterator(obj))
666  return true;
667  if (!astIsUniqueSmartPointer(obj)) {
668  if (astIsSmartPointer(obj))
669  return true;
670  const Token* dotTok = obj->next();
671  if (!Token::simpleMatch(dotTok, ".")) {
672  const Token* endTok = nextAfterAstRightmostLeaf(obj);
673  if (!endTok)
674  dotTok = obj->next();
675  else if (Token::simpleMatch(endTok, "."))
676  dotTok = endTok;
677  else if (Token::simpleMatch(endTok->next(), "."))
678  dotTok = endTok->next();
679  }
680  // If we are dereferencing the member variable then treat it as borrowed
681  if (Token::simpleMatch(dotTok, ".") && dotTok->originalName() == "->")
682  return true;
683  }
684  return var && var->isReference();
685  }))
686  return nullptr;
687  const Token* result = getParentLifetimeObject(*it);
688  if (result != *it)
689  return getParentLifetime(result);
690  return result;
691 }
692 
693 static bool isInConstructorList(const Token* tok)
694 {
695  if (!tok)
696  return false;
697  if (!astIsRHS(tok))
698  return false;
699  const Token* parent = tok->astParent();
700  if (!Token::Match(parent, "{|("))
701  return false;
702  if (!Token::Match(parent->previous(), "%var% {|("))
703  return false;
704  if (!parent->astOperand1() || !parent->astOperand2())
705  return false;
706  do {
707  parent = parent->astParent();
708  } while (Token::simpleMatch(parent, ","));
709  return Token::simpleMatch(parent, ":") && !Token::simpleMatch(parent->astParent(), "?");
710 }
711 
712 std::vector<ValueType> getParentValueTypes(const Token* tok, const Settings& settings, const Token** parent)
713 {
714  if (!tok)
715  return {};
716  if (!tok->astParent())
717  return {};
718  if (isInConstructorList(tok)) {
719  if (parent)
720  *parent = tok->astParent()->astOperand1();
721  if (tok->astParent()->astOperand1()->valueType())
722  return {*tok->astParent()->astOperand1()->valueType()};
723  return {};
724  }
725  const Token* ftok = nullptr;
726  if (Token::Match(tok->astParent(), "(|{|,")) {
727  int argn = -1;
728  ftok = getTokenArgumentFunction(tok, argn);
729  const Token* typeTok = nullptr;
730  if (ftok && argn >= 0) {
731  if (ftok->function()) {
732  std::vector<ValueType> result;
733  const Token* nameTok = nullptr;
734  for (const Variable* var : getArgumentVars(ftok, argn)) {
735  if (!var)
736  continue;
737  if (!var->valueType())
738  continue;
739  nameTok = var->nameToken();
740  result.push_back(*var->valueType());
741  }
742  if (result.size() == 1 && nameTok && parent) {
743  *parent = nameTok;
744  }
745  return result;
746  }
747  if (const Type* t = Token::typeOf(ftok, &typeTok)) {
748  if (astIsPointer(typeTok))
749  return {*typeTok->valueType()};
750  const Scope* scope = t->classScope;
751  // Check for aggregate constructors
752  if (scope && scope->numConstructors == 0 && t->derivedFrom.empty() &&
753  (t->isClassType() || t->isStructType()) && numberOfArguments(ftok) <= scope->varlist.size() &&
754  !scope->varlist.empty()) {
755  assert(argn < scope->varlist.size());
756  auto it = std::next(scope->varlist.cbegin(), argn);
757  if (it->valueType())
758  return {*it->valueType()};
759  }
760  }
761  }
762  }
763  if (Token::Match(tok->astParent()->tokAt(-2), ". push_back|push_front|insert|push (") &&
764  astIsContainer(tok->astParent()->tokAt(-2)->astOperand1())) {
765  const Token* contTok = tok->astParent()->tokAt(-2)->astOperand1();
766  const ValueType* vtCont = contTok->valueType();
767  if (!vtCont->containerTypeToken)
768  return {};
769  ValueType vtParent = ValueType::parseDecl(vtCont->containerTypeToken, settings);
770  return {std::move(vtParent)};
771  }
772  // The return type of a function is not the parent valuetype
773  if (Token::simpleMatch(tok->astParent(), "(") && ftok && !tok->astParent()->isCast() &&
774  ftok->tokType() != Token::eType)
775  return {};
776  if (parent && Token::Match(tok->astParent(), "return|(|{|%assign%")) {
777  *parent = tok->astParent();
778  }
779  if (tok->astParent()->valueType())
780  return {*tok->astParent()->valueType()};
781  return {};
782 }
783 
784 bool astIsLHS(const Token* tok)
785 {
786  if (!tok)
787  return false;
788  const Token* parent = tok->astParent();
789  if (!parent)
790  return false;
791  if (!parent->astOperand1())
792  return false;
793  if (!parent->astOperand2())
794  return false;
795  return parent->astOperand1() == tok;
796 }
797 bool astIsRHS(const Token* tok)
798 {
799  if (!tok)
800  return false;
801  const Token* parent = tok->astParent();
802  if (!parent)
803  return false;
804  if (!parent->astOperand1())
805  return false;
806  if (!parent->astOperand2())
807  return false;
808  return parent->astOperand2() == tok;
809 }
810 
811 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
812 static T* getCondTokImpl(T* tok)
813 {
814  if (!tok)
815  return nullptr;
816  if (Token::simpleMatch(tok, "("))
817  return getCondTok(tok->previous());
818  if (Token::simpleMatch(tok, "do {")) {
819  T* endTok = tok->linkAt(1);
820  if (Token::simpleMatch(endTok, "} while ("))
821  return endTok->tokAt(2)->astOperand2();
822  }
823  if (Token::simpleMatch(tok, "for") && Token::simpleMatch(tok->next()->astOperand2(), ";") &&
824  tok->next()->astOperand2()->astOperand2())
825  return tok->next()->astOperand2()->astOperand2()->astOperand1();
826  if (Token::simpleMatch(tok->next()->astOperand2(), ";"))
827  return tok->next()->astOperand2()->astOperand1();
828  return tok->next()->astOperand2();
829 }
830 
831 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
832 static T* getCondTokFromEndImpl(T* endBlock)
833 {
834  if (!Token::simpleMatch(endBlock, "}"))
835  return nullptr;
836  T* startBlock = endBlock->link();
837  if (!Token::simpleMatch(startBlock, "{"))
838  return nullptr;
839  if (Token::simpleMatch(startBlock->previous(), "do"))
840  return getCondTok(startBlock->previous());
841  if (Token::simpleMatch(startBlock->previous(), ")"))
842  return getCondTok(startBlock->previous()->link());
843  if (Token::simpleMatch(startBlock->tokAt(-2), "} else {"))
844  return getCondTokFromEnd(startBlock->tokAt(-2));
845  return nullptr;
846 }
847 
848 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
849 static T* getInitTokImpl(T* tok)
850 {
851  if (!tok)
852  return nullptr;
853  if (Token::Match(tok, "%name% ("))
854  return getInitTokImpl(tok->next());
855  if (tok->str() != "(")
856  return nullptr;
857  if (!Token::simpleMatch(tok->astOperand2(), ";"))
858  return nullptr;
859  if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
860  return nullptr;
861  return tok->astOperand2()->astOperand1();
862 }
863 
864 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
865 static T* getStepTokImpl(T* tok)
866 {
867  if (!tok)
868  return nullptr;
869  if (Token::Match(tok, "%name% ("))
870  return getStepTokImpl(tok->next());
871  if (tok->str() != "(")
872  return nullptr;
873  if (!Token::simpleMatch(tok->astOperand2(), ";"))
874  return nullptr;
875  if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
876  return nullptr;
877  return tok->astOperand2()->astOperand2()->astOperand2();
878 }
879 
881 {
882  return getCondTokImpl(tok);
883 }
884 const Token* getCondTok(const Token* tok)
885 {
886  return getCondTokImpl(tok);
887 }
888 
890 {
891  return getCondTokFromEndImpl(endBlock);
892 }
893 const Token* getCondTokFromEnd(const Token* endBlock)
894 {
895  return getCondTokFromEndImpl(endBlock);
896 }
897 
899  return getInitTokImpl(tok);
900 }
901 const Token* getInitTok(const Token* tok) {
902  return getInitTokImpl(tok);
903 }
904 
906  return getStepTokImpl(tok);
907 }
908 const Token* getStepTok(const Token* tok) {
909  return getStepTokImpl(tok);
910 }
911 
912 const Token *findNextTokenFromBreak(const Token *breakToken)
913 {
914  const Scope *scope = breakToken->scope();
915  while (scope) {
916  if (scope->isLoopScope() || scope->type == Scope::ScopeType::eSwitch) {
917  if (scope->type == Scope::ScopeType::eDo && Token::simpleMatch(scope->bodyEnd, "} while ("))
918  return scope->bodyEnd->linkAt(2)->next();
919  return scope->bodyEnd;
920  }
921  scope = scope->nestedIn;
922  }
923  return nullptr;
924 }
925 
926 bool extractForLoopValues(const Token *forToken,
927  nonneg int &varid,
928  bool &knownInitValue,
929  MathLib::bigint &initValue,
930  bool &partialCond,
931  MathLib::bigint &stepValue,
932  MathLib::bigint &lastValue)
933 {
934  if (!Token::simpleMatch(forToken, "for (") || !Token::simpleMatch(forToken->next()->astOperand2(), ";"))
935  return false;
936  const Token *initExpr = forToken->next()->astOperand2()->astOperand1();
937  const Token *condExpr = forToken->next()->astOperand2()->astOperand2()->astOperand1();
938  const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2();
939  if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%"))
940  return false;
941  std::vector<MathLib::bigint> minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values());
942  if (minInitValue.empty()) {
943  const ValueFlow::Value* v = initExpr->astOperand2()->getMinValue(true);
944  if (v)
945  minInitValue.push_back(v->intvalue);
946  }
947  if (minInitValue.empty())
948  return false;
949  varid = initExpr->astOperand1()->varId();
950  knownInitValue = initExpr->astOperand2()->hasKnownIntValue();
951  initValue = minInitValue.front();
952  partialCond = Token::Match(condExpr, "%oror%|&&");
953  visitAstNodes(condExpr, [varid, &condExpr](const Token *tok) {
954  if (Token::Match(tok, "%oror%|&&"))
956  if (Token::Match(tok, "<|<=") && tok->isBinaryOp() && tok->astOperand1()->varId() == varid && tok->astOperand2()->hasKnownIntValue()) {
957  if (Token::Match(condExpr, "%oror%|&&") || tok->astOperand2()->getKnownIntValue() < condExpr->astOperand2()->getKnownIntValue())
958  condExpr = tok;
959  }
960  return ChildrenToVisit::none;
961  });
962  if (!Token::Match(condExpr, "<|<=") || !condExpr->isBinaryOp() || condExpr->astOperand1()->varId() != varid || !condExpr->astOperand2()->hasKnownIntValue())
963  return false;
964  if (!incExpr || !incExpr->isUnaryOp("++") || incExpr->astOperand1()->varId() != varid)
965  return false;
966  stepValue = 1;
967  if (condExpr->str() == "<")
968  lastValue = condExpr->astOperand2()->getKnownIntValue() - 1;
969  else
970  lastValue = condExpr->astOperand2()->getKnownIntValue();
971  return true;
972 }
973 
974 
975 static const Token * getVariableInitExpression(const Variable * var)
976 {
977  if (!var)
978  return nullptr;
979  const Token *varDeclEndToken = var->declEndToken();
980  if (!varDeclEndToken)
981  return nullptr;
982  if (Token::Match(varDeclEndToken, "; %varid% =", var->declarationId()))
983  return varDeclEndToken->tokAt(2)->astOperand2();
984  return varDeclEndToken->astOperand2();
985 }
986 
987 const Token* isInLoopCondition(const Token* tok)
988 {
989  const Token* top = tok->astTop();
990  return top && Token::Match(top->previous(), "for|while (") ? top : nullptr;
991 }
992 
993 /// If tok2 comes after tok1
994 bool precedes(const Token * tok1, const Token * tok2)
995 {
996  if (tok1 == tok2)
997  return false;
998  if (!tok1)
999  return false;
1000  if (!tok2)
1001  return true;
1002  return tok1->index() < tok2->index();
1003 }
1004 
1005 /// If tok1 comes after tok2
1006 bool succeeds(const Token* tok1, const Token* tok2)
1007 {
1008  if (tok1 == tok2)
1009  return false;
1010  if (!tok1)
1011  return false;
1012  if (!tok2)
1013  return true;
1014  return tok1->index() > tok2->index();
1015 }
1016 
1017 bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive)
1018 {
1019  if (tok->varId() == varid)
1020  return false;
1021  // NOLINTNEXTLINE(readability-use-anyofallof) - TODO: fix this / also Cppcheck false negative
1022  for (const ValueFlow::Value &val : tok->values()) {
1023  if (!val.isLocalLifetimeValue())
1024  continue;
1025  if (val.tokvalue->varId() == varid) {
1026  if (val.isInconclusive()) {
1027  if (inconclusive)
1028  *inconclusive = true;
1029  else
1030  continue;
1031  }
1032  return true;
1033  }
1034  }
1035  return false;
1036 }
1037 
1038 bool isAliasOf(const Token* tok, const Token* expr, int* indirect, bool* inconclusive)
1039 {
1040  const ValueFlow::Value* value = nullptr;
1041  const Token* r = nullptr;
1042  if (indirect)
1043  *indirect = 1;
1044  for (const ReferenceToken& ref : followAllReferences(tok)) {
1045  const bool pointer = astIsPointer(ref.token);
1046  r = findAstNode(expr, [&](const Token* childTok) {
1047  if (childTok->exprId() == 0)
1048  return false;
1049  if (ref.token != tok && expr->exprId() == childTok->exprId()) {
1050  if (indirect)
1051  *indirect = 0;
1052  return true;
1053  }
1054  for (const ValueFlow::Value& val : ref.token->values()) {
1055  if (val.isImpossible())
1056  continue;
1057  if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
1058  if (findAstNode(val.tokvalue,
1059  [&](const Token* aliasTok) {
1060  return aliasTok != childTok && aliasTok->exprId() == childTok->exprId();
1061  })) {
1062  if (val.isInconclusive() && inconclusive != nullptr) {
1063  value = &val;
1064  } else {
1065  return true;
1066  }
1067  }
1068  }
1069  }
1070  return false;
1071  });
1072  if (r)
1073  break;
1074  }
1075  if (!r && value && inconclusive)
1076  *inconclusive = true;
1077  return r || value;
1078 }
1079 
1080 static bool isAliased(const Token *startTok, const Token *endTok, nonneg int varid)
1081 {
1082  if (!precedes(startTok, endTok))
1083  return false;
1084  for (const Token *tok = startTok; tok != endTok; tok = tok->next()) {
1085  if (Token::Match(tok, "= & %varid% ;", varid))
1086  return true;
1087  if (isAliasOf(tok, varid))
1088  return true;
1089  }
1090  return false;
1091 }
1092 
1093 bool isAliased(const Variable *var)
1094 {
1095  if (!var)
1096  return false;
1097  if (!var->scope())
1098  return false;
1099  const Token *start = var->declEndToken();
1100  if (!start)
1101  return false;
1102  return isAliased(start, var->scope()->bodyEnd, var->declarationId());
1103 }
1104 
1105 bool exprDependsOnThis(const Token* expr, bool onVar, nonneg int depth)
1106 {
1107  if (!expr)
1108  return false;
1109  if (expr->str() == "this")
1110  return true;
1111  if (depth >= 1000)
1112  // Abort recursion to avoid stack overflow
1113  return true;
1114  ++depth;
1115 
1116  // calling nonstatic method?
1117  if (Token::Match(expr, "%name% (") && expr->function() && expr->function()->nestedIn && expr->function()->nestedIn->isClassOrStruct() && !expr->function()->isStatic()) {
1118  // is it a method of this?
1119  const Scope* fScope = expr->scope();
1120  while (!fScope->functionOf && fScope->nestedIn)
1121  fScope = fScope->nestedIn;
1122 
1123  const Scope* classScope = fScope->functionOf;
1124  if (classScope && classScope->function)
1125  classScope = classScope->function->token->scope();
1126 
1127  if (classScope && classScope->isClassOrStruct())
1128  return contains(classScope->findAssociatedScopes(), expr->function()->nestedIn);
1129  return false;
1130  }
1131  if (onVar && expr->variable()) {
1132  const Variable* var = expr->variable();
1133  return ((var->isPrivate() || var->isPublic() || var->isProtected()) && !var->isStatic());
1134  }
1135  if (Token::simpleMatch(expr, "."))
1136  return exprDependsOnThis(expr->astOperand1(), onVar, depth);
1137  return exprDependsOnThis(expr->astOperand1(), onVar, depth) || exprDependsOnThis(expr->astOperand2(), onVar, depth);
1138 }
1139 
1140 static bool hasUnknownVars(const Token* startTok)
1141 {
1142  bool result = false;
1143  visitAstNodes(startTok, [&](const Token* tok) {
1144  if (tok->varId() > 0 && !tok->variable()) {
1145  result = true;
1146  return ChildrenToVisit::done;
1147  }
1149  });
1150  return result;
1151 }
1152 
1154 {
1155  if (!var)
1156  return false;
1157  const Token* tok = var->nameToken();
1158  while (tok && Token::Match(tok->astParent(), "[|,|:"))
1159  tok = tok->astParent();
1160  return tok && (tok->str() == "[" || Token::simpleMatch(tok->previous(), "] :")); // TODO: remove workaround when #11105 is fixed
1161 }
1162 
1163 /// This takes a token that refers to a variable and it will return the token
1164 /// to the expression that the variable is assigned to. If its not valid to
1165 /// make such substitution then it will return the original token.
1166 static const Token * followVariableExpression(const Settings& settings, const Token * tok, const Token * end = nullptr)
1167 {
1168  if (!tok)
1169  return tok;
1170  // Skip following variables that is across multiple files
1171  if (end && end->fileIndex() != tok->fileIndex())
1172  return tok;
1173  // Skip array access
1174  if (Token::Match(tok, "%var% ["))
1175  return tok;
1176  // Skip pointer indirection
1177  if (tok->astParent() && tok->isUnaryOp("*"))
1178  return tok;
1179  // Skip following variables if it is used in an assignment
1180  if (Token::Match(tok->next(), "%assign%"))
1181  return tok;
1182  const Variable * var = tok->variable();
1183  const Token * varTok = getVariableInitExpression(var);
1184  if (!varTok)
1185  return tok;
1186  if (hasUnknownVars(varTok))
1187  return tok;
1188  if (var->isVolatile())
1189  return tok;
1190  if (!var->isLocal() && !var->isConst())
1191  return tok;
1192  if (var->isStatic() && !var->isConst())
1193  return tok;
1194  if (var->isArgument())
1195  return tok;
1196  if (isStructuredBindingVariable(var))
1197  return tok;
1198  // assigning a floating point value to an integer does not preserve the value
1199  if (var->valueType() && var->valueType()->isIntegral() && varTok->valueType() && varTok->valueType()->isFloat())
1200  return tok;
1201  const Token * lastTok = precedes(tok, end) ? end : tok;
1202  // If this is in a loop then check if variables are modified in the entire scope
1203  const Token * endToken = (isInLoopCondition(tok) || isInLoopCondition(varTok) || var->scope() != tok->scope()) ? var->scope()->bodyEnd : lastTok;
1204  if (!var->isConst() && (!precedes(varTok, endToken) || isVariableChanged(varTok, endToken, tok->varId(), false, settings)))
1205  return tok;
1206  if (precedes(varTok, endToken) && isAliased(varTok, endToken, tok->varId()))
1207  return tok;
1208  const Token* startToken = nextAfterAstRightmostLeaf(varTok);
1209  if (!startToken)
1210  startToken = varTok;
1211  if (varTok->exprId() == 0) {
1212  if (!varTok->isLiteral())
1213  return tok;
1214  } else if (!precedes(startToken, endToken)) {
1215  return tok;
1216  } else if (findExpressionChanged(varTok, startToken, endToken, settings)) {
1217  return tok;
1218  }
1219  return varTok;
1220 }
1221 
1222 static void followVariableExpressionError(const Token *tok1, const Token *tok2, ErrorPath* errors)
1223 {
1224  if (!errors)
1225  return;
1226  if (!tok1)
1227  return;
1228  if (!tok2)
1229  return;
1230  ErrorPathItem item = std::make_pair(tok2, "'" + tok1->str() + "' is assigned value '" + tok2->expressionString() + "' here.");
1231  if (std::find(errors->cbegin(), errors->cend(), item) != errors->cend())
1232  return;
1233  errors->push_back(std::move(item));
1234 }
1235 
1237  bool temporary,
1238  bool inconclusive,
1239  ErrorPath errors,
1240  int depth)
1241 {
1242  struct ReferenceTokenLess {
1243  bool operator()(const ReferenceToken& x, const ReferenceToken& y) const {
1244  return x.token < y.token;
1245  }
1246  };
1247  if (!tok)
1248  return {};
1249  if (depth < 0) {
1250  SmallVector<ReferenceToken> refs_result;
1251  refs_result.push_back({tok, std::move(errors)});
1252  return refs_result;
1253  }
1254  const Variable *var = tok->variable();
1255  if (var && var->declarationId() == tok->varId()) {
1256  if (var->nameToken() == tok || isStructuredBindingVariable(var)) {
1257  SmallVector<ReferenceToken> refs_result;
1258  refs_result.push_back({tok, std::move(errors)});
1259  return refs_result;
1260  }
1261  if (var->isReference() || var->isRValueReference()) {
1262  const Token * const varDeclEndToken = var->declEndToken();
1263  if (!varDeclEndToken) {
1264  SmallVector<ReferenceToken> refs_result;
1265  refs_result.push_back({tok, std::move(errors)});
1266  return refs_result;
1267  }
1268  if (var->isArgument()) {
1269  errors.emplace_back(varDeclEndToken, "Passed to reference.");
1270  SmallVector<ReferenceToken> refs_result;
1271  refs_result.push_back({tok, std::move(errors)});
1272  return refs_result;
1273  }
1274  if (Token::simpleMatch(varDeclEndToken, "=")) {
1275  if (astHasToken(varDeclEndToken, tok))
1276  return {};
1277  errors.emplace_back(varDeclEndToken, "Assigned to reference.");
1278  const Token *vartok = varDeclEndToken->astOperand2();
1279  if (vartok == tok || (!temporary && isTemporary(vartok, nullptr, true) &&
1280  (var->isConst() || var->isRValueReference()))) {
1281  SmallVector<ReferenceToken> refs_result;
1282  refs_result.push_back({tok, std::move(errors)});
1283  return refs_result;
1284  }
1285  if (vartok)
1286  return followAllReferences(vartok, temporary, inconclusive, std::move(errors), depth - 1);
1287  }
1288  }
1289  } else if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) {
1290  std::set<ReferenceToken, ReferenceTokenLess> result;
1291  const Token* tok2 = tok->astOperand2();
1292 
1293  auto refs = followAllReferences(tok2->astOperand1(), temporary, inconclusive, errors, depth - 1);
1294  result.insert(refs.cbegin(), refs.cend());
1295  refs = followAllReferences(tok2->astOperand2(), temporary, inconclusive, errors, depth - 1);
1296  result.insert(refs.cbegin(), refs.cend());
1297 
1298  if (!inconclusive && result.size() != 1) {
1299  SmallVector<ReferenceToken> refs_result;
1300  refs_result.push_back({tok, std::move(errors)});
1301  return refs_result;
1302  }
1303 
1304  if (!result.empty()) {
1305  SmallVector<ReferenceToken> refs_result;
1306  refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
1307  return refs_result;
1308  }
1309 
1310  } else if (tok->previous() && tok->previous()->function() && Token::Match(tok->previous(), "%name% (")) {
1311  const Function *f = tok->previous()->function();
1312  if (!Function::returnsReference(f)) {
1313  SmallVector<ReferenceToken> refs_result;
1314  refs_result.push_back({tok, std::move(errors)});
1315  return refs_result;
1316  }
1317  std::set<ReferenceToken, ReferenceTokenLess> result;
1318  std::vector<const Token*> returns = Function::findReturns(f);
1319  for (const Token* returnTok : returns) {
1320  if (returnTok == tok)
1321  continue;
1322  for (const ReferenceToken& rt :
1323  followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
1324  const Variable* argvar = rt.token->variable();
1325  if (!argvar) {
1326  SmallVector<ReferenceToken> refs_result;
1327  refs_result.push_back({tok, std::move(errors)});
1328  return refs_result;
1329  }
1330  if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
1331  const int n = getArgumentPos(argvar, f);
1332  if (n < 0) {
1333  SmallVector<ReferenceToken> refs_result;
1334  refs_result.push_back({tok, std::move(errors)});
1335  return refs_result;
1336  }
1337  std::vector<const Token*> args = getArguments(tok->previous());
1338  if (n >= args.size()) {
1339  SmallVector<ReferenceToken> refs_result;
1340  refs_result.push_back({tok, std::move(errors)});
1341  return refs_result;
1342  }
1343  const Token* argTok = args[n];
1344  ErrorPath er = errors;
1345  er.emplace_back(returnTok, "Return reference.");
1346  er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
1347  auto refs =
1348  followAllReferences(argTok, temporary, inconclusive, std::move(er), depth - returns.size());
1349  result.insert(refs.cbegin(), refs.cend());
1350  if (!inconclusive && result.size() > 1) {
1351  SmallVector<ReferenceToken> refs_result;
1352  refs_result.push_back({tok, std::move(errors)});
1353  return refs_result;
1354  }
1355  }
1356  }
1357  }
1358  if (!result.empty()) {
1359  SmallVector<ReferenceToken> refs_result;
1360  refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
1361  return refs_result;
1362  }
1363  }
1364  SmallVector<ReferenceToken> refs_result;
1365  refs_result.push_back({tok, std::move(errors)});
1366  return refs_result;
1367 }
1368 
1369 const Token* followReferences(const Token* tok, ErrorPath* errors)
1370 {
1371  if (!tok)
1372  return nullptr;
1373  auto refs = followAllReferences(tok, true, false);
1374  if (refs.size() == 1) {
1375  if (errors)
1376  *errors = std::move(refs.front().errors);
1377  return refs.front().token;
1378  }
1379  return nullptr;
1380 }
1381 
1382 static bool isSameLifetime(const Token * const tok1, const Token * const tok2)
1383 {
1385  if (!v1.isLifetimeValue())
1386  return false;
1388  if (!v2.isLifetimeValue())
1389  return false;
1390  return v1.tokvalue == v2.tokvalue;
1391 }
1392 
1393 static bool compareKnownValue(const Token * const tok1, const Token * const tok2, const std::function<bool(const ValueFlow::Value&, const ValueFlow::Value&, bool)> &compare)
1394 {
1395  static const auto isKnownFn = std::mem_fn(&ValueFlow::Value::isKnown);
1396 
1397  const auto v1 = std::find_if(tok1->values().cbegin(), tok1->values().cend(), isKnownFn);
1398  if (v1 == tok1->values().end()) {
1399  return false;
1400  }
1401  if (v1->isNonValue() || v1->isContainerSizeValue() || v1->isSymbolicValue())
1402  return false;
1403  const auto v2 = std::find_if(tok2->values().cbegin(), tok2->values().cend(), isKnownFn);
1404  if (v2 == tok2->values().end()) {
1405  return false;
1406  }
1407  if (v1->valueType != v2->valueType) {
1408  return false;
1409  }
1410  const bool sameLifetime = isSameLifetime(tok1, tok2);
1411  return compare(*v1, *v2, sameLifetime);
1412 }
1413 
1414 bool isEqualKnownValue(const Token * const tok1, const Token * const tok2)
1415 {
1416  return compareKnownValue(tok1, tok2, [&](const ValueFlow::Value& v1, const ValueFlow::Value& v2, bool sameLifetime) {
1417  bool r = v1.equalValue(v2);
1418  if (v1.isIteratorValue()) {
1419  r &= sameLifetime;
1420  }
1421  return r;
1422  });
1423 }
1424 
1425 static inline bool isDifferentKnownValues(const Token * const tok1, const Token * const tok2)
1426 {
1427  return compareKnownValue(tok1, tok2, [&](const ValueFlow::Value& v1, const ValueFlow::Value& v2, bool sameLifetime) {
1428  bool r = v1.equalValue(v2);
1429  if (v1.isIteratorValue()) {
1430  r &= sameLifetime;
1431  }
1432  return !r;
1433  });
1434 }
1435 
1436 static inline bool isSameConstantValue(bool macro, const Token* tok1, const Token* tok2)
1437 {
1438  if (tok1 == nullptr || tok2 == nullptr)
1439  return false;
1440 
1441  auto adjustForCast = [](const Token* tok) {
1442  if (tok->astOperand2() && Token::Match(tok->previous(), "%type% (|{") && tok->previous()->isStandardType())
1443  return tok->astOperand2();
1444  return tok;
1445  };
1446 
1447  tok1 = adjustForCast(tok1);
1448  if (!tok1->isNumber() && !tok1->enumerator())
1449  return false;
1450  tok2 = adjustForCast(tok2);
1451  if (!tok2->isNumber() && !tok2->enumerator())
1452  return false;
1453 
1454  if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro() || tok1->isTemplateArg() || tok2->isTemplateArg()))
1455  return false;
1456 
1457  const ValueType * v1 = tok1->valueType();
1458  const ValueType * v2 = tok2->valueType();
1459 
1460  if (!v1 || !v2 || v1->sign != v2->sign || v1->type != v2->type || v1->pointer != v2->pointer)
1461  return false;
1462 
1463  return isEqualKnownValue(tok1, tok2);
1464 }
1465 
1466 
1467 static bool isForLoopCondition(const Token * const tok)
1468 {
1469  if (!tok)
1470  return false;
1471  const Token *const parent = tok->astParent();
1472  return Token::simpleMatch(parent, ";") && parent->astOperand1() == tok &&
1473  Token::simpleMatch(parent->astParent(), ";") &&
1474  Token::simpleMatch(parent->astParent()->astParent(), "(") &&
1475  parent->astParent()->astParent()->astOperand1()->str() == "for";
1476 }
1477 
1478 static bool isForLoopIncrement(const Token* const tok)
1479 {
1480  if (!tok)
1481  return false;
1482  const Token *const parent = tok->astParent();
1483  return Token::simpleMatch(parent, ";") && parent->astOperand2() == tok &&
1484  Token::simpleMatch(parent->astParent(), ";") &&
1485  Token::simpleMatch(parent->astParent()->astParent(), "(") &&
1486  parent->astParent()->astParent()->astOperand1()->str() == "for";
1487 }
1488 
1489 bool isUsedAsBool(const Token* const tok, const Settings& settings)
1490 {
1491  if (!tok)
1492  return false;
1493  if (isForLoopIncrement(tok))
1494  return false;
1495  if (astIsBool(tok))
1496  return true;
1497  if (Token::Match(tok, "!|&&|%oror%|%comp%"))
1498  return true;
1499  const Token* parent = tok->astParent();
1500  if (!parent)
1501  return false;
1502  if (Token::simpleMatch(parent, "["))
1503  return false;
1504  if (parent->isUnaryOp("*"))
1505  return false;
1506  if (Token::simpleMatch(parent, ".")) {
1507  if (astIsRHS(tok))
1508  return isUsedAsBool(parent, settings);
1509  return false;
1510  }
1511  if (Token::Match(parent, "&&|!|%oror%"))
1512  return true;
1513  if (parent->isCast())
1514  return !Token::simpleMatch(parent->astOperand1(), "dynamic_cast") && isUsedAsBool(parent, settings);
1515  if (parent->isUnaryOp("*"))
1516  return isUsedAsBool(parent, settings);
1517  if (Token::Match(parent, "==|!=") && (tok->astSibling()->isNumber() || tok->astSibling()->isKeyword()) && tok->astSibling()->hasKnownIntValue() &&
1518  tok->astSibling()->values().front().intvalue == 0)
1519  return true;
1520  if (parent->str() == "(" && astIsRHS(tok) && Token::Match(parent->astOperand1(), "if|while"))
1521  return true;
1522  if (Token::simpleMatch(parent, "?") && astIsLHS(tok))
1523  return true;
1524  if (isForLoopCondition(tok))
1525  return true;
1526  if (!Token::Match(parent, "%cop%") && !(parent->str() == "(" && tok == parent->astOperand1())) {
1527  if (parent->str() == "," && parent->isInitComma())
1528  return false;
1529  std::vector<ValueType> vtParents = getParentValueTypes(tok, settings);
1530  return std::any_of(vtParents.cbegin(), vtParents.cend(), [&](const ValueType& vt) {
1531  return vt.pointer == 0 && vt.type == ValueType::BOOL;
1532  });
1533  }
1534  return false;
1535 }
1536 
1537 bool compareTokenFlags(const Token* tok1, const Token* tok2, bool macro) {
1538  if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro() || tok1->isTemplateArg() || tok2->isTemplateArg()))
1539  return false;
1540  if (tok1->isComplex() != tok2->isComplex())
1541  return false;
1542  if (tok1->isLong() != tok2->isLong())
1543  return false;
1544  if (tok1->isUnsigned() != tok2->isUnsigned())
1545  return false;
1546  if (tok1->isSigned() != tok2->isSigned())
1547  return false;
1548  return true;
1549 }
1550 
1551 static bool astIsBoolLike(const Token* tok, const Settings& settings)
1552 {
1553  return astIsBool(tok) || isUsedAsBool(tok, settings);
1554 }
1555 
1556 bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1557 {
1558  if (tok1 == tok2)
1559  return true;
1560  if (tok1 == nullptr || tok2 == nullptr)
1561  return false;
1562  // tokens needs to be from the same TokenList so no need check standard on both of them
1563  if (tok1->isCpp()) {
1564  if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this")
1565  tok1 = tok1->astOperand2();
1566  if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
1567  tok2 = tok2->astOperand2();
1568  }
1569  // Skip double not
1570  if (Token::simpleMatch(tok1, "!") && Token::simpleMatch(tok1->astOperand1(), "!") && !Token::simpleMatch(tok1->astParent(), "=") && astIsBoolLike(tok2, settings)) {
1571  return isSameExpression(macro, tok1->astOperand1()->astOperand1(), tok2, settings, pure, followVar, errors);
1572  }
1573  if (Token::simpleMatch(tok2, "!") && Token::simpleMatch(tok2->astOperand1(), "!") && !Token::simpleMatch(tok2->astParent(), "=") && astIsBoolLike(tok1, settings)) {
1574  return isSameExpression(macro, tok1, tok2->astOperand1()->astOperand1(), settings, pure, followVar, errors);
1575  }
1576  const bool tok_str_eq = tok1->str() == tok2->str();
1577  if (!tok_str_eq && isDifferentKnownValues(tok1, tok2))
1578  return false;
1579 
1580  const Token *followTok1 = tok1, *followTok2 = tok2;
1581  while (Token::simpleMatch(followTok1, "::") && followTok1->astOperand2())
1582  followTok1 = followTok1->astOperand2();
1583  while (Token::simpleMatch(followTok2, "::") && followTok2->astOperand2())
1584  followTok2 = followTok2->astOperand2();
1585  if (isSameConstantValue(macro, followTok1, followTok2))
1586  return true;
1587 
1588  // Follow variable
1589  if (followVar && !tok_str_eq && (followTok1->varId() || followTok2->varId() || followTok1->enumerator() || followTok2->enumerator())) {
1590  const Token * varTok1 = followVariableExpression(settings, followTok1, followTok2);
1591  if ((varTok1->str() == followTok2->str()) || isSameConstantValue(macro, varTok1, followTok2)) {
1592  followVariableExpressionError(followTok1, varTok1, errors);
1593  return isSameExpression(macro, varTok1, followTok2, settings, true, followVar, errors);
1594  }
1595  const Token * varTok2 = followVariableExpression(settings, followTok2, followTok1);
1596  if ((followTok1->str() == varTok2->str()) || isSameConstantValue(macro, followTok1, varTok2)) {
1597  followVariableExpressionError(followTok2, varTok2, errors);
1598  return isSameExpression(macro, followTok1, varTok2, settings, true, followVar, errors);
1599  }
1600  if ((varTok1->str() == varTok2->str()) || isSameConstantValue(macro, varTok1, varTok2)) {
1601  followVariableExpressionError(tok1, varTok1, errors);
1602  followVariableExpressionError(tok2, varTok2, errors);
1603  return isSameExpression(macro, varTok1, varTok2, settings, true, followVar, errors);
1604  }
1605  }
1606  // Follow references
1607  if (!tok_str_eq) {
1608  const Token* refTok1 = followReferences(tok1, errors);
1609  const Token* refTok2 = followReferences(tok2, errors);
1610  if (refTok1 != tok1 || refTok2 != tok2) {
1611  if (refTok1 && !refTok1->varId() && refTok2 && !refTok2->varId()) { // complex reference expression
1612  const Token *start = refTok1, *end = refTok2;
1613  if (!precedes(start, end))
1614  std::swap(start, end);
1615  if (findExpressionChanged(start, start, end, settings))
1616  return false;
1617  }
1618  return isSameExpression(macro, refTok1, refTok2, settings, pure, followVar, errors);
1619  }
1620  }
1621  if (tok1->varId() != tok2->varId() || !tok_str_eq || tok1->originalName() != tok2->originalName()) {
1622  if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
1623  (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
1624  return isSameExpression(macro, tok1->astOperand1(), tok2->astOperand2(), settings, pure, followVar, errors) &&
1625  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand1(), settings, pure, followVar, errors);
1626  }
1627  const Token* condTok = nullptr;
1628  const Token* exprTok = nullptr;
1629  if (Token::Match(tok1, "==|!=")) {
1630  condTok = tok1;
1631  exprTok = tok2;
1632  } else if (Token::Match(tok2, "==|!=")) {
1633  condTok = tok2;
1634  exprTok = tok1;
1635  }
1636  if (condTok && condTok->astOperand1() && condTok->astOperand2() && !Token::Match(exprTok, "%comp%")) {
1637  const Token* varTok1 = nullptr;
1638  const Token* varTok2 = exprTok;
1639  const ValueFlow::Value* value = nullptr;
1640  if (condTok->astOperand1()->hasKnownIntValue()) {
1641  value = &condTok->astOperand1()->values().front();
1642  varTok1 = condTok->astOperand2();
1643  } else if (condTok->astOperand2()->hasKnownIntValue()) {
1644  value = &condTok->astOperand2()->values().front();
1645  varTok1 = condTok->astOperand1();
1646  }
1647  const bool exprIsNot = Token::simpleMatch(exprTok, "!");
1648  if (exprIsNot)
1649  varTok2 = exprTok->astOperand1();
1650  bool compare = false;
1651  if (value) {
1652  if (value->intvalue == 0 && exprIsNot && Token::simpleMatch(condTok, "==")) {
1653  compare = true;
1654  } else if (value->intvalue == 0 && !exprIsNot && Token::simpleMatch(condTok, "!=")) {
1655  compare = true;
1656  } else if (value->intvalue != 0 && exprIsNot && Token::simpleMatch(condTok, "!=")) {
1657  compare = true;
1658  } else if (value->intvalue != 0 && !exprIsNot && Token::simpleMatch(condTok, "==")) {
1659  compare = true;
1660  }
1661  }
1662  if (compare && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings))
1663  return isSameExpression(macro, varTok1, varTok2, settings, pure, followVar, errors);
1664 
1665  }
1666  return false;
1667  }
1668 
1669  if (!compareTokenFlags(tok1, tok2, macro))
1670  return false;
1671 
1672  if (pure && tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof" && !(tok1->variable() && tok1 == tok1->variable()->nameToken())) {
1673  if (!tok1->function()) {
1674  if (Token::simpleMatch(tok1->previous(), ".")) {
1675  const Token *lhs = tok1->previous();
1676  while (Token::Match(lhs, "(|.|["))
1677  lhs = lhs->astOperand1();
1678  if (!lhs)
1679  return false;
1680  const bool lhsIsConst = (lhs->variable() && lhs->variable()->isConst()) ||
1681  (lhs->valueType() && lhs->valueType()->constness > 0) ||
1682  (Token::Match(lhs, "%var% . %name% (") && settings.library.isFunctionConst(lhs->tokAt(2)));
1683  if (!lhsIsConst)
1684  return false;
1685  } else {
1686  const Token * ftok = tok1;
1687  if (!settings.library.isFunctionConst(ftok) && !ftok->isAttributeConst() && !ftok->isAttributePure())
1688  return false;
1689  }
1690  } else {
1691  if (!tok1->function()->isConst() && !tok1->function()->isAttributeConst() &&
1692  !tok1->function()->isAttributePure())
1693  return false;
1694  }
1695  }
1696  // templates/casts
1697  if ((tok1->next() && tok1->next()->link() && Token::Match(tok1, "%name% <")) ||
1698  (tok2->next() && tok2->next()->link() && Token::Match(tok2, "%name% <"))) {
1699 
1700  // non-const template function that is not a dynamic_cast => return false
1701  if (pure && Token::simpleMatch(tok1->next()->link(), "> (") &&
1702  !(tok1->function() && tok1->function()->isConst()) &&
1703  tok1->str() != "dynamic_cast")
1704  return false;
1705 
1706  // some template/cast stuff.. check that the template arguments are same
1707  const Token *t1 = tok1->next();
1708  const Token *t2 = tok2->next();
1709  const Token *end1 = t1->link();
1710  const Token *end2 = t2->link();
1711  while (t1 && t2 && t1 != end1 && t2 != end2) {
1712  if (t1->str() != t2->str() || !compareTokenFlags(t1, t2, macro))
1713  return false;
1714  t1 = t1->next();
1715  t2 = t2->next();
1716  }
1717  if (t1 != end1 || t2 != end2)
1718  return false;
1719  }
1720  if (tok1->tokType() == Token::eIncDecOp || tok1->isAssignmentOp())
1721  return false;
1722  // bailout when we see ({..})
1723  if (tok1->str() == "{")
1724  return false;
1725  // cast => assert that the casts are equal
1726  if (tok1->str() == "(" && tok1->previous() &&
1727  !tok1->previous()->isName() &&
1728  !(tok1->previous()->str() == ">" && tok1->previous()->link())) {
1729  const Token *t1 = tok1->next();
1730  const Token *t2 = tok2->next();
1731  while (t1 && t2 &&
1732  t1->str() == t2->str() &&
1733  compareTokenFlags(t1, t2, macro) &&
1734  (t1->isName() || t1->str() == "*")) {
1735  t1 = t1->next();
1736  t2 = t2->next();
1737  }
1738  if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")")
1739  return false;
1740  }
1741  bool noncommutativeEquals =
1742  isSameExpression(macro, tok1->astOperand1(), tok2->astOperand1(), settings, pure, followVar, errors);
1743  noncommutativeEquals = noncommutativeEquals &&
1744  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand2(), settings, pure, followVar, errors);
1745 
1746  if (noncommutativeEquals)
1747  return true;
1748 
1749  // in c++, a+b might be different to b+a, depending on the type of a and b
1750  if (tok1->isCpp() && tok1->str() == "+" && tok1->isBinaryOp()) {
1751  const ValueType* vt1 = tok1->astOperand1()->valueType();
1752  const ValueType* vt2 = tok1->astOperand2()->valueType();
1753  if (!(vt1 && (vt1->type >= ValueType::VOID || vt1->pointer) && vt2 && (vt2->type >= ValueType::VOID || vt2->pointer)))
1754  return false;
1755  }
1756 
1757  const bool commutative = tok1->isBinaryOp() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
1758  bool commutativeEquals = commutative &&
1759  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand1(), settings, pure, followVar, errors);
1760  commutativeEquals = commutativeEquals &&
1761  isSameExpression(macro, tok1->astOperand1(), tok2->astOperand2(), settings, pure, followVar, errors);
1762 
1763 
1764  return commutativeEquals;
1765 }
1766 
1767 static bool isZeroBoundCond(const Token * const cond)
1768 {
1769  if (cond == nullptr)
1770  return false;
1771  // Assume unsigned
1772  // TODO: Handle reverse conditions
1773  const bool isZero = cond->astOperand2()->getValue(0);
1774  if (cond->str() == "==" || cond->str() == ">=")
1775  return isZero;
1776  if (cond->str() == "<=")
1777  return true;
1778  if (cond->str() == "<")
1779  return !isZero;
1780  if (cond->str() == ">")
1781  return false;
1782  return false;
1783 }
1784 
1785 bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1786 {
1787  if (!cond1 || !cond2)
1788  return false;
1789 
1790  if (isSameExpression(true, cond1, cond2, settings, pure, followVar, errors))
1791  return false;
1792 
1793  if (!isNot && cond1->str() == "&&" && cond2->str() == "&&") {
1794  for (const Token* tok1: {
1795  cond1->astOperand1(), cond1->astOperand2()
1796  }) {
1797  for (const Token* tok2: {
1798  cond2->astOperand1(), cond2->astOperand2()
1799  }) {
1800  if (isSameExpression(true, tok1, tok2, settings, pure, followVar, errors)) {
1801  if (isOppositeCond(isNot, tok1->astSibling(), tok2->astSibling(), settings, pure, followVar, errors))
1802  return true;
1803  }
1804  }
1805  }
1806  }
1807 
1808  if (cond1->str() != cond2->str() && (cond1->str() == "||" || cond2->str() == "||")) {
1809  const Token* orCond = nullptr;
1810  const Token* otherCond = nullptr;
1811  if (cond1->str() == "||") {
1812  orCond = cond1;
1813  otherCond = cond2;
1814  }
1815  if (cond2->str() == "||") {
1816  orCond = cond2;
1817  otherCond = cond1;
1818  }
1819  return isOppositeCond(isNot, orCond->astOperand1(), otherCond, settings, pure, followVar, errors) &&
1820  isOppositeCond(isNot, orCond->astOperand2(), otherCond, settings, pure, followVar, errors);
1821  }
1822 
1823  if (cond1->str() == "!") {
1824  if (cond2->str() == "!=") {
1825  if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
1826  return isSameExpression(true, cond1->astOperand1(), cond2->astOperand2(), settings, pure, followVar, errors);
1827  if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
1828  return isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors);
1829  }
1830  if (!isUsedAsBool(cond2, settings))
1831  return false;
1832  return isSameExpression(true, cond1->astOperand1(), cond2, settings, pure, followVar, errors);
1833  }
1834 
1835  if (cond2->str() == "!")
1836  return isOppositeCond(isNot, cond2, cond1, settings, pure, followVar, errors);
1837 
1838  if (!isNot) {
1839  if (cond1->str() == "==" && cond2->str() == "==") {
1840  if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors))
1841  return isDifferentKnownValues(cond1->astOperand2(), cond2->astOperand2());
1842  if (isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors))
1843  return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1());
1844  }
1845  // TODO: Handle reverse conditions
1848  isSameExpression(true,
1849  cond1->astOperand1()->astOperand1(),
1850  cond2->astOperand1()->astOperand1()->astOperand1(),
1851  settings,
1852  pure,
1853  followVar,
1854  errors)) {
1855  return !isZeroBoundCond(cond2);
1856  }
1857 
1860  isSameExpression(true,
1861  cond2->astOperand1()->astOperand1(),
1862  cond1->astOperand1()->astOperand1()->astOperand1(),
1863  settings,
1864  pure,
1865  followVar,
1866  errors)) {
1867  return !isZeroBoundCond(cond1);
1868  }
1869  }
1870 
1871 
1872  if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
1873  return false;
1874 
1875  const std::string &comp1 = cond1->str();
1876 
1877  // condition found .. get comparator
1878  std::string comp2;
1879  if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors) &&
1880  isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors)) {
1881  comp2 = cond2->str();
1882  } else if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand2(), settings, pure, followVar, errors) &&
1883  isSameExpression(true, cond1->astOperand2(), cond2->astOperand1(), settings, pure, followVar, errors)) {
1884  comp2 = cond2->str();
1885  if (comp2[0] == '>')
1886  comp2[0] = '<';
1887  else if (comp2[0] == '<')
1888  comp2[0] = '>';
1889  }
1890 
1891  if (!isNot && comp2.empty()) {
1892  const Token *expr1 = nullptr, *value1 = nullptr, *expr2 = nullptr, *value2 = nullptr;
1893  std::string op1 = cond1->str(), op2 = cond2->str();
1894  if (cond1->astOperand2()->hasKnownIntValue()) {
1895  expr1 = cond1->astOperand1();
1896  value1 = cond1->astOperand2();
1897  } else if (cond1->astOperand1()->hasKnownIntValue()) {
1898  expr1 = cond1->astOperand2();
1899  value1 = cond1->astOperand1();
1900  if (op1[0] == '>')
1901  op1[0] = '<';
1902  else if (op1[0] == '<')
1903  op1[0] = '>';
1904  }
1905  if (cond2->astOperand2()->hasKnownIntValue()) {
1906  expr2 = cond2->astOperand1();
1907  value2 = cond2->astOperand2();
1908  } else if (cond2->astOperand1()->hasKnownIntValue()) {
1909  expr2 = cond2->astOperand2();
1910  value2 = cond2->astOperand1();
1911  if (op2[0] == '>')
1912  op2[0] = '<';
1913  else if (op2[0] == '<')
1914  op2[0] = '>';
1915  }
1916  if (!expr1 || !value1 || !expr2 || !value2) {
1917  return false;
1918  }
1919  if (!isSameExpression(true, expr1, expr2, settings, pure, followVar, errors))
1920  return false;
1921 
1922  const ValueFlow::Value &rhsValue1 = value1->values().front();
1923  const ValueFlow::Value &rhsValue2 = value2->values().front();
1924 
1925  if (op1 == "<" || op1 == "<=")
1926  return (op2 == "==" || op2 == ">" || op2 == ">=") && (rhsValue1.intvalue < rhsValue2.intvalue);
1927  if (op1 == ">=" || op1 == ">")
1928  return (op2 == "==" || op2 == "<" || op2 == "<=") && (rhsValue1.intvalue > rhsValue2.intvalue);
1929 
1930  return false;
1931  }
1932 
1933  // is condition opposite?
1934  return ((comp1 == "==" && comp2 == "!=") ||
1935  (comp1 == "!=" && comp2 == "==") ||
1936  (comp1 == "<" && comp2 == ">=") ||
1937  (comp1 == "<=" && comp2 == ">") ||
1938  (comp1 == ">" && comp2 == "<=") ||
1939  (comp1 == ">=" && comp2 == "<") ||
1940  (!isNot && ((comp1 == "<" && comp2 == ">") ||
1941  (comp1 == ">" && comp2 == "<") ||
1942  (comp1 == "==" && (comp2 == "!=" || comp2 == ">" || comp2 == "<")) ||
1943  ((comp1 == "!=" || comp1 == ">" || comp1 == "<") && comp2 == "==")
1944  )));
1945 }
1946 
1947 bool isOppositeExpression(const Token * const tok1, const Token * const tok2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1948 {
1949  if (!tok1 || !tok2)
1950  return false;
1951  if (isOppositeCond(true, tok1, tok2, settings, pure, followVar, errors))
1952  return true;
1953  if (tok1->isUnaryOp("-") && !(tok2->astParent() && tok2->astParent()->tokType() == Token::eBitOp))
1954  return isSameExpression(true, tok1->astOperand1(), tok2, settings, pure, followVar, errors);
1955  if (tok2->isUnaryOp("-") && !(tok2->astParent() && tok2->astParent()->tokType() == Token::eBitOp))
1956  return isSameExpression(true, tok2->astOperand1(), tok1, settings, pure, followVar, errors);
1957  return false;
1958 }
1959 
1961 {
1962  return std::any_of(f->argumentList.cbegin(), f->argumentList.cend(), [](const Variable& var) {
1963  if (var.isReference() || var.isPointer())
1964  return !var.isConst();
1965  return true;
1966  });
1967 }
1968 
1969 bool isConstFunctionCall(const Token* ftok, const Library& library)
1970 {
1971  if (isUnevaluated(ftok))
1972  return true;
1973  if (!Token::Match(ftok, "%name% ("))
1974  return false;
1975  if (const Function* f = ftok->function()) {
1976  if (f->isAttributePure() || f->isAttributeConst())
1977  return true;
1978  // Any modified arguments
1980  return false;
1981  if (Function::returnsVoid(f))
1982  return false;
1983  // Member function call
1984  if (Token::simpleMatch(ftok->previous(), ".") || exprDependsOnThis(ftok->next())) {
1985  if (f->isConst())
1986  return true;
1987  // Check for const overloaded function that just return the const version
1988  if (!Function::returnsConst(f)) {
1989  std::vector<const Function*> fs = f->getOverloadedFunctions();
1990  if (std::any_of(fs.cbegin(), fs.cend(), [&](const Function* g) {
1991  if (f == g)
1992  return false;
1993  if (f->argumentList.size() != g->argumentList.size())
1994  return false;
1995  if (functionModifiesArguments(g))
1996  return false;
1997  if (g->isConst() && Function::returnsConst(g))
1998  return true;
1999  return false;
2000  }))
2001  return true;
2002  }
2003  return false;
2004  }
2005  if (f->argumentList.empty())
2006  return f->isConstexpr();
2007  } else if (Token::Match(ftok->previous(), ". %name% (") && ftok->previous()->originalName() != "->" &&
2008  astIsSmartPointer(ftok->previous()->astOperand1())) {
2009  return Token::Match(ftok, "get|get_deleter ( )");
2010  } else if (Token::Match(ftok->previous(), ". %name% (") && astIsContainer(ftok->previous()->astOperand1())) {
2011  const Library::Container* container = ftok->previous()->astOperand1()->valueType()->container;
2012  if (!container)
2013  return false;
2014  if (container->getYield(ftok->str()) != Library::Container::Yield::NO_YIELD)
2015  return true;
2016  if (container->getAction(ftok->str()) == Library::Container::Action::FIND_CONST)
2017  return true;
2018  return false;
2019  } else if (const Library::Function* lf = library.getFunction(ftok)) {
2020  if (lf->ispure)
2021  return true;
2022  if (lf->containerYield != Library::Container::Yield::NO_YIELD)
2023  return true;
2024  if (lf->containerAction == Library::Container::Action::FIND_CONST)
2025  return true;
2026  return false;
2027  } else {
2028  const bool memberFunction = Token::Match(ftok->previous(), ". %name% (");
2029  bool constMember = !memberFunction;
2030  if (Token::Match(ftok->tokAt(-2), "%var% . %name% (")) {
2031  const Variable* var = ftok->tokAt(-2)->variable();
2032  if (var)
2033  constMember = var->isConst();
2034  }
2035  // TODO: Only check const on lvalues
2036  std::vector<const Token*> args = getArguments(ftok);
2037  if (args.empty())
2038  return false;
2039  return constMember && std::all_of(args.cbegin(), args.cend(), [](const Token* tok) {
2040  const Variable* var = tok->variable();
2041  if (var)
2042  return var->isConst();
2043  return false;
2044  });
2045  }
2046  return true;
2047 }
2048 
2049 bool isConstExpression(const Token *tok, const Library& library)
2050 {
2051  if (!tok)
2052  return true;
2053  if (tok->variable() && tok->variable()->isVolatile())
2054  return false;
2055  if (tok->isName() && tok->next()->str() == "(") {
2056  if (!isConstFunctionCall(tok, library))
2057  return false;
2058  }
2059  if (tok->tokType() == Token::eIncDecOp)
2060  return false;
2061  if (tok->isAssignmentOp())
2062  return false;
2063  if (isLikelyStreamRead(tok))
2064  return false;
2065  // bailout when we see ({..})
2066  if (tok->str() == "{")
2067  return false;
2068  return isConstExpression(tok->astOperand1(), library) && isConstExpression(tok->astOperand2(), library);
2069 }
2070 
2071 bool isWithoutSideEffects(const Token* tok, bool checkArrayAccess, bool checkReference)
2072 {
2073  if (!tok)
2074  return true;
2075  if (!tok->isCpp())
2076  return true;
2077 
2078  while (tok && tok->astOperand2() && tok->astOperand2()->str() != "(")
2079  tok = tok->astOperand2();
2080  if (tok && tok->varId()) {
2081  const Variable* var = tok->variable();
2082  return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() || (checkArrayAccess ? var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const) : var->isStlType()));
2083  }
2084  return true;
2085 }
2086 
2087 bool isUniqueExpression(const Token* tok)
2088 {
2089  if (!tok)
2090  return true;
2091  if (tok->function()) {
2092  const Function * fun = tok->function();
2093  const Scope * scope = fun->nestedIn;
2094  if (!scope)
2095  return true;
2096  const std::string returnType = fun->retType ? fun->retType->name() : fun->retDef->stringifyList(fun->tokenDef);
2097  if (!std::all_of(scope->functionList.begin(), scope->functionList.end(), [&](const Function& f) {
2098  if (f.type != Function::eFunction)
2099  return true;
2100 
2101  const std::string freturnType = f.retType ? f.retType->name() : f.retDef->stringifyList(f.returnDefEnd());
2102  return f.argumentList.size() != fun->argumentList.size() || returnType != freturnType || f.name() == fun->name();
2103  }))
2104  return false;
2105  } else if (tok->variable()) {
2106  const Variable * var = tok->variable();
2107  const Scope * scope = var->scope();
2108  if (!scope)
2109  return true;
2110  const Type * varType = var->type();
2111  // Iterate over the variables in scope and the parameters of the function if possible
2112  const Function * fun = scope->function;
2113 
2114  auto pred = [=](const Variable& v) {
2115  if (varType)
2116  return v.type() && v.type()->name() == varType->name() && v.name() != var->name();
2117  return v.isFloatingType() == var->isFloatingType() &&
2118  v.isEnumType() == var->isEnumType() &&
2119  v.isClass() == var->isClass() &&
2120  v.isArray() == var->isArray() &&
2121  v.isPointer() == var->isPointer() &&
2122  v.name() != var->name();
2123  };
2124  if (std::any_of(scope->varlist.cbegin(), scope->varlist.cend(), pred))
2125  return false;
2126  if (fun) {
2127  if (std::any_of(fun->argumentList.cbegin(), fun->argumentList.cend(), pred))
2128  return false;
2129  }
2130  } else if (!isUniqueExpression(tok->astOperand1())) {
2131  return false;
2132  }
2133 
2134  return isUniqueExpression(tok->astOperand2());
2135 }
2136 
2137 static bool isEscaped(const Token* tok, bool functionsScope, const Library& library)
2138 {
2139  if (library.isnoreturn(tok))
2140  return true;
2141  if (functionsScope)
2142  return Token::simpleMatch(tok, "throw");
2143  return Token::Match(tok, "return|throw");
2144 }
2145 
2146 static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library& library)
2147 {
2148  if (library.isnoreturn(tok))
2149  return true;
2150  if (functionsScope)
2151  return Token::simpleMatch(tok, "throw");
2152  return Token::Match(tok, "return|goto|throw|continue|break");
2153 }
2154 
2155 bool isEscapeFunction(const Token* ftok, const Library* library)
2156 {
2157  if (!Token::Match(ftok, "%name% ("))
2158  return false;
2159  const Function* function = ftok->function();
2160  if (function) {
2161  if (function->isEscapeFunction())
2162  return true;
2163  if (function->isAttributeNoreturn())
2164  return true;
2165  } else if (library) {
2166  if (library->isnoreturn(ftok))
2167  return true;
2168  }
2169  return false;
2170 }
2171 
2172 static bool hasNoreturnFunction(const Token* tok, const Library& library, const Token** unknownFunc)
2173 {
2174  if (!tok)
2175  return false;
2176  const Token* ftok = tok->str() == "(" ? tok->previous() : nullptr;
2177  while (Token::simpleMatch(ftok, "("))
2178  ftok = ftok->astOperand1();
2179  if (ftok) {
2180  const Function * function = ftok->function();
2181  if (function) {
2182  if (function->isEscapeFunction())
2183  return true;
2184  if (function->isAttributeNoreturn())
2185  return true;
2186  } else if (library.isnoreturn(ftok)) {
2187  return true;
2188  } else if (Token::Match(ftok, "exit|abort")) {
2189  return true;
2190  }
2191  if (unknownFunc && !function && library.functions.count(library.getFunctionName(ftok)) == 0)
2192  *unknownFunc = ftok;
2193  return false;
2194  }
2195  if (tok->isConstOp()) {
2196  return hasNoreturnFunction(tok->astOperand1(), library, unknownFunc) || hasNoreturnFunction(tok->astOperand2(), library, unknownFunc);
2197  }
2198 
2199  return false;
2200 }
2201 
2202 bool isReturnScope(const Token* const endToken, const Library& library, const Token** unknownFunc, bool functionScope)
2203 {
2204  if (!endToken || endToken->str() != "}")
2205  return false;
2206 
2207  const Token *prev = endToken->previous();
2208  while (prev && Token::simpleMatch(prev->previous(), "; ;"))
2209  prev = prev->previous();
2210  if (prev && Token::simpleMatch(prev->previous(), "} ;"))
2211  prev = prev->previous();
2212 
2213  if (Token::simpleMatch(prev, "}")) {
2214  if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {"))
2215  return isReturnScope(prev, library, unknownFunc, functionScope) &&
2216  isReturnScope(prev->link()->tokAt(-2), library, unknownFunc, functionScope);
2217  // TODO: Check all cases
2218  if (!functionScope && Token::simpleMatch(prev->link()->previous(), ") {") &&
2219  Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") &&
2220  !Token::findsimplematch(prev->link(), "break", prev)) {
2221  return isReturnScope(prev, library, unknownFunc, functionScope);
2222  }
2223  if (isEscaped(prev->link()->astTop(), functionScope, library))
2224  return true;
2225  if (Token::Match(prev->link()->previous(), "[;{}] {"))
2226  return isReturnScope(prev, library, unknownFunc, functionScope);
2227  } else if (Token::simpleMatch(prev, ";")) {
2228  if (prev->tokAt(-2) && hasNoreturnFunction(prev->tokAt(-2)->astTop(), library, unknownFunc))
2229  return true;
2230  // Unknown symbol
2231  if (Token::Match(prev->tokAt(-2), ";|}|{ %name% ;") && prev->previous()->isIncompleteVar()) {
2232  if (unknownFunc)
2233  *unknownFunc = prev->previous();
2234  return false;
2235  }
2236  if (Token::simpleMatch(prev->previous(), ") ;") && prev->previous()->link() &&
2237  isEscaped(prev->previous()->link()->astTop(), functionScope, library))
2238  return true;
2239  if (isEscaped(prev->previous()->astTop(), functionScope, library))
2240  return true;
2241  // return/goto statement
2242  prev = prev->previous();
2243  while (prev && !Token::Match(prev, ";|{|}") && !isEscapedOrJump(prev, functionScope, library))
2244  prev = prev->previous();
2245  return prev && prev->isName();
2246  }
2247  return false;
2248 }
2249 
2250 bool isWithinScope(const Token* tok, const Variable* var, Scope::ScopeType type)
2251 {
2252  if (!tok || !var)
2253  return false;
2254  const Scope* scope = tok->scope();
2255  while (scope && scope != var->scope()) {
2256  if (scope->type == type)
2257  return true;
2258  scope = scope->nestedIn;
2259  }
2260  return false;
2261 }
2262 
2263 bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
2264 {
2265  if (!tok)
2266  return false;
2267  if (tok->varId() == varid)
2268  return isVariableChangedByFunctionCall(tok, indirect, settings, inconclusive);
2269  return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, settings, inconclusive) ||
2270  isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive);
2271 }
2272 
2273 bool isScopeBracket(const Token* tok)
2274 {
2275  if (!Token::Match(tok, "{|}"))
2276  return false;
2277  if (!tok->scope())
2278  return false;
2279  if (tok->str() == "{")
2280  return tok->scope()->bodyStart == tok;
2281  if (tok->str() == "}")
2282  return tok->scope()->bodyEnd == tok;
2283  return false;
2284 }
2285 
2286 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
2287 static T* getTokenArgumentFunctionImpl(T* tok, int& argn)
2288 {
2289  argn = -1;
2290  {
2291  T* parent = tok->astParent();
2292  if (parent && (parent->isUnaryOp("&") || parent->isIncDecOp()))
2293  parent = parent->astParent();
2294  while (parent && parent->isCast())
2295  parent = parent->astParent();
2296  if (Token::Match(parent, "[+-]") && parent->valueType() && parent->valueType()->pointer)
2297  parent = parent->astParent();
2298 
2299  // passing variable to subfunction?
2300  if (Token::Match(parent, "[*[(,{.]") || Token::Match(parent, "%oror%|&&"))
2301  ;
2302  else if (Token::simpleMatch(parent, ":")) {
2303  while (Token::Match(parent, "[?:]"))
2304  parent = parent->astParent();
2305  while (Token::simpleMatch(parent, ","))
2306  parent = parent->astParent();
2307  if (!parent || parent->str() != "(")
2308  return nullptr;
2309  } else
2310  return nullptr;
2311  }
2312 
2313  T* argtok = tok;
2314  while (argtok && argtok->astParent() && (!Token::Match(argtok->astParent(), ",|(|{") || argtok->astParent()->isCast())) {
2315  argtok = argtok->astParent();
2316  }
2317  if (!argtok)
2318  return nullptr;
2319  if (Token::simpleMatch(argtok, ","))
2320  argtok = argtok->astOperand1();
2321  tok = argtok;
2322  while (Token::Match(tok->astParent(), ",|(|{")) {
2323  tok = tok->astParent();
2324  if (Token::Match(tok, "(|{"))
2325  break;
2326  }
2327  argn = getArgumentPos(tok, argtok);
2328  if (argn == -1)
2329  return nullptr;
2330  if (!Token::Match(tok, "{|("))
2331  return nullptr;
2332  if (tok->astOperand2())
2333  tok = tok->astOperand1();
2334  while (tok && (tok->isUnaryOp("*") || tok->str() == "["))
2335  tok = tok->astOperand1();
2336  if (Token::Match(tok, ". * %name%")) // bailout for pointer to member
2337  return tok->tokAt(2);
2338  while (Token::simpleMatch(tok, "."))
2339  tok = tok->astOperand2();
2340  while (Token::simpleMatch(tok, "::")) {
2341  // If there is only a op1 and not op2, then this is a global scope
2342  if (!tok->astOperand2() && tok->astOperand1()) {
2343  tok = tok->astOperand1();
2344  break;
2345  }
2346  tok = tok->astOperand2();
2347  if (Token::simpleMatch(tok, "<") && tok->link())
2348  tok = tok->astOperand1();
2349  }
2350  if (tok && tok->link() && tok->str() == ">")
2351  tok = tok->link()->previous();
2352  if (!Token::Match(tok, "%name%|(|{"))
2353  return nullptr;
2354  // Skip labels
2355  if (Token::Match(tok, "%name% :"))
2356  return nullptr;
2357  return tok;
2358 }
2359 
2360 const Token* getTokenArgumentFunction(const Token* tok, int& argn) {
2361  return getTokenArgumentFunctionImpl(tok, argn);
2362 }
2363 
2365  return getTokenArgumentFunctionImpl(tok, argn);
2366 }
2367 
2368 std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
2369 {
2370  std::vector<const Variable*> result;
2371  if (!tok)
2372  return result;
2373  if (tok->function()) {
2374  const Variable* argvar = tok->function()->getArgumentVar(argnr);
2375  if (argvar)
2376  return {argvar};
2377  return result;
2378  }
2379  if (tok->variable() || Token::simpleMatch(tok, "{") || Token::Match(tok->previous(), "%type% (|{")) {
2380  const Type* type = Token::typeOf(tok);
2381  if (!type)
2382  return result;
2383  const Scope* typeScope = type->classScope;
2384  if (!typeScope)
2385  return result;
2386  const bool tokIsBrace = Token::simpleMatch(tok, "{");
2387  // Aggregate constructor
2388  if (tokIsBrace && typeScope->numConstructors == 0 && argnr < typeScope->varlist.size()) {
2389  auto it = std::next(typeScope->varlist.cbegin(), argnr);
2390  return {&*it};
2391  }
2392  const int argCount = numberOfArguments(tok);
2393  const bool constructor = tokIsBrace || (tok->variable() && tok->variable()->nameToken() == tok);
2394  for (const Function &function : typeScope->functionList) {
2395  if (function.argCount() < argCount)
2396  continue;
2397  if (constructor && !function.isConstructor())
2398  continue;
2399  if (!constructor && !Token::simpleMatch(function.token, "operator()"))
2400  continue;
2401  const Variable* argvar = function.getArgumentVar(argnr);
2402  if (argvar)
2403  result.push_back(argvar);
2404  }
2405  }
2406  return result;
2407 }
2408 
2409 static bool isCPPCastKeyword(const Token* tok)
2410 {
2411  if (!tok)
2412  return false;
2413  return endsWith(tok->str(), "_cast");
2414 }
2415 
2416 static bool isTrivialConstructor(const Token* tok)
2417 {
2418  const Token* typeTok = nullptr;
2419  const Type* t = Token::typeOf(tok, &typeTok);
2420  if (t)
2421  return false;
2422  if (typeTok->valueType() && typeTok->valueType()->isPrimitive())
2423  return true;
2424  return false;
2425 }
2426 
2427 static bool isArray(const Token* tok)
2428 {
2429  if (!tok)
2430  return false;
2431  if (tok->variable())
2432  return tok->variable()->isArray();
2433  if (Token::simpleMatch(tok, "."))
2434  return isArray(tok->astOperand2());
2435  return false;
2436 }
2437 
2438 bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive)
2439 {
2440  if (!tok)
2441  return false;
2442 
2443  if (Token::simpleMatch(tok, ","))
2444  return false;
2445 
2446  const Token * const tok1 = tok;
2447 
2448  // address of variable
2449  const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&");
2450  if (addressOf)
2451  indirect++;
2452 
2453  const bool deref = tok->astParent() && tok->astParent()->isUnaryOp("*");
2454  if (deref && indirect > 0)
2455  indirect--;
2456 
2457  if (indirect == 1 && tok->isCpp() && tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), "new (")) // placement new TODO: fix AST
2458  return true;
2459 
2460  int argnr;
2461  tok = getTokenArgumentFunction(tok, argnr);
2462  if (!tok)
2463  return false; // not a function => variable not changed
2464  if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
2465  return false;
2466  if (tok->isKeyword() && !isCPPCastKeyword(tok) && !startsWith(tok->str(),"operator"))
2467  return false;
2468  // A functional cast won't modify the variable
2469  if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))
2470  return false;
2471  const Token * parenTok = tok->next();
2472  if (Token::simpleMatch(parenTok, "<") && parenTok->link())
2473  parenTok = parenTok->link()->next();
2474  const bool possiblyPassedByReference = (parenTok->next() == tok1 || Token::Match(tok1->previous(), ", %name% [,)}]"));
2475 
2476  if (!tok->function() && !tok->variable() && tok->isName()) {
2477  // Check if direction (in, out, inout) is specified in the library configuration and use that
2478  const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr);
2479  if (argDirection == Library::ArgumentChecks::Direction::DIR_IN)
2480  return false;
2481 
2482  const bool requireNonNull = settings.library.isnullargbad(tok, 1 + argnr);
2483  if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT ||
2485  if (indirect == 0 && isArray(tok1))
2486  return true;
2487  const bool requireInit = settings.library.isuninitargbad(tok, 1 + argnr);
2488  // Assume that if the variable must be initialized then the indirection is 1
2489  if (indirect > 0 && requireInit && requireNonNull)
2490  return true;
2491  }
2492  if (Token::simpleMatch(tok->tokAt(-2), "std :: tie"))
2493  return true;
2494  // if the library says 0 is invalid
2495  // => it is assumed that parameter is an in parameter (TODO: this is a bad heuristic)
2496  if (indirect == 0 && requireNonNull)
2497  return false;
2498  // possible pass-by-reference => inconclusive
2499  if (possiblyPassedByReference) {
2500  if (inconclusive != nullptr)
2501  *inconclusive = true;
2502  return false;
2503  }
2504  // Safe guess: Assume that parameter is changed by function call
2505  return true;
2506  }
2507 
2508  if (const Variable* var = tok->variable()) {
2509  if (tok == var->nameToken() && (!var->isReference() || var->isConst()) && (!var->isClass() || (var->valueType() && var->valueType()->container))) // const ref or passed to (copy) ctor
2510  return false;
2511  }
2512 
2513  std::vector<const Variable*> args = getArgumentVars(tok, argnr);
2514  bool conclusive = false;
2515  for (const Variable *arg:args) {
2516  if (!arg)
2517  continue;
2518  conclusive = true;
2519  if (indirect > 0) {
2520  if (arg->isPointer() && !(arg->valueType() && arg->valueType()->isConst(indirect)))
2521  return true;
2522  if (indirect > 1 && addressOf && arg->isPointer() && (!arg->valueType() || !arg->valueType()->isConst(indirect-1)))
2523  return true;
2524  if (arg->isArray() || (!arg->isPointer() && (!arg->valueType() || arg->valueType()->type == ValueType::UNKNOWN_TYPE)))
2525  return true;
2526  }
2527  if (!arg->isConst() && arg->isReference())
2528  return true;
2529  }
2530  if (addressOf && tok1->astParent()->isUnaryOp("&")) {
2531  const Token* castToken = tok1->astParent();
2532  while (castToken->astParent()->isCast())
2533  castToken = castToken->astParent();
2534  if (Token::Match(castToken->astParent(), ",|(") &&
2535  castToken->valueType() &&
2536  castToken->valueType()->isIntegral() &&
2537  castToken->valueType()->pointer == 0)
2538  return true;
2539  }
2540  if (!conclusive && inconclusive) {
2541  *inconclusive = true;
2542  }
2543  return false;
2544 }
2545 
2546 bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
2547 {
2548  if (!tok)
2549  return false;
2550 
2551  if (indirect == 0 && isConstVarExpression(tok))
2552  return false;
2553 
2554  const Token *tok2 = tok;
2555  int derefs = 0;
2556  while (Token::simpleMatch(tok2->astParent(), "*") ||
2557  (Token::simpleMatch(tok2->astParent(), ".") && !Token::simpleMatch(tok2->astParent()->astParent(), "(")) ||
2558  (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") ||
2559  (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) {
2560  if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->")))
2561  derefs++;
2562  if (derefs > indirect)
2563  break;
2564  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->")
2565  tok2 = tok2->astParent();
2566  tok2 = tok2->astParent();
2567  }
2568 
2569  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&")) {
2570  const Token* parent = tok2->astParent();
2571  while (parent->astParent() && parent->astParent()->isCast())
2572  parent = parent->astParent();
2573  if (parent->astParent() && parent->astParent()->isUnaryOp("*"))
2574  tok2 = parent->astParent();
2575  }
2576 
2577  while ((Token::simpleMatch(tok2, ":") && Token::simpleMatch(tok2->astParent(), "?")) ||
2578  (Token::simpleMatch(tok2->astParent(), ":") && Token::simpleMatch(tok2->astParent()->astParent(), "?")))
2579  tok2 = tok2->astParent();
2580 
2581  if (indirect == 0 && tok2->astParent() && tok2->astParent()->tokType() == Token::eIncDecOp)
2582  return true;
2583 
2584  auto skipRedundantPtrOp = [](const Token* tok, const Token* parent) {
2585  const Token* gparent = parent ? parent->astParent() : nullptr;
2586  while (parent && gparent && ((parent->isUnaryOp("*") && gparent->isUnaryOp("&")) || (parent->isUnaryOp("&") && gparent->isUnaryOp("*")))) {
2587  tok = gparent;
2588  parent = gparent->astParent();
2589  if (parent)
2590  gparent = parent->astParent();
2591  }
2592  return tok;
2593  };
2594  tok2 = skipRedundantPtrOp(tok2, tok2->astParent());
2595 
2596  if (tok2->astParent() && tok2->astParent()->isAssignmentOp()) {
2597  if (((indirect == 0 || tok2 != tok) || (indirect == 1 && tok2->str() == ".")) && tok2 == tok2->astParent()->astOperand1())
2598  return true;
2599  // Check if assigning to a non-const lvalue
2600  const Variable * var = getLHSVariable(tok2->astParent());
2601  if (var && var->isReference() && !var->isConst() &&
2602  ((var->nameToken() && var->nameToken()->next() == tok2->astParent()) || var->isPointer())) {
2603  if (!var->isLocal() || isVariableChanged(var, settings, depth - 1))
2604  return true;
2605  }
2606  }
2607 
2608  const ValueType* vt = tok->variable() ? tok->variable()->valueType() : tok->valueType();
2609 
2610  // Check addressof
2611  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&")) {
2612  if (isVariableChanged(tok2->astParent(), indirect + 1, settings, depth - 1))
2613  return true;
2614  } else {
2615  // If its already const then it cant be modified
2616  if (vt && vt->isConst(indirect))
2617  return false;
2618  }
2619 
2620  if (tok2->isCpp() && Token::Match(tok2->astParent(), ">>|&") && astIsRHS(tok2) && isLikelyStreamRead(tok2->astParent()))
2621  return true;
2622 
2623  if (isLikelyStream(tok2))
2624  return true;
2625 
2626  // Member function call
2627  if (Token::Match(tok2->astParent(), ". %name%") && isFunctionCall(tok2->astParent()->next()) &&
2628  tok2->astParent()->astOperand1() == tok2) {
2629  // Member function cannot change what `this` points to
2630  if (indirect == 0 && astIsPointer(tok))
2631  return false;
2632 
2633  const Token *ftok = tok2->astParent()->astOperand2();
2634  if (astIsContainer(tok2->astParent()->astOperand1()) && vt && vt->container) {
2635  const Library::Container* c = vt->container;
2636  const Library::Container::Action action = c->getAction(ftok->str());
2647  action))
2648  return true;
2649  const Library::Container::Yield yield = c->getYield(ftok->str());
2650  // If accessing element check if the element is changed
2652  return isVariableChanged(ftok->next(), indirect, settings, depth - 1);
2653 
2658  yield)) {
2659  return isVariableChanged(ftok->next(), indirect + 1, settings, depth - 1);
2660  }
2664  yield)) {
2665  return false;
2666  }
2667  }
2668  if (settings.library.isFunctionConst(ftok) || (astIsSmartPointer(tok) && ftok->str() == "get")) // TODO: replace with action/yield?
2669  return false;
2670 
2671  const Function * fun = ftok->function();
2672  if (!fun)
2673  return true;
2674  return !fun->isConst();
2675  }
2676 
2677  // Member pointer
2678  if (Token::Match(tok2->astParent(), ". * ( & %name% ::")) {
2679  const Token* ftok = tok2->astParent()->linkAt(2)->previous();
2680  // TODO: Check for pointer to member variable
2681  if (!ftok->function() || !ftok->function()->isConst())
2682  return true;
2683  }
2684  if (Token::Match(tok2->astParent(), ". * %name%")) // bailout
2685  return true;
2686 
2687  if (Token::simpleMatch(tok2, "[") && astIsContainer(tok) && vt && vt->container && vt->container->stdAssociativeLike)
2688  return true;
2689 
2690  const Token *ftok = tok2;
2691  while (ftok && (!Token::Match(ftok, "[({]") || ftok->isCast()))
2692  ftok = ftok->astParent();
2693 
2694  if (ftok && Token::Match(ftok->link(), ")|} !!{")) {
2695  if (ftok->str() == "(" && Token::simpleMatch(ftok->astOperand1(), "[")) // operator() on array element, bail out
2696  return true;
2697  const Token * ptok = tok2;
2698  while (Token::Match(ptok->astParent(), ".|::|["))
2699  ptok = ptok->astParent();
2700  int pindirect = indirect;
2701  if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next()))
2702  pindirect = 1;
2703  bool inconclusive = false;
2704  bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive);
2705  isChanged |= inconclusive;
2706  if (isChanged)
2707  return true;
2708  }
2709 
2710  const Token *parent = tok2->astParent();
2711  while (Token::Match(parent, ".|::"))
2712  parent = parent->astParent();
2713  if (parent && parent->tokType() == Token::eIncDecOp && (indirect == 0 || tok2 != tok))
2714  return true;
2715 
2716  // structured binding, nonconst reference variable in lhs
2717  if (Token::Match(tok2->astParent(), ":|=") && tok2 == tok2->astParent()->astOperand2() && Token::simpleMatch(tok2->astParent()->previous(), "]")) {
2718  const Token *typeStart = tok2->astParent()->previous()->link()->previous();
2719  if (Token::simpleMatch(typeStart, "&"))
2720  typeStart = typeStart->previous();
2721  if (typeStart && Token::Match(typeStart->previous(), "[;{}(] auto &| [")) {
2722  for (const Token *vartok = typeStart->tokAt(2); vartok != tok2; vartok = vartok->next()) {
2723  if (vartok->varId()) {
2724  const Variable* refvar = vartok->variable();
2725  if (!refvar || (!refvar->isConst() && refvar->isReference()))
2726  return true;
2727  }
2728  }
2729  }
2730  }
2731 
2732  if (Token::simpleMatch(tok2->astParent(), ":") && tok2->astParent()->astParent() && Token::simpleMatch(tok2->astParent()->astParent()->previous(), "for (")) {
2733  // TODO: Check if container is empty or not
2734  if (astIsLHS(tok2))
2735  return true;
2736  const Token * varTok = tok2->astParent()->previous();
2737  if (!varTok)
2738  return false;
2739  const Variable * loopVar = varTok->variable();
2740  if (!loopVar)
2741  return false;
2742  if (!loopVar->isConst() && loopVar->isReference() && isVariableChanged(loopVar, settings, depth - 1))
2743  return true;
2744  return false;
2745  }
2746 
2747  if (indirect > 0) {
2748  // check for `*(ptr + 1) = new_value` case
2749  parent = tok2->astParent();
2750  while (parent && ((parent->isArithmeticalOp() && parent->isBinaryOp()) || parent->isIncDecOp())) {
2751  parent = parent->astParent();
2752  }
2753  if (Token::simpleMatch(parent, "*")) {
2754  if (parent->astParent() && parent->astParent()->isAssignmentOp() &&
2755  (parent->astParent()->astOperand1() == parent)) {
2756  return true;
2757  }
2758  }
2759  }
2760 
2761  return false;
2762 }
2763 
2764 bool isVariableChanged(const Token *start, const Token *end, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2765 {
2766  return findVariableChanged(start, end, 0, exprid, globalvar, settings, depth) != nullptr;
2767 }
2768 
2769 bool isVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2770 {
2771  return findVariableChanged(start, end, indirect, exprid, globalvar, settings, depth) != nullptr;
2772 }
2773 
2774 const Token* findExpression(const Token* start, const nonneg int exprid)
2775 {
2776  const Function* f = Scope::nestedInFunction(start->scope());
2777  if (!f)
2778  return nullptr;
2779  const Scope* scope = f->functionScope;
2780  if (!scope)
2781  return nullptr;
2782  for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
2783  if (tok->exprId() != exprid)
2784  continue;
2785  return tok;
2786  }
2787  return nullptr;
2788 }
2789 
2790 // Thread-unsafe memoization
2791 template<class F, class R=decltype(std::declval<F>()())>
2792 static std::function<R()> memoize(F f)
2793 {
2794  bool init = false;
2795  R result{};
2796  return [=]() mutable -> R {
2797  if (init)
2798  return result;
2799  result = f();
2800  init = true;
2801  return result;
2802  };
2803 }
2804 
2805 template<class F,
2806  REQUIRES("F must be a function that returns a Token class",
2807  std::is_convertible<decltype(std::declval<F>()()), const Token*> )>
2808 static bool isExpressionChangedAt(const F& getExprTok,
2809  const Token* tok,
2810  int indirect,
2811  const nonneg int exprid,
2812  bool globalvar,
2813  const Settings& settings,
2814  int depth)
2815 {
2816  if (depth < 0)
2817  return true;
2818  if (tok->isLiteral() || tok->isKeyword() || tok->isStandardType() || Token::Match(tok, ",|;|:"))
2819  return false;
2820  if (tok->exprId() != exprid || (!tok->varId() && !tok->isName())) {
2821  if (globalvar && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure()))
2822  // TODO: Is global variable really changed by function call?
2823  return true;
2824  int i = 1;
2825  bool aliased = false;
2826  // If we can't find the expression then assume it is an alias
2827  auto expr = getExprTok();
2828  if (!expr)
2829  aliased = true;
2830  if (!aliased)
2831  aliased = isAliasOf(tok, expr, &i);
2832  if (!aliased)
2833  return false;
2834  if (isVariableChanged(tok, indirect + i, settings, depth))
2835  return true;
2836  // TODO: Try to traverse the lambda function
2837  if (Token::Match(tok, "%var% ("))
2838  return true;
2839  return false;
2840  }
2841  return (isVariableChanged(tok, indirect, settings, depth));
2842 }
2843 
2844 bool isExpressionChangedAt(const Token* expr,
2845  const Token* tok,
2846  int indirect,
2847  bool globalvar,
2848  const Settings& settings,
2849  int depth)
2850 {
2851  return isExpressionChangedAt([&] {
2852  return expr;
2853  }, tok, indirect, expr->exprId(), globalvar, settings, depth);
2854 }
2855 
2856 Token* findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2857 {
2858  if (!precedes(start, end))
2859  return nullptr;
2860  if (depth < 0)
2861  return start;
2862  auto getExprTok = memoize([&] {
2863  return findExpression(start, exprid);
2864  });
2865  for (Token *tok = start; tok != end; tok = tok->next()) {
2866  if (isExpressionChangedAt(getExprTok, tok, indirect, exprid, globalvar, settings, depth))
2867  return tok;
2868  }
2869  return nullptr;
2870 }
2871 
2872 const Token* findVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2873 {
2874  return findVariableChanged(const_cast<Token*>(start), end, indirect, exprid, globalvar, settings, depth);
2875 }
2876 
2877 bool isVariableChanged(const Variable * var, const Settings &settings, int depth)
2878 {
2879  if (!var)
2880  return false;
2881  if (!var->scope())
2882  return false;
2883  const Token * start = var->declEndToken();
2884  if (!start)
2885  return false;
2886  if (Token::Match(start, "; %varid% =", var->declarationId()))
2887  start = start->tokAt(2);
2888  if (Token::simpleMatch(start, "=")) {
2889  const Token* next = nextAfterAstRightmostLeafGeneric(start);
2890  if (next)
2891  start = next;
2892  }
2893  return findExpressionChanged(var->nameToken(), start->next(), var->scope()->bodyEnd, settings, depth);
2894 }
2895 
2896 bool isVariablesChanged(const Token* start,
2897  const Token* end,
2898  int indirect,
2899  const std::vector<const Variable*> &vars,
2900  const Settings& settings)
2901 {
2902  std::set<int> varids;
2903  std::transform(vars.cbegin(), vars.cend(), std::inserter(varids, varids.begin()), [](const Variable* var) {
2904  return var->declarationId();
2905  });
2906  const bool globalvar = std::any_of(vars.cbegin(), vars.cend(), [](const Variable* var) {
2907  return var->isGlobal();
2908  });
2909  for (const Token* tok = start; tok != end; tok = tok->next()) {
2910  if (tok->varId() == 0 || varids.count(tok->varId()) == 0) {
2911  if (globalvar && Token::Match(tok, "%name% ("))
2912  // TODO: Is global variable really changed by function call?
2913  return true;
2914  continue;
2915  }
2916  if (isVariableChanged(tok, indirect, settings))
2917  return true;
2918  }
2919  return false;
2920 }
2921 
2922 bool isThisChanged(const Token* tok, int indirect, const Settings& settings)
2923 {
2924  if ((Token::Match(tok->previous(), "%name% (") && !Token::simpleMatch(tok->astOperand1(), ".")) ||
2925  Token::Match(tok->tokAt(-3), "this . %name% (")) {
2926  if (tok->previous()->function()) {
2927  return (!tok->previous()->function()->isConst() && !tok->previous()->function()->isStatic());
2928  }
2929  if (!tok->previous()->isKeyword()) {
2930  return true;
2931  }
2932  }
2933  if (isVariableChanged(tok, indirect, settings))
2934  return true;
2935  return false;
2936 }
2937 
2938 static const Token* findThisChanged(const Token* start, const Token* end, int indirect, const Settings& settings)
2939 {
2940  if (!precedes(start, end))
2941  return nullptr;
2942  for (const Token* tok = start; tok != end; tok = tok->next()) {
2943  if (!exprDependsOnThis(tok))
2944  continue;
2945  if (isThisChanged(tok, indirect, settings))
2946  return tok;
2947  }
2948  return nullptr;
2949 }
2950 
2951 template<class Find>
2952 static const Token* findExpressionChangedImpl(const Token* expr,
2953  const Token* start,
2954  const Token* end,
2955  const Settings& settings,
2956  int depth,
2957  Find find)
2958 {
2959  if (depth < 0)
2960  return start;
2961  if (!precedes(start, end))
2962  return nullptr;
2963  const Token* result = nullptr;
2964  findAstNode(expr, [&](const Token* tok) {
2965  if (exprDependsOnThis(tok)) {
2966  result = findThisChanged(start, end, /*indirect*/ 0, settings);
2967  if (result)
2968  return true;
2969  }
2970  bool global = false;
2971  if (tok->variable()) {
2972  if (tok->variable()->isConst())
2973  return false;
2974  global = !tok->variable()->isLocal() && !tok->variable()->isArgument() &&
2975  !(tok->variable()->isMember() && !tok->variable()->isStatic());
2976  } else if (tok->isIncompleteVar() && !tok->isIncompleteConstant()) {
2977  global = true;
2978  }
2979 
2980  if (tok->exprId() > 0 || global) {
2981  const Token* modifedTok = find(start, end, [&](const Token* tok2) {
2982  int indirect = 0;
2983  if (const ValueType* vt = tok->valueType()) {
2984  indirect = vt->pointer;
2985  if (vt->type == ValueType::ITERATOR)
2986  ++indirect;
2987  }
2988  for (int i = 0; i <= indirect; ++i) {
2989  if (isExpressionChangedAt(tok, tok2, i, global, settings, depth))
2990  return true;
2991  }
2992  return false;
2993  });
2994  if (modifedTok) {
2995  result = modifedTok;
2996  return true;
2997  }
2998  }
2999  return false;
3000  });
3001  return result;
3002 }
3003 
3004 namespace {
3005  struct ExpressionChangedSimpleFind {
3006  template<class F>
3007  const Token* operator()(const Token* start, const Token* end, F f) const
3008  {
3009  return findToken(start, end, f);
3010  }
3011  };
3012 
3013  struct ExpressionChangedSkipDeadCode {
3014  const Library& library;
3015  const std::function<std::vector<MathLib::bigint>(const Token* tok)>* evaluate;
3016  ExpressionChangedSkipDeadCode(const Library& library,
3017  const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate)
3018  : library(library), evaluate(&evaluate)
3019  {}
3020  template<class F>
3021  const Token* operator()(const Token* start, const Token* end, F f) const
3022  {
3023  return findTokenSkipDeadCode(library, start, end, f, *evaluate);
3024  }
3025  };
3026 }
3027 
3028 const Token* findExpressionChanged(const Token* expr,
3029  const Token* start,
3030  const Token* end,
3031  const Settings& settings,
3032  int depth)
3033 {
3034  return findExpressionChangedImpl(expr, start, end, settings, depth, ExpressionChangedSimpleFind{});
3035 }
3036 
3038  const Token* start,
3039  const Token* end,
3040  const Settings& settings,
3041  const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate,
3042  int depth)
3043 {
3045  expr, start, end, settings, depth, ExpressionChangedSkipDeadCode{settings.library, evaluate});
3046 }
3047 
3048 const Token* getArgumentStart(const Token* ftok)
3049 {
3050  const Token* tok = ftok;
3051  if (Token::Match(tok, "%name% (|{|)"))
3052  tok = ftok->next();
3053  while (Token::simpleMatch(tok, ")"))
3054  tok = tok->next();
3055  if (!Token::Match(tok, "(|{|["))
3056  return nullptr;
3057  const Token* startTok = tok->astOperand2();
3058  if (!startTok && tok->next() != tok->link())
3059  startTok = tok->astOperand1();
3060  return startTok;
3061 }
3062 
3063 int numberOfArguments(const Token* ftok) {
3064  return astCount(getArgumentStart(ftok), ",");
3065 }
3066 
3068 {
3069  int arguments = 0;
3070  const Token* openBracket = start->next();
3071  while (Token::simpleMatch(openBracket, ")"))
3072  openBracket = openBracket->next();
3073  if (openBracket && openBracket->str()=="(" && openBracket->next() && openBracket->next()->str()!=")") {
3074  const Token* argument=openBracket->next();
3075  while (argument) {
3076  ++arguments;
3077  argument = argument->nextArgument();
3078  }
3079  }
3080  return arguments;
3081 }
3082 
3083 std::vector<const Token*> getArguments(const Token* ftok) {
3084  return astFlatten(getArgumentStart(ftok), ",");
3085 }
3086 
3087 int getArgumentPos(const Variable* var, const Function* f)
3088 {
3089  auto arg_it = std::find_if(f->argumentList.cbegin(), f->argumentList.cend(), [&](const Variable& v) {
3090  return v.nameToken() == var->nameToken();
3091  });
3092  if (arg_it == f->argumentList.end())
3093  return -1;
3094  return std::distance(f->argumentList.cbegin(), arg_it);
3095 }
3096 
3098 {
3099  if (!tok)
3100  return nullptr;
3101  if (tok->isUnaryOp("*"))
3102  return nullptr;
3103  if (!tok->isName()) {
3104  const Token* iter1 = getIteratorExpression(tok->astOperand1());
3105  if (iter1)
3106  return iter1;
3107  if (tok->str() == "(")
3108  return nullptr;
3109  const Token* iter2 = getIteratorExpression(tok->astOperand2());
3110  if (iter2)
3111  return iter2;
3112  } else if (Token::Match(tok, "begin|cbegin|rbegin|crbegin|end|cend|rend|crend (")) {
3113  if (Token::Match(tok->previous(), ". %name% ( ) !!."))
3114  return tok->previous()->astOperand1();
3115  if (!Token::simpleMatch(tok->previous(), ".") && Token::Match(tok, "%name% ( !!)") &&
3116  !Token::simpleMatch(tok->linkAt(1), ") ."))
3117  return tok->next()->astOperand2();
3118  }
3119  return nullptr;
3120 }
3121 
3122 bool isIteratorPair(const std::vector<const Token*>& args)
3123 {
3124  if (args.size() != 2)
3125  return false;
3126  if (astIsPointer(args[0]) && astIsPointer(args[1]))
3127  return true;
3128  // Check if iterator is from same container
3129  const Token* tok1 = nullptr;
3130  const Token* tok2 = nullptr;
3131  if (astIsIterator(args[0]) && astIsIterator(args[1])) {
3132  tok1 = ValueFlow::getLifetimeObjValue(args[0]).tokvalue;
3133  tok2 = ValueFlow::getLifetimeObjValue(args[1]).tokvalue;
3134  if (!tok1 || !tok2)
3135  return true;
3136  } else {
3137  tok1 = getIteratorExpression(args[0]);
3138  tok2 = getIteratorExpression(args[1]);
3139  }
3140  if (tok1 && tok2)
3141  return tok1->exprId() == tok2->exprId();
3142  return tok1 || tok2;
3143 }
3144 
3145 const Token *findLambdaStartToken(const Token *last)
3146 {
3147  if (!last || !last->isCpp() || last->str() != "}")
3148  return nullptr;
3149  const Token* tok = last->link();
3150  if (Token::simpleMatch(tok->astParent(), "("))
3151  tok = tok->astParent();
3152  if (Token::simpleMatch(tok->astParent(), "["))
3153  return tok->astParent();
3154  return nullptr;
3155 }
3156 
3157 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
3158 static T* findLambdaEndTokenGeneric(T* first)
3159 {
3160  auto maybeLambda = [](T* tok) -> bool {
3161  while (Token::Match(tok, "*|%name%|::|>")) {
3162  if (tok->link())
3163  tok = tok->link()->previous();
3164  else {
3165  if (tok->str() == ">")
3166  return true;
3167  if (tok->str() == "new")
3168  return false;
3169  tok = tok->previous();
3170  }
3171  }
3172  return true;
3173  };
3174 
3175  if (!first || !first->isCpp() || first->str() != "[")
3176  return nullptr;
3177  if (!maybeLambda(first->previous()))
3178  return nullptr;
3179  if (!Token::Match(first->link(), "] (|{|<"))
3180  return nullptr;
3181  const Token* roundOrCurly = first->link()->next();
3182  if (roundOrCurly->link() && roundOrCurly->str() == "<")
3183  roundOrCurly = roundOrCurly->link()->next();
3184  if (first->astOperand1() != roundOrCurly)
3185  return nullptr;
3186  T * tok = first;
3187 
3188  if (tok->astOperand1() && tok->astOperand1()->str() == "(")
3189  tok = tok->astOperand1();
3190  if (tok->astOperand1() && tok->astOperand1()->str() == "{")
3191  return tok->astOperand1()->link();
3192  return nullptr;
3193 }
3194 
3195 const Token* findLambdaEndToken(const Token* first)
3196 {
3197  return findLambdaEndTokenGeneric(first);
3198 }
3200 {
3201  return findLambdaEndTokenGeneric(first);
3202 }
3203 
3204 bool isLikelyStream(const Token *stream)
3205 {
3206  if (!stream)
3207  return false;
3208 
3209  if (!stream->isCpp())
3210  return false;
3211 
3212  if (!Token::Match(stream->astParent(), "&|<<|>>") || !stream->astParent()->isBinaryOp())
3213  return false;
3214 
3215  if (stream->astParent()->astOperand1() != stream)
3216  return false;
3217 
3218  return !astIsIntegral(stream, false);
3219 }
3220 
3221 bool isLikelyStreamRead(const Token *op)
3222 {
3223  if (!op)
3224  return false;
3225 
3226  if (!op->isCpp())
3227  return false;
3228 
3229  if (!Token::Match(op, "&|>>") || !op->isBinaryOp())
3230  return false;
3231 
3232  if (!Token::Match(op->astOperand2(), "%name%|.|*|[") && op->str() != op->astOperand2()->str())
3233  return false;
3234 
3235  const Token *parent = op;
3236  while (parent->astParent() && parent->astParent()->str() == op->str())
3237  parent = parent->astParent();
3238  if (parent->astParent() && !Token::Match(parent->astParent(), "%oror%|&&|(|,|.|!|;|return"))
3239  return false;
3240  if (op->str() == "&" && parent->astParent())
3241  return false;
3242  if (!parent->astOperand1() || !parent->astOperand2())
3243  return false;
3244  return (!parent->astOperand1()->valueType() || !parent->astOperand1()->valueType()->isIntegral());
3245 }
3246 
3247 bool isCPPCast(const Token* tok)
3248 {
3249  return tok && Token::simpleMatch(tok->previous(), "> (") && tok->astOperand2() && tok->astOperand1() && isCPPCastKeyword(tok->astOperand1());
3250 }
3251 
3252 bool isConstVarExpression(const Token *tok, const std::function<bool(const Token*)>& skipPredicate)
3253 {
3254  if (!tok)
3255  return false;
3256  if (tok->str() == "?" && tok->astOperand2() && tok->astOperand2()->str() == ":") // ternary operator
3257  return isConstVarExpression(tok->astOperand2()->astOperand1()) && isConstVarExpression(tok->astOperand2()->astOperand2()); // left and right of ":"
3258  if (skipPredicate && skipPredicate(tok))
3259  return false;
3260  if (Token::simpleMatch(tok->previous(), "sizeof ("))
3261  return true;
3262  if (Token::Match(tok->previous(), "%name% (")) {
3263  if (Token::simpleMatch(tok->astOperand1(), ".") && !isConstVarExpression(tok->astOperand1(), skipPredicate))
3264  return false;
3265  std::vector<const Token *> args = getArguments(tok);
3266  if (args.empty() && tok->previous()->function() && tok->previous()->function()->isConstexpr())
3267  return true;
3268  return !args.empty() && std::all_of(args.cbegin(), args.cend(), [&](const Token* t) {
3269  return isConstVarExpression(t, skipPredicate);
3270  });
3271  }
3272  if (isCPPCast(tok)) {
3273  return isConstVarExpression(tok->astOperand2(), skipPredicate);
3274  }
3275  if (Token::Match(tok, "( %type%"))
3276  return isConstVarExpression(tok->astOperand1(), skipPredicate);
3277  if (tok->str() == "::" && tok->hasKnownValue())
3278  return isConstVarExpression(tok->astOperand2(), skipPredicate);
3279  if (Token::Match(tok, "%cop%|[|.")) {
3280  if (tok->astOperand1() && !isConstVarExpression(tok->astOperand1(), skipPredicate))
3281  return false;
3282  if (tok->astOperand2() && !isConstVarExpression(tok->astOperand2(), skipPredicate))
3283  return false;
3284  return true;
3285  }
3286  if (Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"))
3287  return true;
3288  if (tok->isEnumerator())
3289  return true;
3290  if (tok->variable())
3291  return tok->variable()->isConst() && tok->variable()->nameToken() && tok->variable()->nameToken()->hasKnownValue();
3292  return false;
3293 }
3294 
3295 static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings& settings)
3296 {
3297  const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&");
3298 
3299  int argnr;
3300  const Token* ftok = getTokenArgumentFunction(tok, argnr);
3301  if (!ftok)
3302  return ExprUsage::None;
3303  const Function* func = ftok->function();
3304  // variable init/constructor call?
3305  if (!func && ftok->variable() && ftok == ftok->variable()->nameToken()) {
3306  // STL types or containers don't initialize external variables
3307  if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container))
3308  return ExprUsage::Used;
3309  // TODO: resolve multiple constructors
3310  if (ftok->variable()->type() && ftok->variable()->type()->classScope) {
3311  const int nCtor = ftok->variable()->type()->classScope->numConstructors;
3312  if (nCtor == 0)
3313  return ExprUsage::Used;
3314  if (nCtor == 1) {
3315  const Scope* scope = ftok->variable()->type()->classScope;
3316  auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [](const Function& f) {
3317  return f.isConstructor();
3318  });
3319  if (it != scope->functionList.end())
3320  func = &*it;
3321  }
3322  }
3323  }
3324  if (func) {
3325  std::vector<const Variable*> args = getArgumentVars(ftok, argnr);
3326  for (const Variable* arg : args) {
3327  if (!arg)
3328  continue;
3329  if (arg->isReference() || (arg->isPointer() && indirect == 1)) {
3330  if (!func->hasBody())
3332  for (const Token* bodytok = func->functionScope->bodyStart; bodytok != func->functionScope->bodyEnd; bodytok = bodytok->next()) {
3333  if (bodytok->variable() == arg) {
3334  if (arg->isReference())
3336  if (Token::Match(bodytok->astParent(), "%comp%|!"))
3337  return ExprUsage::NotUsed;
3339  }
3340  }
3341  return ExprUsage::NotUsed;
3342  }
3343  }
3344  if (!args.empty() && indirect == 0 && !addressOf)
3345  return ExprUsage::Used;
3346  } else if (ftok->isControlFlowKeyword()) {
3347  return ExprUsage::Used;
3348  } else if (ftok->str() == "{") {
3349  return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive;
3350  } else {
3351  const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1);
3352  if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad)
3353  return ExprUsage::Used;
3354  bool hasIndirect = false;
3355  const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect);
3356  if (isuninitbad && (!addressOf || isnullbad))
3357  return ExprUsage::Used;
3358  }
3359  return ExprUsage::Inconclusive;
3360 }
3361 
3362 bool isLeafDot(const Token* tok)
3363 {
3364  if (!tok)
3365  return false;
3366  const Token * parent = tok->astParent();
3367  if (!Token::simpleMatch(parent, "."))
3368  return false;
3369  if (parent->astOperand2() == tok && !Token::simpleMatch(parent->astParent(), "."))
3370  return true;
3371  return isLeafDot(parent);
3372 }
3373 
3374 ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings)
3375 {
3376  const Token* parent = tok->astParent();
3377  if (indirect > 0 && parent) {
3378  while (Token::simpleMatch(parent, "[") && parent->astParent())
3379  parent = parent->astParent();
3380  if (Token::Match(parent, "%assign%") && (astIsRHS(tok) || astIsLHS(parent->astOperand1())))
3381  return ExprUsage::NotUsed;
3382  if (Token::Match(parent, "++|--"))
3383  return ExprUsage::NotUsed;
3384  if (parent->isConstOp())
3385  return ExprUsage::NotUsed;
3386  if (parent->isCast())
3387  return ExprUsage::NotUsed;
3388  if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?"))
3389  return getExprUsage(parent->astParent(), indirect, settings);
3390  if (isUsedAsBool(tok, settings))
3391  return ExprUsage::NotUsed;
3392  }
3393  if (indirect == 0) {
3394  if (Token::Match(parent, "%cop%|%assign%|++|--") && parent->str() != "=" &&
3395  !parent->isUnaryOp("&") &&
3396  !(astIsRHS(tok) && isLikelyStreamRead(parent)))
3397  return ExprUsage::Used;
3398  if (isLeafDot(tok)) {
3399  const Token* op = parent->astParent();
3400  while (Token::simpleMatch(op, "."))
3401  op = op->astParent();
3402  if (Token::Match(op, "%assign%|++|--")) {
3403  if (op->str() == "=") {
3404  if (precedes(tok, op))
3405  return ExprUsage::NotUsed;
3406  } else
3407  return ExprUsage::Used;
3408  }
3409  }
3410  if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
3411  const Token* const lhs = parent->astOperand1();
3412  if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken())
3413  return ExprUsage::NotUsed;
3414  return ExprUsage::Used;
3415  }
3416  // Function call or index
3417  if (((Token::simpleMatch(parent, "(") && !parent->isCast()) || (Token::simpleMatch(parent, "[") && tok->valueType())) &&
3418  (astIsLHS(tok) || Token::simpleMatch(parent, "( )")))
3419  return ExprUsage::Used;
3420  }
3421  return getFunctionUsage(tok, indirect, settings);
3422 }
3423 
3424 static void getLHSVariablesRecursive(std::vector<const Variable*>& vars, const Token* tok)
3425 {
3426  if (!tok)
3427  return;
3428  if (vars.empty() && Token::Match(tok, "*|&|&&|[")) {
3429  getLHSVariablesRecursive(vars, tok->astOperand1());
3430  if (!vars.empty() || Token::simpleMatch(tok, "["))
3431  return;
3432  getLHSVariablesRecursive(vars, tok->astOperand2());
3433  } else if (Token::Match(tok->previous(), "this . %var%")) {
3434  getLHSVariablesRecursive(vars, tok->next());
3435  } else if (Token::simpleMatch(tok, ".")) {
3436  getLHSVariablesRecursive(vars, tok->astOperand1());
3437  getLHSVariablesRecursive(vars, tok->astOperand2());
3438  } else if (Token::simpleMatch(tok, "::")) {
3439  getLHSVariablesRecursive(vars, tok->astOperand2());
3440  } else if (tok->variable()) {
3441  vars.push_back(tok->variable());
3442  }
3443 }
3444 
3445 std::vector<const Variable*> getLHSVariables(const Token* tok)
3446 {
3447  std::vector<const Variable*> result;
3448  if (!Token::Match(tok, "%assign%|(|{"))
3449  return result;
3450  if (!tok->astOperand1())
3451  return result;
3452  if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
3453  return {tok->astOperand1()->variable()};
3454  getLHSVariablesRecursive(result, tok->astOperand1());
3455  return result;
3456 }
3457 
3458 static const Token* getLHSVariableRecursive(const Token* tok)
3459 {
3460  if (!tok)
3461  return nullptr;
3462  if (Token::Match(tok, "*|&|&&|[")) {
3463  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3464  if ((vartok && vartok->variable()) || Token::simpleMatch(tok, "["))
3465  return vartok;
3466  return getLHSVariableRecursive(tok->astOperand2());
3467  }
3468  if (Token::Match(tok->previous(), "this . %var%"))
3469  return tok->next();
3470  return tok;
3471 }
3472 
3473 const Variable *getLHSVariable(const Token *tok)
3474 {
3475  if (!tok || !tok->isAssignmentOp())
3476  return nullptr;
3477  if (!tok->astOperand1())
3478  return nullptr;
3479  if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
3480  return tok->astOperand1()->variable();
3481  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3482  if (!vartok)
3483  return nullptr;
3484  return vartok->variable();
3485 }
3486 
3487 const Token* getLHSVariableToken(const Token* tok)
3488 {
3489  if (!Token::Match(tok, "%assign%"))
3490  return nullptr;
3491  if (!tok->astOperand1())
3492  return nullptr;
3493  if (tok->astOperand1()->varId() > 0)
3494  return tok->astOperand1();
3495  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3496  if (vartok && vartok->variable() && vartok->variable()->nameToken() == vartok)
3497  return vartok;
3498  return tok->astOperand1();
3499 }
3500 
3501 const Token* findAllocFuncCallToken(const Token *expr, const Library &library)
3502 {
3503  if (!expr)
3504  return nullptr;
3505  if (Token::Match(expr, "[+-]")) {
3506  const Token *tok1 = findAllocFuncCallToken(expr->astOperand1(), library);
3507  return tok1 ? tok1 : findAllocFuncCallToken(expr->astOperand2(), library);
3508  }
3509  if (expr->isCast())
3510  return findAllocFuncCallToken(expr->astOperand2() ? expr->astOperand2() : expr->astOperand1(), library);
3511  if (Token::Match(expr->previous(), "%name% (") && library.getAllocFuncInfo(expr->astOperand1()))
3512  return expr->astOperand1();
3513  return (Token::simpleMatch(expr, "new") && expr->astOperand1()) ? expr : nullptr;
3514 }
3515 
3516 bool isNullOperand(const Token *expr)
3517 {
3518  if (!expr)
3519  return false;
3520  if (expr->isCpp() && Token::Match(expr, "static_cast|const_cast|dynamic_cast|reinterpret_cast <"))
3521  expr = expr->astParent();
3522  else if (!expr->isCast())
3523  return Token::Match(expr, "NULL|nullptr");
3524  if (expr->valueType() && expr->valueType()->pointer == 0)
3525  return false;
3526  const Token *castOp = expr->astOperand2() ? expr->astOperand2() : expr->astOperand1();
3527  return Token::Match(castOp, "NULL|nullptr") || (MathLib::isInt(castOp->str()) && MathLib::isNullValue(castOp->str()));
3528 }
3529 
3530 bool isGlobalData(const Token *expr)
3531 {
3532  // function call that returns reference => assume global data
3533  if (expr && expr->str() == "(" && expr->valueType() && expr->valueType()->reference != Reference::None) {
3534  if (expr->isBinaryOp())
3535  return true;
3536  if (expr->astOperand1() && precedes(expr->astOperand1(), expr))
3537  return true;
3538  }
3539 
3540  bool globalData = false;
3541  bool var = false;
3542  visitAstNodes(expr,
3543  [expr, &globalData, &var](const Token *tok) {
3544  if (tok->varId())
3545  var = true;
3546  if (tok->varId() && !tok->variable()) {
3547  // Bailout, this is probably global
3548  globalData = true;
3549  return ChildrenToVisit::none;
3550  }
3551  if (tok->originalName() == "->") {
3552  // TODO check if pointer points at local data
3553  globalData = true;
3554  return ChildrenToVisit::none;
3555  }
3556  if (Token::Match(tok, "[*[]") && tok->astOperand1() && tok->astOperand1()->variable()) {
3557  // TODO check if pointer points at local data
3558  const Variable *lhsvar = tok->astOperand1()->variable();
3559  const ValueType *lhstype = tok->astOperand1()->valueType();
3560  if (lhsvar->isPointer()) {
3561  globalData = true;
3562  return ChildrenToVisit::none;
3563  }
3564  if (lhsvar->isArgument() && lhsvar->isArray()) {
3565  globalData = true;
3566  return ChildrenToVisit::none;
3567  }
3568  if (lhsvar->isArgument() && (!lhstype || (lhstype->type <= ValueType::Type::VOID && !lhstype->container))) {
3569  globalData = true;
3570  return ChildrenToVisit::none;
3571  }
3572  }
3573  if (tok->varId() == 0 && tok->isName() && tok->previous()->str() != ".") {
3574  globalData = true;
3575  return ChildrenToVisit::none;
3576  }
3577  if (tok->variable()) {
3578  // TODO : Check references
3579  if (tok->variable()->isReference() && tok != tok->variable()->nameToken()) {
3580  globalData = true;
3581  return ChildrenToVisit::none;
3582  }
3583  if (tok->variable()->isExtern()) {
3584  globalData = true;
3585  return ChildrenToVisit::none;
3586  }
3587  if (tok->previous()->str() != "." && !tok->variable()->isLocal() && !tok->variable()->isArgument()) {
3588  globalData = true;
3589  return ChildrenToVisit::none;
3590  }
3591  if (tok->variable()->isArgument() && tok->variable()->isPointer() && tok != expr) {
3592  globalData = true;
3593  return ChildrenToVisit::none;
3594  }
3595  if (tok->variable()->isPointerArray()) {
3596  globalData = true;
3597  return ChildrenToVisit::none;
3598  }
3599  }
3600  // Unknown argument type => it might be some reference type..
3601  if (tok->isCpp() && tok->str() == "." && tok->astOperand1() && tok->astOperand1()->variable() && !tok->astOperand1()->valueType()) {
3602  globalData = true;
3603  return ChildrenToVisit::none;
3604  }
3605  if (Token::Match(tok, ".|["))
3606  return ChildrenToVisit::op1;
3608  });
3609  return globalData || !var;
3610 }
3611 
3612 bool isUnevaluated(const Token *tok)
3613 {
3614  return Token::Match(tok, "alignof|_Alignof|_alignof|__alignof|__alignof__|decltype|offsetof|sizeof|typeid|typeof|__typeof__ (");
3615 }
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok)
Is given syntax tree a variable comparison against value.
Definition: astutils.cpp:351
int numberOfArgumentsWithoutAst(const Token *start)
Get number of arguments without using AST.
Definition: astutils.cpp:3067
static bool compareKnownValue(const Token *const tok1, const Token *const tok2, const std::function< bool(const ValueFlow::Value &, const ValueFlow::Value &, bool)> &compare)
Definition: astutils.cpp:1393
bool astIsContainer(const Token *tok)
Definition: astutils.cpp:244
static bool isCPPCastKeyword(const Token *tok)
Definition: astutils.cpp:2409
const Token * getIteratorExpression(const Token *tok)
Definition: astutils.cpp:3097
static T * getTokenArgumentFunctionImpl(T *tok, int &argn)
Definition: astutils.cpp:2287
static bool isArray(const Token *tok)
Definition: astutils.cpp:2427
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3083
static bool astIsCharWithSign(const Token *tok, ValueType::Sign sign)
Definition: astutils.cpp:161
static bool astIsBoolLike(const Token *tok, const Settings &settings)
Definition: astutils.cpp:1551
bool isOppositeExpression(const Token *const tok1, const Token *const tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1947
static bool isExpressionChangedAt(const F &getExprTok, const Token *tok, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
Definition: astutils.cpp:2808
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1556
bool astIsPrimitive(const Token *tok)
Definition: astutils.cpp:186
bool astIsContainerView(const Token *tok)
Definition: astutils.cpp:254
bool astIsIntegral(const Token *tok, bool unknown)
Is expression of integral type?
Definition: astutils.cpp:194
static T * getCondTokImpl(T *tok)
Definition: astutils.cpp:812
static T * getStepTokImpl(T *tok)
Definition: astutils.cpp:865
static const Token * getLHSVariableRecursive(const Token *tok)
Definition: astutils.cpp:3458
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
Definition: astutils.cpp:1105
bool isTemporary(const Token *tok, const Library *library, bool unknown)
Definition: astutils.cpp:415
const Token * followReferences(const Token *tok, ErrorPath *errors)
Definition: astutils.cpp:1369
bool astIsRangeBasedForDecl(const Token *tok)
Is given token a range-declaration in a range-based for loop.
Definition: astutils.cpp:321
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:994
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
Definition: astutils.cpp:2360
bool astHasVar(const Token *tok, nonneg int varid)
Definition: astutils.cpp:143
static void getLHSVariablesRecursive(std::vector< const Variable * > &vars, const Token *tok)
Definition: astutils.cpp:3424
bool isUsedAsBool(const Token *const tok, const Settings &settings)
Is token used as boolean, that is to say cast to a bool, or used as a condition in a if/while/for.
Definition: astutils.cpp:1489
static void followVariableExpressionError(const Token *tok1, const Token *tok2, ErrorPath *errors)
Definition: astutils.cpp:1222
bool extractForLoopValues(const Token *forToken, nonneg int &varid, bool &knownInitValue, MathLib::bigint &initValue, bool &partialCond, MathLib::bigint &stepValue, MathLib::bigint &lastValue)
Extract for loop values: loopvar varid, init value, step value, last value (inclusive)
Definition: astutils.cpp:926
static bool hasNoreturnFunction(const Token *tok, const Library &library, const Token **unknownFunc)
Definition: astutils.cpp:2172
bool astIsPointer(const Token *tok)
Definition: astutils.cpp:220
bool compareTokenFlags(const Token *tok1, const Token *tok2, bool macro)
Are the tokens' flags equal?
Definition: astutils.cpp:1537
const Token * isInLoopCondition(const Token *tok)
Definition: astutils.cpp:987
static const Token * getParentLifetimeObject(const Token *tok)
Definition: astutils.cpp:635
static T * findLambdaEndTokenGeneric(T *first)
Definition: astutils.cpp:3158
bool isStlStringType(const Token *tok)
Definition: astutils.cpp:409
bool isLikelyStreamRead(const Token *op)
do we see a likely write of rhs through overloaded operator s >> x; a & x;
Definition: astutils.cpp:3221
bool isUniqueExpression(const Token *tok)
Definition: astutils.cpp:2087
bool astIsContainerOwned(const Token *tok)
Definition: astutils.cpp:260
const Token * findExpressionChanged(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth)
Definition: astutils.cpp:3028
const Token * findAllocFuncCallToken(const Token *expr, const Library &library)
Find a allocation function call in expression, so result of expression is allocated memory/resource.
Definition: astutils.cpp:3501
bool astIsLHS(const Token *tok)
Definition: astutils.cpp:784
bool isGlobalData(const Token *expr)
Definition: astutils.cpp:3530
bool isConstFunctionCall(const Token *ftok, const Library &library)
Definition: astutils.cpp:1969
static bool isTrivialConstructor(const Token *tok)
Definition: astutils.cpp:2416
bool astIsBool(const Token *tok)
Is expression of boolean type?
Definition: astutils.cpp:215
const Token * getArgumentStart(const Token *ftok)
Definition: astutils.cpp:3048
bool isScopeBracket(const Token *tok)
Definition: astutils.cpp:2273
static ExprUsage getFunctionUsage(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:3295
bool isEscapeFunction(const Token *ftok, const Library *library)
Definition: astutils.cpp:2155
bool isVariableDecl(const Token *tok)
Definition: astutils.cpp:396
static bool isFunctionCall(const Token *tok)
Definition: astutils.cpp:483
static bool isInConstructorList(const Token *tok)
Definition: astutils.cpp:693
static bool hasToken(const Token *startTok, const Token *stopTok, const Token *tok)
Definition: astutils.cpp:494
static bool match(const Token *tok, const std::string &rhs)
Definition: astutils.cpp:342
static int getArgumentPos(const Token *ftok, const Token *tokToFind)
Definition: astutils.cpp:98
bool astIsGenericChar(const Token *tok)
Is expression a char according to valueType?
Definition: astutils.cpp:181
bool astHasExpr(const Token *tok, nonneg int exprid)
Definition: astutils.cpp:152
bool isStructuredBindingVariable(const Variable *var)
Definition: astutils.cpp:1153
Token * getInitTok(Token *tok)
Definition: astutils.cpp:898
const Token * findNextTokenFromBreak(const Token *breakToken)
For a "break" token, locate the next token to execute.
Definition: astutils.cpp:912
bool isLeafDot(const Token *tok)
Definition: astutils.cpp:3362
bool astIsUniqueSmartPointer(const Token *tok)
Definition: astutils.cpp:230
static bool isEscaped(const Token *tok, bool functionsScope, const Library &library)
Definition: astutils.cpp:2137
Library::Container::Action astContainerAction(const Token *tok, const Token **ftok)
Definition: astutils.cpp:287
Library::Container::Yield astFunctionYield(const Token *tok, const Settings &settings, const Token **ftok)
Definition: astutils.cpp:307
static bool isDifferentKnownValues(const Token *const tok1, const Token *const tok2)
Definition: astutils.cpp:1425
std::vector< const Token * > astFlatten(const Token *tok, const char *op)
Definition: astutils.cpp:110
bool astIsSmartPointer(const Token *tok)
Definition: astutils.cpp:225
Token * getCondTokFromEnd(Token *endBlock)
Definition: astutils.cpp:889
bool isNullOperand(const Token *expr)
Definition: astutils.cpp:3516
const Token * findLambdaStartToken(const Token *last)
Definition: astutils.cpp:3145
bool astHasToken(const Token *root, const Token *tok)
Definition: astutils.cpp:134
const Token * astParentSkipParens(const Token *tok)
Definition: astutils.cpp:557
bool isOppositeCond(bool isNot, const Token *const cond1, const Token *const cond2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Are two conditions opposite.
Definition: astutils.cpp:1785
bool astIsContainerString(const Token *tok)
Definition: astutils.cpp:264
static bool isForLoopCondition(const Token *const tok)
Definition: astutils.cpp:1467
Token * getCondTok(Token *tok)
Definition: astutils.cpp:880
bool astIsRHS(const Token *tok)
Definition: astutils.cpp:797
bool isWithinScope(const Token *tok, const Variable *var, Scope::ScopeType type)
Is tok within a scope of the given type, nested within var's scope?
Definition: astutils.cpp:2250
static std::function< R()> memoize(F f)
Definition: astutils.cpp:2792
static bool functionModifiesArguments(const Function *f)
Definition: astutils.cpp:1960
std::vector< ValueType > getParentValueTypes(const Token *tok, const Settings &settings, const Token **parent)
Definition: astutils.cpp:712
const Variable * getLHSVariable(const Token *tok)
Definition: astutils.cpp:3473
bool astIsSignedChar(const Token *tok)
Is expression a 'signed char' if no promotion is used.
Definition: astutils.cpp:171
bool isConstVarExpression(const Token *tok, const std::function< bool(const Token *)> &skipPredicate)
Definition: astutils.cpp:3252
bool isWithoutSideEffects(const Token *tok, bool checkArrayAccess, bool checkReference)
Definition: astutils.cpp:2071
bool astIsFloat(const Token *tok, bool unknown)
Is expression of floating point type?
Definition: astutils.cpp:207
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
Definition: astutils.cpp:3195
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
ExprUsage getExprUsage(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:3374
bool isThisChanged(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:2922
static const Token * getVariableInitExpression(const Variable *var)
Definition: astutils.cpp:975
bool astIsNonStringContainer(const Token *tok)
Definition: astutils.cpp:248
static std::vector< const Token * > getParentMembers(const Token *tok)
Definition: astutils.cpp:615
static bool isZeroBoundCond(const Token *const cond)
Definition: astutils.cpp:1767
Token * getStepTok(Token *tok)
Definition: astutils.cpp:905
bool isVariablesChanged(const Token *start, const Token *end, int indirect, const std::vector< const Variable * > &vars, const Settings &settings)
Definition: astutils.cpp:2896
bool isIteratorPair(const std::vector< const Token * > &args)
Are the arguments a pair of iterators/pointers?
Definition: astutils.cpp:3122
bool isAliasOf(const Token *tok, nonneg int varid, bool *inconclusive)
If token is an alias if another variable.
Definition: astutils.cpp:1017
static const Token * getContainerFunction(const Token *tok)
Definition: astutils.cpp:276
const Token * getParentMember(const Token *tok)
Definition: astutils.cpp:576
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
Is variable changed by function call? In case the answer of the question is inconclusive,...
Definition: astutils.cpp:2263
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
Definition: astutils.cpp:2202
Token * findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
Definition: astutils.cpp:2856
static bool hasUnknownVars(const Token *startTok)
Definition: astutils.cpp:1140
static bool isEscapedOrJump(const Token *tok, bool functionsScope, const Library &library)
Definition: astutils.cpp:2146
static const Token * followVariableExpression(const Settings &settings, const Token *tok, const Token *end=nullptr)
This takes a token that refers to a variable and it will return the token to the expression that the ...
Definition: astutils.cpp:1166
static bool isSameConstantValue(bool macro, const Token *tok1, const Token *tok2)
Definition: astutils.cpp:1436
bool astIsUnsigned(const Token *tok)
Definition: astutils.cpp:202
static bool isSameLifetime(const Token *const tok1, const Token *const tok2)
Definition: astutils.cpp:1382
static int findArgumentPosRecursive(const Token *tok, const Token *tokToFind, bool &found, nonneg int depth=0)
Definition: astutils.cpp:68
bool astIsIterator(const Token *tok)
Definition: astutils.cpp:239
const Token * previousBeforeAstLeftmostLeaf(const Token *tok)
Definition: astutils.cpp:514
const Token * findExpressionChangedSkipDeadCode(const Token *expr, const Token *start, const Token *end, const Settings &settings, const std::function< std::vector< MathLib::bigint >(const Token *tok)> &evaluate, int depth)
Definition: astutils.cpp:3037
bool isCPPCast(const Token *tok)
Definition: astutils.cpp:3247
bool isEqualKnownValue(const Token *const tok1, const Token *const tok2)
Definition: astutils.cpp:1414
std::vector< const Variable * > getLHSVariables(const Token *tok)
Definition: astutils.cpp:3445
bool isConstExpression(const Token *tok, const Library &library)
Definition: astutils.cpp:2049
std::vector< const Variable * > getArgumentVars(const Token *tok, int argnr)
Definition: astutils.cpp:2368
static bool isForLoopIncrement(const Token *const tok)
Definition: astutils.cpp:1478
bool isUnevaluated(const Token *tok)
Definition: astutils.cpp:3612
const Token * getLHSVariableToken(const Token *tok)
Definition: astutils.cpp:3487
const Token * getParentLifetime(const Token *tok)
Definition: astutils.cpp:596
SmallVector< ReferenceToken > followAllReferences(const Token *tok, bool temporary, bool inconclusive, ErrorPath errors, int depth)
Definition: astutils.cpp:1236
static bool isAliased(const Token *startTok, const Token *endTok, nonneg int varid)
Definition: astutils.cpp:1080
bool isLikelyStream(const Token *stream)
Definition: astutils.cpp:3204
std::string astCanonicalType(const Token *expr, bool pointedToType)
Get canonical type of expression.
Definition: astutils.cpp:326
Library::Container::Yield astContainerYield(const Token *tok, const Token **ftok)
Definition: astutils.cpp:297
static T * getCondTokFromEndImpl(T *endBlock)
Definition: astutils.cpp:832
static const Token * findThisChanged(const Token *start, const Token *end, int indirect, const Settings &settings)
Definition: astutils.cpp:2938
static int findArgumentPos(const Token *tok, const Token *tokToFind)
Definition: astutils.cpp:90
bool astIsUnknownSignChar(const Token *tok)
Is expression a 'char' if no promotion is used?
Definition: astutils.cpp:176
static const Token * findExpressionChangedImpl(const Token *expr, const Token *start, const Token *end, const Settings &settings, int depth, Find find)
Definition: astutils.cpp:2952
static T * getInitTokImpl(T *tok)
Definition: astutils.cpp:849
bool succeeds(const Token *tok1, const Token *tok2)
If tok1 comes after tok2.
Definition: astutils.cpp:1006
static T * previousBeforeAstLeftmostLeafGeneric(T *tok)
Definition: astutils.cpp:504
int numberOfArguments(const Token *ftok)
Determines the number of arguments - if token is a function call or macro.
Definition: astutils.cpp:3063
nonneg int astCount(const Token *tok, const char *op, int depth)
Definition: astutils.cpp:124
const Token * findExpression(const nonneg int exprid, const Token *start, const Token *end, const std::function< bool(const Token *)> &pred)
Definition: astutils.cpp:50
bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
Definition: astutils.cpp:2546
static T * nextAfterAstRightmostLeafGeneric(T *tok)
Definition: astutils.cpp:524
void visitAstNodes(T *ast, const TFunc &visitor)
Visit AST nodes recursively.
Definition: astutils.h:54
ExprUsage
Definition: astutils.h:439
@ PassedByReference
void astFlattenCopy(T *tok, const char *op, OuputIterator out, nonneg int depth=100)
Definition: astutils.h:120
const Token * findAstNode(const Token *ast, const TFunc &pred)
Definition: astutils.h:88
bool isZero(T x)
Definition: calculate.h:44
static int sign(const T v)
static const std::set< std::string > stl_containers_not_const
Set of the STL types whose operator[] is not const.
Definition: checkclass.h:62
static std::vector< const Token * > findReturns(const Function *f)
const Scope * functionScope
scope of function body
static bool returnsConst(const Function *function, bool unknown=false)
bool hasBody() const
Type type
constructor, destructor, ...
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
const Token * retDef
function return type token
const Token * token
function name token in implementation
const ::Type * retType
function return type
const Scope * nestedIn
Scope the function is declared in.
const Token * tokenDef
function name token in class definition
std::list< Variable > argumentList
argument list, must remain list due to clangimport usage!
static bool returnsVoid(const Function *function, bool unknown=false)
bool isConst() const
Action getAction(const std::string &function) const
Definition: library.h:248
Yield getYield(const std::string &function) const
Definition: library.h:255
bool stdAssociativeLike
Definition: library.h:241
Library definitions handling.
Definition: library.h:52
ArgumentChecks::Direction getArgDirection(const Token *ftok, int argnr) const
Definition: library.cpp:1497
bool isuninitargbad(const Token *ftok, int argnr, int indirect=0, bool *hasIndirect=nullptr) const
Definition: library.cpp:1060
static bool isContainerYield(const Token *const cond, Library::Container::Yield y, const std::string &fallback=emptyString)
Definition: library.cpp:1250
bool isnullargbad(const Token *ftok, int argnr) const
Definition: library.cpp:1047
bool isnoreturn(const Token *ftok) const
Definition: library.cpp:1558
const AllocFunc * getAllocFuncInfo(const Token *tok) const
get allocation info for function
Definition: library.cpp:1077
const Function * getFunction(const Token *ftok) const
Definition: library.cpp:1474
std::string getFunctionName(const Token *ftok) const
Get function name for function call.
Definition: library.cpp:1016
const std::string & returnValueType(const Token *ftok) const
Definition: library.cpp:1444
std::unordered_map< std::string, Function > functions
Definition: library.h:330
bool isFunctionConst(const std::string &functionName, bool pure) const
Definition: library.cpp:1534
long long bigint
Definition: mathlib.h:68
static bool isNullValue(const std::string &str)
Does the string represent the numerical value of 0? In case leading or trailing white space is provid...
Definition: mathlib.cpp:1253
static bool isInt(const std::string &str)
Definition: mathlib.cpp:1007
std::list< Function > functionList
std::list< Variable > varlist
ScopeType type
static Function * nestedInFunction(const Scope *scope)
Function * function
function info for this function
bool isLoopScope() const
const Scope * nestedIn
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
nonneg int numConstructors
const Scope * functionOf
scope this function belongs to
std::vector< const Scope * > findAssociatedScopes() const
bool isClassOrStruct() const
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
Library library
Library.
Definition: settings.h:237
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
void str(T &&s)
Definition: token.h:179
nonneg int index() const
Definition: token.h:1247
Token * astTop()
Definition: token.h:1416
bool hasKnownValue() const
Definition: token.cpp:2528
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:688
nonneg int exprId() const
Definition: token.h:883
bool isEnumerator() const
Definition: token.h:374
bool isKeyword() const
Definition: token.h:358
const std::string & originalName() const
Definition: token.h:1193
bool isName() const
Definition: token.h:361
bool isUnsigned() const
Definition: token.h:424
bool hasKnownIntValue() const
Definition: token.cpp:2519
bool isExpandedMacro() const
Definition: token.h:455
bool isTemplateArg() const
Is current token a template argument?
Definition: token.h:748
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
Definition: token.cpp:2397
bool isArithmeticalOp() const
Definition: token.h:395
std::string stringifyList(const stringifyOptions &options, const std::vector< std::string > *fileNames=nullptr, const Token *end=nullptr) const
Definition: token.cpp:1337
bool isIncompleteVar() const
Definition: token.h:573
bool isBoolean() const
Definition: token.h:404
bool isCpp() const
Definition: token.cpp:2718
bool isControlFlowKeyword() const
Definition: token.h:546
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
Definition: token.cpp:2343
const ValueType * valueType() const
Definition: token.h:331
const Enumerator * enumerator() const
Definition: token.h:1111
void astOperand1(Token *tok)
Definition: token.cpp:1456
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1093
nonneg int varId() const
Definition: token.h:870
std::string expressionString() const
Definition: token.cpp:1647
bool isSigned() const
Definition: token.h:430
bool isCast() const
Definition: token.h:458
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
bool isIncDecOp() const
Definition: token.h:407
bool isLiteral() const
Definition: token.h:368
bool isIncompleteConstant() const
Definition: token.h:587
bool isInitComma() const
Definition: token.h:678
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
Definition: token.h:763
const Token * tokAt(int index) const
Definition: token.cpp:393
bool isConstOp() const
Definition: token.h:385
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1468
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
bool isLong() const
Definition: token.h:443
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:413
@ eBitOp
Definition: token.h:163
@ eType
Definition: token.h:161
@ eIncDecOp
Definition: token.h:163
Token * previous()
Definition: token.h:862
bool isBinaryOp() const
Definition: token.h:410
bool isComplex() const
Definition: token.h:555
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2333
bool isAssignmentOp() const
Definition: token.h:401
Token * astSibling()
Definition: token.h:1396
bool isStandardType() const
Definition: token.h:449
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
bool isComparisonOp() const
Definition: token.h:398
Token * next()
Definition: token.h:830
const std::list< ValueFlow::Value > & values() const
Definition: token.h:1197
bool isAttributeConst() const
Definition: token.h:494
const Token * nextArgument() const
Definition: token.cpp:869
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
nonneg int fileIndex() const
Definition: token.h:809
bool isAttributePure() const
Definition: token.h:488
void astParent(Token *tok)
Definition: token.cpp:1437
Information about a class type.
std::string name() const
const Scope * classScope
const std::string & type() const
bool isIteratorValue() const
Definition: vfvalue.h:235
bool isLifetimeValue() const
Definition: vfvalue.h:229
bool isKnown() const
Definition: vfvalue.h:353
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
bool equalValue(const ValueFlow::Value &rhs) const
Definition: vfvalue.h:60
Value type.
bool isFloat() const
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
bool isConst(nonneg int indirect=0) const
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
Reference reference
Is the outermost indirection of this type a reference or rvalue.
const Library::SmartPointer * smartPointer
Smart pointer.
bool isIntegral() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Token * smartPointerTypeToken
Smart pointer type token.
const Token * containerTypeToken
The container type token.
static ValueType parseDecl(const Token *type, const Settings &settings)
enum ValueType::Sign sign
bool isPrimitive() const
Information about a member variable.
bool isArgument() const
Is variable a function argument.
bool isEnumType() const
Determine whether it's an enumeration type.
bool isClass() const
Is variable a user defined (or unknown) type.
bool isProtected() const
Is variable protected.
bool isReference() const
Is reference variable.
bool isFloatingType() const
Determine whether it's a floating number type.
bool isRValueReference() const
Is reference variable.
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
bool isPublic() const
Is variable public.
const std::string & name() const
Get name string.
bool isConst() const
Is variable const.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
bool isPrivate() const
Is variable private.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isVolatile() const
Is variable volatile.
bool isPointer() const
Is pointer variable.
bool isStatic() const
Is variable static.
const ValueType * valueType() const
#define REQUIRES(msg,...)
Definition: config.h:124
#define nonneg
Definition: config.h:138
T * findToken(T *start, const Token *end, const Predicate &pred)
Definition: findtoken.h:67
T * findTokenSkipDeadCode(const Library &library, T *start, const Token *end, const Predicate &pred, const Evaluate &evaluate)
Definition: findtoken.h:199
std::pair< const Token *, std::string > ErrorPathItem
Definition: errortypes.h:129
const Library::Container * getLibraryContainer(const Token *tok)
Definition: library.cpp:1731
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:130
std::vector< MathLib::bigint > getMinValue(const ValuePtr< InferModel > &model, const std::list< ValueFlow::Value > &values)
Definition: infer.cpp:377
CPPCHECKLIB Value getLifetimeObjValue(const Token *tok, bool inconclusive=false)
Definition: valueflow.cpp:3575
CPPCHECKLIB ValuePtr< InferModel > makeIntegralInferModel()
Definition: valueflow.cpp:6977
static ValueFlow::Value evaluate(const std::string &op, const ValueFlow::Value &lhs, const ValueFlow::Value &rhs)
@ DIR_IN
Input to called function. Data is treated as read-only.
@ DIR_OUT
Output to caller. Data is passed by reference or address and is potentially written.
@ DIR_INOUT
Input to called function, and output to caller. Data is passed by reference or address and is potenti...
const Token * token
Definition: astutils.h:254
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
bool endsWith(const std::string &str, char c)
Definition: utils.h:110
bool contains(const Range &r, const T &x)
Definition: utils.h:62