Cppcheck
token.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2023 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 #include "token.h"
20 
21 #include "astutils.h"
22 #include "errortypes.h"
23 #include "library.h"
24 #include "settings.h"
25 #include "simplecpp.h"
26 #include "symboldatabase.h"
27 #include "tokenlist.h"
28 #include "utils.h"
29 #include "tokenrange.h"
30 #include "valueflow.h"
31 
32 #include <algorithm>
33 #include <cassert>
34 #include <cctype>
35 #include <climits>
36 #include <cstdio>
37 #include <cstring>
38 #include <functional>
39 #include <iostream>
40 #include <iterator>
41 #include <map>
42 #include <set>
43 #include <sstream>
44 #include <stack>
45 #include <type_traits>
46 #include <unordered_set>
47 #include <utility>
48 
49 namespace {
50  struct less {
51  template<class T, class U>
52  bool operator()(const T &x, const U &y) const {
53  return x < y;
54  }
55  };
56 }
57 
58 const std::list<ValueFlow::Value> TokenImpl::mEmptyValueList;
59 
60 Token::Token(TokensFrontBack &tokensFrontBack) :
61  mTokensFrontBack(tokensFrontBack)
62 {
63  mImpl = new TokenImpl();
64 }
65 
66 Token::Token(const Token* tok)
67  : Token(const_cast<Token*>(tok)->mTokensFrontBack)
68 {
69  fileIndex(tok->fileIndex());
70  linenr(tok->linenr());
71 }
72 
74 {
75  delete mImpl;
76 }
77 
78 /*
79  * Get a TokenRange which starts at this token and contains every token following it in order up to but not including 't'
80  * e.g. for the sequence of tokens A B C D E, C.until(E) would yield the Range C D
81  * note t can be nullptr to iterate all the way to the end.
82  */
83 // cppcheck-suppress unusedFunction // only used in testtokenrange.cpp
85 {
86  return ConstTokenRange(this, t);
87 }
88 
89 static const std::unordered_set<std::string> controlFlowKeywords = {
90  "goto",
91  "do",
92  "if",
93  "else",
94  "for",
95  "while",
96  "switch",
97  "case",
98  "break",
99  "continue",
100  "return"
101 };
102 
103 // TODO: replace with Keywords::getX()?
104 // Another list of keywords
105 static const std::unordered_set<std::string> baseKeywords = {
106  "asm",
107  "auto",
108  "break",
109  "case",
110  "const",
111  "continue",
112  "default",
113  "do",
114  "else",
115  "enum",
116  "extern",
117  "for",
118  "goto",
119  "if",
120  "inline",
121  "register",
122  "restrict",
123  "return",
124  "sizeof",
125  "static",
126  "struct",
127  "switch",
128  "typedef",
129  "union",
130  "volatile",
131  "while",
132  "void"
133 };
134 
136 {
138 
139  if (!mStr.empty()) {
140  if (mStr == "true" || mStr == "false")
141  tokType(eBoolean);
142  else if (isStringLiteral(mStr))
143  tokType(eString);
144  else if (isCharLiteral(mStr))
145  tokType(eChar);
146  else if (std::isalpha((unsigned char)mStr[0]) || mStr[0] == '_' || mStr[0] == '$') { // Name
147  if (mImpl->mVarId)
150  tokType(eKeyword);
151  else if (baseKeywords.count(mStr) > 0)
152  tokType(eKeyword);
153  else if (mTokType != eVariable && mTokType != eFunction && mTokType != eType && mTokType != eKeyword)
154  tokType(eName);
155  } else if (simplecpp::Token::isNumberLike(mStr)) {
157  tokType(eNumber);
158  else
159  tokType(eName); // assume it is a user defined literal
160  } else if (mStr == "=" || mStr == "<<=" || mStr == ">>=" ||
161  (mStr.size() == 2U && mStr[1] == '=' && std::strchr("+-*/%&^|", mStr[0])))
163  else if (mStr.size() == 1 && mStr.find_first_of(",[]()?:") != std::string::npos)
165  else if (mStr=="<<" || mStr==">>" || (mStr.size()==1 && mStr.find_first_of("+-*/%") != std::string::npos))
167  else if (mStr.size() == 1 && mStr.find_first_of("&|^~") != std::string::npos)
168  tokType(eBitOp);
169  else if (mStr.size() <= 2 &&
170  (mStr == "&&" ||
171  mStr == "||" ||
172  mStr == "!"))
174  else if (mStr.size() <= 2 && !mLink &&
175  (mStr == "==" ||
176  mStr == "!=" ||
177  mStr == "<" ||
178  mStr == "<=" ||
179  mStr == ">" ||
180  mStr == ">="))
182  else if (mStr == "<=>")
184  else if (mStr.size() == 2 &&
185  (mStr == "++" ||
186  mStr == "--"))
188  else if (mStr.size() == 1 && (mStr.find_first_of("{}") != std::string::npos || (mLink && mStr.find_first_of("<>") != std::string::npos)))
189  tokType(eBracket);
190  else if (mStr == "...")
192  else
193  tokType(eOther);
194  } else {
195  tokType(eNone);
196  }
197 
200 }
201 
202 static const std::unordered_set<std::string> stdTypes = { "bool"
203  , "_Bool"
204  , "char"
205  , "double"
206  , "float"
207  , "int"
208  , "long"
209  , "short"
210  , "size_t"
211  , "void"
212  , "wchar_t"
213 };
214 
216 {
217  isStandardType(false);
218 
219  if (mStr.size() < 3)
220  return;
221 
222  if (stdTypes.find(mStr)!=stdTypes.end()) {
223  isStandardType(true);
224  tokType(eType);
225  }
226 }
227 
229 {
231  return;
232 
234  ((mTokType == Token::eChar) && isPrefixStringCharLiteral(mStr, '\'', "L")));
235 }
236 
238 {
239  if (!isName())
240  return false;
241  return std::none_of(mStr.begin(), mStr.end(), [](char c) {
242  return std::islower(c);
243  });
244 }
245 
246 void Token::concatStr(std::string const& b)
247 {
248  mStr.pop_back();
249  mStr.append(getStringLiteral(b) + "\"");
250 
251  if (isCChar() && isStringLiteral(b) && b[0] != '"') {
252  mStr.insert(0, b.substr(0, b.find('"')));
253  }
255 }
256 
257 std::string Token::strValue() const
258 {
259  assert(mTokType == eString);
260  std::string ret(getStringLiteral(mStr));
261  std::string::size_type pos = 0U;
262  while ((pos = ret.find('\\', pos)) != std::string::npos) {
263  ret.erase(pos,1U);
264  if (ret[pos] >= 'a') {
265  if (ret[pos] == 'n')
266  ret[pos] = '\n';
267  else if (ret[pos] == 'r')
268  ret[pos] = '\r';
269  else if (ret[pos] == 't')
270  ret[pos] = '\t';
271  }
272  if (ret[pos] == '0')
273  return ret.substr(0,pos);
274  pos++;
275  }
276  return ret;
277 }
278 
279 void Token::deleteNext(nonneg int count)
280 {
281  while (mNext && count > 0) {
282  Token *n = mNext;
283 
284  // #8154 we are about to be unknown -> destroy the link to us
285  if (n->mLink && n->mLink->mLink == n)
286  n->mLink->link(nullptr);
287 
288  mNext = n->next();
289  delete n;
290  --count;
291  }
292 
293  if (mNext)
294  mNext->previous(this);
295  else
296  mTokensFrontBack.back = this;
297 }
298 
300 {
301  while (mPrevious && count > 0) {
302  Token *p = mPrevious;
303 
304  // #8154 we are about to be unknown -> destroy the link to us
305  if (p->mLink && p->mLink->mLink == p)
306  p->mLink->link(nullptr);
307 
308  mPrevious = p->previous();
309  delete p;
310  --count;
311  }
312 
313  if (mPrevious)
314  mPrevious->next(this);
315  else
316  mTokensFrontBack.front = this;
317 }
318 
320 {
321  if (mNext) {
322  std::swap(mStr, mNext->mStr);
323  std::swap(mTokType, mNext->mTokType);
324  std::swap(mFlags, mNext->mFlags);
325  std::swap(mImpl, mNext->mImpl);
327  // cppcheck-suppress shadowFunction - TODO: fix this
329  templateSimplifierPointer->token(this);
330  }
331 
333  // cppcheck-suppress shadowFunction - TODO: fix this
336  }
337  if (mNext->mLink)
338  mNext->mLink->mLink = this;
339  if (this->mLink)
340  this->mLink->mLink = mNext;
341  std::swap(mLink, mNext->mLink);
342  }
343 }
344 
345 void Token::takeData(Token *fromToken)
346 {
347  mStr = fromToken->mStr;
348  tokType(fromToken->mTokType);
349  mFlags = fromToken->mFlags;
350  delete mImpl;
351  mImpl = fromToken->mImpl;
352  fromToken->mImpl = nullptr;
354  // cppcheck-suppress shadowFunction - TODO: fix this
356  templateSimplifierPointer->token(this);
357  }
358  mLink = fromToken->mLink;
359  if (mLink)
360  mLink->link(this);
361 }
362 
364 {
365  if (mNext) { // Copy next to this and delete next
366  takeData(mNext);
367  mNext->link(nullptr); // mark as unlinked
368  deleteNext();
369  } else if (mPrevious) { // Copy previous to this and delete previous
371  mPrevious->link(nullptr);
372  deletePrevious();
373  } else {
374  // We are the last token in the list, we can't delete
375  // ourselves, so just make us empty
376  str(";");
377  }
378 }
379 
380 void Token::replace(Token *replaceThis, Token *start, Token *end)
381 {
382  // Fix the whole in the old location of start and end
383  if (start->previous())
384  start->previous()->next(end->next());
385 
386  if (end->next())
387  end->next()->previous(start->previous());
388 
389  // Move start and end to their new location
390  if (replaceThis->previous())
391  replaceThis->previous()->next(start);
392 
393  if (replaceThis->next())
394  replaceThis->next()->previous(end);
395 
396  start->previous(replaceThis->previous());
397  end->next(replaceThis->next());
398 
399  if (end->mTokensFrontBack.back == end) {
400  while (end->next())
401  end = end->next();
402  end->mTokensFrontBack.back = end;
403  }
404 
405  // Update mProgressValue, fileIndex and linenr
406  for (Token *tok = start; tok != end->next(); tok = tok->next())
407  tok->mImpl->mProgressValue = replaceThis->mImpl->mProgressValue;
408 
409  // Delete old token, which is replaced
410  delete replaceThis;
411 }
412 
413 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
414 static T *tokAtImpl(T *tok, int index)
415 {
416  while (index > 0 && tok) {
417  tok = tok->next();
418  --index;
419  }
420  while (index < 0 && tok) {
421  tok = tok->previous();
422  ++index;
423  }
424  return tok;
425 }
426 
427 const Token *Token::tokAt(int index) const
428 {
429  return tokAtImpl(this, index);
430 }
431 
432 Token *Token::tokAt(int index)
433 {
434  return tokAtImpl(this, index);
435 }
436 
437 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
438 static T *linkAtImpl(T *thisTok, int index)
439 {
440  T *tok = thisTok->tokAt(index);
441  if (!tok) {
442  throw InternalError(thisTok, "Internal error. Token::linkAt called with index outside the tokens range.");
443  }
444  return tok->link();
445 }
446 
447 const Token *Token::linkAt(int index) const
448 {
449  return linkAtImpl(this, index);
450 }
451 
452 Token *Token::linkAt(int index)
453 {
454  return linkAtImpl(this, index);
455 }
456 
457 const std::string &Token::strAt(int index) const
458 {
459  const Token *tok = this->tokAt(index);
460  return tok ? tok->mStr : emptyString;
461 }
462 
463 static
464 #if defined(__GNUC__)
465 // GCC does not inline this by itself
466 // need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
467 inline __attribute__((always_inline))
468 #endif
469 int multiComparePercent(const Token *tok, const char*& haystack, nonneg int varid)
470 {
471  ++haystack;
472  // Compare only the first character of the string for optimization reasons
473  switch (haystack[0]) {
474  case 'v':
475  if (haystack[3] == '%') { // %var%
476  haystack += 4;
477  if (tok->varId() != 0)
478  return 1;
479  } else { // %varid%
480  if (varid == 0) {
481  throw InternalError(tok, "Internal error. Token::Match called with varid 0. Please report this to Cppcheck developers");
482  }
483 
484  haystack += 6;
485 
486  if (tok->varId() == varid)
487  return 1;
488  }
489  break;
490  case 't':
491  // Type (%type%)
492  {
493  haystack += 5;
494  if (tok->isName() && tok->varId() == 0)
495  return 1;
496  }
497  break;
498  case 'a':
499  // Accept any token (%any%) or assign (%assign%)
500  {
501  if (haystack[3] == '%') { // %any%
502  haystack += 4;
503  return 1;
504  }
505  // %assign%
506  haystack += 7;
507  if (tok->isAssignmentOp())
508  return 1;
509  }
510  break;
511  case 'n':
512  // Number (%num%) or name (%name%)
513  {
514  if (haystack[4] == '%') { // %name%
515  haystack += 5;
516  if (tok->isName())
517  return 1;
518  } else {
519  haystack += 4;
520  if (tok->isNumber())
521  return 1;
522  }
523  }
524  break;
525  case 'c': {
526  haystack += 1;
527  // Character (%char%)
528  if (haystack[0] == 'h') {
529  haystack += 4;
530  if (tok->tokType() == Token::eChar)
531  return 1;
532  }
533  // Const operator (%cop%)
534  else if (haystack[1] == 'p') {
535  haystack += 3;
536  if (tok->isConstOp())
537  return 1;
538  }
539  // Comparison operator (%comp%)
540  else {
541  haystack += 4;
542  if (tok->isComparisonOp())
543  return 1;
544  }
545  }
546  break;
547  case 's':
548  // String (%str%)
549  {
550  haystack += 4;
551  if (tok->tokType() == Token::eString)
552  return 1;
553  }
554  break;
555  case 'b':
556  // Bool (%bool%)
557  {
558  haystack += 5;
559  if (tok->isBoolean())
560  return 1;
561  }
562  break;
563  case 'o': {
564  ++haystack;
565  if (haystack[1] == '%') {
566  // Op (%op%)
567  if (haystack[0] == 'p') {
568  haystack += 2;
569  if (tok->isOp())
570  return 1;
571  }
572  // Or (%or%)
573  else {
574  haystack += 2;
575  if (tok->tokType() == Token::eBitOp && tok->str() == "|")
576  return 1;
577  }
578  }
579 
580  // Oror (%oror%)
581  else {
582  haystack += 4;
583  if (tok->tokType() == Token::eLogicalOp && tok->str() == "||")
584  return 1;
585  }
586  }
587  break;
588  default:
589  //unknown %cmd%, abort
590  throw InternalError(tok, "Unexpected command");
591  }
592 
593  if (*haystack == '|')
594  haystack += 1;
595  else
596  return -1;
597 
598  return 0xFFFF;
599 }
600 
601 static
602 #if defined(__GNUC__)
603 // need to use the old syntax since the C++11 [[xxx:always_inline]] cannot be used here
604 inline __attribute__((always_inline))
605 #endif
606 int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid)
607 {
608  const char *needle = tok->str().c_str();
609  const char *needlePointer = needle;
610  for (;;) {
611  if (needlePointer == needle && haystack[0] == '%' && haystack[1] != '|' && haystack[1] != '\0' && haystack[1] != ' ') {
612  const int ret = multiComparePercent(tok, haystack, varid);
613  if (ret < 2)
614  return ret;
615  } else if (*haystack == '|') {
616  if (*needlePointer == 0) {
617  // If needle is at the end, we have a match.
618  return 1;
619  }
620 
621  needlePointer = needle;
622  ++haystack;
623  } else if (*needlePointer == *haystack) {
624  if (*needlePointer == '\0')
625  return 1;
626  ++needlePointer;
627  ++haystack;
628  } else if (*haystack == ' ' || *haystack == '\0') {
629  if (needlePointer == needle)
630  return 0;
631  break;
632  }
633  // If haystack and needle don't share the same character,
634  // find next '|' character.
635  else {
636  needlePointer = needle;
637 
638  do {
639  ++haystack;
640 
641  if (*haystack == ' ' || *haystack == '\0') {
642  return -1;
643  }
644  if (*haystack == '|') {
645  break;
646  }
647  } while (true);
648 
649  ++haystack;
650  }
651  }
652 
653  if (*needlePointer == '\0')
654  return 1;
655 
656  return -1;
657 }
658 
659 // cppcheck-suppress unusedFunction - used in tests only
660 int Token::multiCompare(const Token *tok, const char *haystack, nonneg int varid)
661 {
662  return multiCompareImpl(tok, haystack, varid);
663 }
664 
665 bool Token::simpleMatch(const Token *tok, const char pattern[], size_t pattern_len)
666 {
667  if (!tok)
668  return false; // shortcut
669  const char *current = pattern;
670  const char *end = pattern + pattern_len;
671  // cppcheck-suppress shadowFunction - TODO: fix this
672  const char *next = static_cast<const char*>(std::memchr(pattern, ' ', pattern_len));
673  if (!next)
674  next = end;
675 
676  while (*current) {
677  const std::size_t length = next - current;
678 
679  if (!tok || length != tok->mStr.length() || std::strncmp(current, tok->mStr.c_str(), length) != 0)
680  return false;
681 
682  current = next;
683  if (*next) {
684  next = std::strchr(++current, ' ');
685  if (!next)
686  next = end;
687  }
688  tok = tok->next();
689  }
690 
691  return true;
692 }
693 
694 bool Token::firstWordEquals(const char *str, const char *word)
695 {
696  for (;;) {
697  if (*str != *word)
698  return (*str == ' ' && *word == 0);
699  if (*str == 0)
700  break;
701 
702  ++str;
703  ++word;
704  }
705 
706  return true;
707 }
708 
709 const char *Token::chrInFirstWord(const char *str, char c)
710 {
711  for (;;) {
712  if (*str == ' ' || *str == 0)
713  return nullptr;
714 
715  if (*str == c)
716  return str;
717 
718  ++str;
719  }
720 }
721 
722 bool Token::Match(const Token *tok, const char pattern[], nonneg int varid)
723 {
724  if (!(*pattern))
725  return true;
726 
727  const char *p = pattern;
728  while (true) {
729  // Skip spaces in pattern..
730  while (*p == ' ')
731  ++p;
732 
733  // No token => Success!
734  if (*p == '\0')
735  break;
736 
737  if (!tok) {
738  // If we have no tokens, pattern "!!else" should return true
739  if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
740  while (*p && *p != ' ')
741  ++p;
742  continue;
743  }
744 
745  return false;
746  }
747 
748  // [.. => search for a one-character token..
749  if (p[0] == '[' && chrInFirstWord(p, ']')) {
750  if (tok->str().length() != 1)
751  return false;
752 
753  const char *temp = p+1;
754  bool chrFound = false;
755  int count = 0;
756  while (*temp && *temp != ' ') {
757  if (*temp == ']') {
758  ++count;
759  }
760 
761  else if (*temp == tok->str()[0]) {
762  chrFound = true;
763  break;
764  }
765 
766  ++temp;
767  }
768 
769  if (count > 1 && tok->str()[0] == ']')
770  chrFound = true;
771 
772  if (!chrFound)
773  return false;
774 
775  p = temp;
776  }
777 
778  // Parse "not" options. Token can be anything except the given one
779  else if (p[0] == '!' && p[1] == '!' && p[2] != '\0') {
780  p += 2;
781  if (firstWordEquals(p, tok->str().c_str()))
782  return false;
783  }
784 
785  // Parse multi options, such as void|int|char (accept token which is one of these 3)
786  else {
787  const int res = multiCompareImpl(tok, p, varid);
788  if (res == 0) {
789  // Empty alternative matches, use the same token on next round
790  while (*p && *p != ' ')
791  ++p;
792  continue;
793  }
794  if (res == -1) {
795  // No match
796  return false;
797  }
798  }
799 
800  // using strchr() for the other instances leads to a performance decrease
801  if (!(p = strchr(p, ' ')))
802  break;
803 
804  tok = tok->next();
805  }
806 
807  // The end of the pattern has been reached and nothing wrong has been found
808  return true;
809 }
810 
812 {
813  assert(tok != nullptr);
814  assert(tok->mTokType == eString);
815 
816  int len = 0;
817  // cppcheck-suppress shadowFunction - TODO: fix this
818  const std::string str(getStringLiteral(tok->str()));
819  std::string::const_iterator it = str.cbegin();
820  const std::string::const_iterator end = str.cend();
821 
822  while (it != end) {
823  if (*it == '\\') {
824  ++it;
825 
826  // string ends at '\0'
827  if (*it == '0')
828  return len;
829  }
830 
831  if (*it == '\0')
832  return len;
833 
834  ++it;
835  ++len;
836  }
837 
838  return len;
839 }
840 
842 {
843  assert(tok != nullptr);
844  assert(tok->tokType() == eString);
845  // cppcheck-suppress shadowFunction - TODO: fix this
846  const std::string str(getStringLiteral(tok->str()));
847  int sizeofstring = 1;
848  for (int i = 0; i < (int)str.size(); i++) {
849  if (str[i] == '\\')
850  ++i;
851  ++sizeofstring;
852  }
853  return sizeofstring;
854 }
855 
856 nonneg int Token::getStrSize(const Token *tok, const Settings &settings)
857 {
858  assert(tok != nullptr && tok->tokType() == eString);
859  nonneg int sizeofType = 1;
860  if (tok->valueType()) {
861  ValueType vt(*tok->valueType());
862  vt.pointer = 0;
863  sizeofType = ValueFlow::getSizeOf(vt, settings);
864  }
865  return getStrArraySize(tok) * sizeofType;
866 }
867 
868 void Token::move(Token *srcStart, Token *srcEnd, Token *newLocation)
869 {
870  /**[newLocation] -> b -> c -> [srcStart] -> [srcEnd] -> f */
871 
872  // Fix the gap, which tokens to be moved will leave
873  srcStart->previous()->next(srcEnd->next());
874  srcEnd->next()->previous(srcStart->previous());
875 
876  // Fix the tokens to be moved
877  srcEnd->next(newLocation->next());
878  srcStart->previous(newLocation);
879 
880  // Fix the tokens at newLocation
881  newLocation->next()->previous(srcEnd);
882  newLocation->next(srcStart);
883 
884  // Update _progressValue
885  for (Token *tok = srcStart; tok != srcEnd->next(); tok = tok->next())
886  tok->mImpl->mProgressValue = newLocation->mImpl->mProgressValue;
887 }
888 
889 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
890 static T* nextArgumentImpl(T *thisTok)
891 {
892  for (T* tok = thisTok; tok; tok = tok->next()) {
893  if (tok->str() == ",")
894  return tok->next();
895  if (tok->link() && Token::Match(tok, "(|{|[|<"))
896  tok = tok->link();
897  else if (Token::Match(tok, ")|;"))
898  return nullptr;
899  }
900  return nullptr;
901 }
902 
904 {
905  return nextArgumentImpl(this);
906 }
907 
909 {
910  return nextArgumentImpl(this);
911 }
912 
914 {
915  for (const Token* tok = this; tok; tok = tok->next()) {
916  if (tok->str() == ",")
917  return tok->next();
918  if (tok->link() && Token::Match(tok, "(|{|["))
919  tok = tok->link();
920  else if (tok->str() == "<") {
921  const Token* temp = tok->findClosingBracket();
922  if (temp)
923  tok = temp;
924  } else if (Token::Match(tok, ")|;"))
925  return nullptr;
926  }
927  return nullptr;
928 }
929 
931 {
932  for (const Token* tok = this; tok; tok = tok->next()) {
933  if (tok->str() == ",")
934  return tok->next();
935  if (tok->link() && Token::Match(tok, "(|{|[|<"))
936  tok = tok->link();
937  else if (Token::Match(tok, ">|;"))
938  return nullptr;
939  }
940  return nullptr;
941 }
942 
943 static bool isOperator(const Token *tok)
944 {
945  if (tok->link())
946  tok = tok->link();
947  // TODO handle multi token operators
948  return tok->strAt(-1) == "operator";
949 }
950 
952 {
953  if (mStr != "<")
954  return nullptr;
955 
956  if (!mPrevious)
957  return nullptr;
958 
959  if (!(mPrevious->isName() || Token::simpleMatch(mPrevious, "]") ||
960  Token::Match(mPrevious->previous(), "operator %op% <") ||
961  Token::Match(mPrevious->tokAt(-2), "operator [([] [)]] <")))
962  return nullptr;
963 
964  const Token *closing = nullptr;
965  const bool templateParameter(strAt(-1) == "template");
966  std::set<std::string> templateParameters;
967 
968  bool isDecl = true;
969  for (const Token *prev = previous(); prev; prev = prev->previous()) {
970  if (prev->str() == "=")
971  isDecl = false;
972  if (Token::simpleMatch(prev, "template <"))
973  isDecl = true;
974  if (Token::Match(prev, "[;{}]"))
975  break;
976  }
977 
978  unsigned int depth = 0;
979  for (closing = this; closing != nullptr; closing = closing->next()) {
980  if (Token::Match(closing, "{|[|(")) {
981  closing = closing->link();
982  if (!closing)
983  return nullptr; // #6803
984  } else if (Token::Match(closing, "}|]|)|;"))
985  return nullptr;
986  // we can make some guesses for template parameters
987  else if (closing->str() == "<" && closing->previous() &&
988  (closing->previous()->isName() || Token::simpleMatch(closing->previous(), "]") || isOperator(closing->previous())) &&
989  (templateParameter ? templateParameters.find(closing->strAt(-1)) == templateParameters.end() : true))
990  ++depth;
991  else if (closing->str() == ">") {
992  if (--depth == 0)
993  return closing;
994  } else if (closing->str() == ">>" || closing->str() == ">>=") {
995  if (!isDecl && depth == 1)
996  continue;
997  if (depth <= 2)
998  return closing;
999  depth -= 2;
1000  }
1001  // save named template parameter
1002  else if (templateParameter && depth == 1 && closing->str() == "," &&
1003  closing->previous()->isName() && !Match(closing->previous(), "class|typename|."))
1004  templateParameters.insert(closing->strAt(-1));
1005  }
1006 
1007  return closing;
1008 }
1009 
1011 {
1012  // return value of const function
1013  return const_cast<Token*>(const_cast<const Token*>(this)->findClosingBracket());
1014 }
1015 
1017 {
1018  if (mStr != ">")
1019  return nullptr;
1020 
1021  const Token *opening = nullptr;
1022 
1023  unsigned int depth = 0;
1024  for (opening = this; opening != nullptr; opening = opening->previous()) {
1025  if (Token::Match(opening, "}|]|)")) {
1026  opening = opening->link();
1027  if (!opening)
1028  return nullptr;
1029  } else if (Token::Match(opening, "{|{|(|;"))
1030  return nullptr;
1031  else if (opening->str() == ">")
1032  ++depth;
1033  else if (opening->str() == "<") {
1034  if (--depth == 0)
1035  return opening;
1036  }
1037  }
1038 
1039  return opening;
1040 }
1041 
1043 {
1044  // return value of const function
1045  return const_cast<Token*>(const_cast<const Token*>(this)->findOpeningBracket());
1046 }
1047 
1048 //---------------------------------------------------------------------------
1049 
1050 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1051 static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len)
1052 {
1053  for (T* tok = startTok; tok; tok = tok->next()) {
1054  if (Token::simpleMatch(tok, pattern, pattern_len))
1055  return tok;
1056  }
1057  return nullptr;
1058 }
1059 
1060 const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len)
1061 {
1062  return findsimplematchImpl(startTok, pattern, pattern_len);
1063 }
1064 
1065 Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len)
1066 {
1067  return findsimplematchImpl(startTok, pattern, pattern_len);
1068 }
1069 
1070 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1071 static T *findsimplematchImpl(T * const startTok, const char pattern[], size_t pattern_len, const Token * const end)
1072 {
1073  for (T* tok = startTok; tok && tok != end; tok = tok->next()) {
1074  if (Token::simpleMatch(tok, pattern, pattern_len))
1075  return tok;
1076  }
1077  return nullptr;
1078 }
1079 
1080 const Token *Token::findsimplematch(const Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end)
1081 {
1082  return findsimplematchImpl(startTok, pattern, pattern_len, end);
1083 }
1084 
1085 Token *Token::findsimplematch(Token * const startTok, const char pattern[], size_t pattern_len, const Token * const end) {
1086  return findsimplematchImpl(startTok, pattern, pattern_len, end);
1087 }
1088 
1089 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1090 static T *findmatchImpl(T * const startTok, const char pattern[], const nonneg int varId)
1091 {
1092  for (T* tok = startTok; tok; tok = tok->next()) {
1093  if (Token::Match(tok, pattern, varId))
1094  return tok;
1095  }
1096  return nullptr;
1097 }
1098 
1099 const Token *Token::findmatch(const Token * const startTok, const char pattern[], const nonneg int varId)
1100 {
1101  return findmatchImpl(startTok, pattern, varId);
1102 }
1103 
1104 Token *Token::findmatch(Token * const startTok, const char pattern[], const nonneg int varId) {
1105  return findmatchImpl(startTok, pattern, varId);
1106 }
1107 
1108 template<class T, REQUIRES("T must be a Token class", std::is_convertible<T*, const Token*> )>
1109 static T *findmatchImpl(T * const startTok, const char pattern[], const Token * const end, const nonneg int varId)
1110 {
1111  for (T* tok = startTok; tok && tok != end; tok = tok->next()) {
1112  if (Token::Match(tok, pattern, varId))
1113  return tok;
1114  }
1115  return nullptr;
1116 }
1117 
1118 const Token *Token::findmatch(const Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId)
1119 {
1120  return findmatchImpl(startTok, pattern, end, varId);
1121 }
1122 
1123 Token *Token::findmatch(Token * const startTok, const char pattern[], const Token * const end, const nonneg int varId) {
1124  return findmatchImpl(startTok, pattern, end, varId);
1125 }
1126 
1128 {
1129  mImpl->mFunction = f;
1130  if (f) {
1131  if (f->isLambda())
1132  tokType(eLambda);
1133  else
1134  tokType(eFunction);
1135  } else if (mTokType == eFunction)
1136  tokType(eName);
1137 }
1138 
1139 Token* Token::insertToken(const std::string& tokenStr, const std::string& originalNameStr, const std::string& macroNameStr, bool prepend)
1140 {
1141  Token *newToken;
1142  if (mStr.empty())
1143  newToken = this;
1144  else
1145  newToken = new Token(mTokensFrontBack);
1146  newToken->str(tokenStr);
1147  newToken->originalName(originalNameStr);
1148  newToken->setMacroName(macroNameStr);
1149 
1150  if (newToken != this) {
1151  newToken->mImpl->mLineNumber = mImpl->mLineNumber;
1152  newToken->mImpl->mFileIndex = mImpl->mFileIndex;
1153  newToken->mImpl->mProgressValue = mImpl->mProgressValue;
1154 
1155  if (prepend) {
1156  if (this->previous()) {
1157  newToken->previous(this->previous());
1158  newToken->previous()->next(newToken);
1159  } else {
1160  mTokensFrontBack.front = newToken;
1161  }
1162  this->previous(newToken);
1163  newToken->next(this);
1164  } else {
1165  if (this->next()) {
1166  newToken->next(this->next());
1167  newToken->next()->previous(newToken);
1168  } else {
1169  mTokensFrontBack.back = newToken;
1170  }
1171  this->next(newToken);
1172  newToken->previous(this);
1173  }
1174 
1175  if (mImpl->mScopeInfo) {
1176  // If the brace is immediately closed there is no point opening a new scope for it
1177  if (newToken->str() == "{") {
1178  std::string nextScopeNameAddition;
1179  // This might be the opening of a member function
1180  Token *tok1 = newToken;
1181  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
1182  tok1 = tok1->previous();
1183  if (tok1->previous() && tok1->strAt(-1) == ")") {
1184  tok1 = tok1->linkAt(-1);
1185  if (Token::Match(tok1->previous(), "throw|noexcept")) {
1186  tok1 = tok1->previous();
1187  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
1188  tok1 = tok1->previous();
1189  if (tok1->strAt(-1) != ")")
1190  return newToken;
1191  } else if (Token::Match(newToken->tokAt(-2), ":|, %name%")) {
1192  tok1 = tok1->tokAt(-2);
1193  if (tok1->strAt(-1) != ")")
1194  return newToken;
1195  }
1196  if (tok1->strAt(-1) == ">")
1197  tok1 = tok1->previous()->findOpeningBracket();
1198  if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
1199  tok1 = tok1->tokAt(-2);
1200  // cppcheck-suppress shadowFunction - TODO: fix this
1201  std::string scope = tok1->strAt(-1);
1202  while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
1203  scope = tok1->strAt(-3) + " :: " + scope;
1204  tok1 = tok1->tokAt(-2);
1205  }
1206  nextScopeNameAddition += scope;
1207  }
1208  }
1209 
1210  // Or it might be a namespace/class/struct
1211  if (Token::Match(newToken->previous(), "%name%|>")) {
1212  Token* nameTok = newToken->previous();
1213  while (nameTok && !Token::Match(nameTok, "namespace|class|struct|union %name% {|::|:|<")) {
1214  nameTok = nameTok->previous();
1215  }
1216  if (nameTok) {
1217  for (nameTok = nameTok->next(); nameTok && !Token::Match(nameTok, "{|:|<"); nameTok = nameTok->next()) {
1218  nextScopeNameAddition.append(nameTok->str());
1219  nextScopeNameAddition.append(" ");
1220  }
1221  if (!nextScopeNameAddition.empty())
1222  nextScopeNameAddition.pop_back();
1223  }
1224  }
1225 
1226  // New scope is opening, record it here
1227  std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(mImpl->mScopeInfo->name, nullptr, mImpl->mScopeInfo->usingNamespaces);
1228 
1229  if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty()) newScopeInfo->name.append(" :: ");
1230  newScopeInfo->name.append(nextScopeNameAddition);
1231  nextScopeNameAddition = "";
1232 
1233  newToken->scopeInfo(std::move(newScopeInfo));
1234  } else if (newToken->str() == "}") {
1235  Token* matchingTok = newToken->previous();
1236  int depth = 0;
1237  while (matchingTok && (depth != 0 || !Token::simpleMatch(matchingTok, "{"))) {
1238  if (Token::simpleMatch(matchingTok, "}")) depth++;
1239  if (Token::simpleMatch(matchingTok, "{")) depth--;
1240  matchingTok = matchingTok->previous();
1241  }
1242  if (matchingTok && matchingTok->previous()) {
1243  newToken->mImpl->mScopeInfo = matchingTok->previous()->scopeInfo();
1244  }
1245  } else {
1246  if (prepend && newToken->previous()) {
1247  newToken->mImpl->mScopeInfo = newToken->previous()->scopeInfo();
1248  } else {
1249  newToken->mImpl->mScopeInfo = mImpl->mScopeInfo;
1250  }
1251  if (newToken->str() == ";") {
1252  const Token* statementStart;
1253  for (statementStart = newToken; statementStart->previous() && !Token::Match(statementStart->previous(), ";|{"); statementStart = statementStart->previous());
1254  if (Token::Match(statementStart, "using namespace %name% ::|;")) {
1255  const Token * tok1 = statementStart->tokAt(2);
1256  std::string nameSpace;
1257  while (tok1 && tok1->str() != ";") {
1258  if (!nameSpace.empty())
1259  nameSpace += " ";
1260  nameSpace += tok1->str();
1261  tok1 = tok1->next();
1262  }
1263  mImpl->mScopeInfo->usingNamespaces.insert(nameSpace);
1264  }
1265  }
1266  }
1267  }
1268  }
1269  return newToken;
1270 }
1271 
1272 void Token::eraseTokens(Token *begin, const Token *end)
1273 {
1274  if (!begin || begin == end)
1275  return;
1276 
1277  while (begin->next() && begin->next() != end) {
1278  begin->deleteNext();
1279  }
1280 }
1281 
1283 {
1284  assert(begin != nullptr);
1285  assert(end != nullptr);
1286  assert(begin != end);
1287  begin->link(end);
1288  end->link(begin);
1289 }
1290 
1291 void Token::printOut(const char *title) const
1292 {
1293  if (title && title[0])
1294  std::cout << "\n### " << title << " ###\n";
1295  std::cout << stringifyList(stringifyOptions::forPrintOut(), nullptr, nullptr) << std::endl;
1296 }
1297 
1298 void Token::printOut(const char *title, const std::vector<std::string> &fileNames) const
1299 {
1300  if (title && title[0])
1301  std::cout << "\n### " << title << " ###\n";
1302  std::cout << stringifyList(stringifyOptions::forPrintOut(), &fileNames, nullptr) << std::endl;
1303 }
1304 
1305 // cppcheck-suppress unusedFunction - used for debugging
1306 void Token::printLines(int lines) const
1307 {
1308  const Token *end = this;
1309  while (end && end->linenr() < lines + linenr())
1310  end = end->next();
1311  std::cout << stringifyList(stringifyOptions::forDebugExprId(), nullptr, end) << std::endl;
1312 }
1313 
1314 std::string Token::stringify(const stringifyOptions& options) const
1315 {
1316  std::string ret;
1317  if (options.attributes) {
1318  if (isUnsigned())
1319  ret += "unsigned ";
1320  else if (isSigned())
1321  ret += "signed ";
1322  if (isComplex())
1323  ret += "_Complex ";
1324  if (isLong()) {
1325  if (!(mTokType == eString || mTokType == eChar))
1326  ret += "long ";
1327  }
1328  }
1329  if (options.macro && isExpandedMacro())
1330  ret += '$';
1331  if (isName() && mStr.find(' ') != std::string::npos) {
1332  for (const char i : mStr) {
1333  if (i != ' ')
1334  ret += i;
1335  }
1336  } else if (mStr[0] != '\"' || mStr.find('\0') == std::string::npos)
1337  ret += mStr;
1338  else {
1339  for (const char i : mStr) {
1340  if (i == '\0')
1341  ret += "\\0";
1342  else
1343  ret += i;
1344  }
1345  }
1346  if (options.varid && mImpl->mVarId != 0) {
1347  ret += '@';
1348  ret += (options.idtype ? "var" : "");
1349  ret += std::to_string(mImpl->mVarId);
1350  } else if (options.exprid && mImpl->mExprId != 0) {
1351  ret += '@';
1352  ret += (options.idtype ? "expr" : "");
1353  if ((mImpl->mExprId & (1U << efIsUnique)) != 0)
1354  ret += "UNIQUE";
1355  else
1356  ret += std::to_string(mImpl->mExprId);
1357  }
1358 
1359  return ret;
1360 }
1361 
1362 std::string Token::stringify(bool varid, bool attributes, bool macro) const
1363 {
1364  stringifyOptions options;
1365  options.varid = varid;
1366  options.attributes = attributes;
1367  options.macro = macro;
1368  return stringify(options);
1369 }
1370 
1371 std::string Token::stringifyList(const stringifyOptions& options, const std::vector<std::string>* fileNames, const Token* end) const
1372 {
1373  if (this == end)
1374  return "";
1375 
1376  std::string ret;
1377 
1378  unsigned int lineNumber = mImpl->mLineNumber - (options.linenumbers ? 1U : 0U);
1379  // cppcheck-suppress shadowFunction - TODO: fix this
1380  unsigned int fileIndex = options.files ? ~0U : mImpl->mFileIndex;
1381  std::map<int, unsigned int> lineNumbers;
1382  for (const Token *tok = this; tok != end; tok = tok->next()) {
1383  assert(tok && "end precedes token");
1384  if (!tok)
1385  return ret;
1386  bool fileChange = false;
1387  if (tok->mImpl->mFileIndex != fileIndex) {
1388  if (fileIndex != ~0U) {
1389  lineNumbers[fileIndex] = tok->mImpl->mFileIndex;
1390  }
1391 
1392  fileIndex = tok->mImpl->mFileIndex;
1393  if (options.files) {
1394  ret += "\n\n##file ";
1395  if (fileNames && fileNames->size() > tok->mImpl->mFileIndex)
1396  ret += fileNames->at(tok->mImpl->mFileIndex);
1397  else
1398  ret += std::to_string(fileIndex);
1399  ret += '\n';
1400  }
1401 
1402  lineNumber = lineNumbers[fileIndex];
1403  fileChange = true;
1404  }
1405 
1406  if (options.linebreaks && (lineNumber != tok->linenr() || fileChange)) {
1407  if (lineNumber+4 < tok->linenr() && fileIndex == tok->mImpl->mFileIndex) {
1408  ret += '\n';
1409  ret += std::to_string(lineNumber+1);
1410  ret += ":\n|\n";
1411  ret += std::to_string(tok->linenr()-1);
1412  ret += ":\n";
1413  ret += std::to_string(tok->linenr());
1414  ret += ": ";
1415  } else if (this == tok && options.linenumbers) {
1416  ret += std::to_string(tok->linenr());
1417  ret += ": ";
1418  } else if (lineNumber > tok->linenr()) {
1419  lineNumber = tok->linenr();
1420  ret += '\n';
1421  if (options.linenumbers) {
1422  ret += std::to_string(lineNumber);
1423  ret += ':';
1424  ret += ' ';
1425  }
1426  } else {
1427  while (lineNumber < tok->linenr()) {
1428  ++lineNumber;
1429  ret += '\n';
1430  if (options.linenumbers) {
1431  ret += std::to_string(lineNumber);
1432  ret += ':';
1433  if (lineNumber == tok->linenr())
1434  ret += ' ';
1435  }
1436  }
1437  }
1438  lineNumber = tok->linenr();
1439  }
1440 
1441  ret += tok->stringify(options); // print token
1442  if (tok->next() != end && (!options.linebreaks || (tok->next()->linenr() == tok->linenr() && tok->next()->fileIndex() == tok->fileIndex())))
1443  ret += ' ';
1444  }
1445  if (options.linebreaks && (options.files || options.linenumbers))
1446  ret += '\n';
1447  return ret;
1448 }
1449 std::string Token::stringifyList(bool varid, bool attributes, bool linenumbers, bool linebreaks, bool files, const std::vector<std::string>* fileNames, const Token* end) const
1450 {
1451  stringifyOptions options;
1452  options.varid = varid;
1453  options.attributes = attributes;
1454  options.macro = attributes;
1455  options.linenumbers = linenumbers;
1456  options.linebreaks = linebreaks;
1457  options.files = files;
1458  return stringifyList(options, fileNames, end);
1459 }
1460 
1461 std::string Token::stringifyList(const Token* end, bool attributes) const
1462 {
1463  return stringifyList(false, attributes, false, false, false, nullptr, end);
1464 }
1465 
1466 std::string Token::stringifyList(bool varid) const
1467 {
1468  return stringifyList(varid, false, true, true, true, nullptr, nullptr);
1469 }
1470 
1472 {
1473  const Token* tok2 = tok;
1474  while (tok2) {
1475  if (this == tok2)
1476  throw InternalError(this, "Internal error. AST cyclic dependency.");
1477  tok2 = tok2->astParent();
1478  }
1479  // Clear children to avoid nodes referenced twice
1480  if (this->astParent()) {
1481  Token* parent = this->astParent();
1482  if (parent->astOperand1() == this)
1483  parent->mImpl->mAstOperand1 = nullptr;
1484  if (parent->astOperand2() == this)
1485  parent->mImpl->mAstOperand2 = nullptr;
1486  }
1487  mImpl->mAstParent = tok;
1488 }
1489 
1491 {
1492  if (mImpl->mAstOperand1)
1493  mImpl->mAstOperand1->astParent(nullptr);
1494  // goto parent operator
1495  if (tok) {
1496  tok = tok->astTop();
1497  tok->astParent(this);
1498  }
1499  mImpl->mAstOperand1 = tok;
1500 }
1501 
1503 {
1504  if (mImpl->mAstOperand2)
1505  mImpl->mAstOperand2->astParent(nullptr);
1506  // goto parent operator
1507  if (tok) {
1508  tok = tok->astTop();
1509  tok->astParent(this);
1510  }
1511  mImpl->mAstOperand2 = tok;
1512 }
1513 
1514 static const Token* goToLeftParenthesis(const Token* start, const Token* end)
1515 {
1516  // move start to lpar in such expression: '(*it).x'
1517  int par = 0;
1518  for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
1519  if (tok->str() == "(")
1520  ++par;
1521  else if (tok->str() == ")") {
1522  if (par == 0)
1523  start = tok->link();
1524  else
1525  --par;
1526  }
1527  }
1528  return start;
1529 }
1530 
1531 static const Token* goToRightParenthesis(const Token* start, const Token* end)
1532 {
1533  // move end to rpar in such expression: '2>(x+1)'
1534  int par = 0;
1535  for (const Token *tok = end; tok && tok != start; tok = tok->previous()) {
1536  if (tok->str() == ")")
1537  ++par;
1538  else if (tok->str() == "(") {
1539  if (par == 0)
1540  end = tok->link();
1541  else
1542  --par;
1543  }
1544  }
1545  return end;
1546 }
1547 
1548 std::pair<const Token *, const Token *> Token::findExpressionStartEndTokens() const
1549 {
1550  const Token * const top = this;
1551 
1552  // find start node in AST tree
1553  const Token *start = top;
1554  while (start->astOperand1() && precedes(start->astOperand1(), start))
1555  start = start->astOperand1();
1556 
1557  // find end node in AST tree
1558  const Token *end = top;
1559  while (end->astOperand1() && (end->astOperand2() || end->isUnaryPreOp())) {
1560  // lambda..
1561  if (end->str() == "[") {
1562  const Token *lambdaEnd = findLambdaEndToken(end);
1563  if (lambdaEnd) {
1564  end = lambdaEnd;
1565  break;
1566  }
1567  }
1568  if (Token::Match(end,"(|[|{") &&
1569  !(Token::Match(end, "( ::| %type%") && !end->astOperand2())) {
1570  end = end->link();
1571  break;
1572  }
1573  end = end->astOperand2() ? end->astOperand2() : end->astOperand1();
1574  }
1575 
1576  // skip parentheses
1577  start = goToLeftParenthesis(start, end);
1578  end = goToRightParenthesis(start, end);
1579  if (Token::simpleMatch(end, "{"))
1580  end = end->link();
1581 
1582  if (precedes(top, start))
1583  throw InternalError(start, "Cannot find start of expression");
1584  if (succeeds(top, end))
1585  throw InternalError(end, "Cannot find end of expression");
1586 
1587  return std::pair<const Token *, const Token *>(start,end);
1588 }
1589 
1591 {
1592  if (!Token::Match(this, "%cop%|++|--"))
1593  return false;
1594 
1595  if (Token::Match(this, "*|&")) {
1596  // dereference or address-of?
1597  if (!this->astOperand2())
1598  return false;
1599 
1600  if (this->astOperand2()->str() == "[")
1601  return false;
1602 
1603  // type specification?
1604  std::stack<const Token *> operands;
1605  operands.push(this);
1606  while (!operands.empty()) {
1607  const Token *op = operands.top();
1608  operands.pop();
1609  if (op->isNumber() || op->varId() > 0)
1610  return true;
1611  if (op->astOperand1())
1612  operands.push(op->astOperand1());
1613  if (op->astOperand2())
1614  operands.push(op->astOperand2());
1615  else if (Token::Match(op, "*|&"))
1616  return false;
1617  }
1618 
1619  // type specification => return false
1620  return false;
1621  }
1622 
1623  return true;
1624 }
1625 
1627 {
1628  if (!astOperand1() || astOperand2())
1629  return false;
1630  if (this->tokType() != Token::eIncDecOp)
1631  return true;
1632  const Token *tokbefore = mPrevious;
1633  const Token *tokafter = mNext;
1634  for (int distance = 1; distance < 10 && tokbefore; distance++) {
1635  if (tokbefore == mImpl->mAstOperand1)
1636  return false;
1637  if (tokafter == mImpl->mAstOperand1)
1638  return true;
1639  tokbefore = tokbefore->mPrevious;
1640  tokafter = tokafter->mPrevious;
1641  }
1642  return false; // <- guess
1643 }
1644 
1645 static std::string stringFromTokenRange(const Token* start, const Token* end)
1646 {
1647  std::string ret;
1648  if (end)
1649  end = end->next();
1650  for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
1651  if (tok->isUnsigned())
1652  ret += "unsigned ";
1653  if (tok->isLong() && !tok->isLiteral())
1654  ret += "long ";
1655  if (tok->tokType() == Token::eString) {
1656  for (const unsigned char c: tok->str()) {
1657  if (c == '\n')
1658  ret += "\\n";
1659  else if (c == '\r')
1660  ret += "\\r";
1661  else if (c == '\t')
1662  ret += "\\t";
1663  else if (c >= ' ' && c <= 126)
1664  ret += c;
1665  else {
1666  char str[10];
1667  sprintf(str, "\\x%02x", c);
1668  ret += str;
1669  }
1670  }
1671  } else if (tok->originalName().empty() || tok->isUnsigned() || tok->isLong()) {
1672  ret += tok->str();
1673  } else
1674  ret += tok->originalName();
1675  if (Token::Match(tok, "%name%|%num% %name%|%num%"))
1676  ret += ' ';
1677  }
1678  return ret;
1679 }
1680 
1681 std::string Token::expressionString() const
1682 {
1683  const auto tokens = findExpressionStartEndTokens();
1684  return stringFromTokenRange(tokens.first, tokens.second);
1685 }
1686 
1687 static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out)
1688 {
1689  const std::string strindent(indent, ' ');
1690 
1691  out << strindent << "<token str=\"" << tok->str() << '\"';
1692  if (tok->varId())
1693  out << " varId=\"" << tok->varId() << '\"';
1694  if (tok->variable())
1695  out << " variable=\"" << tok->variable() << '\"';
1696  if (tok->function())
1697  out << " function=\"" << tok->function() << '\"';
1698  if (!tok->values().empty())
1699  out << " values=\"" << &tok->values() << '\"';
1700 
1701  if (!tok->astOperand1() && !tok->astOperand2()) {
1702  out << "/>" << std::endl;
1703  }
1704 
1705  else {
1706  out << '>' << std::endl;
1707  if (tok->astOperand1())
1708  astStringXml(tok->astOperand1(), indent+2U, out);
1709  if (tok->astOperand2())
1710  astStringXml(tok->astOperand2(), indent+2U, out);
1711  out << strindent << "</token>" << std::endl;
1712  }
1713 }
1714 
1715 void Token::printAst(bool verbose, bool xml, const std::vector<std::string> &fileNames, std::ostream &out) const
1716 {
1717  if (!xml)
1718  out << "\n\n##AST" << std::endl;
1719 
1720  std::set<const Token *> printed;
1721  for (const Token *tok = this; tok; tok = tok->next()) {
1722  if (!tok->mImpl->mAstParent && tok->mImpl->mAstOperand1) {
1723  if (printed.find(tok) != printed.end())
1724  continue;
1725  printed.insert(tok);
1726 
1727  if (xml) {
1728  out << "<ast scope=\"" << tok->scope() << "\" fileIndex=\"" << tok->fileIndex() << "\" linenr=\"" << tok->linenr()
1729  << "\" column=\"" << tok->column() << "\">" << std::endl;
1730  astStringXml(tok, 2U, out);
1731  out << "</ast>" << std::endl;
1732  } else if (verbose)
1733  out << "[" << fileNames[tok->fileIndex()] << ":" << tok->linenr() << "]" << std::endl << tok->astStringVerbose() << std::endl;
1734  else
1735  out << tok->astString(" ") << std::endl;
1736  if (tok->str() == "(")
1737  tok = tok->link();
1738  }
1739  }
1740 }
1741 
1742 static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
1743 {
1744  for (int i = 0; i < indent1; ++i)
1745  str += ' ';
1746  for (int i = indent1; i < indent2; i += 2)
1747  str += "| ";
1748 }
1749 
1750 void Token::astStringVerboseRecursive(std::string& ret, const nonneg int indent1, const nonneg int indent2) const
1751 {
1752  if (isExpandedMacro())
1753  ret += '$';
1754  ret += mStr;
1755  if (mImpl->mValueType)
1756  ret += " \'" + mImpl->mValueType->str() + '\'';
1757  if (function()) {
1758  std::ostringstream ostr;
1759  ostr << std::hex << function();
1760  ret += " f:" + ostr.str();
1761  }
1762  ret += '\n';
1763 
1764  if (mImpl->mAstOperand1) {
1765  int i1 = indent1, i2 = indent2 + 2;
1766  if (indent1 == indent2 && !mImpl->mAstOperand2)
1767  i1 += 2;
1768  indent(ret, indent1, indent2);
1769  ret += mImpl->mAstOperand2 ? "|-" : "`-";
1770  mImpl->mAstOperand1->astStringVerboseRecursive(ret, i1, i2);
1771  }
1772  if (mImpl->mAstOperand2) {
1773  int i1 = indent1, i2 = indent2 + 2;
1774  if (indent1 == indent2)
1775  i1 += 2;
1776  indent(ret, indent1, indent2);
1777  ret += "`-";
1778  mImpl->mAstOperand2->astStringVerboseRecursive(ret, i1, i2);
1779  }
1780 }
1781 
1782 std::string Token::astStringVerbose() const
1783 {
1784  std::string ret;
1786  return ret;
1787 }
1788 
1789 std::string Token::astStringZ3() const
1790 {
1791  if (!astOperand1())
1792  return str();
1793  if (!astOperand2())
1794  return "(" + str() + " " + astOperand1()->astStringZ3() + ")";
1795  return "(" + str() + " " + astOperand1()->astStringZ3() + " " + astOperand2()->astStringZ3() + ")";
1796 }
1797 
1798 void Token::printValueFlow(bool xml, std::ostream &out) const
1799 {
1800  std::string outs;
1801 
1802  // cppcheck-suppress shadowFunction
1803  int fileIndex = -1;
1804  int line = 0;
1805  if (xml)
1806  outs += " <valueflow>\n";
1807  else
1808  outs += "\n\n##Value flow\n";
1809  for (const Token *tok = this; tok; tok = tok->next()) {
1810  // cppcheck-suppress shadowFunction - TODO: fix this
1811  const auto* const values = tok->mImpl->mValues;
1812  if (!values)
1813  continue;
1814  if (values->empty()) // Values might be removed by removeContradictions
1815  continue;
1816  if (xml) {
1817  outs += " <values id=\"";
1818  outs += id_string(values);
1819  outs += "\">";
1820  outs += '\n';
1821  }
1822  else {
1823  if (fileIndex != tok->fileIndex()) {
1824  outs += "File ";
1825  outs += tok->mTokensFrontBack.list.getFiles()[tok->fileIndex()];
1826  outs += '\n';
1827  line = 0;
1828  }
1829  if (line != tok->linenr()) {
1830  outs += "Line ";
1831  outs += std::to_string(tok->linenr());
1832  outs += '\n';
1833  }
1834  }
1835  fileIndex = tok->fileIndex();
1836  line = tok->linenr();
1837  if (!xml) {
1838  ValueFlow::Value::ValueKind valueKind = values->front().valueKind;
1839  const bool same = std::all_of(values->begin(), values->end(), [&](const ValueFlow::Value& value) {
1840  return value.valueKind == valueKind;
1841  });
1842  outs += " ";
1843  outs += tok->str();
1844  outs += " ";
1845  if (same) {
1846  switch (valueKind) {
1849  outs += "always ";
1850  break;
1852  outs += "inconclusive ";
1853  break;
1855  outs += "possible ";
1856  break;
1857  }
1858  }
1859  if (values->size() > 1U)
1860  outs += '{';
1861  }
1862  for (const ValueFlow::Value& value : *values) {
1863  if (xml) {
1864  outs += " <value ";
1865  switch (value.valueType) {
1867  if (tok->valueType() && tok->valueType()->sign == ValueType::UNSIGNED) {
1868  outs += "intvalue=\"";
1869  outs += std::to_string(static_cast<MathLib::biguint>(value.intvalue));
1870  outs += '\"';
1871  }
1872  else {
1873  outs += "intvalue=\"";
1874  outs += std::to_string(value.intvalue);
1875  outs += '\"';
1876  }
1877  break;
1879  outs += "tokvalue=\"";
1880  outs += id_string(value.tokvalue);
1881  outs += '\"';
1882  break;
1884  outs += "floatvalue=\"";
1885  outs += std::to_string(value.floatValue); // TODO: should this be MathLib::toString()?
1886  outs += '\"';
1887  break;
1889  outs += "movedvalue=\"";
1890  outs += ValueFlow::Value::toString(value.moveKind);
1891  outs += '\"';
1892  break;
1894  outs += "uninit=\"1\"";
1895  break;
1897  outs += "buffer-size=\"";
1898  outs += std::to_string(value.intvalue);
1899  outs += "\"";
1900  break;
1902  outs += "container-size=\"";
1903  outs += std::to_string(value.intvalue);
1904  outs += '\"';
1905  break;
1907  outs += "iterator-start=\"";
1908  outs += std::to_string(value.intvalue);
1909  outs += '\"';
1910  break;
1912  outs += "iterator-end=\"";
1913  outs += std::to_string(value.intvalue);
1914  outs += '\"';
1915  break;
1917  outs += "lifetime=\"";
1918  outs += id_string(value.tokvalue);
1919  outs += '\"';
1920  outs += " lifetime-scope=\"";
1921  outs += ValueFlow::Value::toString(value.lifetimeScope);
1922  outs += "\"";
1923  outs += " lifetime-kind=\"";
1924  outs += ValueFlow::Value::toString(value.lifetimeKind);
1925  outs += "\"";
1926  break;
1928  outs += "symbolic=\"";
1929  outs += id_string(value.tokvalue);
1930  outs += '\"';
1931  outs += " symbolic-delta=\"";
1932  outs += std::to_string(value.intvalue);
1933  outs += '\"';
1934  break;
1935  }
1936  outs += " bound=\"";
1937  outs += ValueFlow::Value::toString(value.bound);
1938  outs += "\"";
1939  if (value.condition) {
1940  outs += " condition-line=\"";
1941  outs += std::to_string(value.condition->linenr());
1942  outs += '\"';
1943  }
1944  if (value.isKnown())
1945  outs += " known=\"true\"";
1946  else if (value.isPossible())
1947  outs += " possible=\"true\"";
1948  else if (value.isImpossible())
1949  outs += " impossible=\"true\"";
1950  else if (value.isInconclusive())
1951  outs += " inconclusive=\"true\"";
1952 
1953  outs += " path=\"";
1954  outs += std::to_string(value.path);
1955  outs += "\"";
1956 
1957  outs += "/>\n";
1958  }
1959 
1960  else {
1961  if (&value != &values->front())
1962  outs += ",";
1963  outs += value.toString();
1964  }
1965  }
1966  if (xml)
1967  outs += " </values>\n";
1968  else if (values->size() > 1U)
1969  outs += "}\n";
1970  else
1971  outs += '\n';
1972  }
1973  if (xml)
1974  outs += " </valueflow>\n";
1975 
1976  out << outs;
1977 }
1978 
1979 const ValueFlow::Value * Token::getValueLE(const MathLib::bigint val, const Settings *settings) const
1980 {
1981  if (!mImpl->mValues)
1982  return nullptr;
1983  return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) {
1984  return !v.isImpossible() && v.isIntValue() && v.intvalue <= val;
1985  });
1986 }
1987 
1988 const ValueFlow::Value * Token::getValueGE(const MathLib::bigint val, const Settings *settings) const
1989 {
1990  if (!mImpl->mValues)
1991  return nullptr;
1992  return ValueFlow::findValue(*mImpl->mValues, settings, [&](const ValueFlow::Value& v) {
1993  return !v.isImpossible() && v.isIntValue() && v.intvalue >= val;
1994  });
1995 }
1996 
1997 const ValueFlow::Value * Token::getInvalidValue(const Token *ftok, nonneg int argnr, const Settings *settings) const
1998 {
1999  if (!mImpl->mValues || !settings)
2000  return nullptr;
2001  const ValueFlow::Value *ret = nullptr;
2002  for (std::list<ValueFlow::Value>::const_iterator it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2003  if (it->isImpossible())
2004  continue;
2005  if ((it->isIntValue() && !settings->library.isIntArgValid(ftok, argnr, it->intvalue)) ||
2006  (it->isFloatValue() && !settings->library.isFloatArgValid(ftok, argnr, it->floatValue))) {
2007  if (!ret || ret->isInconclusive() || (ret->condition && !it->isInconclusive()))
2008  ret = &(*it);
2009  if (!ret->isInconclusive() && !ret->condition)
2010  break;
2011  }
2012  }
2013  if (ret) {
2014  if (ret->isInconclusive() && !settings->certainty.isEnabled(Certainty::inconclusive))
2015  return nullptr;
2016  if (ret->condition && !settings->severity.isEnabled(Severity::warning))
2017  return nullptr;
2018  }
2019  return ret;
2020 }
2021 
2022 const Token *Token::getValueTokenMinStrSize(const Settings &settings, MathLib::bigint* path) const
2023 {
2024  if (!mImpl->mValues)
2025  return nullptr;
2026  const Token *ret = nullptr;
2027  int minsize = INT_MAX;
2028  for (std::list<ValueFlow::Value>::const_iterator it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2029  if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) {
2030  const int size = getStrSize(it->tokvalue, settings);
2031  if (!ret || size < minsize) {
2032  minsize = size;
2033  ret = it->tokvalue;
2034  if (path)
2035  *path = it->path;
2036  }
2037  }
2038  }
2039  return ret;
2040 }
2041 
2043 {
2044  if (!mImpl->mValues)
2045  return nullptr;
2046  const Token *ret = nullptr;
2047  int maxlength = 0;
2048  for (std::list<ValueFlow::Value>::const_iterator it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2049  if (it->isTokValue() && it->tokvalue && it->tokvalue->tokType() == Token::eString) {
2050  const int length = getStrLength(it->tokvalue);
2051  if (!ret || length > maxlength) {
2052  maxlength = length;
2053  ret = it->tokvalue;
2054  }
2055  }
2056  }
2057  return ret;
2058 }
2059 
2060 static bool isAdjacent(const ValueFlow::Value& x, const ValueFlow::Value& y)
2061 {
2062  if (x.bound != ValueFlow::Value::Bound::Point && x.bound == y.bound)
2063  return true;
2065  return false;
2066  return std::abs(x.intvalue - y.intvalue) == 1;
2067 }
2068 
2069 static bool removePointValue(std::list<ValueFlow::Value>& values, std::list<ValueFlow::Value>::iterator& x)
2070 {
2071  const bool isPoint = x->bound == ValueFlow::Value::Bound::Point;
2072  if (!isPoint)
2073  x->decreaseRange();
2074  else
2075  x = values.erase(x);
2076  return isPoint;
2077 }
2078 
2079 static bool removeContradiction(std::list<ValueFlow::Value>& values)
2080 {
2081  bool result = false;
2082  for (auto itx = values.begin(); itx != values.end(); ++itx) {
2083  if (itx->isNonValue())
2084  continue;
2085 
2086  auto ity = itx;
2087  ++ity;
2088  for (; ity != values.end(); ++ity) {
2089  if (ity->isNonValue())
2090  continue;
2091  if (*itx == *ity)
2092  continue;
2093  if (itx->valueType != ity->valueType)
2094  continue;
2095  if (itx->isImpossible() == ity->isImpossible())
2096  continue;
2097  if (itx->isSymbolicValue() && !ValueFlow::Value::sameToken(itx->tokvalue, ity->tokvalue))
2098  continue;
2099  if (!itx->equalValue(*ity)) {
2100  auto compare = [](const std::list<ValueFlow::Value>::const_iterator& x, const std::list<ValueFlow::Value>::const_iterator& y) {
2101  return x->compareValue(*y, less{});
2102  };
2103  auto itMax = std::max(itx, ity, compare);
2104  auto itMin = std::min(itx, ity, compare);
2105  // TODO: Adjust non-points instead of removing them
2106  if (itMax->isImpossible() && itMax->bound == ValueFlow::Value::Bound::Upper) {
2107  values.erase(itMin);
2108  return true;
2109  }
2110  if (itMin->isImpossible() && itMin->bound == ValueFlow::Value::Bound::Lower) {
2111  values.erase(itMax);
2112  return true;
2113  }
2114  continue;
2115  }
2116  const bool removex = !itx->isImpossible() || ity->isKnown();
2117  const bool removey = !ity->isImpossible() || itx->isKnown();
2118  if (itx->bound == ity->bound) {
2119  if (removex)
2120  values.erase(itx);
2121  if (removey)
2122  values.erase(ity);
2123  // itx and ity are invalidated
2124  return true;
2125  }
2126  result = removex || removey;
2127  bool bail = false;
2128  if (removex && removePointValue(values, itx))
2129  bail = true;
2130  if (removey && removePointValue(values, ity))
2131  bail = true;
2132  if (bail)
2133  return true;
2134  }
2135  }
2136  return result;
2137 }
2138 
2139 using ValueIterator = std::list<ValueFlow::Value>::iterator;
2140 
2141 template<class Iterator>
2142 static ValueIterator removeAdjacentValues(std::list<ValueFlow::Value>& values, ValueIterator x, Iterator start, Iterator last)
2143 {
2144  if (!isAdjacent(*x, **start))
2145  return std::next(x);
2146  auto it = std::adjacent_find(start, last, [](ValueIterator x, ValueIterator y) {
2147  return !isAdjacent(*x, *y);
2148  });
2149  if (it == last)
2150  it--;
2151  (*it)->bound = x->bound;
2152  std::for_each(std::move(start), std::move(it), [&](ValueIterator y) {
2153  values.erase(y);
2154  });
2155  return values.erase(x);
2156 }
2157 
2158 static void mergeAdjacent(std::list<ValueFlow::Value>& values)
2159 {
2160  for (auto x = values.begin(); x != values.end();) {
2161  if (x->isNonValue()) {
2162  x++;
2163  continue;
2164  }
2165  if (x->bound == ValueFlow::Value::Bound::Point) {
2166  x++;
2167  continue;
2168  }
2169  std::vector<ValueIterator> adjValues;
2170  for (auto y = values.begin(); y != values.end(); y++) {
2171  if (x == y)
2172  continue;
2173  if (y->isNonValue())
2174  continue;
2175  if (x->valueType != y->valueType)
2176  continue;
2177  if (x->valueKind != y->valueKind)
2178  continue;
2179  if (x->isSymbolicValue() && !ValueFlow::Value::sameToken(x->tokvalue, y->tokvalue))
2180  continue;
2181  if (x->bound != y->bound) {
2182  if (y->bound != ValueFlow::Value::Bound::Point && isAdjacent(*x, *y)) {
2183  adjValues.clear();
2184  break;
2185  }
2186  // No adjacent points for floating points
2187  if (x->valueType == ValueFlow::Value::ValueType::FLOAT)
2188  continue;
2189  if (y->bound != ValueFlow::Value::Bound::Point)
2190  continue;
2191  }
2192  if (x->bound == ValueFlow::Value::Bound::Lower && !y->compareValue(*x, less{}))
2193  continue;
2194  if (x->bound == ValueFlow::Value::Bound::Upper && !x->compareValue(*y, less{}))
2195  continue;
2196  adjValues.push_back(y);
2197  }
2198  if (adjValues.empty()) {
2199  x++;
2200  continue;
2201  }
2202  std::sort(adjValues.begin(), adjValues.end(), [&values](ValueIterator xx, ValueIterator yy) {
2203  (void)values;
2204  assert(xx != values.end() && yy != values.end());
2205  return xx->compareValue(*yy, less{});
2206  });
2207  if (x->bound == ValueFlow::Value::Bound::Lower)
2208  x = removeAdjacentValues(values, x, adjValues.rbegin(), adjValues.rend());
2209  else if (x->bound == ValueFlow::Value::Bound::Upper)
2210  x = removeAdjacentValues(values, x, adjValues.begin(), adjValues.end());
2211  }
2212 }
2213 
2214 static void removeOverlaps(std::list<ValueFlow::Value>& values)
2215 {
2216  for (const ValueFlow::Value& x : values) {
2217  if (x.isNonValue())
2218  continue;
2219  values.remove_if([&](const ValueFlow::Value& y) {
2220  if (y.isNonValue())
2221  return false;
2222  if (&x == &y)
2223  return false;
2224  if (x.valueType != y.valueType)
2225  return false;
2226  if (x.valueKind != y.valueKind)
2227  return false;
2228  // TODO: Remove points covered in a lower or upper bound
2229  // TODO: Remove lower or upper bound already covered by a lower and upper bound
2230  if (!x.equalValue(y))
2231  return false;
2232  if (x.bound != y.bound)
2233  return false;
2234  return true;
2235  });
2236  }
2237  mergeAdjacent(values);
2238 }
2239 
2240 // Removing contradictions is an NP-hard problem. Instead we run multiple
2241 // passes to try to catch most contradictions
2242 static void removeContradictions(std::list<ValueFlow::Value>& values)
2243 {
2244  removeOverlaps(values);
2245  for (int i = 0; i < 4; i++) {
2246  if (!removeContradiction(values))
2247  return;
2248  removeOverlaps(values);
2249  }
2250 }
2251 
2252 static bool sameValueType(const ValueFlow::Value& x, const ValueFlow::Value& y)
2253 {
2254  if (x.valueType != y.valueType)
2255  return false;
2256  // Symbolic are the same type if they share the same tokvalue
2257  if (x.isSymbolicValue())
2258  return x.tokvalue->exprId() == 0 || x.tokvalue->exprId() == y.tokvalue->exprId();
2259  return true;
2260 }
2261 
2263 {
2264  if (value.isKnown() && mImpl->mValues) {
2265  // Clear all other values of the same type since value is known
2266  mImpl->mValues->remove_if([&](const ValueFlow::Value& x) {
2267  return sameValueType(x, value);
2268  });
2269  }
2270 
2271  // Don't add a value if its already known
2272  if (!value.isKnown() && mImpl->mValues &&
2273  std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& x) {
2274  return x.isKnown() && sameValueType(x, value) && !x.equalValue(value);
2275  }))
2276  return false;
2277 
2278  // assert(value.isKnown() || !mImpl->mValues || std::none_of(mImpl->mValues->begin(), mImpl->mValues->end(),
2279  // [&](const ValueFlow::Value& x) {
2280  // return x.isKnown() && sameValueType(x, value);
2281  // }));
2282 
2283  if (mImpl->mValues) {
2284  // Don't handle more than 10 values for performance reasons
2285  // TODO: add setting?
2286  if (mImpl->mValues->size() >= 10U)
2287  return false;
2288 
2289  // if value already exists, don't add it again
2290  std::list<ValueFlow::Value>::iterator it;
2291  for (it = mImpl->mValues->begin(); it != mImpl->mValues->end(); ++it) {
2292  // different types => continue
2293  if (it->valueType != value.valueType)
2294  continue;
2295 
2296  if (it->isImpossible() != value.isImpossible())
2297  continue;
2298 
2299  // different value => continue
2300  if (!it->equalValue(value))
2301  continue;
2302 
2303  if ((value.isTokValue() || value.isLifetimeValue()) && (it->tokvalue != value.tokvalue) && (it->tokvalue->str() != value.tokvalue->str()))
2304  continue;
2305 
2306  // same value, but old value is inconclusive so replace it
2307  if (it->isInconclusive() && !value.isInconclusive() && !value.isImpossible()) {
2308  *it = value;
2309  if (it->varId == 0)
2310  it->varId = mImpl->mVarId;
2311  break;
2312  }
2313 
2314  // Same value already exists, don't add new value
2315  return false;
2316  }
2317 
2318  // Add value
2319  if (it == mImpl->mValues->end()) {
2320  ValueFlow::Value v(value);
2321  if (v.varId == 0)
2322  v.varId = mImpl->mVarId;
2323  if (v.isKnown() && v.isIntValue())
2324  mImpl->mValues->push_front(std::move(v));
2325  else
2326  mImpl->mValues->push_back(std::move(v));
2327  }
2328  } else {
2329  ValueFlow::Value v(value);
2330  if (v.varId == 0)
2331  v.varId = mImpl->mVarId;
2332  mImpl->mValues = new std::list<ValueFlow::Value>;
2333  mImpl->mValues->push_back(std::move(v));
2334  }
2335 
2337 
2338  return true;
2339 }
2340 
2342 {
2343  int total_count = 0;
2344  for (Token *tok2 = tok; tok2; tok2 = tok2->next())
2345  ++total_count;
2346  int count = 0;
2347  for (Token *tok2 = tok; tok2; tok2 = tok2->next())
2348  tok2->mImpl->mProgressValue = count++ *100 / total_count;
2349 }
2350 
2352 {
2353  // cppcheck-suppress shadowFunction - TODO: fix this
2354  int index = (mPrevious ? mPrevious->mImpl->mIndex : 0) + 1;
2355  for (Token *tok = this; tok; tok = tok->next())
2356  tok->mImpl->mIndex = index++;
2357 }
2358 
2360 {
2361  if (vt != mImpl->mValueType) {
2362  delete mImpl->mValueType;
2363  mImpl->mValueType = vt;
2364  }
2365 }
2366 
2367 void Token::type(const ::Type *t)
2368 {
2369  mImpl->mType = t;
2370  if (t) {
2371  tokType(eType);
2373  } else if (mTokType == eType)
2374  tokType(eName);
2375 }
2376 
2377 const ::Type* Token::typeOf(const Token* tok, const Token** typeTok)
2378 {
2379  if (!tok)
2380  return nullptr;
2381  if (typeTok != nullptr)
2382  *typeTok = tok;
2383  const Token* lhsVarTok{};
2384  if (tok->type())
2385  return tok->type();
2386  if (tok->variable())
2387  return tok->variable()->type();
2388  if (tok->function())
2389  return tok->function()->retType;
2390  if (Token::simpleMatch(tok, "return")) {
2391  // cppcheck-suppress shadowFunction - TODO: fix this
2392  const Scope *scope = tok->scope();
2393  if (!scope)
2394  return nullptr;
2395  // cppcheck-suppress shadowFunction - TODO: fix this
2396  const Function *function = scope->function;
2397  if (!function)
2398  return nullptr;
2399  return function->retType;
2400  }
2401  if (Token::Match(tok->previous(), "%type%|= (|{"))
2402  return typeOf(tok->previous(), typeTok);
2403  if (Token::simpleMatch(tok, "=") && (lhsVarTok = getLHSVariableToken(tok)) != tok->next())
2404  return Token::typeOf(lhsVarTok, typeTok);
2405  if (Token::simpleMatch(tok, "."))
2406  return Token::typeOf(tok->astOperand2(), typeTok);
2407  if (Token::simpleMatch(tok, "["))
2408  return Token::typeOf(tok->astOperand1(), typeTok);
2409  if (Token::simpleMatch(tok, "{")) {
2410  int argnr;
2411  const Token* ftok = getTokenArgumentFunction(tok, argnr);
2412  if (argnr < 0)
2413  return nullptr;
2414  if (!ftok)
2415  return nullptr;
2416  if (ftok == tok)
2417  return nullptr;
2418  std::vector<const Variable*> vars = getArgumentVars(ftok, argnr);
2419  if (vars.empty())
2420  return nullptr;
2421  if (std::all_of(
2422  vars.cbegin(), vars.cend(), [&](const Variable* var) {
2423  return var->type() == vars.front()->type();
2424  }))
2425  return vars.front()->type();
2426  }
2427 
2428  return nullptr;
2429 }
2430 
2431 std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool pointedToType)
2432 {
2433  if (!tok)
2434  return {};
2435  if (tok->type())
2436  return {tok, tok->next()};
2437  if (tok->variable()) {
2438  const Variable *var = tok->variable();
2439  if (!var->typeStartToken() || !var->typeEndToken())
2440  return {};
2441  if (pointedToType && astIsSmartPointer(var->nameToken())) {
2442  const ValueType* vt = var->valueType();
2443  if (vt && vt->smartPointerTypeToken)
2444  return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
2445  }
2446  if (pointedToType && astIsIterator(var->nameToken())) {
2447  const ValueType* vt = var->valueType();
2448  if (vt && vt->containerTypeToken)
2449  return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2450  }
2451  std::pair<const Token*, const Token*> result;
2452  if (Token::simpleMatch(var->typeStartToken(), "auto")) {
2453  const Token * tok2 = var->declEndToken();
2454  if (Token::Match(tok2, "; %varid% =", var->declarationId()))
2455  tok2 = tok2->tokAt(2);
2456  if (Token::simpleMatch(tok2, "=") && Token::Match(tok2->astOperand2(), "!!=") && tok != tok2->astOperand2()) {
2457  tok2 = tok2->astOperand2();
2458 
2459  if (Token::simpleMatch(tok2, "[") && tok2->astOperand1()) {
2460  const ValueType* vt = tok2->astOperand1()->valueType();
2461  if (vt && vt->containerTypeToken)
2462  return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2463  }
2464 
2465  const Token* varTok = tok2; // try to find a variable
2466  if (Token::Match(varTok, ":: %name%"))
2467  varTok = varTok->next();
2468  while (Token::Match(varTok, "%name% ::"))
2469  varTok = varTok->tokAt(2);
2470  std::pair<const Token*, const Token*> r = typeDecl(varTok);
2471  if (r.first)
2472  return r;
2473 
2474  if (pointedToType && tok2->astOperand1() && Token::simpleMatch(tok2, "new")) {
2475  if (Token::simpleMatch(tok2->astOperand1(), "("))
2476  return { tok2->next(), tok2->astOperand1() };
2477  const Token* declEnd = nextAfterAstRightmostLeaf(tok2->astOperand1());
2478  if (Token::simpleMatch(declEnd, "<") && declEnd->link())
2479  declEnd = declEnd->link()->next();
2480  return { tok2->next(), declEnd };
2481  }
2482  const Token *typeBeg{}, *typeEnd{};
2483  if (tok2->str() == "::" && Token::simpleMatch(tok2->astOperand2(), "{")) { // empty initlist
2484  typeBeg = previousBeforeAstLeftmostLeaf(tok2);
2485  typeEnd = tok2->astOperand2();
2486  }
2487  else if (tok2->str() == "{") {
2488  typeBeg = previousBeforeAstLeftmostLeaf(tok2);
2489  typeEnd = tok2;
2490  }
2491  if (typeBeg)
2492  result = { typeBeg->next(), typeEnd }; // handle smart pointers/iterators first
2493  }
2494  if (astIsRangeBasedForDecl(var->nameToken()) && astIsContainer(var->nameToken()->astParent()->astOperand2())) { // range-based for
2495  const ValueType* vt = var->nameToken()->astParent()->astOperand2()->valueType();
2496  if (vt && vt->containerTypeToken)
2497  return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2498  }
2499  }
2500  if (result.first)
2501  return result;
2502  return {var->typeStartToken(), var->typeEndToken()->next()};
2503  }
2504  if (Token::simpleMatch(tok, "return")) {
2505  // cppcheck-suppress shadowFunction - TODO: fix this
2506  const Scope* scope = tok->scope();
2507  if (!scope)
2508  return {};
2509  // cppcheck-suppress shadowFunction - TODO: fix this
2510  const Function* function = scope->function;
2511  if (!function)
2512  return {};
2513  return { function->retDef, function->returnDefEnd() };
2514  }
2515  if (tok->previous() && tok->previous()->function()) {
2516  // cppcheck-suppress shadowFunction - TODO: fix this
2517  const Function *function = tok->previous()->function();
2518  return {function->retDef, function->returnDefEnd()};
2519  }
2520  if (Token::simpleMatch(tok, "="))
2521  return Token::typeDecl(tok->astOperand1());
2522  if (Token::simpleMatch(tok, "."))
2523  return Token::typeDecl(tok->astOperand2());
2524 
2525  const ::Type * t = typeOf(tok);
2526  if (!t || !t->classDef)
2527  return {};
2528  return {t->classDef->next(), t->classDef->tokAt(2)};
2529 }
2530 std::string Token::typeStr(const Token* tok)
2531 {
2532  if (tok->valueType()) {
2533  const ValueType * vt = tok->valueType();
2534  std::string ret = vt->str();
2535  if (!ret.empty())
2536  return ret;
2537  }
2538  std::pair<const Token*, const Token*> r = Token::typeDecl(tok);
2539  if (!r.first || !r.second)
2540  return "";
2541  return r.first->stringifyList(r.second, false);
2542 }
2543 
2544 void Token::scopeInfo(std::shared_ptr<ScopeInfo2> newScopeInfo)
2545 {
2546  mImpl->mScopeInfo = std::move(newScopeInfo);
2547 }
2548 std::shared_ptr<ScopeInfo2> Token::scopeInfo() const
2549 {
2550  return mImpl->mScopeInfo;
2551 }
2552 
2554 {
2555  if (!mImpl->mValues)
2556  return false;
2557  return std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) {
2558  return value.isKnown() && value.isIntValue();
2559  });
2560 }
2561 
2563 {
2564  return mImpl->mValues && std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), std::mem_fn(&ValueFlow::Value::isKnown));
2565 }
2566 
2568 {
2569  return mImpl->mValues &&
2570  std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2571  return value.isKnown() && value.valueType == t;
2572  });
2573 }
2574 
2575 bool Token::hasKnownSymbolicValue(const Token* tok) const
2576 {
2577  if (tok->exprId() == 0)
2578  return false;
2579  return mImpl->mValues &&
2580  std::any_of(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2581  return value.isKnown() && value.isSymbolicValue() && value.tokvalue &&
2582  value.tokvalue->exprId() == tok->exprId();
2583  });
2584 }
2585 
2587 {
2588  if (!mImpl->mValues)
2589  return nullptr;
2590  auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [&](const ValueFlow::Value& value) {
2591  return value.isKnown() && value.valueType == t;
2592  });
2593  return it == mImpl->mValues->end() ? nullptr : &*it;
2594 }
2595 
2597 {
2598  if (!mImpl->mValues)
2599  return nullptr;
2600  const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) {
2601  return value.isIntValue() && !value.isImpossible() && value.intvalue == val;
2602  });
2603  return it == mImpl->mValues->end() ? nullptr : &*it;
2604 }
2605 
2606 template<class Compare>
2607 static const ValueFlow::Value* getCompareValue(const std::list<ValueFlow::Value>& values,
2608  bool condition,
2609  MathLib::bigint path,
2610  Compare compare)
2611 {
2612  const ValueFlow::Value* ret = nullptr;
2613  for (const ValueFlow::Value& value : values) {
2614  if (!value.isIntValue())
2615  continue;
2616  if (value.isImpossible())
2617  continue;
2618  if (path > -0 && value.path != 0 && value.path != path)
2619  continue;
2620  if ((!ret || compare(value.intvalue, ret->intvalue)) && ((value.condition != nullptr) == condition))
2621  ret = &value;
2622  }
2623  return ret;
2624 }
2625 
2626 const ValueFlow::Value* Token::getMaxValue(bool condition, MathLib::bigint path) const
2627 {
2628  if (!mImpl->mValues)
2629  return nullptr;
2630  return getCompareValue(*mImpl->mValues, condition, path, std::greater<MathLib::bigint>{});
2631 }
2632 
2633 const ValueFlow::Value* Token::getMinValue(bool condition, MathLib::bigint path) const
2634 {
2635  if (!mImpl->mValues)
2636  return nullptr;
2637  return getCompareValue(*mImpl->mValues, condition, path, std::less<MathLib::bigint>{});
2638 }
2639 
2641 {
2642  if (!mImpl->mValues)
2643  return nullptr;
2644  const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [](const ValueFlow::Value& value) {
2645  return value.isMovedValue() && !value.isImpossible() &&
2646  value.moveKind != ValueFlow::Value::MoveKind::NonMovedVariable;
2647  });
2648  return it == mImpl->mValues->end() ? nullptr : &*it;
2649 }
2650 
2651 // cppcheck-suppress unusedFunction
2653 {
2654  if (!mImpl->mValues)
2655  return nullptr;
2656  const auto it = std::find_if(mImpl->mValues->begin(), mImpl->mValues->end(), [=](const ValueFlow::Value& value) {
2657  return value.isContainerSizeValue() && !value.isImpossible() && value.intvalue == val;
2658  });
2659  return it == mImpl->mValues->end() ? nullptr : &*it;
2660 }
2661 
2663 {
2664  delete mOriginalName;
2665  delete mValueType;
2666  delete mValues;
2667 
2669  for (auto *templateSimplifierPointer : *mTemplateSimplifierPointers) {
2670  templateSimplifierPointer->token(nullptr);
2671  }
2672  }
2674 
2675  while (mCppcheckAttributes) {
2678  delete c;
2679  }
2680 }
2681 
2683 {
2685  while (attr && attr->type != type)
2686  attr = attr->next;
2687  if (attr)
2688  attr->value = value;
2689  else {
2690  attr = new CppcheckAttributes;
2691  attr->type = type;
2692  attr->value = value;
2693  attr->next = mCppcheckAttributes;
2694  mCppcheckAttributes = attr;
2695  }
2696 }
2697 
2699 {
2701  while (attr && attr->type != type)
2702  attr = attr->next;
2703  if (attr)
2704  value = attr->value;
2705  return attr != nullptr;
2706 }
2707 
2709 {
2710  while (Token::Match(tok, "%name%|.|::|*|&|&&|<|(|template|decltype|sizeof")) {
2711  if (Token::Match(tok, "(|<"))
2712  tok = tok->link();
2713  if (!tok)
2714  return nullptr;
2715  tok = tok->next();
2716  }
2717  return tok;
2718 }
2719 
2721 {
2722  if (!Token::simpleMatch(tok, "["))
2723  return nullptr;
2724  tok = tok->link();
2725  if (!Token::Match(tok, "] (|{"))
2726  return nullptr;
2727  tok = tok->linkAt(1);
2728  if (Token::simpleMatch(tok, "}"))
2729  return tok;
2730  if (Token::simpleMatch(tok, ") {"))
2731  return tok->linkAt(1);
2732  if (!Token::simpleMatch(tok, ")"))
2733  return nullptr;
2734  tok = tok->next();
2735  while (Token::Match(tok, "mutable|constexpr|consteval|noexcept|.")) {
2736  if (Token::simpleMatch(tok, "noexcept ("))
2737  tok = tok->linkAt(1);
2738  if (Token::simpleMatch(tok, ".")) {
2739  tok = findTypeEnd(tok);
2740  break;
2741  }
2742  tok = tok->next();
2743  }
2744  if (Token::simpleMatch(tok, "{"))
2745  return tok->link();
2746  return nullptr;
2747 }
2748 const Token* findLambdaEndScope(const Token* tok) {
2749  return findLambdaEndScope(const_cast<Token*>(tok));
2750 }
2751 
2752 bool Token::isCpp() const
2753 {
2754  return mTokensFrontBack.list.isCPP();
2755 }
2756 
2757 bool Token::isC() const
2758 {
2759  return mTokensFrontBack.list.isC();
2760 }
bool astIsContainer(const Token *tok)
Definition: astutils.cpp:244
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:982
const Token * getTokenArgumentFunction(const Token *tok, int &argn)
Return the token to the function and the argument number.
Definition: astutils.cpp:2350
bool astIsSmartPointer(const Token *tok)
Definition: astutils.cpp:225
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
Definition: astutils.cpp:3186
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
bool astIsIterator(const Token *tok)
Definition: astutils.cpp:239
const Token * previousBeforeAstLeftmostLeaf(const Token *tok)
Definition: astutils.cpp:514
std::vector< const Variable * > getArgumentVars(const Token *tok, int argnr)
Definition: astutils.cpp:2358
const Token * getLHSVariableToken(const Token *tok)
Definition: astutils.cpp:3462
bool succeeds(const Token *tok1, const Token *tok2)
If tok1 comes after tok2.
Definition: astutils.cpp:994
bool isLambda() const
const Token * retDef
function return type token
const ::Type * retType
function return type
bool isFloatArgValid(const Token *ftok, int argnr, double argvalue) const
Definition: library.cpp:946
bool isIntArgValid(const Token *ftok, int argnr, const MathLib::bigint argvalue) const
Definition: library.cpp:924
long long bigint
Definition: mathlib.h:68
static bool isFloat(const std::string &str)
Definition: mathlib.cpp:535
static bool isInt(const std::string &str)
Definition: mathlib.cpp:1007
unsigned long long biguint
Definition: mathlib.h:69
Function * function
function info for this function
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
SimpleEnableGroup< Certainty > certainty
Definition: settings.h:356
SimpleEnableGroup< Severity > severity
Definition: settings.h:355
bool isEnabled(T flag) const
Definition: settings.h:66
bool isC() const
bool isKeyword(const std::string &str) const
bool isCPP() const
const std::vector< std::string > & getFiles() const
Get filenames (the sourcefile + the files it include).
Definition: tokenlist.h:141
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
Token(const Token &)=delete
std::string mStr
Definition: token.h:1279
void update_property_info()
Updates internal property cache like _isName or _isBoolean.
Definition: token.cpp:135
nonneg int index() const
Definition: token.h:1247
const ValueFlow::Value * getMovedValue() const
Definition: token.cpp:2640
Token * astTop()
Definition: token.h:1416
bool hasKnownValue() const
Definition: token.cpp:2562
const ValueFlow::Value * getValue(const MathLib::bigint val) const
Definition: token.cpp:2596
const ValueFlow::Value * getContainerSizeValue(const MathLib::bigint val) const
Definition: token.cpp:2652
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
static bool firstWordEquals(const char *str, const char *word)
Works almost like strcmp() except returns only true or false and if str has empty space ' ' character...
Definition: token.cpp:694
Token::Type mTokType
Definition: token.h:1336
void deleteThis()
Remove the contents for this token from the token list.
Definition: token.cpp:363
nonneg int exprId() const
Definition: token.h:883
void takeData(Token *fromToken)
used by deleteThis() to take data from token to delete
Definition: token.cpp:345
bool isC() const
Definition: token.cpp:2757
bool isCChar() const
Definition: token.h:722
uint64_t mFlags
Definition: token.h:1338
void setMacroName(std::string name)
Definition: token.h:758
void printLines(int lines=5) const
print out tokens - used for debugging
Definition: token.cpp:1306
const std::string & originalName() const
Definition: token.h:1193
bool isName() const
Definition: token.h:361
void printOut(const char *title=nullptr) const
For debugging purposes, prints token and all tokens followed by it.
Definition: token.cpp:1291
Token * astOperand1()
Definition: token.h:1378
const ValueFlow::Value * getMinValue(bool condition, MathLib::bigint path=0) const
Definition: token.cpp:2633
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
Definition: token.cpp:1099
std::string stringify(const stringifyOptions &options) const
Definition: token.cpp:1314
bool addValue(const ValueFlow::Value &value)
Add token value.
Definition: token.cpp:2262
std::string astStringZ3() const
Definition: token.cpp:1789
static int multiCompare(const Token *tok, const char *haystack, nonneg int varid)
Needle is build from multiple alternatives.
Definition: token.cpp:660
bool isUnsigned() const
Definition: token.h:424
bool hasKnownIntValue() const
Definition: token.cpp:2553
const ValueFlow::Value * getMaxValue(bool condition, MathLib::bigint path=0) const
Definition: token.cpp:2626
static void replace(Token *replaceThis, Token *start, Token *end)
Replace token replaceThis with tokens between start and end, including start and end.
Definition: token.cpp:380
~Token()
Definition: token.cpp:73
bool isEnumType() const
Definition: token.h:561
bool isExpandedMacro() const
Definition: token.h:455
void concatStr(std::string const &b)
Concatenate two (quoted) strings.
Definition: token.cpp:246
Token * astOperand2()
Definition: token.h:1384
static std::pair< const Token *, const Token * > typeDecl(const Token *tok, bool pointedToType=false)
Definition: token.cpp:2431
const Token * nextTemplateArgument() const
Definition: token.cpp:930
void templateSimplifierPointer(TemplateSimplifier::TokenAndName *tokenAndName)
Definition: token.h:698
const ValueFlow::Value * getInvalidValue(const Token *ftok, nonneg int argnr, const Settings *settings) const
Definition: token.cpp:1997
std::string stringifyList(const stringifyOptions &options, const std::vector< std::string > *fileNames=nullptr, const Token *end=nullptr) const
Definition: token.cpp:1371
static nonneg int getStrSize(const Token *tok, const Settings &settings)
Definition: token.cpp:856
const Token * getValueTokenMaxStrLength() const
Definition: token.cpp:2042
std::shared_ptr< ScopeInfo2 > scopeInfo() const
Definition: token.cpp:2548
const Token * getValueTokenMinStrSize(const Settings &settings, MathLib::bigint *path=nullptr) const
Definition: token.cpp:2022
bool isBoolean() const
Definition: token.h:404
bool isUpperCaseName() const
Definition: token.cpp:237
static void createMutualLinks(Token *begin, Token *end)
Links two elements against each other.
Definition: token.cpp:1282
bool isCpp() const
Definition: token.cpp:2752
const Scope * scope() const
Definition: token.h:1049
void setValueType(ValueType *vt)
Definition: token.cpp:2359
@ efIsUnique
Definition: token.h:1333
static nonneg int getStrLength(const Token *tok)
Definition: token.cpp:811
const ValueFlow::Value * getKnownValue(ValueFlow::Value::ValueType t) const
Definition: token.cpp:2586
ConstTokenRange until(const Token *t) const
Definition: token.cpp:84
static const ::Type * typeOf(const Token *tok, const Token **typeTok=nullptr)
Definition: token.cpp:2377
const ValueType * valueType() const
Definition: token.h:331
const std::string & strAt(int index) const
Definition: token.cpp:457
static void assignProgressValues(Token *tok)
Calculate progress values for all tokens.
Definition: token.cpp:2341
bool hasKnownSymbolicValue(const Token *tok) const
Definition: token.cpp:2575
void astOperand1(Token *tok)
Definition: token.cpp:1490
TokensFrontBack & mTokensFrontBack
Definition: token.h:154
bool isNumber() const
Definition: token.h:371
bool isCalculation() const
Is current token a calculation? Only true for operands.
Definition: token.cpp:1590
const Function * function() const
Definition: token.h:1062
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
std::pair< const Token *, const Token * > findExpressionStartEndTokens() const
Definition: token.cpp:1548
nonneg int varId() const
Definition: token.h:870
static void move(Token *srcStart, Token *srcEnd, Token *newLocation)
Move srcStart and srcEnd tokens and all tokens between them into new a location.
Definition: token.cpp:868
std::string expressionString() const
Definition: token.cpp:1681
const std::string & str() const
Definition: token.h:192
@ fIsControlFlowKeyword
Definition: token.h:1305
bool isSigned() const
Definition: token.h:430
const Token * findClosingBracket() const
Returns the closing bracket of opening '<'.
Definition: token.cpp:951
void astStringVerboseRecursive(std::string &ret, const nonneg int indent1=0, const nonneg int indent2=0) const
Internal helper function to avoid excessive string allocations.
Definition: token.cpp:1750
void setFlag(uint64_t flag_, bool state_)
Set specified flag state.
Definition: token.h:1356
void assignIndexes()
Definition: token.cpp:2351
void printValueFlow(bool xml, std::ostream &out) const
Definition: token.cpp:1798
std::string astStringVerbose() const
Definition: token.cpp:1782
static const char * chrInFirstWord(const char *str, char c)
Works almost like strchr() except if str has empty space ' ' character, that character is handled as ...
Definition: token.cpp:709
Token * mLink
Definition: token.h:1283
const ::Type * type() const
Definition: token.h:1094
void update_property_isStandardType()
Update internal property cache about isStandardType()
Definition: token.cpp:215
bool isUnaryPreOp() const
Definition: token.cpp:1626
Token * mPrevious
Definition: token.h:1282
static nonneg int getStrArraySize(const Token *tok)
Definition: token.cpp:841
bool isOp() const
Definition: token.h:380
Token * astParent()
Definition: token.h:1390
void scopeInfo(std::shared_ptr< ScopeInfo2 > newScopeInfo)
Definition: token.cpp:2544
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
void deleteNext(nonneg int count=1)
Unlink and delete the next 'count' tokens.
Definition: token.cpp:279
bool isConstOp() const
Definition: token.h:385
Token * mNext
Definition: token.h:1281
Token * insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string &macroNameStr=emptyString, bool prepend=false)
Insert new token after this token.
Definition: token.cpp:1139
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
@ eOther
Definition: token.h:167
@ eComparisonOp
Definition: token.h:163
@ eNumber
Definition: token.h:162
@ eKeyword
Definition: token.h:161
@ eName
Definition: token.h:161
@ eString
Definition: token.h:162
@ eArithmeticalOp
Definition: token.h:163
@ eChar
Definition: token.h:162
@ eLambda
Definition: token.h:165
@ eBoolean
Definition: token.h:162
@ eNone
Definition: token.h:168
@ eVariable
Definition: token.h:161
@ eEllipsis
Definition: token.h:166
@ eExtendedOp
Definition: token.h:163
@ eLogicalOp
Definition: token.h:163
@ eBitOp
Definition: token.h:163
@ eAssignmentOp
Definition: token.h:163
@ eBracket
Definition: token.h:164
@ eType
Definition: token.h:161
@ eFunction
Definition: token.h:161
@ eIncDecOp
Definition: token.h:163
Token * previous()
Definition: token.h:862
std::string strValue() const
This can be called only for tokens that are strings, else the assert() is called.
Definition: token.cpp:257
bool isComplex() const
Definition: token.h:555
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2367
static std::string typeStr(const Token *tok)
Definition: token.cpp:2530
const ValueFlow::Value * getValueGE(const MathLib::bigint val, const Settings *settings) const
Definition: token.cpp:1988
bool isAssignmentOp() const
Definition: token.h:401
static void eraseTokens(Token *begin, const Token *end)
Delete tokens between begin and end.
Definition: token.cpp:1272
nonneg int linenr() const
Definition: token.h:816
bool isStandardType() const
Definition: token.h:449
const Token * nextArgumentBeforeCreateLinks2() const
Definition: token.cpp:913
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
bool isComparisonOp() const
Definition: token.h:398
const ValueFlow::Value * getValueLE(const MathLib::bigint val, const Settings *settings) const
Definition: token.cpp:1979
Token * next()
Definition: token.h:830
const std::list< ValueFlow::Value > & values() const
Definition: token.h:1197
void update_property_char_string_literal()
Update internal property cache about string and char literals.
Definition: token.cpp:228
const Token * nextArgument() const
Definition: token.cpp:903
void swapWithNext()
Swap the contents of this token with the next token.
Definition: token.cpp:319
const Token * findOpeningBracket() const
Definition: token.cpp:1016
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
TokenImpl * mImpl
Definition: token.h:1340
void deletePrevious(nonneg int count=1)
Unlink and delete the previous 'count' tokens.
Definition: token.cpp:299
void astParent(Token *tok)
Definition: token.cpp:1471
bool isEnumType() const
bool isIntValue() const
Definition: vfvalue.h:211
bool isSymbolicValue() const
Definition: vfvalue.h:244
bool isTokValue() const
Definition: vfvalue.h:214
Bound bound
The value bound
Definition: vfvalue.h:265
std::string toString() const
Definition: vfvalue.cpp:41
enum ValueFlow::Value::ValueType valueType
ValueKind
How known is this value.
Definition: vfvalue.h:338
@ Impossible
Listed values are impossible.
@ Known
Only listed values are possible.
@ Possible
This value is possible, other unlisted values may also be possible.
bool isLifetimeValue() const
Definition: vfvalue.h:229
static bool sameToken(const Token *tok1, const Token *tok2)
Definition: vfvalue.cpp:158
bool isImpossible() const
Definition: vfvalue.h:365
bool isKnown() const
Definition: vfvalue.h:353
const Token * condition
Condition that this value depends on.
Definition: vfvalue.h:280
const Token * tokvalue
token value - the token that has the value.
Definition: vfvalue.h:271
long long intvalue
int value (or sometimes bool value?)
Definition: vfvalue.h:268
nonneg int varId
For calculated values - varId that calculated value depends on.
Definition: vfvalue.h:287
bool isNonValue() const
Definition: vfvalue.h:260
enum ValueFlow::Value::ValueKind valueKind
bool isInconclusive() const
Definition: vfvalue.h:378
Value type.
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Token * smartPointerTypeToken
Smart pointer type token.
const Token * containerTypeToken
The container type token.
enum ValueType::Sign sign
std::string str() const
Information about a member variable.
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Token * typeEndToken() const
Get type end token.
const Token * nameToken() const
Get name token.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
const Token * typeStartToken() const
Get type start token.
const ValueType * valueType() const
#define REQUIRES(msg,...)
Definition: config.h:124
static const std::string emptyString
Definition: config.h:127
#define nonneg
Definition: config.h:138
Token * findTypeEnd(Token *tok)
Definition: token.cpp:2708
Token * findLambdaEndScope(Token *tok)
Definition: token.cpp:2720
@ warning
Warning.
const Value * findValue(const std::list< Value > &values, const Settings *settings, const std::function< bool(const Value &)> &pred)
size_t getSizeOf(const ValueType &vt, const Settings &settings, int maxRecursion=0)
Definition: valueflow.cpp:1186
Simple container to be thrown when internal error is detected.
Definition: errortypes.h:36
MathLib::bigint value
Definition: token.h:119
enum TokenImpl::CppcheckAttributes::Type type
CppcheckAttributes * next
Definition: token.h:120
std::list< ValueFlow::Value > * mValues
Definition: token.h:107
nonneg int mVarId
Definition: token.h:63
nonneg int mFileIndex
Definition: token.h:64
const Function * mFunction
Definition: token.h:91
std::string * mOriginalName
Definition: token.h:98
nonneg int mLineNumber
Definition: token.h:65
~TokenImpl()
Definition: token.cpp:2662
static const std::list< ValueFlow::Value > mEmptyValueList
Definition: token.h:108
ValueType * mValueType
Definition: token.h:104
nonneg int mProgressValue
A value from 0-100 that provides a rough idea about where in the token list this token is located.
Definition: token.h:73
Token * mAstOperand1
Definition: token.h:84
nonneg int mExprId
Definition: token.h:67
std::set< TemplateSimplifier::TokenAndName * > * mTemplateSimplifierPointers
Definition: token.h:111
CppcheckAttributes * mCppcheckAttributes
Definition: token.h:122
const ::Type * mType
Definition: token.h:93
Token * mAstOperand2
Definition: token.h:85
std::shared_ptr< ScopeInfo2 > mScopeInfo
Definition: token.h:114
void setCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint value)
Definition: token.cpp:2682
nonneg int mIndex
Token index.
Definition: token.h:78
bool getCppcheckAttribute(CppcheckAttributes::Type type, MathLib::bigint &value) const
Definition: token.cpp:2698
Token * mAstParent
Definition: token.h:86
static stringifyOptions forDebugExprId()
Definition: token.h:959
static stringifyOptions forPrintOut()
Definition: token.h:964
This struct stores pointers to the front and back tokens of the list this token is in.
Definition: tokenlist.h:46
Token * back
Definition: tokenlist.h:49
const TokenList & list
Definition: tokenlist.h:50
Token * front
Definition: tokenlist.h:48
static const Token * goToRightParenthesis(const Token *start, const Token *end)
Definition: token.cpp:1531
static const std::unordered_set< std::string > baseKeywords
Definition: token.cpp:105
static const std::unordered_set< std::string > controlFlowKeywords
Definition: token.cpp:89
std::list< ValueFlow::Value >::iterator ValueIterator
Definition: token.cpp:2139
static int multiCompareImpl(const Token *tok, const char *haystack, nonneg int varid)
Definition: token.cpp:606
static void removeOverlaps(std::list< ValueFlow::Value > &values)
Definition: token.cpp:2214
static T * findmatchImpl(T *const startTok, const char pattern[], const nonneg int varId)
Definition: token.cpp:1090
static const Token * goToLeftParenthesis(const Token *start, const Token *end)
Definition: token.cpp:1514
static bool sameValueType(const ValueFlow::Value &x, const ValueFlow::Value &y)
Definition: token.cpp:2252
static const std::unordered_set< std::string > stdTypes
Definition: token.cpp:202
static std::string stringFromTokenRange(const Token *start, const Token *end)
Definition: token.cpp:1645
static bool isOperator(const Token *tok)
Definition: token.cpp:943
static bool removeContradiction(std::list< ValueFlow::Value > &values)
Definition: token.cpp:2079
static void mergeAdjacent(std::list< ValueFlow::Value > &values)
Definition: token.cpp:2158
static bool isAdjacent(const ValueFlow::Value &x, const ValueFlow::Value &y)
Definition: token.cpp:2060
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
Definition: token.cpp:1742
static int multiComparePercent(const Token *tok, const char *&haystack, nonneg int varid)
Definition: token.cpp:469
static T * findsimplematchImpl(T *const startTok, const char pattern[], size_t pattern_len)
Definition: token.cpp:1051
static T * linkAtImpl(T *thisTok, int index)
Definition: token.cpp:438
static const ValueFlow::Value * getCompareValue(const std::list< ValueFlow::Value > &values, bool condition, MathLib::bigint path, Compare compare)
Definition: token.cpp:2607
static void removeContradictions(std::list< ValueFlow::Value > &values)
Definition: token.cpp:2242
static T * nextArgumentImpl(T *thisTok)
Definition: token.cpp:890
static bool removePointValue(std::list< ValueFlow::Value > &values, std::list< ValueFlow::Value >::iterator &x)
Definition: token.cpp:2069
static ValueIterator removeAdjacentValues(std::list< ValueFlow::Value > &values, ValueIterator x, Iterator start, Iterator last)
Definition: token.cpp:2142
static T * tokAtImpl(T *tok, int index)
Definition: token.cpp:414
static void astStringXml(const Token *tok, nonneg int indent, std::ostream &out)
Definition: token.cpp:1687
static bool isStringLiteral(const std::string &str)
Definition: utils.h:159
static std::string id_string(const void *p)
Definition: utils.h:340
static bool isPrefixStringCharLiteral(const std::string &str, char q, const std::string &p)
Definition: utils.h:126
static std::string getStringLiteral(const std::string &str)
Definition: utils.h:175
static bool isCharLiteral(const std::string &str)
Definition: utils.h:164