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, "for") && Token::simpleMatch(tok->next()->astOperand2(), ";") &&
819  tok->next()->astOperand2()->astOperand2())
820  return tok->next()->astOperand2()->astOperand2()->astOperand1();
821  if (Token::simpleMatch(tok->next()->astOperand2(), ";"))
822  return tok->next()->astOperand2()->astOperand1();
823  return tok->next()->astOperand2();
824 }
825 
826 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
827 static T* getCondTokFromEndImpl(T* endBlock)
828 {
829  if (!Token::simpleMatch(endBlock, "}"))
830  return nullptr;
831  T* startBlock = endBlock->link();
832  if (!Token::simpleMatch(startBlock, "{"))
833  return nullptr;
834  if (Token::simpleMatch(startBlock->previous(), ")"))
835  return getCondTok(startBlock->previous()->link());
836  if (Token::simpleMatch(startBlock->tokAt(-2), "} else {"))
837  return getCondTokFromEnd(startBlock->tokAt(-2));
838  return nullptr;
839 }
840 
841 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
842 static T* getInitTokImpl(T* tok)
843 {
844  if (!tok)
845  return nullptr;
846  if (Token::Match(tok, "%name% ("))
847  return getInitTokImpl(tok->next());
848  if (tok->str() != "(")
849  return nullptr;
850  if (!Token::simpleMatch(tok->astOperand2(), ";"))
851  return nullptr;
852  if (Token::simpleMatch(tok->astOperand2()->astOperand1(), ";"))
853  return nullptr;
854  return tok->astOperand2()->astOperand1();
855 }
856 
857 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
858 static T* getStepTokImpl(T* tok)
859 {
860  if (!tok)
861  return nullptr;
862  if (Token::Match(tok, "%name% ("))
863  return getStepTokImpl(tok->next());
864  if (tok->str() != "(")
865  return nullptr;
866  if (!Token::simpleMatch(tok->astOperand2(), ";"))
867  return nullptr;
868  if (!Token::simpleMatch(tok->astOperand2()->astOperand2(), ";"))
869  return nullptr;
870  return tok->astOperand2()->astOperand2()->astOperand2();
871 }
872 
874 {
875  return getCondTokImpl(tok);
876 }
877 const Token* getCondTok(const Token* tok)
878 {
879  return getCondTokImpl(tok);
880 }
881 
883 {
884  return getCondTokFromEndImpl(endBlock);
885 }
886 const Token* getCondTokFromEnd(const Token* endBlock)
887 {
888  return getCondTokFromEndImpl(endBlock);
889 }
890 
892  return getInitTokImpl(tok);
893 }
894 const Token* getInitTok(const Token* tok) {
895  return getInitTokImpl(tok);
896 }
897 
899  return getStepTokImpl(tok);
900 }
901 const Token* getStepTok(const Token* tok) {
902  return getStepTokImpl(tok);
903 }
904 
905 const Token *findNextTokenFromBreak(const Token *breakToken)
906 {
907  const Scope *scope = breakToken->scope();
908  while (scope) {
909  if (scope->isLoopScope() || scope->type == Scope::ScopeType::eSwitch) {
910  if (scope->type == Scope::ScopeType::eDo && Token::simpleMatch(scope->bodyEnd, "} while ("))
911  return scope->bodyEnd->linkAt(2)->next();
912  return scope->bodyEnd;
913  }
914  scope = scope->nestedIn;
915  }
916  return nullptr;
917 }
918 
919 bool extractForLoopValues(const Token *forToken,
920  nonneg int &varid,
921  bool &knownInitValue,
922  MathLib::bigint &initValue,
923  bool &partialCond,
924  MathLib::bigint &stepValue,
925  MathLib::bigint &lastValue)
926 {
927  if (!Token::simpleMatch(forToken, "for (") || !Token::simpleMatch(forToken->next()->astOperand2(), ";"))
928  return false;
929  const Token *initExpr = forToken->next()->astOperand2()->astOperand1();
930  const Token *condExpr = forToken->next()->astOperand2()->astOperand2()->astOperand1();
931  const Token *incExpr = forToken->next()->astOperand2()->astOperand2()->astOperand2();
932  if (!initExpr || !initExpr->isBinaryOp() || initExpr->str() != "=" || !Token::Match(initExpr->astOperand1(), "%var%"))
933  return false;
934  std::vector<MathLib::bigint> minInitValue = getMinValue(ValueFlow::makeIntegralInferModel(), initExpr->astOperand2()->values());
935  if (minInitValue.empty()) {
936  const ValueFlow::Value* v = initExpr->astOperand2()->getMinValue(true);
937  if (v)
938  minInitValue.push_back(v->intvalue);
939  }
940  if (minInitValue.empty())
941  return false;
942  varid = initExpr->astOperand1()->varId();
943  knownInitValue = initExpr->astOperand2()->hasKnownIntValue();
944  initValue = minInitValue.front();
945  partialCond = Token::Match(condExpr, "%oror%|&&");
946  visitAstNodes(condExpr, [varid, &condExpr](const Token *tok) {
947  if (Token::Match(tok, "%oror%|&&"))
949  if (Token::Match(tok, "<|<=") && tok->isBinaryOp() && tok->astOperand1()->varId() == varid && tok->astOperand2()->hasKnownIntValue()) {
950  if (Token::Match(condExpr, "%oror%|&&") || tok->astOperand2()->getKnownIntValue() < condExpr->astOperand2()->getKnownIntValue())
951  condExpr = tok;
952  }
953  return ChildrenToVisit::none;
954  });
955  if (!Token::Match(condExpr, "<|<=") || !condExpr->isBinaryOp() || condExpr->astOperand1()->varId() != varid || !condExpr->astOperand2()->hasKnownIntValue())
956  return false;
957  if (!incExpr || !incExpr->isUnaryOp("++") || incExpr->astOperand1()->varId() != varid)
958  return false;
959  stepValue = 1;
960  if (condExpr->str() == "<")
961  lastValue = condExpr->astOperand2()->getKnownIntValue() - 1;
962  else
963  lastValue = condExpr->astOperand2()->getKnownIntValue();
964  return true;
965 }
966 
967 
968 static const Token * getVariableInitExpression(const Variable * var)
969 {
970  if (!var)
971  return nullptr;
972  const Token *varDeclEndToken = var->declEndToken();
973  if (!varDeclEndToken)
974  return nullptr;
975  if (Token::Match(varDeclEndToken, "; %varid% =", var->declarationId()))
976  return varDeclEndToken->tokAt(2)->astOperand2();
977  return varDeclEndToken->astOperand2();
978 }
979 
980 const Token* isInLoopCondition(const Token* tok)
981 {
982  const Token* top = tok->astTop();
983  return top && Token::Match(top->previous(), "for|while (") ? top : nullptr;
984 }
985 
986 /// If tok2 comes after tok1
987 bool precedes(const Token * tok1, const Token * tok2)
988 {
989  if (tok1 == tok2)
990  return false;
991  if (!tok1)
992  return false;
993  if (!tok2)
994  return true;
995  return tok1->index() < tok2->index();
996 }
997 
998 /// If tok1 comes after tok2
999 bool succeeds(const Token* tok1, const Token* tok2)
1000 {
1001  if (tok1 == tok2)
1002  return false;
1003  if (!tok1)
1004  return false;
1005  if (!tok2)
1006  return true;
1007  return tok1->index() > tok2->index();
1008 }
1009 
1010 bool isAliasOf(const Token *tok, nonneg int varid, bool* inconclusive)
1011 {
1012  if (tok->varId() == varid)
1013  return false;
1014  // NOLINTNEXTLINE(readability-use-anyofallof) - TODO: fix this / also Cppcheck false negative
1015  for (const ValueFlow::Value &val : tok->values()) {
1016  if (!val.isLocalLifetimeValue())
1017  continue;
1018  if (val.tokvalue->varId() == varid) {
1019  if (val.isInconclusive()) {
1020  if (inconclusive)
1021  *inconclusive = true;
1022  else
1023  continue;
1024  }
1025  return true;
1026  }
1027  }
1028  return false;
1029 }
1030 
1031 bool isAliasOf(const Token* tok, const Token* expr, int* indirect, bool* inconclusive)
1032 {
1033  const ValueFlow::Value* value = nullptr;
1034  const Token* r = nullptr;
1035  if (indirect)
1036  *indirect = 1;
1037  for (const ReferenceToken& ref : followAllReferences(tok)) {
1038  const bool pointer = astIsPointer(ref.token);
1039  r = findAstNode(expr, [&](const Token* childTok) {
1040  if (childTok->exprId() == 0)
1041  return false;
1042  if (ref.token != tok && expr->exprId() == childTok->exprId()) {
1043  if (indirect)
1044  *indirect = 0;
1045  return true;
1046  }
1047  for (const ValueFlow::Value& val : ref.token->values()) {
1048  if (val.isImpossible())
1049  continue;
1050  if (val.isLocalLifetimeValue() || (pointer && val.isSymbolicValue() && val.intvalue == 0)) {
1051  if (findAstNode(val.tokvalue,
1052  [&](const Token* aliasTok) {
1053  return aliasTok != childTok && aliasTok->exprId() == childTok->exprId();
1054  })) {
1055  if (val.isInconclusive() && inconclusive != nullptr) {
1056  value = &val;
1057  } else {
1058  return true;
1059  }
1060  }
1061  }
1062  }
1063  return false;
1064  });
1065  if (r)
1066  break;
1067  }
1068  if (!r && value && inconclusive)
1069  *inconclusive = true;
1070  return r || value;
1071 }
1072 
1073 static bool isAliased(const Token *startTok, const Token *endTok, nonneg int varid)
1074 {
1075  if (!precedes(startTok, endTok))
1076  return false;
1077  for (const Token *tok = startTok; tok != endTok; tok = tok->next()) {
1078  if (Token::Match(tok, "= & %varid% ;", varid))
1079  return true;
1080  if (isAliasOf(tok, varid))
1081  return true;
1082  }
1083  return false;
1084 }
1085 
1086 bool isAliased(const Variable *var)
1087 {
1088  if (!var)
1089  return false;
1090  if (!var->scope())
1091  return false;
1092  const Token *start = var->declEndToken();
1093  if (!start)
1094  return false;
1095  return isAliased(start, var->scope()->bodyEnd, var->declarationId());
1096 }
1097 
1098 bool exprDependsOnThis(const Token* expr, bool onVar, nonneg int depth)
1099 {
1100  if (!expr)
1101  return false;
1102  if (expr->str() == "this")
1103  return true;
1104  if (depth >= 1000)
1105  // Abort recursion to avoid stack overflow
1106  return true;
1107  ++depth;
1108 
1109  // calling nonstatic method?
1110  if (Token::Match(expr, "%name% (") && expr->function() && expr->function()->nestedIn && expr->function()->nestedIn->isClassOrStruct() && !expr->function()->isStatic()) {
1111  // is it a method of this?
1112  const Scope* fScope = expr->scope();
1113  while (!fScope->functionOf && fScope->nestedIn)
1114  fScope = fScope->nestedIn;
1115 
1116  const Scope* classScope = fScope->functionOf;
1117  if (classScope && classScope->function)
1118  classScope = classScope->function->token->scope();
1119 
1120  if (classScope && classScope->isClassOrStruct())
1121  return contains(classScope->findAssociatedScopes(), expr->function()->nestedIn);
1122  return false;
1123  }
1124  if (onVar && expr->variable()) {
1125  const Variable* var = expr->variable();
1126  return ((var->isPrivate() || var->isPublic() || var->isProtected()) && !var->isStatic());
1127  }
1128  if (Token::simpleMatch(expr, "."))
1129  return exprDependsOnThis(expr->astOperand1(), onVar, depth);
1130  return exprDependsOnThis(expr->astOperand1(), onVar, depth) || exprDependsOnThis(expr->astOperand2(), onVar, depth);
1131 }
1132 
1133 static bool hasUnknownVars(const Token* startTok)
1134 {
1135  bool result = false;
1136  visitAstNodes(startTok, [&](const Token* tok) {
1137  if (tok->varId() > 0 && !tok->variable()) {
1138  result = true;
1139  return ChildrenToVisit::done;
1140  }
1142  });
1143  return result;
1144 }
1145 
1147 {
1148  if (!var)
1149  return false;
1150  const Token* tok = var->nameToken();
1151  while (tok && Token::Match(tok->astParent(), "[|,|:"))
1152  tok = tok->astParent();
1153  return tok && (tok->str() == "[" || Token::simpleMatch(tok->previous(), "] :")); // TODO: remove workaround when #11105 is fixed
1154 }
1155 
1156 /// This takes a token that refers to a variable and it will return the token
1157 /// to the expression that the variable is assigned to. If its not valid to
1158 /// make such substitution then it will return the original token.
1159 static const Token * followVariableExpression(const Settings& settings, const Token * tok, const Token * end = nullptr)
1160 {
1161  if (!tok)
1162  return tok;
1163  // Skip following variables that is across multiple files
1164  if (end && end->fileIndex() != tok->fileIndex())
1165  return tok;
1166  // Skip array access
1167  if (Token::Match(tok, "%var% ["))
1168  return tok;
1169  // Skip pointer indirection
1170  if (tok->astParent() && tok->isUnaryOp("*"))
1171  return tok;
1172  // Skip following variables if it is used in an assignment
1173  if (Token::Match(tok->next(), "%assign%"))
1174  return tok;
1175  const Variable * var = tok->variable();
1176  const Token * varTok = getVariableInitExpression(var);
1177  if (!varTok)
1178  return tok;
1179  if (hasUnknownVars(varTok))
1180  return tok;
1181  if (var->isVolatile())
1182  return tok;
1183  if (!var->isLocal() && !var->isConst())
1184  return tok;
1185  if (var->isStatic() && !var->isConst())
1186  return tok;
1187  if (var->isArgument())
1188  return tok;
1189  if (isStructuredBindingVariable(var))
1190  return tok;
1191  // assigning a floating point value to an integer does not preserve the value
1192  if (var->valueType() && var->valueType()->isIntegral() && varTok->valueType() && varTok->valueType()->isFloat())
1193  return tok;
1194  const Token * lastTok = precedes(tok, end) ? end : tok;
1195  // If this is in a loop then check if variables are modified in the entire scope
1196  const Token * endToken = (isInLoopCondition(tok) || isInLoopCondition(varTok) || var->scope() != tok->scope()) ? var->scope()->bodyEnd : lastTok;
1197  if (!var->isConst() && (!precedes(varTok, endToken) || isVariableChanged(varTok, endToken, tok->varId(), false, settings)))
1198  return tok;
1199  if (precedes(varTok, endToken) && isAliased(varTok, endToken, tok->varId()))
1200  return tok;
1201  const Token* startToken = nextAfterAstRightmostLeaf(varTok);
1202  if (!startToken)
1203  startToken = varTok;
1204  if (varTok->exprId() == 0) {
1205  if (!varTok->isLiteral())
1206  return tok;
1207  } else if (!precedes(startToken, endToken)) {
1208  return tok;
1209  } else if (findExpressionChanged(varTok, startToken, endToken, settings)) {
1210  return tok;
1211  }
1212  return varTok;
1213 }
1214 
1215 static void followVariableExpressionError(const Token *tok1, const Token *tok2, ErrorPath* errors)
1216 {
1217  if (!errors)
1218  return;
1219  if (!tok1)
1220  return;
1221  if (!tok2)
1222  return;
1223  ErrorPathItem item = std::make_pair(tok2, "'" + tok1->str() + "' is assigned value '" + tok2->expressionString() + "' here.");
1224  if (std::find(errors->cbegin(), errors->cend(), item) != errors->cend())
1225  return;
1226  errors->push_back(std::move(item));
1227 }
1228 
1230  bool temporary,
1231  bool inconclusive,
1232  ErrorPath errors,
1233  int depth)
1234 {
1235  struct ReferenceTokenLess {
1236  bool operator()(const ReferenceToken& x, const ReferenceToken& y) const {
1237  return x.token < y.token;
1238  }
1239  };
1240  if (!tok)
1241  return {};
1242  if (depth < 0) {
1243  SmallVector<ReferenceToken> refs_result;
1244  refs_result.push_back({tok, std::move(errors)});
1245  return refs_result;
1246  }
1247  const Variable *var = tok->variable();
1248  if (var && var->declarationId() == tok->varId()) {
1249  if (var->nameToken() == tok || isStructuredBindingVariable(var)) {
1250  SmallVector<ReferenceToken> refs_result;
1251  refs_result.push_back({tok, std::move(errors)});
1252  return refs_result;
1253  }
1254  if (var->isReference() || var->isRValueReference()) {
1255  const Token * const varDeclEndToken = var->declEndToken();
1256  if (!varDeclEndToken) {
1257  SmallVector<ReferenceToken> refs_result;
1258  refs_result.push_back({tok, std::move(errors)});
1259  return refs_result;
1260  }
1261  if (var->isArgument()) {
1262  errors.emplace_back(varDeclEndToken, "Passed to reference.");
1263  SmallVector<ReferenceToken> refs_result;
1264  refs_result.push_back({tok, std::move(errors)});
1265  return refs_result;
1266  }
1267  if (Token::simpleMatch(varDeclEndToken, "=")) {
1268  if (astHasToken(varDeclEndToken, tok))
1269  return {};
1270  errors.emplace_back(varDeclEndToken, "Assigned to reference.");
1271  const Token *vartok = varDeclEndToken->astOperand2();
1272  if (vartok == tok || (!temporary && isTemporary(vartok, nullptr, true) &&
1273  (var->isConst() || var->isRValueReference()))) {
1274  SmallVector<ReferenceToken> refs_result;
1275  refs_result.push_back({tok, std::move(errors)});
1276  return refs_result;
1277  }
1278  if (vartok)
1279  return followAllReferences(vartok, temporary, inconclusive, std::move(errors), depth - 1);
1280  }
1281  }
1282  } else if (Token::simpleMatch(tok, "?") && Token::simpleMatch(tok->astOperand2(), ":")) {
1283  std::set<ReferenceToken, ReferenceTokenLess> result;
1284  const Token* tok2 = tok->astOperand2();
1285 
1286  auto refs = followAllReferences(tok2->astOperand1(), temporary, inconclusive, errors, depth - 1);
1287  result.insert(refs.cbegin(), refs.cend());
1288  refs = followAllReferences(tok2->astOperand2(), temporary, inconclusive, errors, depth - 1);
1289  result.insert(refs.cbegin(), refs.cend());
1290 
1291  if (!inconclusive && result.size() != 1) {
1292  SmallVector<ReferenceToken> refs_result;
1293  refs_result.push_back({tok, std::move(errors)});
1294  return refs_result;
1295  }
1296 
1297  if (!result.empty()) {
1298  SmallVector<ReferenceToken> refs_result;
1299  refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
1300  return refs_result;
1301  }
1302 
1303  } else if (tok->previous() && tok->previous()->function() && Token::Match(tok->previous(), "%name% (")) {
1304  const Function *f = tok->previous()->function();
1305  if (!Function::returnsReference(f)) {
1306  SmallVector<ReferenceToken> refs_result;
1307  refs_result.push_back({tok, std::move(errors)});
1308  return refs_result;
1309  }
1310  std::set<ReferenceToken, ReferenceTokenLess> result;
1311  std::vector<const Token*> returns = Function::findReturns(f);
1312  for (const Token* returnTok : returns) {
1313  if (returnTok == tok)
1314  continue;
1315  for (const ReferenceToken& rt :
1316  followAllReferences(returnTok, temporary, inconclusive, errors, depth - returns.size())) {
1317  const Variable* argvar = rt.token->variable();
1318  if (!argvar) {
1319  SmallVector<ReferenceToken> refs_result;
1320  refs_result.push_back({tok, std::move(errors)});
1321  return refs_result;
1322  }
1323  if (argvar->isArgument() && (argvar->isReference() || argvar->isRValueReference())) {
1324  const int n = getArgumentPos(argvar, f);
1325  if (n < 0) {
1326  SmallVector<ReferenceToken> refs_result;
1327  refs_result.push_back({tok, std::move(errors)});
1328  return refs_result;
1329  }
1330  std::vector<const Token*> args = getArguments(tok->previous());
1331  if (n >= args.size()) {
1332  SmallVector<ReferenceToken> refs_result;
1333  refs_result.push_back({tok, std::move(errors)});
1334  return refs_result;
1335  }
1336  const Token* argTok = args[n];
1337  ErrorPath er = errors;
1338  er.emplace_back(returnTok, "Return reference.");
1339  er.emplace_back(tok->previous(), "Called function passing '" + argTok->expressionString() + "'.");
1340  auto refs =
1341  followAllReferences(argTok, temporary, inconclusive, std::move(er), depth - returns.size());
1342  result.insert(refs.cbegin(), refs.cend());
1343  if (!inconclusive && result.size() > 1) {
1344  SmallVector<ReferenceToken> refs_result;
1345  refs_result.push_back({tok, std::move(errors)});
1346  return refs_result;
1347  }
1348  }
1349  }
1350  }
1351  if (!result.empty()) {
1352  SmallVector<ReferenceToken> refs_result;
1353  refs_result.insert(refs_result.end(), result.cbegin(), result.cend());
1354  return refs_result;
1355  }
1356  }
1357  SmallVector<ReferenceToken> refs_result;
1358  refs_result.push_back({tok, std::move(errors)});
1359  return refs_result;
1360 }
1361 
1362 const Token* followReferences(const Token* tok, ErrorPath* errors)
1363 {
1364  if (!tok)
1365  return nullptr;
1366  auto refs = followAllReferences(tok, true, false);
1367  if (refs.size() == 1) {
1368  if (errors)
1369  *errors = std::move(refs.front().errors);
1370  return refs.front().token;
1371  }
1372  return nullptr;
1373 }
1374 
1375 static bool isSameLifetime(const Token * const tok1, const Token * const tok2)
1376 {
1378  if (!v1.isLifetimeValue())
1379  return false;
1381  if (!v2.isLifetimeValue())
1382  return false;
1383  return v1.tokvalue == v2.tokvalue;
1384 }
1385 
1386 static bool compareKnownValue(const Token * const tok1, const Token * const tok2, const std::function<bool(const ValueFlow::Value&, const ValueFlow::Value&, bool)> &compare)
1387 {
1388  static const auto isKnownFn = std::mem_fn(&ValueFlow::Value::isKnown);
1389 
1390  const auto v1 = std::find_if(tok1->values().cbegin(), tok1->values().cend(), isKnownFn);
1391  if (v1 == tok1->values().end()) {
1392  return false;
1393  }
1394  if (v1->isNonValue() || v1->isContainerSizeValue() || v1->isSymbolicValue())
1395  return false;
1396  const auto v2 = std::find_if(tok2->values().cbegin(), tok2->values().cend(), isKnownFn);
1397  if (v2 == tok2->values().end()) {
1398  return false;
1399  }
1400  if (v1->valueType != v2->valueType) {
1401  return false;
1402  }
1403  const bool sameLifetime = isSameLifetime(tok1, tok2);
1404  return compare(*v1, *v2, sameLifetime);
1405 }
1406 
1407 bool isEqualKnownValue(const Token * const tok1, const Token * const tok2)
1408 {
1409  return compareKnownValue(tok1, tok2, [&](const ValueFlow::Value& v1, const ValueFlow::Value& v2, bool sameLifetime) {
1410  bool r = v1.equalValue(v2);
1411  if (v1.isIteratorValue()) {
1412  r &= sameLifetime;
1413  }
1414  return r;
1415  });
1416 }
1417 
1418 static inline bool isDifferentKnownValues(const Token * const tok1, const Token * const tok2)
1419 {
1420  return compareKnownValue(tok1, tok2, [&](const ValueFlow::Value& v1, const ValueFlow::Value& v2, bool sameLifetime) {
1421  bool r = v1.equalValue(v2);
1422  if (v1.isIteratorValue()) {
1423  r &= sameLifetime;
1424  }
1425  return !r;
1426  });
1427 }
1428 
1429 static inline bool isSameConstantValue(bool macro, const Token* tok1, const Token* tok2)
1430 {
1431  if (tok1 == nullptr || tok2 == nullptr)
1432  return false;
1433 
1434  auto adjustForCast = [](const Token* tok) {
1435  if (tok->astOperand2() && Token::Match(tok->previous(), "%type% (|{") && tok->previous()->isStandardType())
1436  return tok->astOperand2();
1437  return tok;
1438  };
1439 
1440  tok1 = adjustForCast(tok1);
1441  if (!tok1->isNumber() && !tok1->enumerator())
1442  return false;
1443  tok2 = adjustForCast(tok2);
1444  if (!tok2->isNumber() && !tok2->enumerator())
1445  return false;
1446 
1447  if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro() || tok1->isTemplateArg() || tok2->isTemplateArg()))
1448  return false;
1449 
1450  const ValueType * v1 = tok1->valueType();
1451  const ValueType * v2 = tok2->valueType();
1452 
1453  if (!v1 || !v2 || v1->sign != v2->sign || v1->type != v2->type || v1->pointer != v2->pointer)
1454  return false;
1455 
1456  return isEqualKnownValue(tok1, tok2);
1457 }
1458 
1459 
1460 static bool isForLoopCondition(const Token * const tok)
1461 {
1462  if (!tok)
1463  return false;
1464  const Token *const parent = tok->astParent();
1465  return Token::simpleMatch(parent, ";") && parent->astOperand1() == tok &&
1466  Token::simpleMatch(parent->astParent(), ";") &&
1467  Token::simpleMatch(parent->astParent()->astParent(), "(") &&
1468  parent->astParent()->astParent()->astOperand1()->str() == "for";
1469 }
1470 
1471 static bool isForLoopIncrement(const Token* const tok)
1472 {
1473  if (!tok)
1474  return false;
1475  const Token *const parent = tok->astParent();
1476  return Token::simpleMatch(parent, ";") && parent->astOperand2() == tok &&
1477  Token::simpleMatch(parent->astParent(), ";") &&
1478  Token::simpleMatch(parent->astParent()->astParent(), "(") &&
1479  parent->astParent()->astParent()->astOperand1()->str() == "for";
1480 }
1481 
1482 bool isUsedAsBool(const Token* const tok, const Settings& settings)
1483 {
1484  if (!tok)
1485  return false;
1486  if (isForLoopIncrement(tok))
1487  return false;
1488  if (astIsBool(tok))
1489  return true;
1490  if (Token::Match(tok, "!|&&|%oror%|%comp%"))
1491  return true;
1492  const Token* parent = tok->astParent();
1493  if (!parent)
1494  return false;
1495  if (Token::simpleMatch(parent, "["))
1496  return false;
1497  if (parent->isUnaryOp("*"))
1498  return false;
1499  if (Token::simpleMatch(parent, ".")) {
1500  if (astIsRHS(tok))
1501  return isUsedAsBool(parent, settings);
1502  return false;
1503  }
1504  if (Token::Match(parent, "&&|!|%oror%"))
1505  return true;
1506  if (parent->isCast())
1507  return !Token::simpleMatch(parent->astOperand1(), "dynamic_cast") && isUsedAsBool(parent, settings);
1508  if (parent->isUnaryOp("*"))
1509  return isUsedAsBool(parent, settings);
1510  if (Token::Match(parent, "==|!=") && (tok->astSibling()->isNumber() || tok->astSibling()->isKeyword()) && tok->astSibling()->hasKnownIntValue() &&
1511  tok->astSibling()->values().front().intvalue == 0)
1512  return true;
1513  if (parent->str() == "(" && astIsRHS(tok) && Token::Match(parent->astOperand1(), "if|while"))
1514  return true;
1515  if (Token::simpleMatch(parent, "?") && astIsLHS(tok))
1516  return true;
1517  if (isForLoopCondition(tok))
1518  return true;
1519  if (!Token::Match(parent, "%cop%") && !(parent->str() == "(" && tok == parent->astOperand1())) {
1520  if (parent->str() == "," && parent->isInitComma())
1521  return false;
1522  std::vector<ValueType> vtParents = getParentValueTypes(tok, settings);
1523  return std::any_of(vtParents.cbegin(), vtParents.cend(), [&](const ValueType& vt) {
1524  return vt.pointer == 0 && vt.type == ValueType::BOOL;
1525  });
1526  }
1527  return false;
1528 }
1529 
1530 bool compareTokenFlags(const Token* tok1, const Token* tok2, bool macro) {
1531  if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro() || tok1->isTemplateArg() || tok2->isTemplateArg()))
1532  return false;
1533  if (tok1->isComplex() != tok2->isComplex())
1534  return false;
1535  if (tok1->isLong() != tok2->isLong())
1536  return false;
1537  if (tok1->isUnsigned() != tok2->isUnsigned())
1538  return false;
1539  if (tok1->isSigned() != tok2->isSigned())
1540  return false;
1541  return true;
1542 }
1543 
1544 static bool astIsBoolLike(const Token* tok, const Settings& settings)
1545 {
1546  return astIsBool(tok) || isUsedAsBool(tok, settings);
1547 }
1548 
1549 bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1550 {
1551  if (tok1 == tok2)
1552  return true;
1553  if (tok1 == nullptr || tok2 == nullptr)
1554  return false;
1555  // tokens needs to be from the same TokenList so no need check standard on both of them
1556  if (tok1->isCpp()) {
1557  if (tok1->str() == "." && tok1->astOperand1() && tok1->astOperand1()->str() == "this")
1558  tok1 = tok1->astOperand2();
1559  if (tok2->str() == "." && tok2->astOperand1() && tok2->astOperand1()->str() == "this")
1560  tok2 = tok2->astOperand2();
1561  }
1562  // Skip double not
1563  if (Token::simpleMatch(tok1, "!") && Token::simpleMatch(tok1->astOperand1(), "!") && !Token::simpleMatch(tok1->astParent(), "=") && astIsBoolLike(tok2, settings)) {
1564  return isSameExpression(macro, tok1->astOperand1()->astOperand1(), tok2, settings, pure, followVar, errors);
1565  }
1566  if (Token::simpleMatch(tok2, "!") && Token::simpleMatch(tok2->astOperand1(), "!") && !Token::simpleMatch(tok2->astParent(), "=") && astIsBoolLike(tok1, settings)) {
1567  return isSameExpression(macro, tok1, tok2->astOperand1()->astOperand1(), settings, pure, followVar, errors);
1568  }
1569  const bool tok_str_eq = tok1->str() == tok2->str();
1570  if (!tok_str_eq && isDifferentKnownValues(tok1, tok2))
1571  return false;
1572 
1573  const Token *followTok1 = tok1, *followTok2 = tok2;
1574  while (Token::simpleMatch(followTok1, "::") && followTok1->astOperand2())
1575  followTok1 = followTok1->astOperand2();
1576  while (Token::simpleMatch(followTok2, "::") && followTok2->astOperand2())
1577  followTok2 = followTok2->astOperand2();
1578  if (isSameConstantValue(macro, followTok1, followTok2))
1579  return true;
1580 
1581  // Follow variable
1582  if (followVar && !tok_str_eq && (followTok1->varId() || followTok2->varId() || followTok1->enumerator() || followTok2->enumerator())) {
1583  const Token * varTok1 = followVariableExpression(settings, followTok1, followTok2);
1584  if ((varTok1->str() == followTok2->str()) || isSameConstantValue(macro, varTok1, followTok2)) {
1585  followVariableExpressionError(followTok1, varTok1, errors);
1586  return isSameExpression(macro, varTok1, followTok2, settings, true, followVar, errors);
1587  }
1588  const Token * varTok2 = followVariableExpression(settings, followTok2, followTok1);
1589  if ((followTok1->str() == varTok2->str()) || isSameConstantValue(macro, followTok1, varTok2)) {
1590  followVariableExpressionError(followTok2, varTok2, errors);
1591  return isSameExpression(macro, followTok1, varTok2, settings, true, followVar, errors);
1592  }
1593  if ((varTok1->str() == varTok2->str()) || isSameConstantValue(macro, varTok1, varTok2)) {
1594  followVariableExpressionError(tok1, varTok1, errors);
1595  followVariableExpressionError(tok2, varTok2, errors);
1596  return isSameExpression(macro, varTok1, varTok2, settings, true, followVar, errors);
1597  }
1598  }
1599  // Follow references
1600  if (!tok_str_eq) {
1601  const Token* refTok1 = followReferences(tok1, errors);
1602  const Token* refTok2 = followReferences(tok2, errors);
1603  if (refTok1 != tok1 || refTok2 != tok2) {
1604  if (refTok1 && !refTok1->varId() && refTok2 && !refTok2->varId()) { // complex reference expression
1605  const Token *start = refTok1, *end = refTok2;
1606  if (!precedes(start, end))
1607  std::swap(start, end);
1608  if (findExpressionChanged(start, start, end, settings))
1609  return false;
1610  }
1611  return isSameExpression(macro, refTok1, refTok2, settings, pure, followVar, errors);
1612  }
1613  }
1614  if (tok1->varId() != tok2->varId() || !tok_str_eq || tok1->originalName() != tok2->originalName()) {
1615  if ((Token::Match(tok1,"<|>") && Token::Match(tok2,"<|>")) ||
1616  (Token::Match(tok1,"<=|>=") && Token::Match(tok2,"<=|>="))) {
1617  return isSameExpression(macro, tok1->astOperand1(), tok2->astOperand2(), settings, pure, followVar, errors) &&
1618  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand1(), settings, pure, followVar, errors);
1619  }
1620  const Token* condTok = nullptr;
1621  const Token* exprTok = nullptr;
1622  if (Token::Match(tok1, "==|!=")) {
1623  condTok = tok1;
1624  exprTok = tok2;
1625  } else if (Token::Match(tok2, "==|!=")) {
1626  condTok = tok2;
1627  exprTok = tok1;
1628  }
1629  if (condTok && condTok->astOperand1() && condTok->astOperand2() && !Token::Match(exprTok, "%comp%")) {
1630  const Token* varTok1 = nullptr;
1631  const Token* varTok2 = exprTok;
1632  const ValueFlow::Value* value = nullptr;
1633  if (condTok->astOperand1()->hasKnownIntValue()) {
1634  value = &condTok->astOperand1()->values().front();
1635  varTok1 = condTok->astOperand2();
1636  } else if (condTok->astOperand2()->hasKnownIntValue()) {
1637  value = &condTok->astOperand2()->values().front();
1638  varTok1 = condTok->astOperand1();
1639  }
1640  const bool exprIsNot = Token::simpleMatch(exprTok, "!");
1641  if (exprIsNot)
1642  varTok2 = exprTok->astOperand1();
1643  bool compare = false;
1644  if (value) {
1645  if (value->intvalue == 0 && exprIsNot && Token::simpleMatch(condTok, "==")) {
1646  compare = true;
1647  } else if (value->intvalue == 0 && !exprIsNot && Token::simpleMatch(condTok, "!=")) {
1648  compare = true;
1649  } else if (value->intvalue != 0 && exprIsNot && Token::simpleMatch(condTok, "!=")) {
1650  compare = true;
1651  } else if (value->intvalue != 0 && !exprIsNot && Token::simpleMatch(condTok, "==")) {
1652  compare = true;
1653  }
1654  }
1655  if (compare && astIsBoolLike(varTok1, settings) && astIsBoolLike(varTok2, settings))
1656  return isSameExpression(macro, varTok1, varTok2, settings, pure, followVar, errors);
1657 
1658  }
1659  return false;
1660  }
1661 
1662  if (!compareTokenFlags(tok1, tok2, macro))
1663  return false;
1664 
1665  if (pure && tok1->isName() && tok1->next()->str() == "(" && tok1->str() != "sizeof" && !(tok1->variable() && tok1 == tok1->variable()->nameToken())) {
1666  if (!tok1->function()) {
1667  if (Token::simpleMatch(tok1->previous(), ".")) {
1668  const Token *lhs = tok1->previous();
1669  while (Token::Match(lhs, "(|.|["))
1670  lhs = lhs->astOperand1();
1671  if (!lhs)
1672  return false;
1673  const bool lhsIsConst = (lhs->variable() && lhs->variable()->isConst()) ||
1674  (lhs->valueType() && lhs->valueType()->constness > 0) ||
1675  (Token::Match(lhs, "%var% . %name% (") && settings.library.isFunctionConst(lhs->tokAt(2)));
1676  if (!lhsIsConst)
1677  return false;
1678  } else {
1679  const Token * ftok = tok1;
1680  if (Token::simpleMatch(tok1->previous(), "::"))
1681  ftok = tok1->previous();
1682  if (!settings.library.isFunctionConst(ftok) && !ftok->isAttributeConst() && !ftok->isAttributePure())
1683  return false;
1684  }
1685  } else {
1686  if (!tok1->function()->isConst() && !tok1->function()->isAttributeConst() &&
1687  !tok1->function()->isAttributePure())
1688  return false;
1689  }
1690  }
1691  // templates/casts
1692  if ((tok1->next() && tok1->next()->link() && Token::Match(tok1, "%name% <")) ||
1693  (tok2->next() && tok2->next()->link() && Token::Match(tok2, "%name% <"))) {
1694 
1695  // non-const template function that is not a dynamic_cast => return false
1696  if (pure && Token::simpleMatch(tok1->next()->link(), "> (") &&
1697  !(tok1->function() && tok1->function()->isConst()) &&
1698  tok1->str() != "dynamic_cast")
1699  return false;
1700 
1701  // some template/cast stuff.. check that the template arguments are same
1702  const Token *t1 = tok1->next();
1703  const Token *t2 = tok2->next();
1704  const Token *end1 = t1->link();
1705  const Token *end2 = t2->link();
1706  while (t1 && t2 && t1 != end1 && t2 != end2) {
1707  if (t1->str() != t2->str() || !compareTokenFlags(t1, t2, macro))
1708  return false;
1709  t1 = t1->next();
1710  t2 = t2->next();
1711  }
1712  if (t1 != end1 || t2 != end2)
1713  return false;
1714  }
1715  if (tok1->tokType() == Token::eIncDecOp || tok1->isAssignmentOp())
1716  return false;
1717  // bailout when we see ({..})
1718  if (tok1->str() == "{")
1719  return false;
1720  // cast => assert that the casts are equal
1721  if (tok1->str() == "(" && tok1->previous() &&
1722  !tok1->previous()->isName() &&
1723  !(tok1->previous()->str() == ">" && tok1->previous()->link())) {
1724  const Token *t1 = tok1->next();
1725  const Token *t2 = tok2->next();
1726  while (t1 && t2 &&
1727  t1->str() == t2->str() &&
1728  compareTokenFlags(t1, t2, macro) &&
1729  (t1->isName() || t1->str() == "*")) {
1730  t1 = t1->next();
1731  t2 = t2->next();
1732  }
1733  if (!t1 || !t2 || t1->str() != ")" || t2->str() != ")")
1734  return false;
1735  }
1736  bool noncommutativeEquals =
1737  isSameExpression(macro, tok1->astOperand1(), tok2->astOperand1(), settings, pure, followVar, errors);
1738  noncommutativeEquals = noncommutativeEquals &&
1739  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand2(), settings, pure, followVar, errors);
1740 
1741  if (noncommutativeEquals)
1742  return true;
1743 
1744  // in c++, a+b might be different to b+a, depending on the type of a and b
1745  if (tok1->isCpp() && tok1->str() == "+" && tok1->isBinaryOp()) {
1746  const ValueType* vt1 = tok1->astOperand1()->valueType();
1747  const ValueType* vt2 = tok1->astOperand2()->valueType();
1748  if (!(vt1 && (vt1->type >= ValueType::VOID || vt1->pointer) && vt2 && (vt2->type >= ValueType::VOID || vt2->pointer)))
1749  return false;
1750  }
1751 
1752  const bool commutative = tok1->isBinaryOp() && Token::Match(tok1, "%or%|%oror%|+|*|&|&&|^|==|!=");
1753  bool commutativeEquals = commutative &&
1754  isSameExpression(macro, tok1->astOperand2(), tok2->astOperand1(), settings, pure, followVar, errors);
1755  commutativeEquals = commutativeEquals &&
1756  isSameExpression(macro, tok1->astOperand1(), tok2->astOperand2(), settings, pure, followVar, errors);
1757 
1758 
1759  return commutativeEquals;
1760 }
1761 
1762 static bool isZeroBoundCond(const Token * const cond)
1763 {
1764  if (cond == nullptr)
1765  return false;
1766  // Assume unsigned
1767  // TODO: Handle reverse conditions
1768  const bool isZero = cond->astOperand2()->getValue(0);
1769  if (cond->str() == "==" || cond->str() == ">=")
1770  return isZero;
1771  if (cond->str() == "<=")
1772  return true;
1773  if (cond->str() == "<")
1774  return !isZero;
1775  if (cond->str() == ">")
1776  return false;
1777  return false;
1778 }
1779 
1780 bool isOppositeCond(bool isNot, const Token * const cond1, const Token * const cond2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1781 {
1782  if (!cond1 || !cond2)
1783  return false;
1784 
1785  if (isSameExpression(true, cond1, cond2, settings, pure, followVar, errors))
1786  return false;
1787 
1788  if (!isNot && cond1->str() == "&&" && cond2->str() == "&&") {
1789  for (const Token* tok1: {
1790  cond1->astOperand1(), cond1->astOperand2()
1791  }) {
1792  for (const Token* tok2: {
1793  cond2->astOperand1(), cond2->astOperand2()
1794  }) {
1795  if (isSameExpression(true, tok1, tok2, settings, pure, followVar, errors)) {
1796  if (isOppositeCond(isNot, tok1->astSibling(), tok2->astSibling(), settings, pure, followVar, errors))
1797  return true;
1798  }
1799  }
1800  }
1801  }
1802 
1803  if (cond1->str() != cond2->str() && (cond1->str() == "||" || cond2->str() == "||")) {
1804  const Token* orCond = nullptr;
1805  const Token* otherCond = nullptr;
1806  if (cond1->str() == "||") {
1807  orCond = cond1;
1808  otherCond = cond2;
1809  }
1810  if (cond2->str() == "||") {
1811  orCond = cond2;
1812  otherCond = cond1;
1813  }
1814  return isOppositeCond(isNot, orCond->astOperand1(), otherCond, settings, pure, followVar, errors) &&
1815  isOppositeCond(isNot, orCond->astOperand2(), otherCond, settings, pure, followVar, errors);
1816  }
1817 
1818  if (cond1->str() == "!") {
1819  if (cond2->str() == "!=") {
1820  if (cond2->astOperand1() && cond2->astOperand1()->str() == "0")
1821  return isSameExpression(true, cond1->astOperand1(), cond2->astOperand2(), settings, pure, followVar, errors);
1822  if (cond2->astOperand2() && cond2->astOperand2()->str() == "0")
1823  return isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors);
1824  }
1825  if (!isUsedAsBool(cond2, settings))
1826  return false;
1827  return isSameExpression(true, cond1->astOperand1(), cond2, settings, pure, followVar, errors);
1828  }
1829 
1830  if (cond2->str() == "!")
1831  return isOppositeCond(isNot, cond2, cond1, settings, pure, followVar, errors);
1832 
1833  if (!isNot) {
1834  if (cond1->str() == "==" && cond2->str() == "==") {
1835  if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors))
1836  return isDifferentKnownValues(cond1->astOperand2(), cond2->astOperand2());
1837  if (isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors))
1838  return isDifferentKnownValues(cond1->astOperand1(), cond2->astOperand1());
1839  }
1840  // TODO: Handle reverse conditions
1843  isSameExpression(true,
1844  cond1->astOperand1()->astOperand1(),
1845  cond2->astOperand1()->astOperand1()->astOperand1(),
1846  settings,
1847  pure,
1848  followVar,
1849  errors)) {
1850  return !isZeroBoundCond(cond2);
1851  }
1852 
1855  isSameExpression(true,
1856  cond2->astOperand1()->astOperand1(),
1857  cond1->astOperand1()->astOperand1()->astOperand1(),
1858  settings,
1859  pure,
1860  followVar,
1861  errors)) {
1862  return !isZeroBoundCond(cond1);
1863  }
1864  }
1865 
1866 
1867  if (!cond1->isComparisonOp() || !cond2->isComparisonOp())
1868  return false;
1869 
1870  const std::string &comp1 = cond1->str();
1871 
1872  // condition found .. get comparator
1873  std::string comp2;
1874  if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand1(), settings, pure, followVar, errors) &&
1875  isSameExpression(true, cond1->astOperand2(), cond2->astOperand2(), settings, pure, followVar, errors)) {
1876  comp2 = cond2->str();
1877  } else if (isSameExpression(true, cond1->astOperand1(), cond2->astOperand2(), settings, pure, followVar, errors) &&
1878  isSameExpression(true, cond1->astOperand2(), cond2->astOperand1(), settings, pure, followVar, errors)) {
1879  comp2 = cond2->str();
1880  if (comp2[0] == '>')
1881  comp2[0] = '<';
1882  else if (comp2[0] == '<')
1883  comp2[0] = '>';
1884  }
1885 
1886  if (!isNot && comp2.empty()) {
1887  const Token *expr1 = nullptr, *value1 = nullptr, *expr2 = nullptr, *value2 = nullptr;
1888  std::string op1 = cond1->str(), op2 = cond2->str();
1889  if (cond1->astOperand2()->hasKnownIntValue()) {
1890  expr1 = cond1->astOperand1();
1891  value1 = cond1->astOperand2();
1892  } else if (cond1->astOperand1()->hasKnownIntValue()) {
1893  expr1 = cond1->astOperand2();
1894  value1 = cond1->astOperand1();
1895  if (op1[0] == '>')
1896  op1[0] = '<';
1897  else if (op1[0] == '<')
1898  op1[0] = '>';
1899  }
1900  if (cond2->astOperand2()->hasKnownIntValue()) {
1901  expr2 = cond2->astOperand1();
1902  value2 = cond2->astOperand2();
1903  } else if (cond2->astOperand1()->hasKnownIntValue()) {
1904  expr2 = cond2->astOperand2();
1905  value2 = cond2->astOperand1();
1906  if (op2[0] == '>')
1907  op2[0] = '<';
1908  else if (op2[0] == '<')
1909  op2[0] = '>';
1910  }
1911  if (!expr1 || !value1 || !expr2 || !value2) {
1912  return false;
1913  }
1914  if (!isSameExpression(true, expr1, expr2, settings, pure, followVar, errors))
1915  return false;
1916 
1917  const ValueFlow::Value &rhsValue1 = value1->values().front();
1918  const ValueFlow::Value &rhsValue2 = value2->values().front();
1919 
1920  if (op1 == "<" || op1 == "<=")
1921  return (op2 == "==" || op2 == ">" || op2 == ">=") && (rhsValue1.intvalue < rhsValue2.intvalue);
1922  if (op1 == ">=" || op1 == ">")
1923  return (op2 == "==" || op2 == "<" || op2 == "<=") && (rhsValue1.intvalue > rhsValue2.intvalue);
1924 
1925  return false;
1926  }
1927 
1928  // is condition opposite?
1929  return ((comp1 == "==" && comp2 == "!=") ||
1930  (comp1 == "!=" && comp2 == "==") ||
1931  (comp1 == "<" && comp2 == ">=") ||
1932  (comp1 == "<=" && comp2 == ">") ||
1933  (comp1 == ">" && comp2 == "<=") ||
1934  (comp1 == ">=" && comp2 == "<") ||
1935  (!isNot && ((comp1 == "<" && comp2 == ">") ||
1936  (comp1 == ">" && comp2 == "<") ||
1937  (comp1 == "==" && (comp2 == "!=" || comp2 == ">" || comp2 == "<")) ||
1938  ((comp1 == "!=" || comp1 == ">" || comp1 == "<") && comp2 == "==")
1939  )));
1940 }
1941 
1942 bool isOppositeExpression(const Token * const tok1, const Token * const tok2, const Settings& settings, bool pure, bool followVar, ErrorPath* errors)
1943 {
1944  if (!tok1 || !tok2)
1945  return false;
1946  if (isOppositeCond(true, tok1, tok2, settings, pure, followVar, errors))
1947  return true;
1948  if (tok1->isUnaryOp("-") && !(tok2->astParent() && tok2->astParent()->tokType() == Token::eBitOp))
1949  return isSameExpression(true, tok1->astOperand1(), tok2, settings, pure, followVar, errors);
1950  if (tok2->isUnaryOp("-") && !(tok2->astParent() && tok2->astParent()->tokType() == Token::eBitOp))
1951  return isSameExpression(true, tok2->astOperand1(), tok1, settings, pure, followVar, errors);
1952  return false;
1953 }
1954 
1956 {
1957  return std::any_of(f->argumentList.cbegin(), f->argumentList.cend(), [](const Variable& var) {
1958  if (var.isReference() || var.isPointer())
1959  return !var.isConst();
1960  return true;
1961  });
1962 }
1963 
1964 bool isConstFunctionCall(const Token* ftok, const Library& library)
1965 {
1966  if (isUnevaluated(ftok))
1967  return true;
1968  if (!Token::Match(ftok, "%name% ("))
1969  return false;
1970  if (const Function* f = ftok->function()) {
1971  if (f->isAttributePure() || f->isAttributeConst())
1972  return true;
1973  // Any modified arguments
1975  return false;
1976  if (Function::returnsVoid(f))
1977  return false;
1978  // Member function call
1979  if (Token::simpleMatch(ftok->previous(), ".") || exprDependsOnThis(ftok->next())) {
1980  if (f->isConst())
1981  return true;
1982  // Check for const overloaded function that just return the const version
1983  if (!Function::returnsConst(f)) {
1984  std::vector<const Function*> fs = f->getOverloadedFunctions();
1985  if (std::any_of(fs.cbegin(), fs.cend(), [&](const Function* g) {
1986  if (f == g)
1987  return false;
1988  if (f->argumentList.size() != g->argumentList.size())
1989  return false;
1990  if (functionModifiesArguments(g))
1991  return false;
1992  if (g->isConst() && Function::returnsConst(g))
1993  return true;
1994  return false;
1995  }))
1996  return true;
1997  }
1998  return false;
1999  }
2000  if (f->argumentList.empty())
2001  return f->isConstexpr();
2002  } else if (Token::Match(ftok->previous(), ". %name% (") && ftok->previous()->originalName() != "->" &&
2003  astIsSmartPointer(ftok->previous()->astOperand1())) {
2004  return Token::Match(ftok, "get|get_deleter ( )");
2005  } else if (Token::Match(ftok->previous(), ". %name% (") && astIsContainer(ftok->previous()->astOperand1())) {
2006  const Library::Container* container = ftok->previous()->astOperand1()->valueType()->container;
2007  if (!container)
2008  return false;
2009  if (container->getYield(ftok->str()) != Library::Container::Yield::NO_YIELD)
2010  return true;
2011  if (container->getAction(ftok->str()) == Library::Container::Action::FIND_CONST)
2012  return true;
2013  return false;
2014  } else if (const Library::Function* lf = library.getFunction(ftok)) {
2015  if (lf->ispure)
2016  return true;
2017  if (lf->containerYield != Library::Container::Yield::NO_YIELD)
2018  return true;
2019  if (lf->containerAction == Library::Container::Action::FIND_CONST)
2020  return true;
2021  return false;
2022  } else {
2023  const bool memberFunction = Token::Match(ftok->previous(), ". %name% (");
2024  bool constMember = !memberFunction;
2025  if (Token::Match(ftok->tokAt(-2), "%var% . %name% (")) {
2026  const Variable* var = ftok->tokAt(-2)->variable();
2027  if (var)
2028  constMember = var->isConst();
2029  }
2030  // TODO: Only check const on lvalues
2031  std::vector<const Token*> args = getArguments(ftok);
2032  if (args.empty())
2033  return false;
2034  return constMember && std::all_of(args.cbegin(), args.cend(), [](const Token* tok) {
2035  const Variable* var = tok->variable();
2036  if (var)
2037  return var->isConst();
2038  return false;
2039  });
2040  }
2041  return true;
2042 }
2043 
2044 bool isConstExpression(const Token *tok, const Library& library)
2045 {
2046  if (!tok)
2047  return true;
2048  if (tok->variable() && tok->variable()->isVolatile())
2049  return false;
2050  if (tok->isName() && tok->next()->str() == "(") {
2051  if (!isConstFunctionCall(tok, library))
2052  return false;
2053  }
2054  if (tok->tokType() == Token::eIncDecOp)
2055  return false;
2056  if (tok->isAssignmentOp())
2057  return false;
2058  if (isLikelyStreamRead(tok))
2059  return false;
2060  // bailout when we see ({..})
2061  if (tok->str() == "{")
2062  return false;
2063  return isConstExpression(tok->astOperand1(), library) && isConstExpression(tok->astOperand2(), library);
2064 }
2065 
2066 bool isWithoutSideEffects(const Token* tok, bool checkArrayAccess, bool checkReference)
2067 {
2068  if (!tok)
2069  return true;
2070  if (!tok->isCpp())
2071  return true;
2072 
2073  while (tok && tok->astOperand2() && tok->astOperand2()->str() != "(")
2074  tok = tok->astOperand2();
2075  if (tok && tok->varId()) {
2076  const Variable* var = tok->variable();
2077  return var && ((!var->isClass() && (checkReference || !var->isReference())) || var->isPointer() || (checkArrayAccess ? var->isStlType() && !var->isStlType(CheckClass::stl_containers_not_const) : var->isStlType()));
2078  }
2079  return true;
2080 }
2081 
2082 bool isUniqueExpression(const Token* tok)
2083 {
2084  if (!tok)
2085  return true;
2086  if (tok->function()) {
2087  const Function * fun = tok->function();
2088  const Scope * scope = fun->nestedIn;
2089  if (!scope)
2090  return true;
2091  const std::string returnType = fun->retType ? fun->retType->name() : fun->retDef->stringifyList(fun->tokenDef);
2092  if (!std::all_of(scope->functionList.begin(), scope->functionList.end(), [&](const Function& f) {
2093  if (f.type != Function::eFunction)
2094  return true;
2095 
2096  const std::string freturnType = f.retType ? f.retType->name() : f.retDef->stringifyList(f.returnDefEnd());
2097  return f.argumentList.size() != fun->argumentList.size() || returnType != freturnType || f.name() == fun->name();
2098  }))
2099  return false;
2100  } else if (tok->variable()) {
2101  const Variable * var = tok->variable();
2102  const Scope * scope = var->scope();
2103  if (!scope)
2104  return true;
2105  const Type * varType = var->type();
2106  // Iterate over the variables in scope and the parameters of the function if possible
2107  const Function * fun = scope->function;
2108 
2109  auto pred = [=](const Variable& v) {
2110  if (varType)
2111  return v.type() && v.type()->name() == varType->name() && v.name() != var->name();
2112  return v.isFloatingType() == var->isFloatingType() &&
2113  v.isEnumType() == var->isEnumType() &&
2114  v.isClass() == var->isClass() &&
2115  v.isArray() == var->isArray() &&
2116  v.isPointer() == var->isPointer() &&
2117  v.name() != var->name();
2118  };
2119  if (std::any_of(scope->varlist.cbegin(), scope->varlist.cend(), pred))
2120  return false;
2121  if (fun) {
2122  if (std::any_of(fun->argumentList.cbegin(), fun->argumentList.cend(), pred))
2123  return false;
2124  }
2125  } else if (!isUniqueExpression(tok->astOperand1())) {
2126  return false;
2127  }
2128 
2129  return isUniqueExpression(tok->astOperand2());
2130 }
2131 
2132 static bool isEscaped(const Token* tok, bool functionsScope, const Library& library)
2133 {
2134  if (library.isnoreturn(tok))
2135  return true;
2136  if (functionsScope)
2137  return Token::simpleMatch(tok, "throw");
2138  return Token::Match(tok, "return|throw");
2139 }
2140 
2141 static bool isEscapedOrJump(const Token* tok, bool functionsScope, const Library& library)
2142 {
2143  if (library.isnoreturn(tok))
2144  return true;
2145  if (functionsScope)
2146  return Token::simpleMatch(tok, "throw");
2147  return Token::Match(tok, "return|goto|throw|continue|break");
2148 }
2149 
2150 bool isEscapeFunction(const Token* ftok, const Library* library)
2151 {
2152  if (!Token::Match(ftok, "%name% ("))
2153  return false;
2154  const Function* function = ftok->function();
2155  if (function) {
2156  if (function->isEscapeFunction())
2157  return true;
2158  if (function->isAttributeNoreturn())
2159  return true;
2160  } else if (library) {
2161  if (library->isnoreturn(ftok))
2162  return true;
2163  }
2164  return false;
2165 }
2166 
2167 static bool hasNoreturnFunction(const Token* tok, const Library& library, const Token** unknownFunc)
2168 {
2169  if (!tok)
2170  return false;
2171  const Token* ftok = tok->str() == "(" ? tok->previous() : nullptr;
2172  while (Token::simpleMatch(ftok, "("))
2173  ftok = ftok->astOperand1();
2174  if (ftok) {
2175  const Function * function = ftok->function();
2176  if (function) {
2177  if (function->isEscapeFunction())
2178  return true;
2179  if (function->isAttributeNoreturn())
2180  return true;
2181  } else if (library.isnoreturn(ftok)) {
2182  return true;
2183  } else if (Token::Match(ftok, "exit|abort")) {
2184  return true;
2185  }
2186  if (unknownFunc && !function && library.functions.count(library.getFunctionName(ftok)) == 0)
2187  *unknownFunc = ftok;
2188  return false;
2189  }
2190  if (tok->isConstOp()) {
2191  return hasNoreturnFunction(tok->astOperand1(), library, unknownFunc) || hasNoreturnFunction(tok->astOperand2(), library, unknownFunc);
2192  }
2193 
2194  return false;
2195 }
2196 
2197 bool isReturnScope(const Token* const endToken, const Library& library, const Token** unknownFunc, bool functionScope)
2198 {
2199  if (!endToken || endToken->str() != "}")
2200  return false;
2201 
2202  const Token *prev = endToken->previous();
2203  while (prev && Token::simpleMatch(prev->previous(), "; ;"))
2204  prev = prev->previous();
2205  if (prev && Token::simpleMatch(prev->previous(), "} ;"))
2206  prev = prev->previous();
2207 
2208  if (Token::simpleMatch(prev, "}")) {
2209  if (Token::simpleMatch(prev->link()->tokAt(-2), "} else {"))
2210  return isReturnScope(prev, library, unknownFunc, functionScope) &&
2211  isReturnScope(prev->link()->tokAt(-2), library, unknownFunc, functionScope);
2212  // TODO: Check all cases
2213  if (!functionScope && Token::simpleMatch(prev->link()->previous(), ") {") &&
2214  Token::simpleMatch(prev->link()->linkAt(-1)->previous(), "switch (") &&
2215  !Token::findsimplematch(prev->link(), "break", prev)) {
2216  return isReturnScope(prev, library, unknownFunc, functionScope);
2217  }
2218  if (isEscaped(prev->link()->astTop(), functionScope, library))
2219  return true;
2220  if (Token::Match(prev->link()->previous(), "[;{}] {"))
2221  return isReturnScope(prev, library, unknownFunc, functionScope);
2222  } else if (Token::simpleMatch(prev, ";")) {
2223  if (prev->tokAt(-2) && hasNoreturnFunction(prev->tokAt(-2)->astTop(), library, unknownFunc))
2224  return true;
2225  // Unknown symbol
2226  if (Token::Match(prev->tokAt(-2), ";|}|{ %name% ;") && prev->previous()->isIncompleteVar()) {
2227  if (unknownFunc)
2228  *unknownFunc = prev->previous();
2229  return false;
2230  }
2231  if (Token::simpleMatch(prev->previous(), ") ;") && prev->previous()->link() &&
2232  isEscaped(prev->previous()->link()->astTop(), functionScope, library))
2233  return true;
2234  if (isEscaped(prev->previous()->astTop(), functionScope, library))
2235  return true;
2236  // return/goto statement
2237  prev = prev->previous();
2238  while (prev && !Token::Match(prev, ";|{|}") && !isEscapedOrJump(prev, functionScope, library))
2239  prev = prev->previous();
2240  return prev && prev->isName();
2241  }
2242  return false;
2243 }
2244 
2245 bool isWithinScope(const Token* tok, const Variable* var, Scope::ScopeType type)
2246 {
2247  if (!tok || !var)
2248  return false;
2249  const Scope* scope = tok->scope();
2250  while (scope && scope != var->scope()) {
2251  if (scope->type == type)
2252  return true;
2253  scope = scope->nestedIn;
2254  }
2255  return false;
2256 }
2257 
2258 bool isVariableChangedByFunctionCall(const Token *tok, int indirect, nonneg int varid, const Settings &settings, bool *inconclusive)
2259 {
2260  if (!tok)
2261  return false;
2262  if (tok->varId() == varid)
2263  return isVariableChangedByFunctionCall(tok, indirect, settings, inconclusive);
2264  return isVariableChangedByFunctionCall(tok->astOperand1(), indirect, varid, settings, inconclusive) ||
2265  isVariableChangedByFunctionCall(tok->astOperand2(), indirect, varid, settings, inconclusive);
2266 }
2267 
2268 bool isScopeBracket(const Token* tok)
2269 {
2270  if (!Token::Match(tok, "{|}"))
2271  return false;
2272  if (!tok->scope())
2273  return false;
2274  if (tok->str() == "{")
2275  return tok->scope()->bodyStart == tok;
2276  if (tok->str() == "}")
2277  return tok->scope()->bodyEnd == tok;
2278  return false;
2279 }
2280 
2281 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
2282 static T* getTokenArgumentFunctionImpl(T* tok, int& argn)
2283 {
2284  argn = -1;
2285  {
2286  T* parent = tok->astParent();
2287  if (parent && (parent->isUnaryOp("&") || parent->isIncDecOp()))
2288  parent = parent->astParent();
2289  while (parent && parent->isCast())
2290  parent = parent->astParent();
2291  if (Token::Match(parent, "[+-]") && parent->valueType() && parent->valueType()->pointer)
2292  parent = parent->astParent();
2293 
2294  // passing variable to subfunction?
2295  if (Token::Match(parent, "[*[(,{.]") || Token::Match(parent, "%oror%|&&"))
2296  ;
2297  else if (Token::simpleMatch(parent, ":")) {
2298  while (Token::Match(parent, "[?:]"))
2299  parent = parent->astParent();
2300  while (Token::simpleMatch(parent, ","))
2301  parent = parent->astParent();
2302  if (!parent || parent->str() != "(")
2303  return nullptr;
2304  } else
2305  return nullptr;
2306  }
2307 
2308  T* argtok = tok;
2309  while (argtok && argtok->astParent() && (!Token::Match(argtok->astParent(), ",|(|{") || argtok->astParent()->isCast())) {
2310  argtok = argtok->astParent();
2311  }
2312  if (!argtok)
2313  return nullptr;
2314  if (Token::simpleMatch(argtok, ","))
2315  argtok = argtok->astOperand1();
2316  tok = argtok;
2317  while (Token::Match(tok->astParent(), ",|(|{")) {
2318  tok = tok->astParent();
2319  if (Token::Match(tok, "(|{"))
2320  break;
2321  }
2322  argn = getArgumentPos(tok, argtok);
2323  if (argn == -1)
2324  return nullptr;
2325  if (!Token::Match(tok, "{|("))
2326  return nullptr;
2327  if (tok->astOperand2())
2328  tok = tok->astOperand1();
2329  while (tok && (tok->isUnaryOp("*") || tok->str() == "["))
2330  tok = tok->astOperand1();
2331  if (Token::Match(tok, ". * %name%")) // bailout for pointer to member
2332  return tok->tokAt(2);
2333  while (Token::simpleMatch(tok, "."))
2334  tok = tok->astOperand2();
2335  while (Token::simpleMatch(tok, "::")) {
2336  // If there is only a op1 and not op2, then this is a global scope
2337  if (!tok->astOperand2() && tok->astOperand1()) {
2338  tok = tok->astOperand1();
2339  break;
2340  }
2341  tok = tok->astOperand2();
2342  if (Token::simpleMatch(tok, "<") && tok->link())
2343  tok = tok->astOperand1();
2344  }
2345  if (tok && tok->link() && tok->str() == ">")
2346  tok = tok->link()->previous();
2347  if (!Token::Match(tok, "%name%|(|{"))
2348  return nullptr;
2349  // Skip labels
2350  if (Token::Match(tok, "%name% :"))
2351  return nullptr;
2352  return tok;
2353 }
2354 
2355 const Token* getTokenArgumentFunction(const Token* tok, int& argn) {
2356  return getTokenArgumentFunctionImpl(tok, argn);
2357 }
2358 
2360  return getTokenArgumentFunctionImpl(tok, argn);
2361 }
2362 
2363 std::vector<const Variable*> getArgumentVars(const Token* tok, int argnr)
2364 {
2365  std::vector<const Variable*> result;
2366  if (!tok)
2367  return result;
2368  if (tok->function()) {
2369  const Variable* argvar = tok->function()->getArgumentVar(argnr);
2370  if (argvar)
2371  return {argvar};
2372  return result;
2373  }
2374  if (tok->variable() || Token::simpleMatch(tok, "{") || Token::Match(tok->previous(), "%type% (|{")) {
2375  const Type* type = Token::typeOf(tok);
2376  if (!type)
2377  return result;
2378  const Scope* typeScope = type->classScope;
2379  if (!typeScope)
2380  return result;
2381  const bool tokIsBrace = Token::simpleMatch(tok, "{");
2382  // Aggregate constructor
2383  if (tokIsBrace && typeScope->numConstructors == 0 && argnr < typeScope->varlist.size()) {
2384  auto it = std::next(typeScope->varlist.cbegin(), argnr);
2385  return {&*it};
2386  }
2387  const int argCount = numberOfArguments(tok);
2388  const bool constructor = tokIsBrace || (tok->variable() && tok->variable()->nameToken() == tok);
2389  for (const Function &function : typeScope->functionList) {
2390  if (function.argCount() < argCount)
2391  continue;
2392  if (constructor && !function.isConstructor())
2393  continue;
2394  if (!constructor && !Token::simpleMatch(function.token, "operator()"))
2395  continue;
2396  const Variable* argvar = function.getArgumentVar(argnr);
2397  if (argvar)
2398  result.push_back(argvar);
2399  }
2400  }
2401  return result;
2402 }
2403 
2404 static bool isCPPCastKeyword(const Token* tok)
2405 {
2406  if (!tok)
2407  return false;
2408  return endsWith(tok->str(), "_cast");
2409 }
2410 
2411 static bool isTrivialConstructor(const Token* tok)
2412 {
2413  const Token* typeTok = nullptr;
2414  const Type* t = Token::typeOf(tok, &typeTok);
2415  if (t)
2416  return false;
2417  if (typeTok->valueType() && typeTok->valueType()->isPrimitive())
2418  return true;
2419  return false;
2420 }
2421 
2422 static bool isArray(const Token* tok)
2423 {
2424  if (!tok)
2425  return false;
2426  if (tok->variable())
2427  return tok->variable()->isArray();
2428  if (Token::simpleMatch(tok, "."))
2429  return isArray(tok->astOperand2());
2430  return false;
2431 }
2432 
2433 bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings &settings, bool *inconclusive)
2434 {
2435  if (!tok)
2436  return false;
2437 
2438  if (Token::simpleMatch(tok, ","))
2439  return false;
2440 
2441  const Token * const tok1 = tok;
2442 
2443  // address of variable
2444  const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&");
2445  if (addressOf)
2446  indirect++;
2447 
2448  const bool deref = tok->astParent() && tok->astParent()->isUnaryOp("*");
2449  if (deref && indirect > 0)
2450  indirect--;
2451 
2452  if (indirect == 1 && tok->isCpp() && tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), "new (")) // placement new TODO: fix AST
2453  return true;
2454 
2455  int argnr;
2456  tok = getTokenArgumentFunction(tok, argnr);
2457  if (!tok)
2458  return false; // not a function => variable not changed
2459  if (Token::simpleMatch(tok, "{") && isTrivialConstructor(tok))
2460  return false;
2461  if (tok->isKeyword() && !isCPPCastKeyword(tok) && !startsWith(tok->str(),"operator"))
2462  return false;
2463  // A functional cast won't modify the variable
2464  if (Token::Match(tok, "%type% (|{") && tok->tokType() == Token::eType && astIsPrimitive(tok->next()))
2465  return false;
2466  const Token * parenTok = tok->next();
2467  if (Token::simpleMatch(parenTok, "<") && parenTok->link())
2468  parenTok = parenTok->link()->next();
2469  const bool possiblyPassedByReference = (parenTok->next() == tok1 || Token::Match(tok1->previous(), ", %name% [,)}]"));
2470 
2471  if (!tok->function() && !tok->variable() && tok->isName()) {
2472  // Check if direction (in, out, inout) is specified in the library configuration and use that
2473  const Library::ArgumentChecks::Direction argDirection = settings.library.getArgDirection(tok, 1 + argnr);
2474  if (argDirection == Library::ArgumentChecks::Direction::DIR_IN)
2475  return false;
2476 
2477  const bool requireNonNull = settings.library.isnullargbad(tok, 1 + argnr);
2478  if (argDirection == Library::ArgumentChecks::Direction::DIR_OUT ||
2480  if (indirect == 0 && isArray(tok1))
2481  return true;
2482  const bool requireInit = settings.library.isuninitargbad(tok, 1 + argnr);
2483  // Assume that if the variable must be initialized then the indirection is 1
2484  if (indirect > 0 && requireInit && requireNonNull)
2485  return true;
2486  }
2487  if (Token::simpleMatch(tok->tokAt(-2), "std :: tie"))
2488  return true;
2489  // if the library says 0 is invalid
2490  // => it is assumed that parameter is an in parameter (TODO: this is a bad heuristic)
2491  if (indirect == 0 && requireNonNull)
2492  return false;
2493  // possible pass-by-reference => inconclusive
2494  if (possiblyPassedByReference) {
2495  if (inconclusive != nullptr)
2496  *inconclusive = true;
2497  return false;
2498  }
2499  // Safe guess: Assume that parameter is changed by function call
2500  return true;
2501  }
2502 
2503  if (const Variable* var = tok->variable()) {
2504  if (tok == var->nameToken() && (!var->isReference() || var->isConst()) && (!var->isClass() || (var->valueType() && var->valueType()->container))) // const ref or passed to (copy) ctor
2505  return false;
2506  }
2507 
2508  std::vector<const Variable*> args = getArgumentVars(tok, argnr);
2509  bool conclusive = false;
2510  for (const Variable *arg:args) {
2511  if (!arg)
2512  continue;
2513  conclusive = true;
2514  if (indirect > 0) {
2515  if (arg->isPointer() && !(arg->valueType() && arg->valueType()->isConst(indirect)))
2516  return true;
2517  if (indirect > 1 && addressOf && arg->isPointer() && (!arg->valueType() || !arg->valueType()->isConst(indirect-1)))
2518  return true;
2519  if (arg->isArray() || (!arg->isPointer() && (!arg->valueType() || arg->valueType()->type == ValueType::UNKNOWN_TYPE)))
2520  return true;
2521  }
2522  if (!arg->isConst() && arg->isReference())
2523  return true;
2524  }
2525  if (addressOf && tok1->astParent()->isUnaryOp("&")) {
2526  const Token* castToken = tok1->astParent();
2527  while (castToken->astParent()->isCast())
2528  castToken = castToken->astParent();
2529  if (Token::Match(castToken->astParent(), ",|(") &&
2530  castToken->valueType() &&
2531  castToken->valueType()->isIntegral() &&
2532  castToken->valueType()->pointer == 0)
2533  return true;
2534  }
2535  if (!conclusive && inconclusive) {
2536  *inconclusive = true;
2537  }
2538  return false;
2539 }
2540 
2541 bool isVariableChanged(const Token *tok, int indirect, const Settings &settings, int depth)
2542 {
2543  if (!tok)
2544  return false;
2545 
2546  if (indirect == 0 && isConstVarExpression(tok))
2547  return false;
2548 
2549  const Token *tok2 = tok;
2550  int derefs = 0;
2551  while (Token::simpleMatch(tok2->astParent(), "*") ||
2552  (Token::simpleMatch(tok2->astParent(), ".") && !Token::simpleMatch(tok2->astParent()->astParent(), "(")) ||
2553  (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->") ||
2554  (Token::simpleMatch(tok2->astParent(), "[") && tok2 == tok2->astParent()->astOperand1())) {
2555  if (tok2->astParent() && (tok2->astParent()->isUnaryOp("*") || (astIsLHS(tok2) && tok2->astParent()->originalName() == "->")))
2556  derefs++;
2557  if (derefs > indirect)
2558  break;
2559  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&") && Token::simpleMatch(tok2->astParent()->astParent(), ".") && tok2->astParent()->astParent()->originalName()=="->")
2560  tok2 = tok2->astParent();
2561  tok2 = tok2->astParent();
2562  }
2563 
2564  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&")) {
2565  const Token* parent = tok2->astParent();
2566  while (parent->astParent() && parent->astParent()->isCast())
2567  parent = parent->astParent();
2568  if (parent->astParent() && parent->astParent()->isUnaryOp("*"))
2569  tok2 = parent->astParent();
2570  }
2571 
2572  while ((Token::simpleMatch(tok2, ":") && Token::simpleMatch(tok2->astParent(), "?")) ||
2573  (Token::simpleMatch(tok2->astParent(), ":") && Token::simpleMatch(tok2->astParent()->astParent(), "?")))
2574  tok2 = tok2->astParent();
2575 
2576  if (indirect == 0 && tok2->astParent() && tok2->astParent()->tokType() == Token::eIncDecOp)
2577  return true;
2578 
2579  auto skipRedundantPtrOp = [](const Token* tok, const Token* parent) {
2580  const Token* gparent = parent ? parent->astParent() : nullptr;
2581  while (parent && gparent && ((parent->isUnaryOp("*") && gparent->isUnaryOp("&")) || (parent->isUnaryOp("&") && gparent->isUnaryOp("*")))) {
2582  tok = gparent;
2583  parent = gparent->astParent();
2584  if (parent)
2585  gparent = parent->astParent();
2586  }
2587  return tok;
2588  };
2589  tok2 = skipRedundantPtrOp(tok2, tok2->astParent());
2590 
2591  if (tok2->astParent() && tok2->astParent()->isAssignmentOp()) {
2592  if (((indirect == 0 || tok2 != tok) || (indirect == 1 && tok2->str() == ".")) && tok2 == tok2->astParent()->astOperand1())
2593  return true;
2594  // Check if assigning to a non-const lvalue
2595  const Variable * var = getLHSVariable(tok2->astParent());
2596  if (var && var->isReference() && !var->isConst() &&
2597  ((var->nameToken() && var->nameToken()->next() == tok2->astParent()) || var->isPointer())) {
2598  if (!var->isLocal() || isVariableChanged(var, settings, depth - 1))
2599  return true;
2600  }
2601  }
2602 
2603  const ValueType* vt = tok->variable() ? tok->variable()->valueType() : tok->valueType();
2604 
2605  // Check addressof
2606  if (tok2->astParent() && tok2->astParent()->isUnaryOp("&")) {
2607  if (isVariableChanged(tok2->astParent(), indirect + 1, settings, depth - 1))
2608  return true;
2609  } else {
2610  // If its already const then it cant be modified
2611  if (vt && vt->isConst(indirect))
2612  return false;
2613  }
2614 
2615  if (tok2->isCpp() && Token::Match(tok2->astParent(), ">>|&") && astIsRHS(tok2) && isLikelyStreamRead(tok2->astParent()))
2616  return true;
2617 
2618  if (isLikelyStream(tok2))
2619  return true;
2620 
2621  // Member function call
2622  if (Token::Match(tok2->astParent(), ". %name%") && isFunctionCall(tok2->astParent()->next()) &&
2623  tok2->astParent()->astOperand1() == tok2) {
2624  // Member function cannot change what `this` points to
2625  if (indirect == 0 && astIsPointer(tok))
2626  return false;
2627 
2628  const Token *ftok = tok2->astParent()->astOperand2();
2629  if (astIsContainer(tok2->astParent()->astOperand1()) && vt && vt->container) {
2630  const Library::Container* c = vt->container;
2631  const Library::Container::Action action = c->getAction(ftok->str());
2642  action))
2643  return true;
2644  const Library::Container::Yield yield = c->getYield(ftok->str());
2645  // If accessing element check if the element is changed
2647  return isVariableChanged(ftok->next(), indirect, settings, depth - 1);
2648 
2653  yield)) {
2654  return isVariableChanged(ftok->next(), indirect + 1, settings, depth - 1);
2655  }
2659  yield)) {
2660  return false;
2661  }
2662  }
2663  if (settings.library.isFunctionConst(ftok) || (astIsSmartPointer(tok) && ftok->str() == "get")) // TODO: replace with action/yield?
2664  return false;
2665 
2666  const Function * fun = ftok->function();
2667  if (!fun)
2668  return true;
2669  return !fun->isConst();
2670  }
2671 
2672  // Member pointer
2673  if (Token::Match(tok2->astParent(), ". * ( & %name% ::")) {
2674  const Token* ftok = tok2->astParent()->linkAt(2)->previous();
2675  // TODO: Check for pointer to member variable
2676  if (!ftok->function() || !ftok->function()->isConst())
2677  return true;
2678  }
2679  if (Token::Match(tok2->astParent(), ". * %name%")) // bailout
2680  return true;
2681 
2682  if (Token::simpleMatch(tok2, "[") && astIsContainer(tok) && vt && vt->container && vt->container->stdAssociativeLike)
2683  return true;
2684 
2685  const Token *ftok = tok2;
2686  while (ftok && (!Token::Match(ftok, "[({]") || ftok->isCast()))
2687  ftok = ftok->astParent();
2688 
2689  if (ftok && Token::Match(ftok->link(), ")|} !!{")) {
2690  if (ftok->str() == "(" && Token::simpleMatch(ftok->astOperand1(), "[")) // operator() on array element, bail out
2691  return true;
2692  const Token * ptok = tok2;
2693  while (Token::Match(ptok->astParent(), ".|::|["))
2694  ptok = ptok->astParent();
2695  int pindirect = indirect;
2696  if (indirect == 0 && astIsLHS(tok2) && Token::Match(ptok, ". %var%") && astIsPointer(ptok->next()))
2697  pindirect = 1;
2698  bool inconclusive = false;
2699  bool isChanged = isVariableChangedByFunctionCall(ptok, pindirect, settings, &inconclusive);
2700  isChanged |= inconclusive;
2701  if (isChanged)
2702  return true;
2703  }
2704 
2705  const Token *parent = tok2->astParent();
2706  while (Token::Match(parent, ".|::"))
2707  parent = parent->astParent();
2708  if (parent && parent->tokType() == Token::eIncDecOp && (indirect == 0 || tok2 != tok))
2709  return true;
2710 
2711  // structured binding, nonconst reference variable in lhs
2712  if (Token::Match(tok2->astParent(), ":|=") && tok2 == tok2->astParent()->astOperand2() && Token::simpleMatch(tok2->astParent()->previous(), "]")) {
2713  const Token *typeStart = tok2->astParent()->previous()->link()->previous();
2714  if (Token::simpleMatch(typeStart, "&"))
2715  typeStart = typeStart->previous();
2716  if (typeStart && Token::Match(typeStart->previous(), "[;{}(] auto &| [")) {
2717  for (const Token *vartok = typeStart->tokAt(2); vartok != tok2; vartok = vartok->next()) {
2718  if (vartok->varId()) {
2719  const Variable* refvar = vartok->variable();
2720  if (!refvar || (!refvar->isConst() && refvar->isReference()))
2721  return true;
2722  }
2723  }
2724  }
2725  }
2726 
2727  if (Token::simpleMatch(tok2->astParent(), ":") && tok2->astParent()->astParent() && Token::simpleMatch(tok2->astParent()->astParent()->previous(), "for (")) {
2728  // TODO: Check if container is empty or not
2729  if (astIsLHS(tok2))
2730  return true;
2731  const Token * varTok = tok2->astParent()->previous();
2732  if (!varTok)
2733  return false;
2734  const Variable * loopVar = varTok->variable();
2735  if (!loopVar)
2736  return false;
2737  if (!loopVar->isConst() && loopVar->isReference() && isVariableChanged(loopVar, settings, depth - 1))
2738  return true;
2739  return false;
2740  }
2741 
2742  if (indirect > 0) {
2743  // check for `*(ptr + 1) = new_value` case
2744  parent = tok2->astParent();
2745  while (parent && ((parent->isArithmeticalOp() && parent->isBinaryOp()) || parent->isIncDecOp())) {
2746  parent = parent->astParent();
2747  }
2748  if (Token::simpleMatch(parent, "*")) {
2749  if (parent->astParent() && parent->astParent()->isAssignmentOp() &&
2750  (parent->astParent()->astOperand1() == parent)) {
2751  return true;
2752  }
2753  }
2754  }
2755 
2756  return false;
2757 }
2758 
2759 bool isVariableChanged(const Token *start, const Token *end, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2760 {
2761  return findVariableChanged(start, end, 0, exprid, globalvar, settings, depth) != nullptr;
2762 }
2763 
2764 bool isVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2765 {
2766  return findVariableChanged(start, end, indirect, exprid, globalvar, settings, depth) != nullptr;
2767 }
2768 
2769 const Token* findExpression(const Token* start, const nonneg int exprid)
2770 {
2771  const Function* f = Scope::nestedInFunction(start->scope());
2772  if (!f)
2773  return nullptr;
2774  const Scope* scope = f->functionScope;
2775  if (!scope)
2776  return nullptr;
2777  for (const Token *tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
2778  if (tok->exprId() != exprid)
2779  continue;
2780  return tok;
2781  }
2782  return nullptr;
2783 }
2784 
2785 // Thread-unsafe memoization
2786 template<class F, class R=decltype(std::declval<F>()())>
2787 static std::function<R()> memoize(F f)
2788 {
2789  bool init = false;
2790  R result{};
2791  return [=]() mutable -> R {
2792  if (init)
2793  return result;
2794  result = f();
2795  init = true;
2796  return result;
2797  };
2798 }
2799 
2800 template<class F,
2801  REQUIRES("F must be a function that returns a Token class",
2802  std::is_convertible<decltype(std::declval<F>()()), const Token*> )>
2803 static bool isExpressionChangedAt(const F& getExprTok,
2804  const Token* tok,
2805  int indirect,
2806  const nonneg int exprid,
2807  bool globalvar,
2808  const Settings& settings,
2809  int depth)
2810 {
2811  if (depth < 0)
2812  return true;
2813  if (tok->isLiteral() || tok->isKeyword() || tok->isStandardType() || Token::Match(tok, ",|;|:"))
2814  return false;
2815  if (tok->exprId() != exprid || (!tok->varId() && !tok->isName())) {
2816  if (globalvar && Token::Match(tok, "%name% (") && !(tok->function() && tok->function()->isAttributePure()))
2817  // TODO: Is global variable really changed by function call?
2818  return true;
2819  int i = 1;
2820  bool aliased = false;
2821  // If we can't find the expression then assume it is an alias
2822  auto expr = getExprTok();
2823  if (!expr)
2824  aliased = true;
2825  if (!aliased)
2826  aliased = isAliasOf(tok, expr, &i);
2827  if (!aliased)
2828  return false;
2829  if (isVariableChanged(tok, indirect + i, settings, depth))
2830  return true;
2831  // TODO: Try to traverse the lambda function
2832  if (Token::Match(tok, "%var% ("))
2833  return true;
2834  return false;
2835  }
2836  return (isVariableChanged(tok, indirect, settings, depth));
2837 }
2838 
2839 bool isExpressionChangedAt(const Token* expr,
2840  const Token* tok,
2841  int indirect,
2842  bool globalvar,
2843  const Settings& settings,
2844  int depth)
2845 {
2846  return isExpressionChangedAt([&] {
2847  return expr;
2848  }, tok, indirect, expr->exprId(), globalvar, settings, depth);
2849 }
2850 
2851 Token* findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2852 {
2853  if (!precedes(start, end))
2854  return nullptr;
2855  if (depth < 0)
2856  return start;
2857  auto getExprTok = memoize([&] {
2858  return findExpression(start, exprid);
2859  });
2860  for (Token *tok = start; tok != end; tok = tok->next()) {
2861  if (isExpressionChangedAt(getExprTok, tok, indirect, exprid, globalvar, settings, depth))
2862  return tok;
2863  }
2864  return nullptr;
2865 }
2866 
2867 const Token* findVariableChanged(const Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
2868 {
2869  return findVariableChanged(const_cast<Token*>(start), end, indirect, exprid, globalvar, settings, depth);
2870 }
2871 
2872 bool isVariableChanged(const Variable * var, const Settings &settings, int depth)
2873 {
2874  if (!var)
2875  return false;
2876  if (!var->scope())
2877  return false;
2878  const Token * start = var->declEndToken();
2879  if (!start)
2880  return false;
2881  if (Token::Match(start, "; %varid% =", var->declarationId()))
2882  start = start->tokAt(2);
2883  if (Token::simpleMatch(start, "=")) {
2884  const Token* next = nextAfterAstRightmostLeafGeneric(start);
2885  if (next)
2886  start = next;
2887  }
2888  return findExpressionChanged(var->nameToken(), start->next(), var->scope()->bodyEnd, settings, depth);
2889 }
2890 
2891 bool isVariablesChanged(const Token* start,
2892  const Token* end,
2893  int indirect,
2894  const std::vector<const Variable*> &vars,
2895  const Settings& settings)
2896 {
2897  std::set<int> varids;
2898  std::transform(vars.cbegin(), vars.cend(), std::inserter(varids, varids.begin()), [](const Variable* var) {
2899  return var->declarationId();
2900  });
2901  const bool globalvar = std::any_of(vars.cbegin(), vars.cend(), [](const Variable* var) {
2902  return var->isGlobal();
2903  });
2904  for (const Token* tok = start; tok != end; tok = tok->next()) {
2905  if (tok->varId() == 0 || varids.count(tok->varId()) == 0) {
2906  if (globalvar && Token::Match(tok, "%name% ("))
2907  // TODO: Is global variable really changed by function call?
2908  return true;
2909  continue;
2910  }
2911  if (isVariableChanged(tok, indirect, settings))
2912  return true;
2913  }
2914  return false;
2915 }
2916 
2917 bool isThisChanged(const Token* tok, int indirect, const Settings& settings)
2918 {
2919  if ((Token::Match(tok->previous(), "%name% (") && !Token::simpleMatch(tok->astOperand1(), ".")) ||
2920  Token::Match(tok->tokAt(-3), "this . %name% (")) {
2921  if (tok->previous()->function()) {
2922  return (!tok->previous()->function()->isConst() && !tok->previous()->function()->isStatic());
2923  }
2924  if (!tok->previous()->isKeyword()) {
2925  return true;
2926  }
2927  }
2928  if (isVariableChanged(tok, indirect, settings))
2929  return true;
2930  return false;
2931 }
2932 
2933 static const Token* findThisChanged(const Token* start, const Token* end, int indirect, const Settings& settings)
2934 {
2935  if (!precedes(start, end))
2936  return nullptr;
2937  for (const Token* tok = start; tok != end; tok = tok->next()) {
2938  if (!exprDependsOnThis(tok))
2939  continue;
2940  if (isThisChanged(tok, indirect, settings))
2941  return tok;
2942  }
2943  return nullptr;
2944 }
2945 
2946 template<class Find>
2947 static const Token* findExpressionChangedImpl(const Token* expr,
2948  const Token* start,
2949  const Token* end,
2950  const Settings& settings,
2951  int depth,
2952  Find find)
2953 {
2954  if (depth < 0)
2955  return start;
2956  if (!precedes(start, end))
2957  return nullptr;
2958  const Token* result = nullptr;
2959  findAstNode(expr, [&](const Token* tok) {
2960  if (exprDependsOnThis(tok)) {
2961  result = findThisChanged(start, end, /*indirect*/ 0, settings);
2962  if (result)
2963  return true;
2964  }
2965  bool global = false;
2966  if (tok->variable()) {
2967  if (tok->variable()->isConst())
2968  return false;
2969  global = !tok->variable()->isLocal() && !tok->variable()->isArgument() &&
2970  !(tok->variable()->isMember() && !tok->variable()->isStatic());
2971  } else if (tok->isIncompleteVar() && !tok->isIncompleteConstant()) {
2972  global = true;
2973  }
2974 
2975  if (tok->exprId() > 0 || global) {
2976  const Token* modifedTok = find(start, end, [&](const Token* tok2) {
2977  int indirect = 0;
2978  if (const ValueType* vt = tok->valueType()) {
2979  indirect = vt->pointer;
2980  if (vt->type == ValueType::ITERATOR)
2981  ++indirect;
2982  }
2983  for (int i = 0; i <= indirect; ++i) {
2984  if (isExpressionChangedAt(tok, tok2, i, global, settings, depth))
2985  return true;
2986  }
2987  return false;
2988  });
2989  if (modifedTok) {
2990  result = modifedTok;
2991  return true;
2992  }
2993  }
2994  return false;
2995  });
2996  return result;
2997 }
2998 
2999 namespace {
3000  struct ExpressionChangedSimpleFind {
3001  template<class F>
3002  const Token* operator()(const Token* start, const Token* end, F f) const
3003  {
3004  return findToken(start, end, f);
3005  }
3006  };
3007 
3008  struct ExpressionChangedSkipDeadCode {
3009  const Library& library;
3010  const std::function<std::vector<MathLib::bigint>(const Token* tok)>* evaluate;
3011  ExpressionChangedSkipDeadCode(const Library& library,
3012  const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate)
3013  : library(library), evaluate(&evaluate)
3014  {}
3015  template<class F>
3016  const Token* operator()(const Token* start, const Token* end, F f) const
3017  {
3018  return findTokenSkipDeadCode(library, start, end, f, *evaluate);
3019  }
3020  };
3021 }
3022 
3023 const Token* findExpressionChanged(const Token* expr,
3024  const Token* start,
3025  const Token* end,
3026  const Settings& settings,
3027  int depth)
3028 {
3029  return findExpressionChangedImpl(expr, start, end, settings, depth, ExpressionChangedSimpleFind{});
3030 }
3031 
3033  const Token* start,
3034  const Token* end,
3035  const Settings& settings,
3036  const std::function<std::vector<MathLib::bigint>(const Token* tok)>& evaluate,
3037  int depth)
3038 {
3040  expr, start, end, settings, depth, ExpressionChangedSkipDeadCode{settings.library, evaluate});
3041 }
3042 
3043 const Token* getArgumentStart(const Token* ftok)
3044 {
3045  const Token* tok = ftok;
3046  if (Token::Match(tok, "%name% (|{|)"))
3047  tok = ftok->next();
3048  while (Token::simpleMatch(tok, ")"))
3049  tok = tok->next();
3050  if (!Token::Match(tok, "(|{|["))
3051  return nullptr;
3052  const Token* startTok = tok->astOperand2();
3053  if (!startTok && tok->next() != tok->link())
3054  startTok = tok->astOperand1();
3055  return startTok;
3056 }
3057 
3058 int numberOfArguments(const Token* ftok) {
3059  return astCount(getArgumentStart(ftok), ",");
3060 }
3061 
3063 {
3064  int arguments = 0;
3065  const Token* openBracket = start->next();
3066  while (Token::simpleMatch(openBracket, ")"))
3067  openBracket = openBracket->next();
3068  if (openBracket && openBracket->str()=="(" && openBracket->next() && openBracket->next()->str()!=")") {
3069  const Token* argument=openBracket->next();
3070  while (argument) {
3071  ++arguments;
3072  argument = argument->nextArgument();
3073  }
3074  }
3075  return arguments;
3076 }
3077 
3078 std::vector<const Token*> getArguments(const Token* ftok) {
3079  return astFlatten(getArgumentStart(ftok), ",");
3080 }
3081 
3082 int getArgumentPos(const Variable* var, const Function* f)
3083 {
3084  auto arg_it = std::find_if(f->argumentList.cbegin(), f->argumentList.cend(), [&](const Variable& v) {
3085  return v.nameToken() == var->nameToken();
3086  });
3087  if (arg_it == f->argumentList.end())
3088  return -1;
3089  return std::distance(f->argumentList.cbegin(), arg_it);
3090 }
3091 
3093 {
3094  if (!tok)
3095  return nullptr;
3096  if (tok->isUnaryOp("*"))
3097  return nullptr;
3098  if (!tok->isName()) {
3099  const Token* iter1 = getIteratorExpression(tok->astOperand1());
3100  if (iter1)
3101  return iter1;
3102  if (tok->str() == "(")
3103  return nullptr;
3104  const Token* iter2 = getIteratorExpression(tok->astOperand2());
3105  if (iter2)
3106  return iter2;
3107  } else if (Token::Match(tok, "begin|cbegin|rbegin|crbegin|end|cend|rend|crend (")) {
3108  if (Token::Match(tok->previous(), ". %name% ( ) !!."))
3109  return tok->previous()->astOperand1();
3110  if (!Token::simpleMatch(tok->previous(), ".") && Token::Match(tok, "%name% ( !!)") &&
3111  !Token::simpleMatch(tok->linkAt(1), ") ."))
3112  return tok->next()->astOperand2();
3113  }
3114  return nullptr;
3115 }
3116 
3117 bool isIteratorPair(const std::vector<const Token*>& args)
3118 {
3119  if (args.size() != 2)
3120  return false;
3121  if (astIsPointer(args[0]) && astIsPointer(args[1]))
3122  return true;
3123  // Check if iterator is from same container
3124  const Token* tok1 = nullptr;
3125  const Token* tok2 = nullptr;
3126  if (astIsIterator(args[0]) && astIsIterator(args[1])) {
3127  tok1 = ValueFlow::getLifetimeObjValue(args[0]).tokvalue;
3128  tok2 = ValueFlow::getLifetimeObjValue(args[1]).tokvalue;
3129  if (!tok1 || !tok2)
3130  return true;
3131  } else {
3132  tok1 = getIteratorExpression(args[0]);
3133  tok2 = getIteratorExpression(args[1]);
3134  }
3135  if (tok1 && tok2)
3136  return tok1->exprId() == tok2->exprId();
3137  return tok1 || tok2;
3138 }
3139 
3140 const Token *findLambdaStartToken(const Token *last)
3141 {
3142  if (!last || !last->isCpp() || last->str() != "}")
3143  return nullptr;
3144  const Token* tok = last->link();
3145  if (Token::simpleMatch(tok->astParent(), "("))
3146  tok = tok->astParent();
3147  if (Token::simpleMatch(tok->astParent(), "["))
3148  return tok->astParent();
3149  return nullptr;
3150 }
3151 
3152 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
3153 static T* findLambdaEndTokenGeneric(T* first)
3154 {
3155  auto maybeLambda = [](T* tok) -> bool {
3156  while (Token::Match(tok, "*|%name%|::|>")) {
3157  if (tok->link())
3158  tok = tok->link()->previous();
3159  else {
3160  if (tok->str() == ">")
3161  return true;
3162  if (tok->str() == "new")
3163  return false;
3164  tok = tok->previous();
3165  }
3166  }
3167  return true;
3168  };
3169 
3170  if (!first || !first->isCpp() || first->str() != "[")
3171  return nullptr;
3172  if (!maybeLambda(first->previous()))
3173  return nullptr;
3174  if (!Token::Match(first->link(), "] (|{|<"))
3175  return nullptr;
3176  const Token* roundOrCurly = first->link()->next();
3177  if (roundOrCurly->link() && roundOrCurly->str() == "<")
3178  roundOrCurly = roundOrCurly->link()->next();
3179  if (first->astOperand1() != roundOrCurly)
3180  return nullptr;
3181  T * tok = first;
3182 
3183  if (tok->astOperand1() && tok->astOperand1()->str() == "(")
3184  tok = tok->astOperand1();
3185  if (tok->astOperand1() && tok->astOperand1()->str() == "{")
3186  return tok->astOperand1()->link();
3187  return nullptr;
3188 }
3189 
3190 const Token* findLambdaEndToken(const Token* first)
3191 {
3192  return findLambdaEndTokenGeneric(first);
3193 }
3195 {
3196  return findLambdaEndTokenGeneric(first);
3197 }
3198 
3199 bool isLikelyStream(const Token *stream)
3200 {
3201  if (!stream)
3202  return false;
3203 
3204  if (!stream->isCpp())
3205  return false;
3206 
3207  if (!Token::Match(stream->astParent(), "&|<<|>>") || !stream->astParent()->isBinaryOp())
3208  return false;
3209 
3210  if (stream->astParent()->astOperand1() != stream)
3211  return false;
3212 
3213  return !astIsIntegral(stream, false);
3214 }
3215 
3216 bool isLikelyStreamRead(const Token *op)
3217 {
3218  if (!op)
3219  return false;
3220 
3221  if (!op->isCpp())
3222  return false;
3223 
3224  if (!Token::Match(op, "&|>>") || !op->isBinaryOp())
3225  return false;
3226 
3227  if (!Token::Match(op->astOperand2(), "%name%|.|*|[") && op->str() != op->astOperand2()->str())
3228  return false;
3229 
3230  const Token *parent = op;
3231  while (parent->astParent() && parent->astParent()->str() == op->str())
3232  parent = parent->astParent();
3233  if (parent->astParent() && !Token::Match(parent->astParent(), "%oror%|&&|(|,|.|!|;|return"))
3234  return false;
3235  if (op->str() == "&" && parent->astParent())
3236  return false;
3237  if (!parent->astOperand1() || !parent->astOperand2())
3238  return false;
3239  return (!parent->astOperand1()->valueType() || !parent->astOperand1()->valueType()->isIntegral());
3240 }
3241 
3242 bool isCPPCast(const Token* tok)
3243 {
3244  return tok && Token::simpleMatch(tok->previous(), "> (") && tok->astOperand2() && tok->astOperand1() && isCPPCastKeyword(tok->astOperand1());
3245 }
3246 
3247 bool isConstVarExpression(const Token *tok, const std::function<bool(const Token*)>& skipPredicate)
3248 {
3249  if (!tok)
3250  return false;
3251  if (tok->str() == "?" && tok->astOperand2() && tok->astOperand2()->str() == ":") // ternary operator
3252  return isConstVarExpression(tok->astOperand2()->astOperand1()) && isConstVarExpression(tok->astOperand2()->astOperand2()); // left and right of ":"
3253  if (skipPredicate && skipPredicate(tok))
3254  return false;
3255  if (Token::simpleMatch(tok->previous(), "sizeof ("))
3256  return true;
3257  if (Token::Match(tok->previous(), "%name% (")) {
3258  if (Token::simpleMatch(tok->astOperand1(), ".") && !isConstVarExpression(tok->astOperand1(), skipPredicate))
3259  return false;
3260  std::vector<const Token *> args = getArguments(tok);
3261  if (args.empty() && tok->previous()->function() && tok->previous()->function()->isConstexpr())
3262  return true;
3263  return !args.empty() && std::all_of(args.cbegin(), args.cend(), [&](const Token* t) {
3264  return isConstVarExpression(t, skipPredicate);
3265  });
3266  }
3267  if (isCPPCast(tok)) {
3268  return isConstVarExpression(tok->astOperand2(), skipPredicate);
3269  }
3270  if (Token::Match(tok, "( %type%"))
3271  return isConstVarExpression(tok->astOperand1(), skipPredicate);
3272  if (tok->str() == "::" && tok->hasKnownValue())
3273  return isConstVarExpression(tok->astOperand2(), skipPredicate);
3274  if (Token::Match(tok, "%cop%|[|.")) {
3275  if (tok->astOperand1() && !isConstVarExpression(tok->astOperand1(), skipPredicate))
3276  return false;
3277  if (tok->astOperand2() && !isConstVarExpression(tok->astOperand2(), skipPredicate))
3278  return false;
3279  return true;
3280  }
3281  if (Token::Match(tok, "%bool%|%num%|%str%|%char%|nullptr|NULL"))
3282  return true;
3283  if (tok->isEnumerator())
3284  return true;
3285  if (tok->variable())
3286  return tok->variable()->isConst() && tok->variable()->nameToken() && tok->variable()->nameToken()->hasKnownValue();
3287  return false;
3288 }
3289 
3290 static ExprUsage getFunctionUsage(const Token* tok, int indirect, const Settings& settings)
3291 {
3292  const bool addressOf = tok->astParent() && tok->astParent()->isUnaryOp("&");
3293 
3294  int argnr;
3295  const Token* ftok = getTokenArgumentFunction(tok, argnr);
3296  if (!ftok)
3297  return ExprUsage::None;
3298  if (ftok->function()) {
3299  std::vector<const Variable*> args = getArgumentVars(ftok, argnr);
3300  for (const Variable* arg : args) {
3301  if (!arg)
3302  continue;
3303  if (arg->isReference() || (arg->isPointer() && indirect == 1)) {
3304  if (!ftok->function()->hasBody())
3306  for (const Token* bodytok = ftok->function()->functionScope->bodyStart; bodytok != ftok->function()->functionScope->bodyEnd; bodytok = bodytok->next()) {
3307  if (bodytok->variable() == arg) {
3308  if (arg->isReference())
3310  if (Token::Match(bodytok->astParent(), "%comp%|!"))
3311  return ExprUsage::NotUsed;
3313  }
3314  }
3315  return ExprUsage::NotUsed;
3316  }
3317  }
3318  if (!args.empty() && indirect == 0 && !addressOf)
3319  return ExprUsage::Used;
3320  } else if (ftok->isControlFlowKeyword()) {
3321  return ExprUsage::Used;
3322  } else if (ftok->str() == "{") {
3323  return indirect == 0 ? ExprUsage::Used : ExprUsage::Inconclusive;
3324  } else if (ftok->variable() && ftok == ftok->variable()->nameToken()) { // variable init/constructor call
3325  if (ftok->variable()->type() && ftok->variable()->type()->classScope && ftok->variable()->type()->classScope->numConstructors == 0)
3326  return ExprUsage::Used;
3327  if (ftok->variable()->isStlType() || (ftok->variable()->valueType() && ftok->variable()->valueType()->container)) // STL types or containers don't initialize external variables
3328  return ExprUsage::Used;
3329  } else {
3330  const bool isnullbad = settings.library.isnullargbad(ftok, argnr + 1);
3331  if (indirect == 0 && astIsPointer(tok) && !addressOf && isnullbad)
3332  return ExprUsage::Used;
3333  bool hasIndirect = false;
3334  const bool isuninitbad = settings.library.isuninitargbad(ftok, argnr + 1, indirect, &hasIndirect);
3335  if (isuninitbad && (!addressOf || isnullbad))
3336  return ExprUsage::Used;
3337  }
3338  return ExprUsage::Inconclusive;
3339 }
3340 
3341 bool isLeafDot(const Token* tok)
3342 {
3343  if (!tok)
3344  return false;
3345  const Token * parent = tok->astParent();
3346  if (!Token::simpleMatch(parent, "."))
3347  return false;
3348  if (parent->astOperand2() == tok && !Token::simpleMatch(parent->astParent(), "."))
3349  return true;
3350  return isLeafDot(parent);
3351 }
3352 
3353 ExprUsage getExprUsage(const Token* tok, int indirect, const Settings& settings)
3354 {
3355  const Token* parent = tok->astParent();
3356  if (indirect > 0 && parent) {
3357  while (Token::simpleMatch(parent, "[") && parent->astParent())
3358  parent = parent->astParent();
3359  if (Token::Match(parent, "%assign%") && (astIsRHS(tok) || astIsLHS(parent->astOperand1())))
3360  return ExprUsage::NotUsed;
3361  if (Token::Match(parent, "++|--"))
3362  return ExprUsage::NotUsed;
3363  if (parent->isConstOp())
3364  return ExprUsage::NotUsed;
3365  if (parent->isCast())
3366  return ExprUsage::NotUsed;
3367  if (Token::simpleMatch(parent, ":") && Token::simpleMatch(parent->astParent(), "?"))
3368  return getExprUsage(parent->astParent(), indirect, settings);
3369  if (isUsedAsBool(tok, settings))
3370  return ExprUsage::NotUsed;
3371  }
3372  if (indirect == 0) {
3373  if (Token::Match(parent, "%cop%|%assign%|++|--") && parent->str() != "=" &&
3374  !parent->isUnaryOp("&") &&
3375  !(astIsRHS(tok) && isLikelyStreamRead(parent)))
3376  return ExprUsage::Used;
3377  if (isLeafDot(tok)) {
3378  const Token* op = parent->astParent();
3379  while (Token::simpleMatch(op, "."))
3380  op = op->astParent();
3381  if (Token::Match(op, "%assign%|++|--")) {
3382  if (op->str() == "=") {
3383  if (precedes(tok, op))
3384  return ExprUsage::NotUsed;
3385  } else
3386  return ExprUsage::Used;
3387  }
3388  }
3389  if (Token::simpleMatch(parent, "=") && astIsRHS(tok)) {
3390  const Token* const lhs = parent->astOperand1();
3391  if (lhs && lhs->variable() && lhs->variable()->isReference() && lhs == lhs->variable()->nameToken())
3392  return ExprUsage::NotUsed;
3393  return ExprUsage::Used;
3394  }
3395  // Function call or index
3396  if (((Token::simpleMatch(parent, "(") && !parent->isCast()) || (Token::simpleMatch(parent, "[") && tok->valueType())) &&
3397  (astIsLHS(tok) || Token::simpleMatch(parent, "( )")))
3398  return ExprUsage::Used;
3399  }
3400  return getFunctionUsage(tok, indirect, settings);
3401 }
3402 
3403 static void getLHSVariablesRecursive(std::vector<const Variable*>& vars, const Token* tok)
3404 {
3405  if (!tok)
3406  return;
3407  if (vars.empty() && Token::Match(tok, "*|&|&&|[")) {
3408  getLHSVariablesRecursive(vars, tok->astOperand1());
3409  if (!vars.empty() || Token::simpleMatch(tok, "["))
3410  return;
3411  getLHSVariablesRecursive(vars, tok->astOperand2());
3412  } else if (Token::Match(tok->previous(), "this . %var%")) {
3413  getLHSVariablesRecursive(vars, tok->next());
3414  } else if (Token::simpleMatch(tok, ".")) {
3415  getLHSVariablesRecursive(vars, tok->astOperand1());
3416  getLHSVariablesRecursive(vars, tok->astOperand2());
3417  } else if (Token::simpleMatch(tok, "::")) {
3418  getLHSVariablesRecursive(vars, tok->astOperand2());
3419  } else if (tok->variable()) {
3420  vars.push_back(tok->variable());
3421  }
3422 }
3423 
3424 std::vector<const Variable*> getLHSVariables(const Token* tok)
3425 {
3426  std::vector<const Variable*> result;
3427  if (!Token::Match(tok, "%assign%|(|{"))
3428  return result;
3429  if (!tok->astOperand1())
3430  return result;
3431  if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
3432  return {tok->astOperand1()->variable()};
3433  getLHSVariablesRecursive(result, tok->astOperand1());
3434  return result;
3435 }
3436 
3437 static const Token* getLHSVariableRecursive(const Token* tok)
3438 {
3439  if (!tok)
3440  return nullptr;
3441  if (Token::Match(tok, "*|&|&&|[")) {
3442  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3443  if ((vartok && vartok->variable()) || Token::simpleMatch(tok, "["))
3444  return vartok;
3445  return getLHSVariableRecursive(tok->astOperand2());
3446  }
3447  if (Token::Match(tok->previous(), "this . %var%"))
3448  return tok->next();
3449  return tok;
3450 }
3451 
3452 const Variable *getLHSVariable(const Token *tok)
3453 {
3454  if (!tok || !tok->isAssignmentOp())
3455  return nullptr;
3456  if (!tok->astOperand1())
3457  return nullptr;
3458  if (tok->astOperand1()->varId() > 0 && tok->astOperand1()->variable())
3459  return tok->astOperand1()->variable();
3460  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3461  if (!vartok)
3462  return nullptr;
3463  return vartok->variable();
3464 }
3465 
3466 const Token* getLHSVariableToken(const Token* tok)
3467 {
3468  if (!Token::Match(tok, "%assign%"))
3469  return nullptr;
3470  if (!tok->astOperand1())
3471  return nullptr;
3472  if (tok->astOperand1()->varId() > 0)
3473  return tok->astOperand1();
3474  const Token* vartok = getLHSVariableRecursive(tok->astOperand1());
3475  if (vartok && vartok->variable() && vartok->variable()->nameToken() == vartok)
3476  return vartok;
3477  return tok->astOperand1();
3478 }
3479 
3480 const Token* findAllocFuncCallToken(const Token *expr, const Library &library)
3481 {
3482  if (!expr)
3483  return nullptr;
3484  if (Token::Match(expr, "[+-]")) {
3485  const Token *tok1 = findAllocFuncCallToken(expr->astOperand1(), library);
3486  return tok1 ? tok1 : findAllocFuncCallToken(expr->astOperand2(), library);
3487  }
3488  if (expr->isCast())
3489  return findAllocFuncCallToken(expr->astOperand2() ? expr->astOperand2() : expr->astOperand1(), library);
3490  if (Token::Match(expr->previous(), "%name% (") && library.getAllocFuncInfo(expr->astOperand1()))
3491  return expr->astOperand1();
3492  return (Token::simpleMatch(expr, "new") && expr->astOperand1()) ? expr : nullptr;
3493 }
3494 
3495 bool isNullOperand(const Token *expr)
3496 {
3497  if (!expr)
3498  return false;
3499  if (expr->isCpp() && Token::Match(expr, "static_cast|const_cast|dynamic_cast|reinterpret_cast <"))
3500  expr = expr->astParent();
3501  else if (!expr->isCast())
3502  return Token::Match(expr, "NULL|nullptr");
3503  if (expr->valueType() && expr->valueType()->pointer == 0)
3504  return false;
3505  const Token *castOp = expr->astOperand2() ? expr->astOperand2() : expr->astOperand1();
3506  return Token::Match(castOp, "NULL|nullptr") || (MathLib::isInt(castOp->str()) && MathLib::isNullValue(castOp->str()));
3507 }
3508 
3509 bool isGlobalData(const Token *expr)
3510 {
3511  // function call that returns reference => assume global data
3512  if (expr && expr->str() == "(" && expr->valueType() && expr->valueType()->reference != Reference::None) {
3513  if (expr->isBinaryOp())
3514  return true;
3515  if (expr->astOperand1() && precedes(expr->astOperand1(), expr))
3516  return true;
3517  }
3518 
3519  bool globalData = false;
3520  bool var = false;
3521  visitAstNodes(expr,
3522  [expr, &globalData, &var](const Token *tok) {
3523  if (tok->varId())
3524  var = true;
3525  if (tok->varId() && !tok->variable()) {
3526  // Bailout, this is probably global
3527  globalData = true;
3528  return ChildrenToVisit::none;
3529  }
3530  if (tok->originalName() == "->") {
3531  // TODO check if pointer points at local data
3532  globalData = true;
3533  return ChildrenToVisit::none;
3534  }
3535  if (Token::Match(tok, "[*[]") && tok->astOperand1() && tok->astOperand1()->variable()) {
3536  // TODO check if pointer points at local data
3537  const Variable *lhsvar = tok->astOperand1()->variable();
3538  const ValueType *lhstype = tok->astOperand1()->valueType();
3539  if (lhsvar->isPointer()) {
3540  globalData = true;
3541  return ChildrenToVisit::none;
3542  }
3543  if (lhsvar->isArgument() && lhsvar->isArray()) {
3544  globalData = true;
3545  return ChildrenToVisit::none;
3546  }
3547  if (lhsvar->isArgument() && (!lhstype || (lhstype->type <= ValueType::Type::VOID && !lhstype->container))) {
3548  globalData = true;
3549  return ChildrenToVisit::none;
3550  }
3551  }
3552  if (tok->varId() == 0 && tok->isName() && tok->previous()->str() != ".") {
3553  globalData = true;
3554  return ChildrenToVisit::none;
3555  }
3556  if (tok->variable()) {
3557  // TODO : Check references
3558  if (tok->variable()->isReference() && tok != tok->variable()->nameToken()) {
3559  globalData = true;
3560  return ChildrenToVisit::none;
3561  }
3562  if (tok->variable()->isExtern()) {
3563  globalData = true;
3564  return ChildrenToVisit::none;
3565  }
3566  if (tok->previous()->str() != "." && !tok->variable()->isLocal() && !tok->variable()->isArgument()) {
3567  globalData = true;
3568  return ChildrenToVisit::none;
3569  }
3570  if (tok->variable()->isArgument() && tok->variable()->isPointer() && tok != expr) {
3571  globalData = true;
3572  return ChildrenToVisit::none;
3573  }
3574  if (tok->variable()->isPointerArray()) {
3575  globalData = true;
3576  return ChildrenToVisit::none;
3577  }
3578  }
3579  // Unknown argument type => it might be some reference type..
3580  if (tok->isCpp() && tok->str() == "." && tok->astOperand1() && tok->astOperand1()->variable() && !tok->astOperand1()->valueType()) {
3581  globalData = true;
3582  return ChildrenToVisit::none;
3583  }
3584  if (Token::Match(tok, ".|["))
3585  return ChildrenToVisit::op1;
3587  });
3588  return globalData || !var;
3589 }
3590 
3591 bool isUnevaluated(const Token *tok)
3592 {
3593  return Token::Match(tok, "alignof|_Alignof|_alignof|__alignof|__alignof__|decltype|offsetof|sizeof|typeid|typeof|__typeof__ (");
3594 }
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:3062
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:1386
bool astIsContainer(const Token *tok)
Definition: astutils.cpp:244
static bool isCPPCastKeyword(const Token *tok)
Definition: astutils.cpp:2404
const Token * getIteratorExpression(const Token *tok)
Definition: astutils.cpp:3092
static T * getTokenArgumentFunctionImpl(T *tok, int &argn)
Definition: astutils.cpp:2282
static bool isArray(const Token *tok)
Definition: astutils.cpp:2422
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3078
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:1544
bool isOppositeExpression(const Token *const tok1, const Token *const tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1942
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:2803
bool isSameExpression(bool macro, const Token *tok1, const Token *tok2, const Settings &settings, bool pure, bool followVar, ErrorPath *errors)
Definition: astutils.cpp:1549
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:858
static const Token * getLHSVariableRecursive(const Token *tok)
Definition: astutils.cpp:3437
bool exprDependsOnThis(const Token *expr, bool onVar, nonneg int depth)
Definition: astutils.cpp:1098
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:1362
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:987
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
Definition: astutils.cpp:2355
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:3403
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:1482
static void followVariableExpressionError(const Token *tok1, const Token *tok2, ErrorPath *errors)
Definition: astutils.cpp:1215
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:919
static bool hasNoreturnFunction(const Token *tok, const Library &library, const Token **unknownFunc)
Definition: astutils.cpp:2167
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:1530
const Token * isInLoopCondition(const Token *tok)
Definition: astutils.cpp:980
static const Token * getParentLifetimeObject(const Token *tok)
Definition: astutils.cpp:635
static T * findLambdaEndTokenGeneric(T *first)
Definition: astutils.cpp:3153
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:3216
bool isUniqueExpression(const Token *tok)
Definition: astutils.cpp:2082
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:3023
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:3480
bool astIsLHS(const Token *tok)
Definition: astutils.cpp:784
bool isGlobalData(const Token *expr)
Definition: astutils.cpp:3509
bool isConstFunctionCall(const Token *ftok, const Library &library)
Definition: astutils.cpp:1964
static bool isTrivialConstructor(const Token *tok)
Definition: astutils.cpp:2411
bool astIsBool(const Token *tok)
Is expression of boolean type?
Definition: astutils.cpp:215
const Token * getArgumentStart(const Token *ftok)
Definition: astutils.cpp:3043
bool isScopeBracket(const Token *tok)
Definition: astutils.cpp:2268
static ExprUsage getFunctionUsage(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:3290
bool isEscapeFunction(const Token *ftok, const Library *library)
Definition: astutils.cpp:2150
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:1146
Token * getInitTok(Token *tok)
Definition: astutils.cpp:891
const Token * findNextTokenFromBreak(const Token *breakToken)
For a "break" token, locate the next token to execute.
Definition: astutils.cpp:905
bool isLeafDot(const Token *tok)
Definition: astutils.cpp:3341
bool astIsUniqueSmartPointer(const Token *tok)
Definition: astutils.cpp:230
static bool isEscaped(const Token *tok, bool functionsScope, const Library &library)
Definition: astutils.cpp:2132
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:1418
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:882
bool isNullOperand(const Token *expr)
Definition: astutils.cpp:3495
const Token * findLambdaStartToken(const Token *last)
Definition: astutils.cpp:3140
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:1780
bool astIsContainerString(const Token *tok)
Definition: astutils.cpp:264
static bool isForLoopCondition(const Token *const tok)
Definition: astutils.cpp:1460
Token * getCondTok(Token *tok)
Definition: astutils.cpp:873
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:2245
static std::function< R()> memoize(F f)
Definition: astutils.cpp:2787
static bool functionModifiesArguments(const Function *f)
Definition: astutils.cpp:1955
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:3452
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:3247
bool isWithoutSideEffects(const Token *tok, bool checkArrayAccess, bool checkReference)
Definition: astutils.cpp:2066
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:3190
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
ExprUsage getExprUsage(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:3353
bool isThisChanged(const Token *tok, int indirect, const Settings &settings)
Definition: astutils.cpp:2917
static const Token * getVariableInitExpression(const Variable *var)
Definition: astutils.cpp:968
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:1762
Token * getStepTok(Token *tok)
Definition: astutils.cpp:898
bool isVariablesChanged(const Token *start, const Token *end, int indirect, const std::vector< const Variable * > &vars, const Settings &settings)
Definition: astutils.cpp:2891
bool isIteratorPair(const std::vector< const Token * > &args)
Are the arguments a pair of iterators/pointers?
Definition: astutils.cpp:3117
bool isAliasOf(const Token *tok, nonneg int varid, bool *inconclusive)
If token is an alias if another variable.
Definition: astutils.cpp:1010
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:2258
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:2197
Token * findVariableChanged(Token *start, const Token *end, int indirect, const nonneg int exprid, bool globalvar, const Settings &settings, int depth)
Definition: astutils.cpp:2851
static bool hasUnknownVars(const Token *startTok)
Definition: astutils.cpp:1133
static bool isEscapedOrJump(const Token *tok, bool functionsScope, const Library &library)
Definition: astutils.cpp:2141
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:1159
static bool isSameConstantValue(bool macro, const Token *tok1, const Token *tok2)
Definition: astutils.cpp:1429
bool astIsUnsigned(const Token *tok)
Definition: astutils.cpp:202
static bool isSameLifetime(const Token *const tok1, const Token *const tok2)
Definition: astutils.cpp:1375
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:3032
bool isCPPCast(const Token *tok)
Definition: astutils.cpp:3242
bool isEqualKnownValue(const Token *const tok1, const Token *const tok2)
Definition: astutils.cpp:1407
std::vector< const Variable * > getLHSVariables(const Token *tok)
Definition: astutils.cpp:3424
bool isConstExpression(const Token *tok, const Library &library)
Definition: astutils.cpp:2044
std::vector< const Variable * > getArgumentVars(const Token *tok, int argnr)
Definition: astutils.cpp:2363
static bool isForLoopIncrement(const Token *const tok)
Definition: astutils.cpp:1471
bool isUnevaluated(const Token *tok)
Definition: astutils.cpp:3591
const Token * getLHSVariableToken(const Token *tok)
Definition: astutils.cpp:3466
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:1229
static bool isAliased(const Token *startTok, const Token *endTok, nonneg int varid)
Definition: astutils.cpp:1073
bool isLikelyStream(const Token *stream)
Definition: astutils.cpp:3199
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:827
static const Token * findThisChanged(const Token *start, const Token *end, int indirect, const Settings &settings)
Definition: astutils.cpp:2933
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:2947
static T * getInitTokImpl(T *tok)
Definition: astutils.cpp:842
bool succeeds(const Token *tok1, const Token *tok2)
If tok1 comes after tok2.
Definition: astutils.cpp:999
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:3058
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:2541
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)
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:1481
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:1542
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:1458
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:1428
std::unordered_map< std::string, Function > functions
Definition: library.h:330
bool isFunctionConst(const std::string &functionName, bool pure) const
Definition: library.cpp:1518
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:2562
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:722
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:2553
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:2431
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:1371
bool isIncompleteVar() const
Definition: token.h:573
bool isBoolean() const
Definition: token.h:404
bool isCpp() const
Definition: token.cpp:2752
bool isControlFlowKeyword() const
Definition: token.h:546
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
Definition: token.cpp:2377
const ValueType * valueType() const
Definition: token.h:331
const Enumerator * enumerator() const
Definition: token.h:1111
void astOperand1(Token *tok)
Definition: token.cpp:1490
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
nonneg int varId() const
Definition: token.h:870
std::string expressionString() const
Definition: token.cpp:1681
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:427
bool isConstOp() const
Definition: token.h:385
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1502
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:447
@ 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:2367
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:903
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:1471
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:1715
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