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