Cppcheck
tokenize.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 //---------------------------------------------------------------------------
20 #include "tokenize.h"
21 
22 #include "errorlogger.h"
23 #include "errortypes.h"
24 #include "library.h"
25 #include "mathlib.h"
26 #include "path.h"
27 #include "platform.h"
28 #include "preprocessor.h"
29 #include "settings.h"
30 #include "standards.h"
31 #include "summaries.h"
32 #include "symboldatabase.h"
33 #include "templatesimplifier.h"
34 #include "timer.h"
35 #include "token.h"
36 #include "utils.h"
37 #include "valueflow.h"
38 #include "vfvalue.h"
39 
40 #include <algorithm>
41 #include <cassert>
42 #include <cctype>
43 #include <cstdlib>
44 #include <cstring>
45 #include <ctime>
46 #include <iostream>
47 #include <iterator>
48 #include <exception>
49 #include <memory>
50 #include <set>
51 #include <sstream>
52 #include <stack>
53 #include <stdexcept>
54 #include <unordered_map>
55 #include <unordered_set>
56 #include <utility>
57 #include <vector>
58 
59 #include <simplecpp.h>
60 
61 //---------------------------------------------------------------------------
62 
63 namespace {
64  // local struct used in setVarId
65  // in order to store information about the scope
66  struct VarIdScopeInfo {
67  VarIdScopeInfo() = default;
68  VarIdScopeInfo(bool isExecutable, bool isStructInit, bool isEnum, nonneg int startVarid)
69  : isExecutable(isExecutable), isStructInit(isStructInit), isEnum(isEnum), startVarid(startVarid) {}
70 
71  const bool isExecutable{};
72  const bool isStructInit{};
73  const bool isEnum{};
74  const nonneg int startVarid{};
75  };
76 }
77 
78 /** Return whether tok is the "{" that starts an enumerator list */
79 static bool isEnumStart(const Token* tok)
80 {
81  if (!tok || tok->str() != "{")
82  return false;
83  return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum") || Token::Match(tok->tokAt(-3), "enum class %name%");
84 }
85 
86 template<typename T>
87 static void skipEnumBody(T *&tok)
88 {
89  T *defStart = tok;
90  while (Token::Match(defStart, "%name%|::|:"))
91  defStart = defStart->next();
92  if (defStart && defStart->str() == "{")
93  tok = defStart->link()->next();
94 }
95 
96 const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith)
97 {
98  if (!tok)
99  return nullptr;
100  if (tok->str() == "(")
101  tok = tok->link();
102  if (tok->str() != ")")
103  return nullptr;
104  if (!tok->isCpp() && !Token::Match(tok->link()->previous(), "%name%|)"))
105  return nullptr;
106  if (Token::Match(tok, ") ;|{|[")) {
107  tok = tok->next();
108  while (tok && tok->str() == "[" && tok->link()) {
109  if (endsWith.find(tok->str()) != std::string::npos)
110  return tok;
111  tok = tok->link()->next();
112  }
113  return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
114  }
115  if (tok->isCpp() && tok->str() == ")") {
116  tok = tok->next();
117  while (Token::Match(tok, "const|noexcept|override|final|volatile|mutable|&|&& !!(") ||
118  (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
119  tok = tok->next();
120  if (tok && tok->str() == ")")
121  tok = tok->next();
122  while (tok && tok->str() == "[")
123  tok = tok->link()->next();
124  if (Token::Match(tok, "throw|noexcept ("))
125  tok = tok->linkAt(1)->next();
126  if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
127  tok = tok->linkAt(1)->next();
128  if (tok && tok->originalName() == "->") { // trailing return type
129  for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
130  if (tok->link() && Token::Match(tok, "<|[|("))
131  tok = tok->link();
132  }
133  while (Token::Match(tok, "override|final !!(") ||
134  (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
135  tok = tok->next();
136  if (Token::Match(tok, "= 0|default|delete ;"))
137  tok = tok->tokAt(2);
138  if (tok && tok->str() == ":" && !Token::Match(tok->next(), "%name%|::"))
139  return nullptr;
140  return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
141  }
142  return nullptr;
143 }
144 
145 /**
146  * is tok the start brace { of a class, struct, union, or enum
147  */
148 static bool isClassStructUnionEnumStart(const Token * tok)
149 {
150  if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
151  return false;
152  const Token * tok2 = tok->previous();
153  while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
154  tok2 = tok2->previous();
155  return Token::Match(tok2, "class|struct|union|enum");
156 }
157 
158 //---------------------------------------------------------------------------
159 
160 Tokenizer::Tokenizer(const Settings &settings, ErrorLogger &errorLogger) :
161  list(&settings),
162  mSettings(settings),
163  mErrorLogger(errorLogger),
164  mTemplateSimplifier(new TemplateSimplifier(*this))
165 {}
166 
168 {
169  delete mSymbolDatabase;
170  delete mTemplateSimplifier;
171 }
172 
173 
174 //---------------------------------------------------------------------------
175 // SizeOfType - gives the size of a type
176 //---------------------------------------------------------------------------
177 
178 nonneg int Tokenizer::sizeOfType(const std::string& type) const
179 {
180  const std::map<std::string, int>::const_iterator it = mTypeSize.find(type);
181  if (it == mTypeSize.end()) {
182  const Library::PodType* podtype = mSettings.library.podtype(type);
183  if (!podtype)
184  return 0;
185 
186  return podtype->size;
187  }
188  return it->second;
189 }
190 
191 nonneg int Tokenizer::sizeOfType(const Token *type) const
192 {
193  if (!type || type->str().empty())
194  return 0;
195 
196  if (type->tokType() == Token::eString)
197  return Token::getStrLength(type) + 1U;
198 
199  const std::map<std::string, int>::const_iterator it = mTypeSize.find(type->str());
200  if (it == mTypeSize.end()) {
201  const Library::PodType* podtype = mSettings.library.podtype(type->str());
202  if (!podtype)
203  return 0;
204 
205  return podtype->size;
206  }
207  if (type->isLong()) {
208  if (type->str() == "double")
210  if (type->str() == "long")
212  }
213 
214  return it->second;
215 }
216 //---------------------------------------------------------------------------
217 
218 // check if this statement is a duplicate definition
219 bool Tokenizer::duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const
220 {
221  // check for an end of definition
222  Token * tok = tokPtr;
223  if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) {
224  Token * end = tok->next();
225 
226  if (end->str() == "[") {
227  if (!end->link())
228  syntaxError(end); // invalid code
229  end = end->link()->next();
230  } else if (end->str() == ",") {
231  // check for derived class
232  if (Token::Match(tok->previous(), "public|private|protected"))
233  return false;
234 
235  // find end of definition
236  while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
237  if (end->next()->str() == "(")
238  end = end->linkAt(1);
239 
240  end = (end)?end->next():nullptr;
241  }
242  if (end)
243  end = end->next();
244  } else if (end->str() == "(") {
245  if (startsWith(tok->previous()->str(), "operator"))
246  // conversion operator
247  return false;
248  if (tok->previous()->str() == "typedef")
249  // typedef of function returning this type
250  return false;
251  if (Token::Match(tok->previous(), "public:|private:|protected:"))
252  return false;
253  if (tok->previous()->str() == ">") {
254  if (!Token::Match(tok->tokAt(-2), "%type%"))
255  return false;
256 
257  if (!Token::Match(tok->tokAt(-3), ",|<"))
258  return false;
259 
260  tokPtr = end->link();
261  return true;
262  }
263  }
264 
265  if (end) {
266  if (Token::simpleMatch(end, ") {")) { // function parameter ?
267  // look backwards
268  if (Token::Match(tok->previous(), "%type%") &&
269  !Token::Match(tok->previous(), "return|new|const|struct")) {
270  // duplicate definition so skip entire function
271  tokPtr = end->next()->link();
272  return true;
273  }
274  } else if (end->str() == ">") { // template parameter ?
275  // look backwards
276  if (Token::Match(tok->previous(), "%type%") &&
277  !Token::Match(tok->previous(), "return|new|const|volatile")) {
278  // duplicate definition so skip entire template
279  while (end && end->str() != "{")
280  end = end->next();
281  if (end) {
282  tokPtr = end->link();
283  return true;
284  }
285  }
286  } else {
287  // look backwards
288  if (Token::Match(tok->previous(), "typedef|}|>") ||
289  (end->str() == ";" && tok->previous()->str() == ",") ||
290  (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
291  (Token::Match(tok->previous(), "%type%") &&
292  (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
293  !Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
294  // scan backwards for the end of the previous statement
295  while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
296  if (tok->previous()->str() == "}") {
297  tok = tok->previous()->link();
298  } else if (tok->previous()->str() == "typedef") {
299  return true;
300  } else if (tok->previous()->str() == "enum") {
301  return true;
302  } else if (tok->previous()->str() == "struct") {
303  if (tok->strAt(-2) == "typedef" &&
304  tok->next()->str() == "{" &&
305  typeDef->strAt(3) != "{") {
306  // declaration after forward declaration
307  return true;
308  }
309  if (tok->next()->str() == "{")
310  return true;
311  if (Token::Match(tok->next(), ")|*"))
312  return true;
313  if (tok->next()->str() == name->str())
314  return true;
315  if (tok->next()->str() != ";")
316  return true;
317  return false;
318  } else if (tok->previous()->str() == "union") {
319  return tok->next()->str() != ";";
320  } else if (tok->isCpp() && tok->previous()->str() == "class") {
321  return tok->next()->str() != ";";
322  }
323  if (tok)
324  tok = tok->previous();
325  }
326 
327  if (tokPtr->strAt(1) != "(" || !Token::Match(tokPtr->linkAt(1), ") .|(|["))
328  return true;
329  }
330  }
331  }
332  }
333 
334  return false;
335 }
336 
337 void Tokenizer::unsupportedTypedef(const Token *tok) const
338 {
340  return;
341 
342  std::ostringstream str;
343  const Token *tok1 = tok;
344  int level = 0;
345  while (tok) {
346  if (level == 0 && tok->str() == ";")
347  break;
348  if (tok->str() == "{")
349  ++level;
350  else if (tok->str() == "}") {
351  if (level == 0)
352  break;
353  --level;
354  }
355 
356  if (tok != tok1)
357  str << " ";
358  str << tok->str();
359  tok = tok->next();
360  }
361  if (tok)
362  str << " ;";
363 
364  reportError(tok1, Severity::debug, "simplifyTypedef",
365  "Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
366 }
367 
369 {
370  Token *tok = nullptr;
371 
372  // remove typedef but leave ;
373  while (typeDef->next()) {
374  if (typeDef->next()->str() == ";") {
375  typeDef->deleteNext();
376  break;
377  }
378  if (typeDef->next()->str() == "{")
379  Token::eraseTokens(typeDef, typeDef->linkAt(1));
380  else if (typeDef->next()->str() == "}")
381  break;
382  typeDef->deleteNext();
383  }
384 
385  if (typeDef != list.front()) {
386  tok = typeDef->previous();
387  tok->deleteNext();
388  } else {
389  list.front()->deleteThis();
390  tok = list.front();
391  }
392 
393  return tok;
394 }
395 
396 namespace {
397  struct Space {
398  std::string className;
399  const Token* bodyEnd{}; // for body contains typedef define
400  const Token* bodyEnd2{}; // for body contains typedef using
401  bool isNamespace{};
402  std::set<std::string> recordTypes;
403  };
404 }
405 
406 static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
407 {
408  std::string name;
409  std::set<std::string> qualifiers;
410 
411  while (Token::Match(tok->next(), "const|volatile")) {
412  qualifiers.insert(tok->next()->str());
413  tok->deleteNext();
414  }
415 
416  // skip "class|struct|union|enum"
417  Token *tok1 = tok->tokAt(2);
418 
419  const bool hasName = Token::Match(tok1, "%name%");
420 
421  // skip name
422  if (hasName) {
423  name = tok1->str();
424  tok1 = tok1->next();
425  }
426 
427  // skip base classes if present
428  if (tok1->str() == ":") {
429  tok1 = tok1->next();
430  while (tok1 && tok1->str() != "{")
431  tok1 = tok1->next();
432  if (!tok1)
433  return nullptr;
434  }
435 
436  // skip to end
437  tok1 = tok1->link();
438 
439  if (!hasName) { // unnamed
440  if (tok1->next()) {
441  // use typedef name if available
442  if (Token::Match(tok1->next(), "%type%"))
443  name = tok1->next()->str();
444  else // create a unique name
445  name = "Unnamed" + std::to_string((*unnamedCount)++);
446  tok->next()->insertToken(name);
447  } else
448  return nullptr;
449  }
450 
451  tok1->insertToken(";");
452  tok1 = tok1->next();
453 
454  if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
455  tok->deleteThis();
456  tok1->deleteThis();
457  return nullptr;
458  }
459  tok1->insertToken("typedef");
460  tok1 = tok1->next();
461  Token * tok3 = tok1;
462  for (const std::string &qualifier : qualifiers) {
463  tok1->insertToken(qualifier);
464  tok1 = tok1->next();
465  }
466  tok1->insertToken(tok->next()->str()); // struct, union or enum
467  tok1 = tok1->next();
468  tok1->insertToken(name);
469  tok->deleteThis();
470  tok = tok3;
471 
472  return tok;
473 }
474 
475 /* This function is called when processing function related typedefs.
476  * If simplifyTypedef generates an "Internal Error" message and the
477  * code that generated it deals in some way with functions, then this
478  * function will probably need to be extended to handle a new function
479  * related pattern */
480 const Token *Tokenizer::processFunc(const Token *tok2, bool inOperator) const
481 {
482  if (tok2->next() && tok2->next()->str() != ")" &&
483  tok2->next()->str() != ",") {
484  // skip over tokens for some types of canonicalization
485  if (Token::Match(tok2->next(), "( * %type% ) ("))
486  tok2 = tok2->linkAt(5);
487  else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
488  tok2 = tok2->linkAt(6);
489  else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
490  tok2 = tok2->tokAt(5);
491  else if (Token::Match(tok2->next(), "* ( %type% [") &&
492  Token::Match(tok2->linkAt(4), "] ) ;|="))
493  tok2 = tok2->linkAt(4)->next();
494  else if (Token::Match(tok2->next(), "* ( * %type% ("))
495  tok2 = tok2->linkAt(5)->next();
496  else if (Token::simpleMatch(tok2->next(), "* [") &&
497  Token::simpleMatch(tok2->linkAt(2), "] ;"))
498  tok2 = tok2->next();
499  else {
500  if (tok2->next()->str() == "(")
501  tok2 = tok2->next()->link();
502  else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
503  tok2 = tok2->next();
504 
505  while (Token::Match(tok2, "*|&") &&
506  !Token::Match(tok2->next(), ")|>"))
507  tok2 = tok2->next();
508 
509  // skip over namespace
510  while (Token::Match(tok2, "%name% ::"))
511  tok2 = tok2->tokAt(2);
512 
513  if (!tok2)
514  return nullptr;
515 
516  if (tok2->str() == "(" &&
517  tok2->link()->next() &&
518  tok2->link()->next()->str() == "(") {
519  tok2 = tok2->link();
520 
521  if (tok2->next()->str() == "(")
522  tok2 = tok2->next()->link();
523  }
524 
525  // skip over typedef parameter
526  if (tok2->next() && tok2->next()->str() == "(") {
527  tok2 = tok2->next()->link();
528  if (!tok2->next())
529  syntaxError(tok2);
530 
531  if (tok2->next()->str() == "(")
532  tok2 = tok2->next()->link();
533  }
534  }
535  }
536  }
537  return tok2;
538 }
539 
540 Token *Tokenizer::processFunc(Token *tok2, bool inOperator)
541 {
542  return const_cast<Token*>(processFunc(const_cast<const Token*>(tok2), inOperator));
543 }
544 
546 {
548  return;
549 
550  for (Token *tok = list.front(); tok; tok = tok->next()) {
551  // using a::b; => typedef a::b b;
552  if ((Token::Match(tok, "[;{}] using %name% :: %name% ::|;") && !tok->tokAt(2)->isKeyword()) ||
553  (Token::Match(tok, "[;{}] using :: %name% :: %name% ::|;") && !tok->tokAt(3)->isKeyword())) {
554  Token *endtok = tok->tokAt(5);
555  if (Token::Match(endtok, "%name%"))
556  endtok = endtok->next();
557  while (Token::Match(endtok, ":: %name%"))
558  endtok = endtok->tokAt(2);
559  if (endtok && endtok->str() == ";") {
560  tok->next()->str("typedef");
561  endtok = endtok->previous();
562  endtok->insertToken(endtok->str());
563  }
564  }
565  }
566 }
567 
569 {
570  if (!list.front())
571  return;
572 
573  for (Token* tok = list.front()->next(); tok; tok = tok->next()) {
574  if (tok->str() == "typedef") {
575  bool doSimplify = !Token::Match(tok->previous(), ";|{|}|:|public:|private:|protected:");
576  if (doSimplify && Token::simpleMatch(tok->previous(), ")") && Token::Match(tok->linkAt(-1)->previous(), "if|for|while"))
577  doSimplify = false;
578  bool haveStart = false;
579  Token* start{};
580  if (!doSimplify && Token::simpleMatch(tok->previous(), "}")) {
581  start = tok->linkAt(-1)->previous();
582  while (Token::Match(start, "%name%")) {
583  if (Token::Match(start, "class|struct|union|enum")) {
584  start = start->previous();
585  doSimplify = true;
586  haveStart = true;
587  break;
588  }
589  start = start->previous();
590  }
591  }
592  if (doSimplify) {
593  if (!haveStart) {
594  start = tok;
595  while (start && !Token::Match(start, "[;{}]"))
596  start = start->previous();
597  }
598  if (start)
599  start = start->next();
600  else
601  start = list.front();
602  start->insertTokenBefore(tok->str());
603  tok->deleteThis();
604  }
605  }
606  }
607 }
608 
609 namespace {
610  class TypedefSimplifier {
611  private:
612  Token* mTypedefToken; // The "typedef" token
613  Token* mEndToken{nullptr}; // Semicolon
614  std::pair<Token*, Token*> mRangeType;
615  std::pair<Token*, Token*> mRangeTypeQualifiers;
616  std::pair<Token*, Token*> mRangeAfterVar;
617  Token* mNameToken{nullptr};
618  bool mFail = false;
619  bool mReplaceFailed = false;
620  bool mUsed = false;
621 
622  public:
623  explicit TypedefSimplifier(Token* typedefToken) : mTypedefToken(typedefToken) {
624  Token* start = typedefToken->next();
625  if (Token::simpleMatch(start, "typename"))
626  start = start->next();
627 
628  // TODO handle unnamed structs etc
629  if (Token::Match(start, "const| enum|struct|union|class %name%| {")) {
630  const std::pair<Token*, Token*> rangeBefore(start, Token::findsimplematch(start, "{"));
631 
632  // find typedef name token
633  Token* nameToken = rangeBefore.second->link()->next();
634  while (Token::Match(nameToken, "%name%|* %name%|*"))
635  nameToken = nameToken->next();
636  const std::pair<Token*, Token*> rangeQualifiers(rangeBefore.second->link()->next(), nameToken);
637 
638  if (Token::Match(nameToken, "%name% ;")) {
639  if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {"))
640  rangeBefore.second->previous()->insertToken(nameToken->str());
641  mRangeType = rangeBefore;
642  mRangeTypeQualifiers = rangeQualifiers;
643  Token* typeName = rangeBefore.second->previous();
644  if (typeName->isKeyword()) {
645  // TODO typeName->insertToken("T:" + std::to_string(num++));
646  typeName->insertToken(nameToken->str());
647  }
648  mNameToken = nameToken;
649  mEndToken = nameToken->next();
650  return;
651  }
652  }
653 
654  for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) {
655  if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) {
656  mRangeType.first = start;
657  mRangeType.second = type;
658  mNameToken = type;
659  mEndToken = mNameToken->next();
660  return;
661  }
662  if (type != start && Token::Match(type, "%name% [")) {
663  Token* end = type->linkAt(1);
664  while (Token::simpleMatch(end, "] ["))
665  end = end->linkAt(1);
666  if (!Token::simpleMatch(end, "] ;"))
667  break;
668  mRangeType.first = start;
669  mRangeType.second = type;
670  mNameToken = type;
671  mEndToken = end->next();
672  mRangeAfterVar.first = mNameToken->next();
673  mRangeAfterVar.second = mEndToken;
674  return;
675  }
676  if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) {
677  mNameToken = type->linkAt(1)->previous();
678  mEndToken = type->linkAt(1)->linkAt(1)->next();
679  mRangeType.first = start;
680  mRangeType.second = mNameToken;
681  mRangeAfterVar.first = mNameToken->next();
682  mRangeAfterVar.second = mEndToken;
683  return;
684  }
685  if (Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
686  mNameToken = type;
687  mEndToken = type->linkAt(1)->next();
688  mRangeType.first = start;
689  mRangeType.second = type;
690  mRangeAfterVar.first = mNameToken->next();
691  mRangeAfterVar.second = mEndToken;
692  return;
693  }
694  }
695  // TODO: handle all typedefs
696  if ((false))
697  printTypedef(typedefToken);
698  mFail = true;
699  }
700 
701  const Token* getTypedefToken() const {
702  return mTypedefToken;
703  }
704 
705  bool isUsed() const {
706  return mUsed;
707  }
708 
709  bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
710  if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
711  return false;
712  const auto it = m.find(mTypedefToken->strAt(2));
713  if (it == m.end())
714  return false;
715  return Token::Match(it->second.mNameToken, "%name% (");
716  }
717 
718  bool fail() const {
719  return mFail;
720  }
721 
722  bool replaceFailed() const {
723  return mReplaceFailed;
724  }
725 
726  bool isStructEtc() const {
727  return mRangeType.second && mRangeType.second->str() == "{";
728  }
729 
730  std::string name() const {
731  return mNameToken ? mNameToken->str() : "";
732  }
733 
734  void replace(Token* tok) {
735  if (tok == mNameToken)
736  return;
737 
738  mUsed = true;
739 
740  // Special handling for T() when T is a pointer
741  if (Token::Match(tok, "%name% ( )")) {
742  bool pointerType = false;
743  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
744  if (type->str() == "*" || type->str() == "&") {
745  pointerType = true;
746  break;
747  }
748  }
749  for (const Token* type = mRangeTypeQualifiers.first; type != mRangeTypeQualifiers.second; type = type->next()) {
750  if (type->str() == "*" || type->str() == "&") {
751  pointerType = true;
752  break;
753  }
754  }
755  if (pointerType) {
756  tok->deleteThis();
757  tok->next()->insertToken("0");
758  Token* tok2 = insertTokens(tok, mRangeType);
759  insertTokens(tok2, mRangeTypeQualifiers);
760  return;
761  }
762  }
763 
764  // Special handling of function pointer cast
765  const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
766  if (isFunctionPointer && isCast(tok->previous())) {
767  tok->insertToken("*");
768  insertTokens(tok, std::pair<Token*, Token*>(mRangeType.first, mNameToken->linkAt(1)));
769  tok->deleteThis();
770  return;
771  }
772 
773  // Inherited type => skip "struct" / "class"
774  if (Token::Match(mRangeType.first, "const| struct|class %name% {") && Token::Match(tok->previous(), "public|protected|private|<")) {
775  tok->originalName(tok->str());
776  tok->str(mRangeType.second->previous()->str());
777  return;
778  }
779 
780  if (Token::Match(tok, "%name% ::")) {
781  if (Token::Match(mRangeType.first, "const| struct|class %name% %name% ;")) {
782  tok->originalName(tok->str());
783  tok->str(mRangeType.second->previous()->str());
784  } else {
785  mReplaceFailed = true;
786  }
787  return;
788  }
789 
790  // pointer => move "const"
791  if (Token::simpleMatch(tok->previous(), "const")) {
792  bool pointerType = false;
793  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
794  if (type->str() == "*") {
795  pointerType = true;
796  break;
797  }
798  }
799  if (pointerType) {
800  tok->insertToken("const");
801  tok->next()->column(tok->column());
802  tok->next()->setMacroName(tok->previous()->getMacroName());
803  tok->deletePrevious();
804  }
805  }
806 
807  // Do not duplicate class/struct/enum/union
808  if (Token::Match(tok->previous(), "enum|union|struct|class")) {
809  bool found = false;
810  const std::string &kw = tok->previous()->str();
811  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
812  if (type->str() == kw) {
813  found = true;
814  break;
815  }
816  }
817  if (found)
818  tok->deletePrevious();
819  else {
820  mReplaceFailed = true;
821  return;
822  }
823  }
824 
825  // don't add class|struct|union in inheritance list
826  auto rangeType = mRangeType;
827  if (Token::Match(tok->previous(), "public|private|protected")) {
828  while (Token::Match(rangeType.first, "const|class|struct|union"))
829  rangeType.first = rangeType.first->next();
830  }
831 
832  Token* const tok2 = insertTokens(tok, rangeType);
833  Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
834 
835  tok2->originalName(tok->str());
836  tok3->originalName(tok->str());
837  Token *after = tok3;
838  while (Token::Match(after, "%name%|*|&|&&|::"))
839  after = after->next();
840  if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
841  while (Token::Match(after, "(|["))
842  after = after->link()->next();
843  if (after) {
844  tok3->insertToken("(");
845  after->previous()->insertToken(")");
846  Token::createMutualLinks(tok3->next(), after->previous());
847  }
848  }
849 
850  bool useAfterVarRange = true;
851  if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
852  if (Token::Match(after->previous(), "%name% ( !!*")) {
853  useAfterVarRange = false;
854  // Function return type => replace array with "*"
855  for (const Token* a = mRangeAfterVar.first; Token::simpleMatch(a, "["); a = a->link()->next())
856  tok3->insertToken("*");
857  } else if (Token::Match(after->previous(), "%name% ( * %name% ) [")) {
858  after = after->linkAt(4)->next();
859  } else {
860  Token* prev = after->previous();
861  if (prev->isName() && prev != tok3)
862  prev = prev->previous();
863  if (Token::Match(prev, "*|&|&&") && prev != tok3) {
864  while (Token::Match(prev, "*|&|&&") && prev != tok3)
865  prev = prev->previous();
866  prev->insertToken("(");
867  after->previous()->insertToken(")");
868  }
869  }
870  }
871 
872  if (isFunctionPointer) {
873  if (Token::Match(after, "( * %name% ) ("))
874  after = after->link()->linkAt(1)->next();
875  else if (after->str() == "(") {
876  useAfterVarRange = false;
877  if (Token::simpleMatch(tok3->previous(), "( *"))
878  tok3->deletePrevious();
879  }
880  else if (after->str() == "[") {
881  while (after && after->str() == "[")
882  after = after->link()->next();
883  }
884  }
885  else {
886  while (Token::simpleMatch(after, "["))
887  after = after->link()->next();
888  }
889 
890  if (!after)
891  throw InternalError(tok, "Failed to simplify typedef. Is the code valid?");
892 
893  Token* const tok4 = useAfterVarRange ? insertTokens(after->previous(), mRangeAfterVar)->next() : tok3->next();
894 
895  tok->deleteThis();
896 
897  // Unsplit variable declarations
898  if (tok4 && tok4->isSplittedVarDeclEq() &&
899  ((tok4->isCpp() && Token::Match(tok4->tokAt(-2), "&|&& %name% ;")) || Token::Match(tok4->previous(), "] ; %name% = {"))) {
900  tok4->deleteNext();
901  tok4->deleteThis();
902  }
903 
904  // Set links
905  std::stack<Token*> brackets;
906  for (; tok != tok4; tok = tok->next()) {
907  if (Token::Match(tok, "[{([]"))
908  brackets.push(tok);
909  else if (Token::Match(tok, "[})]]")) {
910  Token::createMutualLinks(brackets.top(), tok);
911  brackets.pop();
912  }
913  }
914  }
915 
916  void removeDeclaration() {
917  if (Token::simpleMatch(mRangeType.second, "{")) {
918  while (Token::Match(mTypedefToken, "typedef|const"))
919  mTypedefToken->deleteThis();
920  Token::eraseTokens(mRangeType.second->link(), mEndToken);
921  } else {
922  Token::eraseTokens(mTypedefToken, mEndToken);
923  mTypedefToken->deleteThis();
924  }
925  }
926 
927  static int canReplaceStatic(const Token* tok) {
928  if (!Token::Match(tok, "%name% %name%|*|&|&&|;|(|)|,|::")) {
929  if (Token::Match(tok->previous(), "( %name% =") && Token::Match(tok->linkAt(-1), ") %name%|{") && !tok->tokAt(-2)->isKeyword())
930  return true;
931  if (Token::Match(tok->previous(), ", %name% ="))
932  return true;
933  if (Token::Match(tok->previous(), "new %name% ["))
934  return true;
935  if (Token::Match(tok->previous(), "< %name%") && tok->previous()->findClosingBracket())
936  return true;
937  if (Token::Match(tok->previous(), ", %name% >|>>")) {
938  for (const Token* prev = tok->previous(); prev; prev = prev->previous()) {
939  if (Token::Match(prev, "[;{}(]"))
940  break;
941  if (prev->str() == "<" && prev->findClosingBracket() == tok->next())
942  return true;
943  if (prev->str() == ")")
944  prev = prev->link();
945  }
946  return true;
947  }
948  if (Token::Match(tok->previous(), "public|protected|private"))
949  return true;
950  if (Token::Match(tok->previous(), ", %name% :")) {
951  bool isGeneric = false;
952  for (; tok; tok = tok->previous()) {
953  if (Token::Match(tok, ")|]"))
954  tok = tok->link();
955  else if (Token::Match(tok, "[;{}(]")) {
956  isGeneric = Token::simpleMatch(tok->previous(), "_Generic (");
957  break;
958  }
959  }
960  return isGeneric;
961  }
962  return false;
963  }
964  return -1;
965  }
966 
967  bool canReplace(const Token* tok) {
968  if (mNameToken == tok)
969  return false;
970  if (!Token::Match(tok->previous(), "%name%|;|{|}|(|,|<") && !Token::Match(tok->previous(), "!!. %name% ("))
971  return false;
972  {
973  const int res = canReplaceStatic(tok);
974  if (res == 0 || res == 1)
975  return res != 0;
976  }
977  if (Token::Match(tok->previous(), "%name%") && !tok->previous()->isKeyword())
978  return false;
979  if (Token::simpleMatch(tok->next(), "(") && Token::Match(tok->linkAt(1), ") %name%|{"))
980  return false;
981  if (Token::Match(tok->previous(), "struct|union|class|enum %name% %name%") &&
982  Token::simpleMatch(mRangeType.second, "{") &&
983  tok->str() != mRangeType.second->previous()->str())
984  return true;
985  if (Token::Match(tok->previous(), "; %name% ;"))
986  return false;
987  if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
988  return true;
989  for (const Token* after = tok->next(); after; after = after->next()) {
990  if (Token::Match(after, "%name%|::|&|*|&&"))
991  continue;
992  if (after->str() == "<" && after->link())
993  break;
994  if (after->isNumber())
995  return false;
996  if (after->isComparisonOp() || after->isArithmeticalOp())
997  return false;
998  break;
999  }
1000  for (const Token* before = tok->previous(); before; before = before->previous()) {
1001  if (Token::Match(before, "[+-*/&|~!]"))
1002  return false;
1003  if (Token::Match(before, "struct|union|class|enum") || before->isStandardType())
1004  return false;
1005  if (before->str() == "::")
1006  return false;
1007  if (before->isName())
1008  continue;
1009  break;
1010  }
1011  return true;
1012  }
1013 
1014  Token* endToken() const {
1015  return mEndToken;
1016  }
1017 
1018  private:
1019  static bool isCast(const Token* tok) {
1020  if (Token::Match(tok, "( %name% ) (|%name%"))
1021  return !tok->tokAt(2)->isKeyword();
1022  if (Token::Match(tok, "< %name% > (") && tok->previous() && endsWith(tok->previous()->str(), "_cast", 5))
1023  return true;
1024  return false;
1025  }
1026 
1027  static Token* insertTokens(Token* to, std::pair<Token*,Token*> range) {
1028  for (const Token* from = range.first; from != range.second; from = from->next()) {
1029  to->insertToken(from->str());
1030  to->next()->column(to->column());
1031  to = to->next();
1032  to->isSimplifiedTypedef(true);
1033  to->isExternC(from->isExternC());
1034  }
1035  return to;
1036  }
1037 
1038  static void printTypedef(const Token *tok) {
1039  int indent = 0;
1040  while (tok && (indent > 0 || tok->str() != ";")) {
1041  if (tok->str() == "{")
1042  ++indent;
1043  else if (tok->str() == "}")
1044  --indent;
1045  std::cout << " " << tok->str();
1046  tok = tok->next();
1047  }
1048  std::cout << "\n";
1049  }
1050  };
1051 }
1052 
1054 {
1055  // Simplify global typedefs that are not redefined with the fast 1-pass simplification.
1056  // Then use the slower old typedef simplification.
1057  std::map<std::string, int> numberOfTypedefs;
1058  for (Token* tok = list.front(); tok; tok = tok->next()) {
1059  if (tok->str() == "typedef") {
1060  TypedefSimplifier ts(tok);
1061  if (!ts.fail())
1062  numberOfTypedefs[ts.name()]++;
1063  continue;
1064  }
1065  }
1066 
1067  int indentlevel = 0;
1068  std::map<std::string, TypedefSimplifier> typedefs;
1069  for (Token* tok = list.front(); tok; tok = tok->next()) {
1070  if (!tok->isName()) {
1071  if (tok->str()[0] == '{')
1072  ++indentlevel;
1073  else if (tok->str()[0] == '}')
1074  --indentlevel;
1075  continue;
1076  }
1077 
1078  if (indentlevel == 0 && tok->str() == "typedef") {
1079  TypedefSimplifier ts(tok);
1080  if (!ts.fail() && numberOfTypedefs[ts.name()] == 1) {
1081  if (mSettings.severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
1082  reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
1083  "It is unspecified behavior to const qualify a function type.");
1084  typedefs.emplace(ts.name(), ts);
1085  if (!ts.isStructEtc())
1086  tok = ts.endToken();
1087  }
1088  continue;
1089  }
1090 
1091  auto it = typedefs.find(tok->str());
1092  if (it != typedefs.end() && it->second.canReplace(tok)) {
1093  std::set<std::string> r;
1094  while (it != typedefs.end() && r.insert(tok->str()).second) {
1095  it->second.replace(tok);
1096  it = typedefs.find(tok->str());
1097  }
1098  } else if (tok->str() == "enum") {
1099  while (Token::Match(tok, "%name%|:|::"))
1100  tok = tok->next();
1101  if (!tok)
1102  break;
1103  if (tok->str() == "{")
1104  tok = tok->link();
1105  }
1106  }
1107 
1108  if (!typedefs.empty())
1109  {
1110  // remove typedefs
1111  for (auto &t: typedefs) {
1112  if (!t.second.replaceFailed()) {
1113  const Token* const typedefToken = t.second.getTypedefToken();
1114  TypedefInfo typedefInfo;
1115  typedefInfo.name = t.second.name();
1116  typedefInfo.filename = list.file(typedefToken);
1117  typedefInfo.lineNumber = typedefToken->linenr();
1118  typedefInfo.column = typedefToken->column();
1119  typedefInfo.used = t.second.isUsed();
1120  mTypedefInfo.push_back(std::move(typedefInfo));
1121 
1122  t.second.removeDeclaration();
1123  }
1124  }
1125 
1126  while (Token::Match(list.front(), "; %any%"))
1127  list.front()->deleteThis();
1128  }
1129 
1131 }
1132 
1133 static bool isEnumScope(const Token* tok)
1134 {
1135  if (!Token::simpleMatch(tok, "{"))
1136  return false;
1137  tok = tok->previous();
1138  while (tok && !tok->isKeyword() && Token::Match(tok, "%name%|::|:"))
1139  tok = tok->previous();
1140  if (Token::simpleMatch(tok, "class"))
1141  tok = tok->previous();
1142  return Token::simpleMatch(tok, "enum");
1143 }
1144 
1146 {
1147  bool isNamespace = false;
1148  std::string className, fullClassName;
1149  bool hasClass = false;
1150  bool goback = false;
1151 
1152  // add global namespace
1153  std::vector<Space> spaceInfo(1);
1154 
1155  // Convert "using a::b;" to corresponding typedef statements
1157 
1158  const std::time_t maxTime = mSettings.typedefMaxTime > 0 ? std::time(nullptr) + mSettings.typedefMaxTime: 0;
1159 
1160  for (Token *tok = list.front(); tok; tok = tok->next()) {
1161  if (!list.getFiles().empty())
1162  mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
1163 
1164  if (Settings::terminated())
1165  return;
1166 
1167  if (maxTime > 0 && std::time(nullptr) > maxTime) {
1168  if (mSettings.debugwarnings) {
1169  ErrorMessage::FileLocation loc(list.getFiles()[0], 0, 0);
1170  ErrorMessage errmsg({std::move(loc)},
1171  emptyString,
1173  "Typedef simplification instantiation maximum time exceeded",
1174  "typedefMaxTime",
1176  mErrorLogger.reportErr(errmsg);
1177  }
1178  return;
1179  }
1180 
1181  if (goback) {
1182  //jump back once, see the comment at the end of the function
1183  goback = false;
1184  tok = tok->previous();
1185  }
1186 
1187  if (tok->str() != "typedef") {
1188  if (Token::simpleMatch(tok, "( typedef")) {
1189  // Skip typedefs inside parentheses (#2453 and #4002)
1190  tok = tok->next();
1191  } else if (Token::Match(tok, "class|struct|namespace %any%") &&
1192  (!tok->previous() || tok->previous()->str() != "enum")) {
1193  isNamespace = (tok->str() == "namespace");
1194  hasClass = true;
1195  className = tok->next()->str();
1196  const Token *tok1 = tok->next();
1197  fullClassName = className;
1198  while (Token::Match(tok1, "%name% :: %name%")) {
1199  tok1 = tok1->tokAt(2);
1200  fullClassName += " :: " + tok1->str();
1201  }
1202  } else if (hasClass && tok->str() == ";") {
1203  hasClass = false;
1204  } else if (hasClass && tok->str() == "{") {
1205  if (!isNamespace)
1206  spaceInfo.back().recordTypes.insert(fullClassName);
1207 
1208  Space info;
1209  info.isNamespace = isNamespace;
1210  info.className = className;
1211  info.bodyEnd = tok->link();
1212  info.bodyEnd2 = tok->link();
1213  spaceInfo.push_back(std::move(info));
1214 
1215  hasClass = false;
1216  } else if (spaceInfo.size() > 1 && tok->str() == "}" && spaceInfo.back().bodyEnd == tok) {
1217  spaceInfo.pop_back();
1218  }
1219  continue;
1220  }
1221 
1222  // pull struct, union, enum or class definition out of typedef
1223  // use typedef name for unnamed struct, union, enum or class
1224  const Token* tokClass = tok->next();
1225  while (Token::Match(tokClass, "const|volatile"))
1226  tokClass = tokClass->next();
1227  if (Token::Match(tokClass, "struct|enum|union|class %type%| {|:")) {
1229  if (!tok1)
1230  continue;
1231  tok = tok1;
1232  }
1233 
1234  /** @todo add support for union */
1235  if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
1236  tok->deleteNext(3);
1237  tok->deleteThis();
1238  if (tok->next())
1239  tok->deleteThis();
1240  //now the next token to process is 'tok', not 'tok->next()';
1241  goback = true;
1242  continue;
1243  }
1244 
1245  Token *typeName;
1246  Token *typeStart = nullptr;
1247  Token *typeEnd = nullptr;
1248  Token *argStart = nullptr;
1249  Token *argEnd = nullptr;
1250  Token *arrayStart = nullptr;
1251  Token *arrayEnd = nullptr;
1252  Token *specStart = nullptr;
1253  Token *specEnd = nullptr;
1254  Token *typeDef = tok;
1255  Token *argFuncRetStart = nullptr;
1256  Token *argFuncRetEnd = nullptr;
1257  Token *funcStart = nullptr;
1258  Token *funcEnd = nullptr;
1259  Token *tokOffset = tok->next();
1260  bool function = false;
1261  bool functionPtr = false;
1262  bool functionRetFuncPtr = false;
1263  bool functionPtrRetFuncPtr = false;
1264  bool ptrToArray = false;
1265  bool refToArray = false;
1266  bool ptrMember = false;
1267  bool typeOf = false;
1268  Token *namespaceStart = nullptr;
1269  Token *namespaceEnd = nullptr;
1270 
1271  // check for invalid input
1272  if (!tokOffset || tokOffset->isControlFlowKeyword())
1273  syntaxError(tok);
1274 
1275  if (tokOffset->str() == "::") {
1276  typeStart = tokOffset;
1277  tokOffset = tokOffset->next();
1278 
1279  while (Token::Match(tokOffset, "%type% ::"))
1280  tokOffset = tokOffset->tokAt(2);
1281 
1282  typeEnd = tokOffset;
1283 
1284  if (Token::Match(tokOffset, "%type%"))
1285  tokOffset = tokOffset->next();
1286  } else if (Token::Match(tokOffset, "%type% ::")) {
1287  typeStart = tokOffset;
1288 
1289  do {
1290  tokOffset = tokOffset->tokAt(2);
1291  } while (Token::Match(tokOffset, "%type% ::"));
1292 
1293  typeEnd = tokOffset;
1294 
1295  if (Token::Match(tokOffset, "%type%"))
1296  tokOffset = tokOffset->next();
1297  } else if (Token::Match(tokOffset, "%type%")) {
1298  typeStart = tokOffset;
1299 
1300  while (Token::Match(tokOffset, "const|struct|enum %type%") ||
1301  (tokOffset->next() && tokOffset->next()->isStandardType() && !Token::Match(tokOffset->next(), "%name% ;")))
1302  tokOffset = tokOffset->next();
1303 
1304  typeEnd = tokOffset;
1305  if (!Token::Match(tokOffset->next(), "%name% ;"))
1306  tokOffset = tokOffset->next();
1307 
1308  while (Token::Match(tokOffset, "%type%") &&
1309  (tokOffset->isStandardType() || Token::Match(tokOffset, "unsigned|signed")) &&
1310  !Token::Match(tokOffset->next(), "%name% ;")) {
1311  typeEnd = tokOffset;
1312  tokOffset = tokOffset->next();
1313  }
1314 
1315  bool atEnd = false;
1316  while (!atEnd) {
1317  if (tokOffset && tokOffset->str() == "::") {
1318  typeEnd = tokOffset;
1319  tokOffset = tokOffset->next();
1320  }
1321 
1322  if (Token::Match(tokOffset, "%type%") &&
1323  tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
1324  typeEnd = tokOffset;
1325  tokOffset = tokOffset->next();
1326  } else if (Token::simpleMatch(tokOffset, "const (")) {
1327  typeEnd = tokOffset;
1328  tokOffset = tokOffset->next();
1329  atEnd = true;
1330  } else
1331  atEnd = true;
1332  }
1333  } else
1334  continue; // invalid input
1335 
1336  // check for invalid input
1337  if (!tokOffset)
1338  syntaxError(tok);
1339 
1340  // check for template
1341  if (!isC() && tokOffset->str() == "<") {
1342  typeEnd = tokOffset->findClosingBracket();
1343 
1344  while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
1345  typeEnd = typeEnd->tokAt(2);
1346 
1347  if (!typeEnd) {
1348  // internal error
1349  return;
1350  }
1351 
1352  while (Token::Match(typeEnd->next(), "const|volatile"))
1353  typeEnd = typeEnd->next();
1354 
1355  tok = typeEnd;
1356  tokOffset = tok->next();
1357  }
1358 
1359  std::list<std::string> pointers;
1360  // check for pointers and references
1361  while (Token::Match(tokOffset, "*|&|&&|const")) {
1362  pointers.push_back(tokOffset->str());
1363  tokOffset = tokOffset->next();
1364  }
1365 
1366  // check for invalid input
1367  if (!tokOffset)
1368  syntaxError(tok);
1369 
1370  if (tokOffset->isName() && !tokOffset->isKeyword()) {
1371  // found the type name
1372  typeName = tokOffset;
1373  tokOffset = tokOffset->next();
1374 
1375  // check for array
1376  while (tokOffset && tokOffset->str() == "[") {
1377  if (!arrayStart)
1378  arrayStart = tokOffset;
1379  arrayEnd = tokOffset->link();
1380  tokOffset = arrayEnd->next();
1381  }
1382 
1383  // check for end or another
1384  if (Token::Match(tokOffset, ";|,"))
1385  tok = tokOffset;
1386 
1387  // or a function typedef
1388  else if (tokOffset && tokOffset->str() == "(") {
1389  Token *tokOffset2 = nullptr;
1390  if (Token::Match(tokOffset, "( *|%name%")) {
1391  tokOffset2 = tokOffset->next();
1392  if (tokOffset2->str() == "typename")
1393  tokOffset2 = tokOffset2->next();
1394  while (Token::Match(tokOffset2, "%type% ::"))
1395  tokOffset2 = tokOffset2->tokAt(2);
1396  }
1397 
1398  // unhandled typedef, skip it and continue
1399  if (typeName->str() == "void") {
1400  unsupportedTypedef(typeDef);
1401  tok = deleteInvalidTypedef(typeDef);
1402  if (tok == list.front())
1403  //now the next token to process is 'tok', not 'tok->next()';
1404  goback = true;
1405  continue;
1406  }
1407 
1408  // function pointer
1409  if (Token::Match(tokOffset2, "* %name% ) (")) {
1410  // name token wasn't a name, it was part of the type
1411  typeEnd = typeEnd->next();
1412  functionPtr = true;
1413  funcStart = funcEnd = tokOffset2; // *
1414  tokOffset = tokOffset2->tokAt(3); // (
1415  typeName = tokOffset->tokAt(-2);
1416  argStart = tokOffset;
1417  argEnd = tokOffset->link();
1418  tok = argEnd->next();
1419  }
1420 
1421  // function
1422  else if (isFunctionHead(tokOffset->link(), ";,")) {
1423  function = true;
1424  if (tokOffset->link()->next()->str() == "const") {
1425  specStart = tokOffset->link()->next();
1426  specEnd = specStart;
1427  }
1428  argStart = tokOffset;
1429  argEnd = tokOffset->link();
1430  tok = argEnd->next();
1431  if (specStart)
1432  tok = tok->next();
1433  }
1434 
1435  // syntax error
1436  else
1437  syntaxError(tok);
1438  }
1439 
1440  // unhandled typedef, skip it and continue
1441  else {
1442  unsupportedTypedef(typeDef);
1443  tok = deleteInvalidTypedef(typeDef);
1444  if (tok == list.front())
1445  //now the next token to process is 'tok', not 'tok->next()';
1446  goback = true;
1447  continue;
1448  }
1449  }
1450 
1451  // typeof: typedef typeof ( ... ) type;
1452  else if (Token::simpleMatch(tokOffset->previous(), "typeof (") &&
1453  Token::Match(tokOffset->link(), ") %type% ;")) {
1454  argStart = tokOffset;
1455  argEnd = tokOffset->link();
1456  typeName = tokOffset->link()->next();
1457  tok = typeName->next();
1458  typeOf = true;
1459  }
1460 
1461  // function: typedef ... ( ... type )( ... );
1462  // typedef ... (( ... type )( ... ));
1463  // typedef ... ( * ( ... type )( ... ));
1464  else if (tokOffset->str() == "(" && (
1465  (tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
1466  Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
1467  (Token::simpleMatch(tokOffset, "( (") &&
1468  tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
1469  Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
1470  (Token::simpleMatch(tokOffset, "( * (") &&
1471  tokOffset->linkAt(2) && Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
1472  Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
1473  if (tokOffset->next()->str() == "(")
1474  tokOffset = tokOffset->next();
1475  else if (Token::simpleMatch(tokOffset, "( * (")) {
1476  pointers.emplace_back("*");
1477  tokOffset = tokOffset->tokAt(2);
1478  }
1479 
1480  if (tokOffset->link()->strAt(-2) == "*")
1481  functionPtr = true;
1482  else
1483  function = true;
1484  funcStart = tokOffset->next();
1485  tokOffset = tokOffset->link();
1486  funcEnd = tokOffset->tokAt(-2);
1487  typeName = tokOffset->previous();
1488  argStart = tokOffset->next();
1489  argEnd = tokOffset->next()->link();
1490  if (!argEnd)
1491  syntaxError(argStart);
1492 
1493  tok = argEnd->next();
1494  Token *spec = tok;
1495  if (Token::Match(spec, "const|volatile")) {
1496  specStart = spec;
1497  specEnd = spec;
1498  while (Token::Match(spec->next(), "const|volatile")) {
1499  specEnd = spec->next();
1500  spec = specEnd;
1501  }
1502  tok = specEnd->next();
1503  }
1504  if (!tok)
1505  syntaxError(specEnd);
1506 
1507  if (tok->str() == ")")
1508  tok = tok->next();
1509  }
1510 
1511  else if (Token::Match(tokOffset, "( %type% (")) {
1512  function = true;
1513  if (tokOffset->link()->next()) {
1514  tok = tokOffset->link()->next();
1515  tokOffset = tokOffset->tokAt(2);
1516  typeName = tokOffset->previous();
1517  argStart = tokOffset;
1518  argEnd = tokOffset->link();
1519  } else {
1520  // internal error
1521  continue;
1522  }
1523  }
1524 
1525  // pointer to function returning pointer to function
1526  else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
1527  Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
1528  Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
1529  functionPtrRetFuncPtr = true;
1530 
1531  tokOffset = tokOffset->tokAt(6);
1532  typeName = tokOffset->tokAt(-2);
1533  argStart = tokOffset;
1534  argEnd = tokOffset->link();
1535  if (!argEnd)
1536  syntaxError(arrayStart);
1537 
1538  argFuncRetStart = argEnd->tokAt(2);
1539  argFuncRetEnd = argFuncRetStart->link();
1540  if (!argFuncRetEnd)
1541  syntaxError(argFuncRetStart);
1542 
1543  tok = argFuncRetEnd->next();
1544  }
1545 
1546  // function returning pointer to function
1547  else if (Token::Match(tokOffset, "( * %type% (") &&
1548  Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
1549  Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
1550  functionRetFuncPtr = true;
1551 
1552  tokOffset = tokOffset->tokAt(3);
1553  typeName = tokOffset->previous();
1554  argStart = tokOffset;
1555  argEnd = tokOffset->link();
1556 
1557  argFuncRetStart = argEnd->tokAt(2);
1558  if (!argFuncRetStart)
1559  syntaxError(tokOffset);
1560 
1561  argFuncRetEnd = argFuncRetStart->link();
1562  if (!argFuncRetEnd)
1563  syntaxError(tokOffset);
1564 
1565  tok = argFuncRetEnd->next();
1566  } else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
1567  functionRetFuncPtr = true;
1568 
1569  tokOffset = tokOffset->tokAt(5);
1570  typeName = tokOffset->tokAt(-2);
1571  argStart = tokOffset;
1572  argEnd = tokOffset->link();
1573  if (!argEnd)
1574  syntaxError(arrayStart);
1575 
1576  argFuncRetStart = argEnd->tokAt(2);
1577  if (!argFuncRetStart)
1578  syntaxError(tokOffset);
1579 
1580  argFuncRetEnd = argFuncRetStart->link();
1581  if (!argFuncRetEnd)
1582  syntaxError(tokOffset);
1583 
1584  tok = argFuncRetEnd->next();
1585  }
1586 
1587  // pointer/reference to array
1588  else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
1589  ptrToArray = (tokOffset->next()->str() == "*");
1590  refToArray = !ptrToArray;
1591  tokOffset = tokOffset->tokAt(2);
1592  typeName = tokOffset;
1593  arrayStart = tokOffset->tokAt(2);
1594  arrayEnd = arrayStart->link();
1595  if (!arrayEnd)
1596  syntaxError(arrayStart);
1597 
1598  tok = arrayEnd->next();
1599  }
1600 
1601  // pointer to class member
1602  else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
1603  tokOffset = tokOffset->tokAt(2);
1604  namespaceStart = tokOffset->previous();
1605  namespaceEnd = tokOffset;
1606  ptrMember = true;
1607  tokOffset = tokOffset->tokAt(2);
1608  typeName = tokOffset;
1609  tok = tokOffset->tokAt(2);
1610  }
1611 
1612  // unhandled typedef, skip it and continue
1613  else {
1614  unsupportedTypedef(typeDef);
1615  tok = deleteInvalidTypedef(typeDef);
1616  if (tok == list.front())
1617  //now the next token to process is 'tok', not 'tok->next()';
1618  goback = true;
1619  continue;
1620  }
1621 
1622  bool done = false;
1623  bool ok = true;
1624 
1625  TypedefInfo typedefInfo;
1626  typedefInfo.name = typeName->str();
1627  typedefInfo.filename = list.file(typeName);
1628  typedefInfo.lineNumber = typeName->linenr();
1629  typedefInfo.column = typeName->column();
1630  typedefInfo.used = false;
1631  mTypedefInfo.push_back(std::move(typedefInfo));
1632 
1633  while (!done) {
1634  std::string pattern = typeName->str();
1635  int scope = 0;
1636  bool simplifyType = false;
1637  bool inMemberFunc = false;
1638  int memberScope = 0;
1639  bool globalScope = false;
1640  int classLevel = spaceInfo.size();
1641  bool inTypeDef = false;
1642  bool inEnum = false;
1643  std::string removed;
1644  std::string classPath;
1645  for (size_t i = 1; i < spaceInfo.size(); ++i) {
1646  if (!classPath.empty())
1647  classPath += " :: ";
1648  classPath += spaceInfo[i].className;
1649  }
1650 
1651  for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1652  if (Settings::terminated())
1653  return;
1654 
1655  removed.clear();
1656 
1657  if (Token::simpleMatch(tok2, "typedef"))
1658  inTypeDef = true;
1659 
1660  if (inTypeDef && Token::simpleMatch(tok2, ";"))
1661  inTypeDef = false;
1662 
1663  // Check for variable declared with the same name
1664  if (!inTypeDef && spaceInfo.size() == 1 && Token::Match(tok2->previous(), "%name%") &&
1665  !tok2->previous()->isKeyword()) {
1666  Token* varDecl = tok2;
1667  while (Token::Match(varDecl, "*|&|&&|const"))
1668  varDecl = varDecl->next();
1669  if (Token::Match(varDecl, "%name% ;|,|)|=") && varDecl->str() == typeName->str()) {
1670  // Skip to the next closing brace
1671  if (Token::Match(varDecl, "%name% ) {")) { // is argument variable
1672  tok2 = varDecl->linkAt(2)->next();
1673  } else {
1674  tok2 = varDecl;
1675  while (tok2 && !Token::simpleMatch(tok2, "}")) {
1676  if (Token::Match(tok2, "(|{|["))
1677  tok2 = tok2->link();
1678  tok2 = tok2->next();
1679  }
1680  }
1681  if (!tok2)
1682  break;
1683  continue;
1684  }
1685  }
1686 
1687  if (tok2->link()) { // Pre-check for performance
1688  // check for end of scope
1689  if (tok2->str() == "}") {
1690  // check for end of member function
1691  if (inMemberFunc) {
1692  --memberScope;
1693  if (memberScope == 0)
1694  inMemberFunc = false;
1695  }
1696  inEnum = false;
1697 
1698  if (classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd2) {
1699  --classLevel;
1700  pattern.clear();
1701 
1702  for (int i = classLevel; i < spaceInfo.size(); ++i)
1703  pattern += (spaceInfo[i].className + " :: ");
1704 
1705  pattern += typeName->str();
1706  } else {
1707  if (scope == 0 && !(classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd))
1708  break;
1709  scope = std::max(scope - 1, 0);
1710  }
1711  }
1712 
1713  // check for member functions
1714  else if (tok2->isCpp() && tok2->str() == "(" && isFunctionHead(tok2, "{:")) {
1715  const Token *func = tok2->previous();
1716 
1717  /** @todo add support for multi-token operators */
1718  if (func->previous()->str() == "operator")
1719  func = func->previous();
1720 
1721  if (!func->previous())
1722  syntaxError(func);
1723 
1724  // check for qualifier
1725  if (Token::Match(func->tokAt(-2), "%name% ::")) {
1726  int offset = -2;
1727  while (Token::Match(func->tokAt(offset - 2), "%name% ::"))
1728  offset -= 2;
1729  // check for available and matching class name
1730  if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1731  func->strAt(offset) == spaceInfo[classLevel].className) {
1732  memberScope = 0;
1733  inMemberFunc = true;
1734  }
1735  }
1736  }
1737 
1738  // check for entering a new scope
1739  else if (tok2->str() == "{") {
1740  // check for entering a new namespace
1741  if (tok2->isCpp()) {
1742  if (tok2->strAt(-2) == "namespace") {
1743  if (classLevel < spaceInfo.size() &&
1744  spaceInfo[classLevel].isNamespace &&
1745  spaceInfo[classLevel].className == tok2->previous()->str()) {
1746  spaceInfo[classLevel].bodyEnd2 = tok2->link();
1747  ++classLevel;
1748  pattern.clear();
1749  for (int i = classLevel; i < spaceInfo.size(); ++i)
1750  pattern += spaceInfo[i].className + " :: ";
1751 
1752  pattern += typeName->str();
1753  }
1754  ++scope;
1755  }
1756  if (isEnumScope(tok2))
1757  inEnum = true;
1758  }
1759 
1760  // keep track of scopes within member function
1761  if (inMemberFunc)
1762  ++memberScope;
1763 
1764  ++scope;
1765  }
1766  }
1767 
1768  // check for operator typedef
1769  /** @todo add support for multi-token operators */
1770  else if (tok2->isCpp() &&
1771  tok2->str() == "operator" &&
1772  tok2->next() &&
1773  tok2->next()->str() == typeName->str() &&
1774  tok2->linkAt(2) &&
1775  tok2->strAt(2) == "(" &&
1776  Token::Match(tok2->linkAt(2), ") const| {")) {
1777  // check for qualifier
1778  if (tok2->previous()->str() == "::") {
1779  // check for available and matching class name
1780  if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1781  tok2->strAt(-2) == spaceInfo[classLevel].className) {
1782  tok2 = tok2->next();
1783  simplifyType = true;
1784  }
1785  }
1786  }
1787 
1788  else if (Token::Match(tok2->previous(), "class|struct %name% [:{]")) {
1789  // don't replace names in struct/class definition
1790  }
1791 
1792  // check for typedef that can be substituted
1793  else if ((tok2->isNameOnly() || (tok2->isName() && (tok2->isExpandedMacro() || tok2->isInline()))) &&
1794  (Token::simpleMatch(tok2, pattern.c_str(), pattern.size()) ||
1795  (inMemberFunc && tok2->str() == typeName->str()))) {
1796  // member function class variables don't need qualification
1797  if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
1798  Token *start = tok2;
1799  int count = 0;
1800  int back = classLevel - 1;
1801  bool good = true;
1802  // check for extra qualification
1803  while (back >= 1) {
1804  Token *qualificationTok = start->tokAt(-2);
1805  if (!Token::Match(qualificationTok, "%type% ::"))
1806  break;
1807  if (qualificationTok->str() == spaceInfo[back].className) {
1808  start = qualificationTok;
1809  back--;
1810  count++;
1811  } else {
1812  good = false;
1813  break;
1814  }
1815  }
1816  // check global namespace
1817  if (good && back == 1 && start->strAt(-1) == "::")
1818  good = false;
1819 
1820  if (good) {
1821  // remove any extra qualification if present
1822  while (count) {
1823  if (!removed.empty())
1824  removed.insert(0, " ");
1825  removed.insert(0, tok2->strAt(-2) + " " + tok2->strAt(-1));
1826  tok2->tokAt(-3)->deleteNext(2);
1827  --count;
1828  }
1829 
1830  // remove global namespace if present
1831  if (tok2->strAt(-1) == "::") {
1832  removed.insert(0, ":: ");
1833  tok2->tokAt(-2)->deleteNext();
1834  globalScope = true;
1835  }
1836 
1837  // remove qualification if present
1838  for (int i = classLevel; i < spaceInfo.size(); ++i) {
1839  if (!removed.empty())
1840  removed += " ";
1841  removed += (tok2->str() + " " + tok2->strAt(1));
1842  tok2->deleteThis();
1843  tok2->deleteThis();
1844  }
1845  simplifyType = true;
1846  }
1847  } else {
1848  if (tok2->strAt(-1) == "::") {
1849  int relativeSpaceInfoSize = spaceInfo.size();
1850  Token * tokBeforeType = tok2->previous();
1851  while (relativeSpaceInfoSize > 1 &&
1852  tokBeforeType && tokBeforeType->str() == "::" &&
1853  tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
1854  tokBeforeType = tokBeforeType->tokAt(-2);
1855  --relativeSpaceInfoSize;
1856  }
1857  if (tokBeforeType && tokBeforeType->str() != "::") {
1858  Token::eraseTokens(tokBeforeType, tok2);
1859  simplifyType = true;
1860  }
1861  } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
1862  tok2 = tok2->next();
1863  } else if (duplicateTypedef(tok2, typeName, typeDef)) {
1864  // skip to end of scope if not already there
1865  if (tok2->str() != "}") {
1866  while (tok2->next()) {
1867  if (tok2->next()->str() == "{")
1868  tok2 = tok2->linkAt(1)->previous();
1869  else if (tok2->next()->str() == "}")
1870  break;
1871 
1872  tok2 = tok2->next();
1873  }
1874  }
1875  } else if (Token::Match(tok2->tokAt(-2), "%type% *|&")) {
1876  // Ticket #5868: Don't substitute variable names
1877  } else if (tok2->previous()->str() != ".") {
1878  simplifyType = (TypedefSimplifier::canReplaceStatic(tok2) != 0);
1879  }
1880  }
1881  }
1882 
1883  simplifyType = simplifyType && (!inEnum || !Token::simpleMatch(tok2->next(), "="));
1884  simplifyType = simplifyType && !(Token::simpleMatch(tok2->next(), "<") && Token::simpleMatch(typeEnd, ">"));
1885 
1886  if (simplifyType) {
1887  mTypedefInfo.back().used = true;
1888 
1889  // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
1890  if (functionPtr && (tok2->previous()->str() == "operator" ||
1891  (tok2->next() && tok2->next()->str() == "operator"))) {
1892  simplifyType = false;
1893  tok2 = tok2->next();
1894  continue;
1895  }
1896 
1897  // There are 2 categories of typedef substitutions:
1898  // 1. variable declarations that preserve the variable name like
1899  // global, local, and function parameters
1900  // 2. not variable declarations that have no name like derived
1901  // classes, casts, operators, and template parameters
1902 
1903  // try to determine which category this substitution is
1904  bool inCast = false;
1905  bool inTemplate = false;
1906  bool inOperator = false;
1907  bool inSizeof = false;
1908 
1909  const bool sameStartEnd = (typeStart == typeEnd);
1910 
1911  // check for derived class: class A : some_typedef {
1912  const bool isDerived = Token::Match(tok2->previous(), "public|protected|private|: %type% {|,");
1913 
1914  // check for cast: (some_typedef) A or static_cast<some_typedef>(A)
1915  // todo: check for more complicated casts like: (const some_typedef *)A
1916  if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
1917  (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")) ||
1918  Token::Match(tok2->tokAt(-2), "( const %name% )"))
1919  inCast = true;
1920 
1921  // check for template parameters: t<some_typedef> t1
1922  else if (Token::Match(tok2->previous(), "<|,") &&
1923  Token::Match(tok2->next(), "&|*| &|*| >|,"))
1924  inTemplate = true;
1925 
1926  else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
1927  inSizeof = true;
1928 
1929  // check for operator
1930  if (tok2->strAt(-1) == "operator" ||
1931  Token::simpleMatch(tok2->tokAt(-2), "operator const"))
1932  inOperator = true;
1933 
1934  if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
1935  // Remove one typename if it is already contained in the goal
1936  typeStart = typeStart->next();
1937  }
1938 
1939  // skip over class or struct in derived class declaration
1940  bool structRemoved = false;
1941  if ((isDerived || inTemplate) && Token::Match(typeStart, "class|struct")) {
1942  if (typeStart->str() == "struct")
1943  structRemoved = true;
1944  typeStart = typeStart->next();
1945  }
1946  if (Token::Match(typeStart, "struct|class|union") && Token::Match(tok2, "%name% ::"))
1947  typeStart = typeStart->next();
1948 
1949  if (sameStartEnd)
1950  typeEnd = typeStart;
1951 
1952  // Is this a "T()" expression where T is a pointer type?
1953  const bool isPointerTypeCall = !inOperator && Token::Match(tok2, "%name% ( )") && !pointers.empty();
1954 
1955  // start substituting at the typedef name by replacing it with the type
1956  Token* replStart = tok2; // track first replaced token
1957  for (Token* tok3 = typeStart; tok3 && (tok3->str() != ";"); tok3 = tok3->next())
1958  tok3->isSimplifiedTypedef(true);
1959  if (isPointerTypeCall) {
1960  tok2->deleteThis();
1961  tok2->insertToken("0");
1962  tok2 = tok2->next();
1963  tok2->next()->insertToken("0");
1964  }
1965  if (Token::Match(tok2->tokAt(-1), "class|struct|union") && tok2->strAt(-1) == typeStart->str())
1966  tok2->deletePrevious();
1967  tok2->str(typeStart->str());
1968 
1969  // restore qualification if it was removed
1970  if (Token::Match(typeStart, "class|struct|union") || structRemoved) {
1971  if (structRemoved)
1972  tok2 = tok2->previous();
1973 
1974  if (globalScope) {
1975  replStart = tok2->insertToken("::");
1976  tok2 = tok2->next();
1977  }
1978 
1979  for (int i = classLevel; i < spaceInfo.size(); ++i) {
1980  tok2->insertToken(spaceInfo[i].className);
1981  tok2 = tok2->next();
1982  tok2->insertToken("::");
1983  tok2 = tok2->next();
1984  }
1985  }
1986 
1987  // add some qualification back if needed
1988  Token *start = tok2;
1989  std::string removed1 = removed;
1990  std::string::size_type idx = removed1.rfind(" ::");
1991 
1992  if (idx != std::string::npos)
1993  removed1.resize(idx);
1994  if (removed1 == classPath && !removed1.empty()) {
1995  for (std::vector<Space>::const_reverse_iterator it = spaceInfo.crbegin(); it != spaceInfo.crend(); ++it) {
1996  if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
1997  std::string::size_type spaceIdx = 0;
1998  std::string::size_type startIdx = 0;
1999  while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
2000  tok2->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
2001  startIdx = spaceIdx + 1;
2002  }
2003  tok2->previous()->insertToken(removed1.substr(startIdx));
2004  replStart = tok2->previous()->insertToken("::");
2005  break;
2006  }
2007  idx = removed1.rfind(" ::");
2008  if (idx == std::string::npos)
2009  break;
2010 
2011  removed1.resize(idx);
2012  }
2013  }
2014  replStart->isSimplifiedTypedef(true);
2015  Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
2016  // add remainder of type
2017  tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
2018 
2019  if (!pointers.empty()) {
2020  for (const std::string &p : pointers) {
2021  tok2->insertToken(p);
2022  tok2->isSimplifiedTypedef(true);
2023  tok2 = tok2->next();
2024  }
2025  if (constTok) {
2026  constTok->deleteThis();
2027  tok2->insertToken("const");
2028  tok2->isSimplifiedTypedef(true);
2029  tok2 = tok2->next();
2030  }
2031  }
2032 
2033  if (funcStart && funcEnd) {
2034  tok2->insertToken("(");
2035  tok2 = tok2->next();
2036  Token *paren = tok2;
2037  tok2 = TokenList::copyTokens(tok2, funcStart, funcEnd);
2038 
2039  if (!inCast)
2040  tok2 = processFunc(tok2, inOperator);
2041 
2042  if (!tok2)
2043  break;
2044 
2045  while (Token::Match(tok2, "%name%|] ["))
2046  tok2 = tok2->linkAt(1);
2047 
2048  tok2->insertToken(")");
2049  tok2 = tok2->next();
2050  Token::createMutualLinks(tok2, paren);
2051 
2052  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2053 
2054  if (specStart) {
2055  Token *spec = specStart;
2056  tok2->insertToken(spec->str());
2057  tok2 = tok2->next();
2058  while (spec != specEnd) {
2059  spec = spec->next();
2060  tok2->insertToken(spec->str());
2061  tok2 = tok2->next();
2062  }
2063  }
2064  }
2065 
2066  else if (functionPtr || function) {
2067  // don't add parentheses around function names because it
2068  // confuses other simplifications
2069  bool needParen = true;
2070  if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
2071  needParen = false;
2072  if (needParen) {
2073  tok2->insertToken("(");
2074  tok2 = tok2->next();
2075  }
2076  Token *tok3 = tok2;
2077  if (namespaceStart) {
2078  const Token *tok4 = namespaceStart;
2079 
2080  while (tok4 != namespaceEnd) {
2081  tok2->insertToken(tok4->str());
2082  tok2 = tok2->next();
2083  tok4 = tok4->next();
2084  }
2085  tok2->insertToken(namespaceEnd->str());
2086  tok2 = tok2->next();
2087  }
2088  if (functionPtr) {
2089  tok2->insertToken("*");
2090  tok2 = tok2->next();
2091  }
2092 
2093  if (!inCast)
2094  tok2 = processFunc(tok2, inOperator);
2095 
2096  if (needParen) {
2097  if (!tok2)
2098  syntaxError(nullptr);
2099 
2100  tok2->insertToken(")");
2101  tok2 = tok2->next();
2102  Token::createMutualLinks(tok2, tok3);
2103  }
2104  if (!tok2)
2105  syntaxError(nullptr);
2106 
2107  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2108  if (inTemplate) {
2109  if (!tok2)
2110  syntaxError(nullptr);
2111 
2112  tok2 = tok2->next();
2113  }
2114 
2115  if (specStart) {
2116  Token *spec = specStart;
2117  tok2->insertToken(spec->str());
2118  tok2 = tok2->next();
2119  while (spec != specEnd) {
2120  spec = spec->next();
2121  tok2->insertToken(spec->str());
2122  tok2 = tok2->next();
2123  }
2124  }
2125  } else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
2126  tok2->insertToken("(");
2127  tok2 = tok2->next();
2128  Token *tok3 = tok2;
2129  tok2->insertToken("*");
2130  tok2 = tok2->next();
2131 
2132  Token * tok4 = nullptr;
2133  if (functionPtrRetFuncPtr) {
2134  tok2->insertToken("(");
2135  tok2 = tok2->next();
2136  tok4 = tok2;
2137  tok2->insertToken("*");
2138  tok2 = tok2->next();
2139  }
2140 
2141  // skip over variable name if there
2142  if (!inCast) {
2143  if (!tok2 || !tok2->next())
2144  syntaxError(nullptr);
2145 
2146  if (tok2->next()->str() != ")")
2147  tok2 = tok2->next();
2148  }
2149 
2150  if (tok4 && functionPtrRetFuncPtr) {
2151  tok2->insertToken(")");
2152  tok2 = tok2->next();
2153  Token::createMutualLinks(tok2, tok4);
2154  }
2155 
2156  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2157 
2158  tok2->insertToken(")");
2159  tok2 = tok2->next();
2160  Token::createMutualLinks(tok2, tok3);
2161 
2162  tok2 = TokenList::copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
2163  } else if (ptrToArray || refToArray) {
2164  tok2->insertToken("(");
2165  tok2 = tok2->next();
2166  Token *tok3 = tok2;
2167 
2168  if (ptrToArray)
2169  tok2->insertToken("*");
2170  else
2171  tok2->insertToken("&");
2172  tok2 = tok2->next();
2173 
2174  bool hasName = false;
2175  // skip over name
2176  if (tok2->next() && tok2->next()->str() != ")" && tok2->next()->str() != "," &&
2177  tok2->next()->str() != ">") {
2178  hasName = true;
2179  if (tok2->next()->str() != "(")
2180  tok2 = tok2->next();
2181 
2182  // check for function and skip over args
2183  if (tok2 && tok2->next() && tok2->next()->str() == "(")
2184  tok2 = tok2->next()->link();
2185 
2186  // check for array
2187  if (tok2 && tok2->next() && tok2->next()->str() == "[")
2188  tok2 = tok2->next()->link();
2189  }
2190 
2191  tok2->insertToken(")");
2192  Token::createMutualLinks(tok2->next(), tok3);
2193 
2194  if (!hasName)
2195  tok2 = tok2->next();
2196  } else if (ptrMember) {
2197  if (Token::simpleMatch(tok2, "* (")) {
2198  tok2->insertToken("*");
2199  tok2 = tok2->next();
2200  } else {
2201  // This is the case of casting operator.
2202  // Name is not available, and () should not be
2203  // inserted
2204  const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
2205  Token *openParenthesis = nullptr;
2206 
2207  if (!castOperator) {
2208  tok2->insertToken("(");
2209  tok2 = tok2->next();
2210 
2211  openParenthesis = tok2;
2212  }
2213 
2214  const Token *tok4 = namespaceStart;
2215 
2216  while (tok4 != namespaceEnd) {
2217  tok2->insertToken(tok4->str());
2218  tok2 = tok2->next();
2219  tok4 = tok4->next();
2220  }
2221  tok2->insertToken(namespaceEnd->str());
2222  tok2 = tok2->next();
2223 
2224  tok2->insertToken("*");
2225  tok2 = tok2->next();
2226 
2227  if (openParenthesis) {
2228  // Skip over name, if any
2229  if (Token::Match(tok2->next(), "%name%"))
2230  tok2 = tok2->next();
2231 
2232  tok2->insertToken(")");
2233  tok2 = tok2->next();
2234 
2235  Token::createMutualLinks(tok2, openParenthesis);
2236  }
2237  }
2238  } else if (typeOf) {
2239  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2240  } else if (Token::Match(tok2, "%name% [")) {
2241  while (Token::Match(tok2, "%name%|] [")) {
2242  tok2 = tok2->linkAt(1);
2243  }
2244  tok2 = tok2->previous();
2245  }
2246 
2247  if (arrayStart && arrayEnd) {
2248  do {
2249  if (!tok2->next())
2250  syntaxError(tok2); // can't recover so quit
2251 
2252  if (!inCast && !inSizeof && !inTemplate)
2253  tok2 = tok2->next();
2254 
2255  if (tok2->str() == "const")
2256  tok2 = tok2->next();
2257 
2258  // reference or pointer to array?
2259  if (Token::Match(tok2, "&|*|&&")) {
2260  tok2 = tok2->previous();
2261  tok2->insertToken("(");
2262  Token *tok3 = tok2->next();
2263 
2264  // handle missing variable name
2265  if (Token::Match(tok3, "( *|&|&& *|&|&& %name%"))
2266  tok2 = tok3->tokAt(3);
2267  else if (Token::Match(tok2->tokAt(3), "[(),;]"))
2268  tok2 = tok2->tokAt(2);
2269  else if (Token::simpleMatch(tok2->tokAt(3), ">"))
2270  tok2 = tok2->tokAt(2);
2271  else
2272  tok2 = tok2->tokAt(3);
2273  if (!tok2)
2274  syntaxError(nullptr);
2275 
2276  while (tok2->strAt(1) == "::")
2277  tok2 = tok2->tokAt(2);
2278 
2279  // skip over function parameters
2280  if (tok2->str() == "(")
2281  tok2 = tok2->link();
2282 
2283  if (tok2->strAt(1) == "(")
2284  tok2 = tok2->linkAt(1);
2285 
2286  // skip over const/noexcept
2287  while (Token::Match(tok2->next(), "const|noexcept")) {
2288  tok2 = tok2->next();
2289  if (Token::Match(tok2->next(), "( true|false )"))
2290  tok2 = tok2->tokAt(3);
2291  }
2292 
2293  tok2->insertToken(")");
2294  tok2 = tok2->next();
2295  Token::createMutualLinks(tok2, tok3);
2296  }
2297 
2298  if (!tok2->next())
2299  syntaxError(tok2); // can't recover so quit
2300 
2301  // skip over array dimensions
2302  while (tok2->next()->str() == "[")
2303  tok2 = tok2->linkAt(1);
2304 
2305  tok2 = TokenList::copyTokens(tok2, arrayStart, arrayEnd);
2306  if (!tok2->next())
2307  syntaxError(tok2);
2308 
2309  if (tok2->str() == "=") {
2310  if (tok2->next()->str() == "{")
2311  tok2 = tok2->next()->link()->next();
2312  else if (tok2->next()->str().at(0) == '\"')
2313  tok2 = tok2->tokAt(2);
2314  }
2315  } while (Token::Match(tok2, ", %name% ;|=|,"));
2316  }
2317 
2318  simplifyType = false;
2319  }
2320  if (!tok2)
2321  break;
2322  }
2323 
2324  if (!tok)
2325  syntaxError(nullptr);
2326 
2327  if (tok->str() == ";")
2328  done = true;
2329  else if (tok->str() == ",") {
2330  arrayStart = nullptr;
2331  arrayEnd = nullptr;
2332  tokOffset = tok->next();
2333  pointers.clear();
2334 
2335  while (Token::Match(tokOffset, "*|&")) {
2336  pointers.push_back(tokOffset->str());
2337  tokOffset = tokOffset->next();
2338  }
2339 
2340  if (Token::Match(tokOffset, "%type%")) {
2341  typeName = tokOffset;
2342  tokOffset = tokOffset->next();
2343 
2344  if (tokOffset && tokOffset->str() == "[") {
2345  arrayStart = tokOffset;
2346 
2347  for (;;) {
2348  while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
2349  tokOffset = tokOffset->next();
2350 
2351  if (!tokOffset->next())
2352  return; // invalid input
2353  if (tokOffset->next()->str() == ";")
2354  break;
2355  if (tokOffset->str() == "]")
2356  break;
2357  tokOffset = tokOffset->next();
2358  }
2359 
2360  arrayEnd = tokOffset;
2361  tokOffset = tokOffset->next();
2362  }
2363 
2364  if (Token::Match(tokOffset, ";|,"))
2365  tok = tokOffset;
2366  else {
2367  // we encountered a typedef we don't support yet so just continue
2368  done = true;
2369  ok = false;
2370  }
2371  } else {
2372  // we encountered a typedef we don't support yet so just continue
2373  done = true;
2374  ok = false;
2375  }
2376  } else {
2377  // something is really wrong (internal error)
2378  done = true;
2379  ok = false;
2380  }
2381  }
2382 
2383  if (ok) {
2384  // remove typedef
2385  Token::eraseTokens(typeDef, tok);
2386 
2387  if (typeDef != list.front()) {
2388  tok = typeDef->previous();
2389  tok->deleteNext();
2390  //no need to remove last token in the list
2391  if (tok->tokAt(2))
2392  tok->deleteNext();
2393  } else {
2394  list.front()->deleteThis();
2395  //no need to remove last token in the list
2396  if (list.front()->next())
2397  list.front()->deleteThis();
2398  tok = list.front();
2399  //now the next token to process is 'tok', not 'tok->next()';
2400  goback = true;
2401  }
2402  }
2403  }
2404 }
2405 
2406 namespace {
2407  struct ScopeInfo3 {
2408  enum Type { Global, Namespace, Record, MemberFunction, Other };
2409  ScopeInfo3() : parent(nullptr), type(Global), bodyStart(nullptr), bodyEnd(nullptr) {}
2410  ScopeInfo3(ScopeInfo3 *parent_, Type type_, std::string name_, const Token *bodyStart_, const Token *bodyEnd_)
2411  : parent(parent_), type(type_), name(std::move(name_)), bodyStart(bodyStart_), bodyEnd(bodyEnd_) {
2412  if (name.empty())
2413  return;
2414  fullName = name;
2415  ScopeInfo3 *scope = parent;
2416  while (scope && scope->parent) {
2417  if (scope->name.empty())
2418  break;
2419  fullName = scope->name + " :: " + fullName;
2420  scope = scope->parent;
2421  }
2422  }
2423  ScopeInfo3 *parent;
2424  std::list<ScopeInfo3> children;
2425  Type type;
2426  std::string fullName;
2427  std::string name;
2428  const Token * bodyStart;
2429  const Token * bodyEnd;
2430  std::set<std::string> usingNamespaces;
2431  std::set<std::string> recordTypes;
2432  std::set<std::string> baseTypes;
2433 
2434  ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) {
2435  children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken);
2436  return &children.back();
2437  }
2438 
2439  bool hasChild(const std::string &childName) const {
2440  return std::any_of(children.cbegin(), children.cend(), [&](const ScopeInfo3& child) {
2441  return child.name == childName;
2442  });
2443  }
2444 
2445  const ScopeInfo3 * findInChildren(const std::string & scope) const {
2446  for (const auto & child : children) {
2447  if (child.type == Record && (child.name == scope || child.fullName == scope))
2448  return &child;
2449 
2450  const ScopeInfo3 * temp = child.findInChildren(scope);
2451  if (temp)
2452  return temp;
2453  }
2454  return nullptr;
2455  }
2456 
2457  const ScopeInfo3 * findScope(const std::string & scope) const {
2458  const ScopeInfo3 * tempScope = this;
2459  while (tempScope) {
2460  // check children
2461  auto it = std::find_if(tempScope->children.cbegin(), tempScope->children.cend(), [&](const ScopeInfo3& child) {
2462  return &child != this && child.type == Record && (child.name == scope || child.fullName == scope);
2463  });
2464  if (it != tempScope->children.end())
2465  return &*it;
2466  // check siblings for same name
2467  if (tempScope->parent) {
2468  for (const auto &sibling : tempScope->parent->children) {
2469  if (sibling.name == tempScope->name && &sibling != this) {
2470  const ScopeInfo3 * temp = sibling.findInChildren(scope);
2471  if (temp)
2472  return temp;
2473  }
2474  }
2475  }
2476  tempScope = tempScope->parent;
2477  }
2478  return nullptr;
2479  }
2480 
2481  bool findTypeInBase(const std::string &scope) const {
2482  if (scope.empty())
2483  return false;
2484  // check in base types first
2485  if (baseTypes.find(scope) != baseTypes.end())
2486  return true;
2487  // check in base types base types
2488  for (const std::string & base : baseTypes) {
2489  const ScopeInfo3 * baseScope = findScope(base);
2490  // bail on uninstantiated recursive template
2491  if (baseScope == this)
2492  return false;
2493  if (baseScope && baseScope->fullName == scope)
2494  return true;
2495  if (baseScope && baseScope->findTypeInBase(scope))
2496  return true;
2497  }
2498  return false;
2499  }
2500 
2501  ScopeInfo3 * findScope(const ScopeInfo3 * scope) {
2502  if (scope->bodyStart == bodyStart)
2503  return this;
2504  for (auto & child : children) {
2505  ScopeInfo3 * temp = child.findScope(scope);
2506  if (temp)
2507  return temp;
2508  }
2509  return nullptr;
2510  }
2511  };
2512 
2513  void setScopeInfo(Token *tok, ScopeInfo3 *&scopeInfo, bool debug=false)
2514  {
2515  if (!tok)
2516  return;
2517  if (tok->str() == "{" && scopeInfo->parent && tok == scopeInfo->bodyStart)
2518  return;
2519  if (tok->str() == "}") {
2520  if (scopeInfo->parent && tok == scopeInfo->bodyEnd)
2521  scopeInfo = scopeInfo->parent;
2522  else {
2523  // Try to find parent scope
2524  ScopeInfo3 *parent = scopeInfo->parent;
2525  while (parent && parent->bodyEnd != tok)
2526  parent = parent->parent;
2527  if (parent) {
2528  scopeInfo = parent;
2529  if (debug)
2530  throw std::runtime_error("Internal error: unmatched }");
2531  }
2532  }
2533  return;
2534  }
2535  if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::|<")) {
2536  // check for using namespace
2537  if (Token::Match(tok, "using namespace %name% ;|::")) {
2538  const Token * tok1 = tok->tokAt(2);
2539  std::string nameSpace;
2540  while (tok1 && tok1->str() != ";") {
2541  if (!nameSpace.empty())
2542  nameSpace += " ";
2543  nameSpace += tok1->str();
2544  tok1 = tok1->next();
2545  }
2546  scopeInfo->usingNamespaces.insert(std::move(nameSpace));
2547  }
2548  // check for member function
2549  else if (tok->str() == "{") {
2550  bool added = false;
2551  Token *tok1 = tok;
2552  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2553  tok1 = tok1->previous();
2554  if (tok1->previous() && (tok1->strAt(-1) == ")" || tok->strAt(-1) == "}")) {
2555  tok1 = tok1->linkAt(-1);
2556  if (Token::Match(tok1->previous(), "throw|noexcept (")) {
2557  tok1 = tok1->previous();
2558  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2559  tok1 = tok1->previous();
2560  if (tok1->strAt(-1) != ")")
2561  return;
2562  tok1 = tok1->linkAt(-1);
2563  } else {
2564  while (Token::Match(tok1->tokAt(-2), ":|, %name%")) {
2565  tok1 = tok1->tokAt(-2);
2566  if (tok1->strAt(-1) != ")" && tok1->strAt(-1) != "}")
2567  return;
2568  tok1 = tok1->linkAt(-1);
2569  }
2570  }
2571  if (tok1->strAt(-1) == ">")
2572  tok1 = tok1->previous()->findOpeningBracket();
2573  if (tok1 && (Token::Match(tok1->tokAt(-3), "%name% :: %name%") ||
2574  Token::Match(tok1->tokAt(-4), "%name% :: ~ %name%"))) {
2575  tok1 = tok1->tokAt(-2);
2576  if (tok1->str() == "~")
2577  tok1 = tok1->previous();
2578  std::string scope = tok1->strAt(-1);
2579  while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
2580  scope = tok1->strAt(-3) + " :: " + scope;
2581  tok1 = tok1->tokAt(-2);
2582  }
2583  scopeInfo = scopeInfo->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link());
2584  added = true;
2585  }
2586  }
2587 
2588  if (!added)
2589  scopeInfo = scopeInfo->addChild(ScopeInfo3::Other, emptyString, tok, tok->link());
2590  }
2591  return;
2592  }
2593 
2594  const bool record = Token::Match(tok, "class|struct|union %name%");
2595  tok = tok->next();
2596  std::string classname = tok->str();
2597  while (Token::Match(tok, "%name% :: %name%")) {
2598  tok = tok->tokAt(2);
2599  classname += " :: " + tok->str();
2600  }
2601 
2602  // add record type to scope info
2603  if (record)
2604  scopeInfo->recordTypes.insert(classname);
2605  tok = tok->next();
2606 
2607  // skip template parameters
2608  if (tok && tok->str() == "<") {
2609  tok = tok->findClosingBracket();
2610  if (tok)
2611  tok = tok->next();
2612  }
2613 
2614  // get base class types
2615  std::set<std::string> baseTypes;
2616  if (tok && tok->str() == ":") {
2617  do {
2618  tok = tok->next();
2619  while (Token::Match(tok, "public|protected|private|virtual"))
2620  tok = tok->next();
2621  std::string base;
2622  while (tok && !Token::Match(tok, ";|,|{")) {
2623  if (!base.empty())
2624  base += ' ';
2625  base += tok->str();
2626  tok = tok->next();
2627  // add template parameters
2628  if (tok && tok->str() == "<") {
2629  const Token* endTok = tok->findClosingBracket();
2630  if (endTok) {
2631  endTok = endTok->next();
2632  while (tok != endTok) {
2633  base += tok->str();
2634  tok = tok->next();
2635  }
2636  }
2637  }
2638  }
2639  baseTypes.insert(std::move(base));
2640  } while (tok && !Token::Match(tok, ";|{"));
2641  }
2642 
2643  if (tok && tok->str() == "{") {
2644  scopeInfo = scopeInfo->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link());
2645  scopeInfo->baseTypes = std::move(baseTypes);
2646  }
2647  }
2648 
2649  Token *findSemicolon(Token *tok)
2650  {
2651  int level = 0;
2652 
2653  for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
2654  if (tok->str() == "{")
2655  ++level;
2656  else if (level > 0 && tok->str() == "}")
2657  --level;
2658  }
2659 
2660  return tok;
2661  }
2662 
2663  bool usingMatch(
2664  const Token *nameToken,
2665  const std::string &scope,
2666  Token *&tok,
2667  const std::string &scope1,
2668  const ScopeInfo3 *currentScope,
2669  const ScopeInfo3 *memberClassScope)
2670  {
2671  Token *tok1 = tok;
2672 
2673  if (tok1 && tok1->str() != nameToken->str())
2674  return false;
2675 
2676  // skip this using
2677  if (tok1 == nameToken) {
2678  tok = findSemicolon(tok1);
2679  return false;
2680  }
2681 
2682  // skip other using with this name
2683  if (tok1->strAt(-1) == "using") {
2684  // fixme: this is wrong
2685  // skip to end of scope
2686  if (currentScope->bodyEnd)
2687  tok = const_cast<Token*>(currentScope->bodyEnd->previous());
2688  return false;
2689  }
2690 
2691  if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) {
2692  // fixme
2693  return false;
2694  }
2695 
2696  // get qualification
2697  std::string qualification;
2698  const Token* tok2 = tok1;
2699  std::string::size_type index = scope.size();
2700  std::string::size_type new_index = std::string::npos;
2701  bool match = true;
2702  while (Token::Match(tok2->tokAt(-2), "%name% ::") && !tok2->tokAt(-2)->isKeyword()) {
2703  std::string last;
2704  if (match && !scope1.empty()) {
2705  new_index = scope1.rfind(' ', index - 1);
2706  if (new_index != std::string::npos)
2707  last = scope1.substr(new_index, index - new_index);
2708  else if (!qualification.empty())
2709  last.clear();
2710  else
2711  last = scope1;
2712  } else
2713  match = false;
2714  if (match && tok2->strAt(-2) == last)
2715  index = new_index;
2716  else {
2717  if (!qualification.empty())
2718  qualification = " :: " + qualification;
2719  qualification = tok2->strAt(-2) + qualification;
2720  }
2721  tok2 = tok2->tokAt(-2);
2722  }
2723 
2724  std::string fullScope1 = scope1;
2725  if (!scope1.empty() && !qualification.empty())
2726  fullScope1 += " :: ";
2727  fullScope1 += qualification;
2728 
2729  if (scope == fullScope1)
2730  return true;
2731 
2732  const ScopeInfo3 *scopeInfo = memberClassScope ? memberClassScope : currentScope;
2733 
2734  // check in base types
2735  if (qualification.empty() && scopeInfo->findTypeInBase(scope))
2736  return true;
2737 
2738  // check using namespace
2739  const ScopeInfo3 * tempScope = scopeInfo;
2740  while (tempScope) {
2741  //if (!tempScope->parent->usingNamespaces.empty()) {
2742  const std::set<std::string>& usingNS = tempScope->usingNamespaces;
2743  if (!usingNS.empty()) {
2744  if (qualification.empty()) {
2745  if (usingNS.find(scope) != usingNS.end())
2746  return true;
2747  } else {
2748  const std::string suffix = " :: " + qualification;
2749  if (std::any_of(usingNS.cbegin(), usingNS.cend(), [&](const std::string& ns) {
2750  return scope == ns + suffix;
2751  }))
2752  return true;
2753  }
2754  }
2755  tempScope = tempScope->parent;
2756  }
2757 
2758  std::string newScope1 = scope1;
2759 
2760  // scopes didn't match so try higher scopes
2761  index = newScope1.size();
2762  while (!newScope1.empty()) {
2763  const std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
2764  if (separator != std::string::npos)
2765  newScope1.resize(separator);
2766  else
2767  newScope1.clear();
2768 
2769  std::string newFullScope1 = newScope1;
2770  if (!newScope1.empty() && !qualification.empty())
2771  newFullScope1 += " :: ";
2772  newFullScope1 += qualification;
2773 
2774  if (scope == newFullScope1)
2775  return true;
2776  }
2777 
2778  return false;
2779  }
2780 
2781  std::string memberFunctionScope(const Token *tok)
2782  {
2783  std::string qualification;
2784  const Token *qualTok = tok->strAt(-2) == "~" ? tok->tokAt(-4) : tok->tokAt(-3);
2785  while (Token::Match(qualTok, "%type% ::")) {
2786  if (!qualification.empty())
2787  qualification = " :: " + qualification;
2788  qualification = qualTok->str() + qualification;
2789  qualTok = qualTok->tokAt(-2);
2790  }
2791  return qualification;
2792  }
2793 
2794  const Token * memberFunctionEnd(const Token *tok)
2795  {
2796  if (tok->str() != "(")
2797  return nullptr;
2798  const Token *end = tok->link()->next();
2799  while (end) {
2800  if (end->str() == "{" && !Token::Match(end->tokAt(-2), ":|, %name%"))
2801  return end;
2802  if (end->str() == ";")
2803  break;
2804  end = end->next();
2805  }
2806  return nullptr;
2807  }
2808 } // namespace
2809 
2810 bool Tokenizer::isMemberFunction(const Token *openParen)
2811 {
2812  return (Token::Match(openParen->tokAt(-2), ":: %name% (") ||
2813  Token::Match(openParen->tokAt(-3), ":: ~ %name% (")) &&
2814  isFunctionHead(openParen, "{|:");
2815 }
2816 
2817 static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
2818 {
2819  if (scope1.empty() || scope2.empty())
2820  return false;
2821 
2822  // check if scopes match
2823  if (scope1 == scope2)
2824  return true;
2825 
2826  // check if scopes only differ by global qualification
2827  if (scope1 == (":: " + scope2)) {
2828  std::string::size_type end = scope2.find_first_of(' ');
2829  if (end == std::string::npos)
2830  end = scope2.size();
2831  if (globalScope->hasChild(scope2.substr(0, end)))
2832  return true;
2833  } else if (scope2 == (":: " + scope1)) {
2834  std::string::size_type end = scope1.find_first_of(' ');
2835  if (end == std::string::npos)
2836  end = scope1.size();
2837  if (globalScope->hasChild(scope1.substr(0, end)))
2838  return true;
2839  }
2840 
2841  return false;
2842 }
2843 
2844 static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
2845  unsigned int dist = 0;
2846  const Token* tok = tok1;
2847  while (tok != tok2) {
2848  ++dist;
2849  tok = tok->next();
2850  }
2851  return dist;
2852 }
2853 
2855 {
2857  return false;
2858 
2859  // simplify using N::x; to using x = N::x;
2860  for (Token* tok = list.front(); tok; tok = tok->next()) {
2861  if (!Token::Match(tok, "using ::| %name% ::"))
2862  continue;
2863  const Token* ns = tok->tokAt(tok->strAt(1) == "::" ? 2 : 1);
2864  if (ns->isKeyword())
2865  continue;
2866  Token* end = tok->tokAt(3);
2867  while (end && !Token::Match(end, "[;,]")) {
2868  if (end->str() == "<") // skip template args
2869  end = end->findClosingBracket();
2870  else
2871  end = end->next();
2872  }
2873  if (!end)
2874  continue;
2875  if (!end->tokAt(-1)->isNameOnly() || end->tokAt(-2)->isLiteral()) // e.g. operator=, operator""sv
2876  continue;
2877  tok->insertToken(end->strAt(-1))->insertToken("=")->isSimplifiedTypedef(true);
2878  if (end->str() == ",") { // comma-separated list
2879  end->str(";");
2880  end->insertToken("using");
2881  }
2882  tok = end;
2883  }
2884 
2885  const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace
2886 
2887  bool substitute = false;
2888  ScopeInfo3 scopeInfo;
2889  ScopeInfo3 *currentScope = &scopeInfo;
2890  struct Using {
2891  Using(Token *start, Token *end) : startTok(start), endTok(end) {}
2892  Token *startTok;
2893  Token *endTok;
2894  };
2895  std::list<Using> usingList;
2896 
2897  for (Token *tok = list.front(); tok; tok = tok->next()) {
2898  if (!list.getFiles().empty())
2899  mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue());
2900 
2901  if (Settings::terminated())
2902  return substitute;
2903 
2904  if (Token::Match(tok, "enum class|struct")) {
2905  Token *bodyStart = tok;
2906  while (Token::Match(bodyStart, "%name%|:|::|<")) {
2907  if (bodyStart->str() == "<")
2908  bodyStart = bodyStart->findClosingBracket();
2909  bodyStart = bodyStart ? bodyStart->next() : nullptr;
2910  }
2911  if (Token::simpleMatch(bodyStart, "{"))
2912  tok = bodyStart->link();
2913  continue;
2914  }
2915 
2916  if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
2917  Token::Match(tok, "using namespace %name% ;|::")) {
2918  try {
2919  setScopeInfo(tok, currentScope, mSettings.debugwarnings);
2920  } catch (const std::runtime_error &) {
2921  reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2922  "simplifyUsing: unmatched body end");
2923  }
2924  continue;
2925  }
2926 
2927  // skip template declarations
2928  if (Token::Match(tok, "template < !!>")) {
2929  // add template record type to scope info
2930  const Token *end = tok->next()->findClosingBracket();
2931  if (end && Token::Match(end->next(), "class|struct|union %name%"))
2932  currentScope->recordTypes.insert(end->strAt(2));
2933 
2935  if (declEndToken)
2936  tok = declEndToken;
2937  continue;
2938  }
2939 
2940  // look for non-template type aliases
2941  if (!(tok->strAt(-1) != ">" &&
2942  (Token::Match(tok, "using %name% = ::| %name%") ||
2943  (Token::Match(tok, "using %name% [ [") &&
2944  Token::Match(tok->linkAt(2), "] ] = ::| %name%")))))
2945  continue;
2946 
2947  const std::string& name = tok->strAt(1);
2948  const Token *nameToken = tok->next();
2949  std::string scope = currentScope->fullName;
2950  Token *usingStart = tok;
2951  Token *start;
2952  if (tok->strAt(2) == "=") {
2953  if (currentScope->type == ScopeInfo3::Record && tok->tokAt(2)->isSimplifiedTypedef()) // don't simplify within class definition
2954  continue;
2955  start = tok->tokAt(3);
2956  }
2957  else
2958  start = tok->linkAt(2)->tokAt(3);
2959  Token *usingEnd = findSemicolon(start);
2960  if (!usingEnd)
2961  continue;
2962 
2963  // Move struct defined in using out of using.
2964  // using T = struct t { }; => struct t { }; using T = struct t;
2965  // fixme: this doesn't handle attributes
2966  if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
2967  Token *structEnd = start->tokAt(1);
2968  const bool hasName = Token::Match(structEnd, "%name%");
2969 
2970  // skip over name if present
2971  if (hasName)
2972  structEnd = structEnd->next();
2973 
2974  // skip over base class information
2975  if (structEnd->str() == ":") {
2976  structEnd = structEnd->next(); // skip over ":"
2977  while (structEnd && structEnd->str() != "{")
2978  structEnd = structEnd->next();
2979  if (!structEnd)
2980  continue;
2981  }
2982 
2983  // use link to go to end
2984  structEnd = structEnd->link();
2985 
2986  // add ';' after end of struct
2987  structEnd->insertToken(";", emptyString);
2988 
2989  // add name for anonymous struct
2990  if (!hasName) {
2991  std::string newName;
2992  if (structEnd->strAt(2) == ";")
2993  newName = name;
2994  else
2995  newName = "Unnamed" + std::to_string(mUnnamedCount++);
2996  TokenList::copyTokens(structEnd->next(), tok, start);
2997  structEnd->tokAt(5)->insertToken(newName, emptyString);
2998  start->insertToken(newName, emptyString);
2999  } else
3000  TokenList::copyTokens(structEnd->next(), tok, start->next());
3001 
3002  // add using after end of struct
3003  usingStart = structEnd->tokAt(2);
3004  nameToken = usingStart->next();
3005  if (usingStart->strAt(2) == "=")
3006  start = usingStart->tokAt(3);
3007  else
3008  start = usingStart->linkAt(2)->tokAt(3);
3009  usingEnd = findSemicolon(start);
3010 
3011  // delete original using before struct
3012  tok->deleteThis();
3013  tok->deleteThis();
3014  tok->deleteThis();
3015  tok = usingStart;
3016  }
3017 
3018  // remove 'typename' and 'template'
3019  else if (start->str() == "typename") {
3020  start->deleteThis();
3021  Token *temp = start;
3022  while (Token::Match(temp, "%name% ::"))
3023  temp = temp->tokAt(2);
3024  if (Token::Match(temp, "template %name%"))
3025  temp->deleteThis();
3026  }
3027 
3028  if (usingEnd)
3029  tok = usingEnd;
3030 
3031  // Unfortunately we have to start searching from the beginning
3032  // of the token stream because templates are instantiated at
3033  // the end of the token stream and it may be used before then.
3034  ScopeInfo3 scopeInfo1;
3035  ScopeInfo3 *currentScope1 = &scopeInfo1;
3036  Token *startToken = list.front();
3037  Token *endToken = nullptr;
3038  bool inMemberFunc = false;
3039  const ScopeInfo3 * memberFuncScope = nullptr;
3040  const Token * memberFuncEnd = nullptr;
3041 
3042  // We can limit the search to the current function when the type alias
3043  // is defined in that function.
3044  if (currentScope->type == ScopeInfo3::Other ||
3045  currentScope->type == ScopeInfo3::MemberFunction) {
3046  scopeInfo1 = scopeInfo;
3047  currentScope1 = scopeInfo1.findScope(currentScope);
3048  if (!currentScope1)
3049  return substitute; // something bad happened
3050  startToken = usingEnd->next();
3051  endToken = const_cast<Token*>(currentScope->bodyEnd->next());
3052  if (currentScope->type == ScopeInfo3::MemberFunction) {
3053  const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName);
3054  if (temp) {
3055  inMemberFunc = true;
3056  memberFuncScope = temp;
3057  memberFuncEnd = endToken;
3058  }
3059  }
3060  }
3061 
3062  std::string scope1 = currentScope1->fullName;
3063  bool skip = false; // don't erase type aliases we can't parse
3064  Token *enumOpenBrace = nullptr;
3065  for (Token* tok1 = startToken; !skip && tok1 && tok1 != endToken; tok1 = tok1->next()) {
3066  // skip enum body
3067  if (tok1 && tok1 == enumOpenBrace) {
3068  tok1 = tok1->link();
3069  enumOpenBrace = nullptr;
3070  continue;
3071  }
3072 
3073  if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
3074  Token::Match(tok1, "using namespace %name% ;|::")) {
3075  try {
3076  setScopeInfo(tok1, currentScope1, mSettings.debugwarnings);
3077  } catch (const std::runtime_error &) {
3078  reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
3079  "simplifyUsing: unmatched body end");
3080  }
3081  scope1 = currentScope1->fullName;
3082  if (inMemberFunc && memberFuncEnd && tok1 == memberFuncEnd) {
3083  inMemberFunc = false;
3084  memberFuncScope = nullptr;
3085  memberFuncEnd = nullptr;
3086  }
3087  continue;
3088  }
3089 
3090  // skip template definitions
3091  if (Token::Match(tok1, "template < !!>")) {
3093  if (declEndToken)
3094  tok1 = declEndToken;
3095  continue;
3096  }
3097 
3098  // check for enum with body
3099  if (tok1->str() == "enum") {
3100  if (Token::Match(tok1, "enum class|struct"))
3101  tok1 = tok1->next();
3102  Token *defStart = tok1;
3103  while (Token::Match(defStart, "%name%|::|:"))
3104  defStart = defStart->next();
3105  if (Token::simpleMatch(defStart, "{"))
3106  enumOpenBrace = defStart;
3107  continue;
3108  }
3109 
3110  // check for member function and adjust scope
3111  if (isMemberFunction(tok1)) {
3112  if (!scope1.empty())
3113  scope1 += " :: ";
3114  scope1 += memberFunctionScope(tok1);
3115  const ScopeInfo3 * temp = currentScope1->findScope(scope1);
3116  if (temp) {
3117  const Token *end = memberFunctionEnd(tok1);
3118  if (end) {
3119  inMemberFunc = true;
3120  memberFuncScope = temp;
3121  memberFuncEnd = end;
3122  }
3123  }
3124  continue;
3125  }
3126  if (inMemberFunc && memberFuncScope) {
3127  if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, memberFuncScope))
3128  continue;
3129  } else if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, nullptr))
3130  continue;
3131 
3132  const auto nReplace = tokDistance(start, usingEnd);
3133  if (nReplace > maxReplacementTokens) {
3134  simplifyUsingError(usingStart, usingEnd);
3135  continue;
3136  }
3137 
3138  // remove the qualification
3139  std::string fullScope = scope;
3140  std::string removed;
3141  while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
3142  removed = (tok1->strAt(-2) + " :: ") + removed;
3143  if (fullScope == tok1->strAt(-2)) {
3144  tok1->deletePrevious();
3145  tok1->deletePrevious();
3146  break;
3147  }
3148  const std::string::size_type idx = fullScope.rfind("::");
3149 
3150  if (idx == std::string::npos)
3151  break;
3152 
3153  if (tok1->strAt(-2) == fullScope.substr(idx + 3)) {
3154  tok1->deletePrevious();
3155  tok1->deletePrevious();
3156  fullScope.resize(idx - 1);
3157  } else
3158  break;
3159  }
3160 
3161  // remove global namespace if present
3162  if (tok1->strAt(-1) == "::") {
3163  removed.insert(0, ":: ");
3164  tok1->deletePrevious();
3165  }
3166 
3167  Token * arrayStart = nullptr;
3168 
3169  // parse the type
3170  Token *type = start;
3171  if (type->str() == "::") {
3172  type = type->next();
3173  while (Token::Match(type, "%type% ::"))
3174  type = type->tokAt(2);
3175  if (Token::Match(type, "%type%"))
3176  type = type->next();
3177  } else if (Token::Match(type, "%type% ::")) {
3178  do {
3179  type = type->tokAt(2);
3180  } while (Token::Match(type, "%type% ::"));
3181  if (Token::Match(type, "%type%"))
3182  type = type->next();
3183  } else if (Token::Match(type, "%type%")) {
3184  while (Token::Match(type, "const|class|struct|union|enum %type%") ||
3185  (type->next() && type->next()->isStandardType()))
3186  type = type->next();
3187 
3188  type = type->next();
3189 
3190  while (Token::Match(type, "%type%") &&
3191  (type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
3192  type = type->next();
3193  }
3194 
3195  bool atEnd = false;
3196  while (!atEnd) {
3197  if (type && type->str() == "::") {
3198  type = type->next();
3199  }
3200 
3201  if (Token::Match(type, "%type%") &&
3202  type->next() && !Token::Match(type->next(), "[|,|(")) {
3203  type = type->next();
3204  } else if (Token::simpleMatch(type, "const (")) {
3205  type = type->next();
3206  atEnd = true;
3207  } else
3208  atEnd = true;
3209  }
3210  } else
3211  syntaxError(type);
3212 
3213  // check for invalid input
3214  if (!type)
3215  syntaxError(tok1);
3216 
3217  // check for template
3218  if (type->str() == "<") {
3219  type = type->findClosingBracket();
3220 
3221  while (type && Token::Match(type->next(), ":: %type%"))
3222  type = type->tokAt(2);
3223 
3224  if (!type) {
3225  syntaxError(tok1);
3226  }
3227 
3228  while (Token::Match(type->next(), "const|volatile"))
3229  type = type->next();
3230 
3231  type = type->next();
3232  }
3233 
3234  // check for pointers and references
3235  std::list<std::string> pointers;
3236  while (Token::Match(type, "*|&|&&|const")) {
3237  pointers.push_back(type->str());
3238  type = type->next();
3239  }
3240 
3241  // check for array
3242  if (type && type->str() == "[") {
3243  do {
3244  if (!arrayStart)
3245  arrayStart = type;
3246 
3247  bool atEnd = false;
3248  while (!atEnd) {
3249  while (type->next() && !Token::Match(type->next(), ";|,")) {
3250  type = type->next();
3251  }
3252 
3253  if (!type->next())
3254  syntaxError(type); // invalid input
3255  else if (type->next()->str() == ";")
3256  atEnd = true;
3257  else if (type->str() == "]")
3258  atEnd = true;
3259  else
3260  type = type->next();
3261  }
3262 
3263  type = type->next();
3264  } while (type && type->str() == "[");
3265  }
3266 
3267  // make sure we are in a good state
3268  if (!tok1 || !tok1->next())
3269  break; // bail
3270 
3271  Token* after = tok1->next();
3272  // check if type was parsed
3273  if (type && type == usingEnd) {
3274  // check for array syntax and add type around variable
3275  if (arrayStart) {
3276  if (Token::Match(tok1->next(), "%name%")) {
3277  TokenList::copyTokens(tok1->next(), arrayStart, usingEnd->previous());
3278  TokenList::copyTokens(tok1, start, arrayStart->previous());
3279  tok1->deleteThis();
3280  substitute = true;
3281  }
3282  } else {
3283  // add some qualification back if needed
3284  std::string removed1 = std::move(removed);
3285  std::string::size_type idx = removed1.rfind(" ::");
3286  if (idx != std::string::npos)
3287  removed1.resize(idx);
3288  if (scopesMatch(removed1, scope, &scopeInfo1)) {
3289  ScopeInfo3 * tempScope = currentScope;
3290  while (tempScope->parent) {
3291  if (tempScope->recordTypes.find(start->str()) != tempScope->recordTypes.end()) {
3292  std::string::size_type spaceIdx = 0;
3293  std::string::size_type startIdx = 0;
3294  while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
3295  tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
3296  startIdx = spaceIdx + 1;
3297  }
3298  tok1->previous()->insertToken(removed1.substr(startIdx));
3299  tok1->previous()->insertToken("::");
3300  break;
3301  }
3302  idx = removed1.rfind(" ::");
3303  if (idx == std::string::npos)
3304  break;
3305 
3306  removed1.resize(idx);
3307  tempScope = tempScope->parent;
3308  }
3309  }
3310 
3311  // Is this a "T()" expression where T is a pointer type?
3312  if (Token::Match(tok1, "%name% ( )") && !pointers.empty()) {
3313  Token* tok2 = tok1->linkAt(1);
3314  tok1->deleteThis();
3315  TokenList::copyTokens(tok1, start, usingEnd->previous());
3316  tok2->insertToken("0");
3317  after = tok2->next();
3318  }
3319  else { // just replace simple type aliases
3320  TokenList::copyTokens(tok1, start, usingEnd->previous());
3321  tok1->deleteThis();
3322  }
3323  substitute = true;
3324  }
3325  } else {
3326  skip = true;
3327  simplifyUsingError(usingStart, usingEnd);
3328  }
3329  tok1 = after->previous();
3330  }
3331 
3332  if (!skip)
3333  usingList.emplace_back(usingStart, usingEnd);
3334  }
3335 
3336  // delete all used type alias definitions
3337  for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
3338  Token *usingStart = it->startTok;
3339  Token *usingEnd = it->endTok;
3340  if (usingStart->previous()) {
3341  if (usingEnd->next())
3342  Token::eraseTokens(usingStart->previous(), usingEnd->next());
3343  else {
3344  Token::eraseTokens(usingStart->previous(), usingEnd);
3345  usingEnd->deleteThis();
3346  }
3347  } else {
3348  if (usingEnd->next()) {
3349  Token::eraseTokens(usingStart, usingEnd->next());
3350  usingStart->deleteThis();
3351  } else {
3352  // this is the only code being checked so leave ';'
3353  Token::eraseTokens(usingStart, usingEnd);
3354  usingStart->deleteThis();
3355  }
3356  }
3357  }
3358 
3359  return substitute;
3360 }
3361 
3362 void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
3363 {
3364  if (mSettings.debugwarnings) {
3365  std::string str;
3366  for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
3367  if (!str.empty())
3368  str += ' ';
3369  str += tok->str();
3370  }
3371  str += " ;";
3372  std::list<const Token *> callstack(1, usingStart);
3373  mErrorLogger.reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
3374  "Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
3375  }
3376 }
3377 
3378 bool Tokenizer::simplifyTokens1(const std::string &configuration)
3379 {
3380  // Fill the map mTypeSize..
3381  fillTypeSizes();
3382 
3383  mConfiguration = configuration;
3384 
3385  if (mTimerResults) {
3386  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings.showtime, mTimerResults);
3387  if (!simplifyTokenList1(list.getFiles().front().c_str()))
3388  return false;
3389  } else {
3390  if (!simplifyTokenList1(list.getFiles().front().c_str()))
3391  return false;
3392  }
3393 
3394  if (mTimerResults) {
3395  Timer t("Tokenizer::simplifyTokens1::createAst", mSettings.showtime, mTimerResults);
3396  list.createAst();
3398  } else {
3399  list.createAst();
3401  }
3402 
3403  if (mTimerResults) {
3404  Timer t("Tokenizer::simplifyTokens1::createSymbolDatabase", mSettings.showtime, mTimerResults);
3406  } else {
3408  }
3409 
3410  if (mTimerResults) {
3411  Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings.showtime, mTimerResults);
3414  } else {
3417  }
3418 
3419  if (!mSettings.buildDir.empty())
3420  Summaries::create(*this, configuration);
3421 
3422  // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only
3423  const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW");
3424  const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0);
3425 
3426  if (doValueFlow) {
3427  if (mTimerResults) {
3428  Timer t("Tokenizer::simplifyTokens1::ValueFlow", mSettings.showtime, mTimerResults);
3430  } else {
3432  }
3433 
3435  }
3436 
3437  // Warn about unhandled character literals
3439  for (const Token *tok = tokens(); tok; tok = tok->next()) {
3440  if (tok->tokType() == Token::eChar && tok->values().empty()) {
3441  try {
3442  simplecpp::characterLiteralToLL(tok->str());
3443  } catch (const std::exception &e) {
3444  unhandledCharLiteral(tok, e.what());
3445  }
3446  }
3447  }
3448  }
3449 
3450  if (doValueFlow) {
3452  }
3453 
3454  printDebugOutput(1);
3455 
3456  return true;
3457 }
3458 
3459 //---------------------------------------------------------------------------
3460 
3462 {
3463  validate();
3465 }
3466 
3468 {
3469  for (const Token *tok = list.front(); tok; tok = tok->next()) {
3470  if (Token::Match(tok, "enum %name% {")) {
3471  tok = tok->tokAt(2);
3472  const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
3473  if (tok2)
3474  syntaxError(tok2);
3475  tok = tok->link();
3476  }
3477  }
3478 }
3479 
3481 {
3482  mTypeSize.clear();
3483  mTypeSize["char"] = 1;
3496 }
3497 
3499 {
3500  const bool cpp = isCPP();
3501 
3502  // Combine tokens..
3503  for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
3504  const char c1 = tok->str()[0];
3505 
3506  if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
3507  const char c2 = tok->next()->str()[0];
3508 
3509  // combine +-*/ and =
3510  if (c2 == '=' && (std::strchr("+-*/%|^=!<>", c1)) && !Token::Match(tok->previous(), "%type% *")) {
3511  // skip templates
3512  if (cpp && (tok->str() == ">" || Token::simpleMatch(tok->previous(), "> *"))) {
3513  const Token* opening =
3514  tok->str() == ">" ? tok->findOpeningBracket() : tok->previous()->findOpeningBracket();
3515  if (opening && Token::Match(opening->previous(), "%name%"))
3516  continue;
3517  }
3518  tok->str(tok->str() + c2);
3519  tok->deleteNext();
3520  continue;
3521  }
3522  } else if (tok->next()->str() == "=") {
3523  if (tok->str() == ">>") {
3524  tok->str(">>=");
3525  tok->deleteNext();
3526  } else if (tok->str() == "<<") {
3527  tok->str("<<=");
3528  tok->deleteNext();
3529  }
3530  } else if (cpp && (c1 == 'p' || c1 == '_') &&
3531  Token::Match(tok, "private|protected|public|__published : !!:")) {
3532  bool simplify = false;
3533  int par = 0;
3534  for (const Token *prev = tok->previous(); prev; prev = prev->previous()) {
3535  if (prev->str() == ")") {
3536  ++par;
3537  } else if (prev->str() == "(") {
3538  if (par == 0U)
3539  break;
3540  --par;
3541  }
3542  if (par != 0U || prev->str() == "(")
3543  continue;
3544  if (Token::Match(prev, "[;{}]")) {
3545  simplify = true;
3546  break;
3547  }
3548  if (prev->isName() && prev->isUpperCaseName())
3549  continue;
3550  if (prev->isName() && endsWith(prev->str(), ':'))
3551  simplify = true;
3552  break;
3553  }
3554  if (simplify) {
3555  tok->str(tok->str() + ":");
3556  tok->deleteNext();
3557  }
3558  } else if (tok->str() == "->") {
3559  // If the preceding sequence is "( & %name% )", replace it by "%name%"
3560  Token *t = tok->tokAt(-4);
3561  if (Token::Match(t, "( & %name% )") && !Token::simpleMatch(t->previous(), ">")) {
3562  t->deleteThis();
3563  t->deleteThis();
3564  t->deleteNext();
3565  tok->str(".");
3566  } else {
3567  tok->str(".");
3568  tok->originalName("->");
3569  }
3570  }
3571  }
3572 }
3573 
3575 {
3576  // Combine strings
3577  for (Token *tok = list.front(); tok; tok = tok->next()) {
3578  if (!isStringLiteral(tok->str()))
3579  continue;
3580 
3581  tok->str(simplifyString(tok->str()));
3582 
3583  while (Token::Match(tok->next(), "%str%") || Token::Match(tok->next(), "_T|_TEXT|TEXT ( %str% )")) {
3584  if (tok->next()->isName()) {
3585  if (!mSettings.platform.isWindows())
3586  break;
3587  tok->deleteNext(2);
3588  tok->next()->deleteNext();
3589  }
3590  // Two strings after each other, combine them
3591  tok->concatStr(simplifyString(tok->next()->str()));
3592  tok->deleteNext();
3593  }
3594  }
3595 }
3596 
3598 {
3599  for (Token *tok = list.front(); tok; tok = tok->next()) {
3600  if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->tokType() == Token::eIncDecOp)
3601  continue;
3602 
3603  while (tok->str() != ">" && tok->next() && tok->next()->str() == "+" && (!Token::Match(tok->tokAt(2), "%name% (|;") || Token::Match(tok, "%op%")))
3604  tok->deleteNext();
3605 
3606  if (Token::Match(tok->next(), "- %num%")) {
3607  tok->deleteNext();
3608  tok->next()->str("-" + tok->next()->str());
3609  }
3610  }
3611 }
3612 
3614 {
3615  if (isC())
3616  return;
3617 
3618  // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens.
3619  for (Token *tok = list.front(); tok; tok = tok->next()) {
3620  if (Token::Match(tok, "extern \"C\"|\"C++\"")) {
3621  Token *tok2 = tok->next();
3622  const bool isExtC = tok->next()->str().size() == 3;
3623  if (tok->strAt(2) == "{") {
3624  tok2 = tok2->next(); // skip {
3625  while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2))
3626  tok2->isExternC(isExtC);
3627  tok->linkAt(2)->deleteThis(); // }
3628  tok->deleteNext(2); // "C" {
3629  } else {
3630  while ((tok2 = tok2->next()) && !Token::Match(tok2, "[;{]"))
3631  tok2->isExternC(isExtC);
3632  tok->deleteNext(); // "C"
3633  }
3634  tok->deleteThis(); // extern
3635  }
3636  }
3637 }
3638 
3640 {
3641  for (Token *tok = list.front(); tok; tok = tok->next()) {
3642  while (Token::Match(tok, "[;{}:] ( {") &&
3643  Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
3644  if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
3645  break;
3646  Token *end = tok->linkAt(2)->tokAt(-3);
3647  if (Token::Match(end, "[;{}] %num%|%str% ;"))
3648  end->deleteNext(2);
3649  tok->linkAt(2)->previous()->deleteNext(3);
3650  tok->deleteNext(2);
3651  }
3652  if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
3653  tok->deleteNext();
3654  tok->deleteThis();
3655  tok->deleteNext(3);
3656  }
3657  }
3658 }
3659 
3661 {
3662  for (Token *tok = list.front(); tok; tok = tok->next()) {
3663  if (!Token::simpleMatch(tok, "__CPPCHECK_EMBEDDED_SQL_EXEC__ SQL"))
3664  continue;
3665 
3666  const Token *end = findSQLBlockEnd(tok);
3667  if (end == nullptr)
3668  syntaxError(nullptr);
3669 
3670  const std::string instruction = tok->stringifyList(end);
3671  // delete all tokens until the embedded SQL block end
3672  Token::eraseTokens(tok, end);
3673 
3674  // insert "asm ( "instruction" ) ;"
3675  tok->str("asm");
3676  // it can happen that 'end' is NULL when wrong code is inserted
3677  if (!tok->next())
3678  tok->insertToken(";");
3679  tok->insertToken(")");
3680  tok->insertToken("\"" + instruction + "\"");
3681  tok->insertToken("(");
3682  // jump to ';' and continue
3683  tok = tok->tokAt(3);
3684  }
3685 }
3686 
3688 {
3689  // 0[a] -> a[0]
3690  for (Token *tok = list.front(); tok; tok = tok->next()) {
3691  if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
3692  const std::string number(tok->str());
3693  Token* indexTok = tok->tokAt(2);
3694  tok->str(indexTok->str());
3695  tok->varId(indexTok->varId());
3696  indexTok->str(number);
3697  }
3698  }
3699 }
3700 
3702 {
3703  for (Token* tok = list.front(); tok; tok = tok->next()) {
3704  if (Token::Match(tok, "%name% ( void )") && !Token::Match(tok, "sizeof|decltype|typeof|return")) {
3705  tok->next()->deleteNext();
3706  tok->next()->setRemovedVoidParameter(true);
3707  }
3708  }
3709 }
3710 
3712 {
3713  // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
3714  for (Token *tok = list.front(); tok;) {
3715  if (Token::simpleMatch(tok, "= {")) {
3716  tok = tok->linkAt(1);
3717  } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
3718  //remove internal parentheses
3719  tok->next()->link()->deleteThis();
3720  tok->deleteNext();
3721  } else
3722  tok = tok->next();
3723  }
3724 }
3725 
3727 {
3728  // Convert - - into + and + - into -
3729  for (Token *tok = list.front(); tok; tok = tok->next()) {
3730  while (tok->next()) {
3731  if (tok->str() == "+") {
3732  if (tok->next()->str()[0] == '-') {
3733  tok = tok->next();
3734  if (tok->str().size() == 1) {
3735  tok = tok->previous();
3736  tok->str("-");
3737  tok->deleteNext();
3738  } else if (tok->isNumber()) {
3739  tok->str(tok->str().substr(1));
3740  tok = tok->previous();
3741  tok->str("-");
3742  }
3743  continue;
3744  }
3745  } else if (tok->str() == "-") {
3746  if (tok->next()->str()[0] == '-') {
3747  tok = tok->next();
3748  if (tok->str().size() == 1) {
3749  tok = tok->previous();
3750  tok->str("+");
3751  tok->deleteNext();
3752  } else if (tok->isNumber()) {
3753  tok->str(tok->str().substr(1));
3754  tok = tok->previous();
3755  tok->str("+");
3756  }
3757  continue;
3758  }
3759  }
3760 
3761  break;
3762  }
3763  }
3764 }
3765 
3766 /** Specify array size if it hasn't been given */
3767 
3769 {
3770  auto getStrTok = [](Token* tok, bool addLength, Token*& endStmt) -> Token* {
3771  if (addLength) {
3772  endStmt = tok->tokAt(5);
3773  return tok->tokAt(4);
3774  }
3775  if (Token::Match(tok, "%var% [ ] =")) {
3776  tok = tok->tokAt(4);
3777  int parCount = 0;
3778  while (Token::simpleMatch(tok, "(")) {
3779  ++parCount;
3780  tok = tok->next();
3781  }
3782  if (Token::Match(tok, "%str%")) {
3783  endStmt = tok->tokAt(parCount + 1);
3784  return tok;
3785  }
3786  }
3787  return nullptr;
3788  };
3789 
3790  for (Token *tok = list.front(); tok; tok = tok->next()) {
3791  if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
3792  continue;
3793  bool addlength = false;
3794  if (Token::Match(tok->previous(), "!!* %var% [ ] = { %str% } ;")) {
3795  Token *t = tok->tokAt(3);
3796  t->deleteNext();
3797  t->next()->deleteNext();
3798  addlength = true;
3799  }
3800 
3801  Token* endStmt{};
3802  if (const Token* strTok = getStrTok(tok, addlength, endStmt)) {
3803  const int sz = Token::getStrArraySize(strTok);
3804  tok->next()->insertToken(std::to_string(sz));
3805  tok = endStmt;
3806  }
3807 
3808  else if (Token::Match(tok, "%var% [ ] = {")) {
3809  MathLib::biguint sz = 1;
3810  tok = tok->next();
3811  Token *end = tok->linkAt(3);
3812  for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
3813  if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
3814  if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
3815  if (Token::Match(tok2, "[ %num% ]"))
3816  sz = std::max(sz, MathLib::toBigUNumber(tok2->strAt(1)) + 1U);
3817  else {
3818  sz = 0;
3819  break;
3820  }
3821  }
3822  tok2 = tok2->link();
3823  } else if (tok2->str() == ",") {
3824  if (!Token::Match(tok2->next(), "[},]"))
3825  ++sz;
3826  else {
3827  tok2 = tok2->previous();
3828  tok2->deleteNext();
3829  }
3830  }
3831  }
3832 
3833  if (sz != 0)
3834  tok->insertToken(std::to_string(sz));
3835 
3836  tok = end->next() ? end->next() : end;
3837  }
3838  }
3839 }
3840 
3842 {
3843  // After ValueFlow, adjust array sizes.
3844  for (const Variable* var: mSymbolDatabase->variableList()) {
3845  if (!var || !var->isArray())
3846  continue;
3847  if (!Token::Match(var->nameToken(), "%name% [ ] = { ["))
3848  continue;
3849  MathLib::bigint maxIndex = -1;
3850  const Token* const startToken = var->nameToken()->tokAt(4);
3851  const Token* const endToken = startToken->link();
3852  for (const Token* tok = startToken; tok != endToken; tok = tok->next()) {
3853  if (!Token::Match(tok, "[{,] [") || !Token::simpleMatch(tok->linkAt(1), "] ="))
3854  continue;
3855  const Token* expr = tok->next()->astOperand1();
3856  if (expr && expr->hasKnownIntValue())
3857  maxIndex = std::max(maxIndex, expr->getKnownIntValue());
3858  }
3859  if (maxIndex >= 0) {
3860  // insert array size
3861  Token* tok = const_cast<Token*>(var->nameToken()->next());
3862  tok->insertToken(std::to_string(maxIndex + 1));
3863  // ast
3864  tok->astOperand2(tok->next());
3865  // Token::scope
3866  tok->next()->scope(tok->scope());
3867  // Value flow
3868  ValueFlow::Value value(maxIndex + 1);
3869  value.setKnown();
3870  tok->next()->addValue(value);
3871  // Set array dimensions
3872  Dimension d;
3873  d.num = maxIndex + 1;
3874  std::vector<Dimension> dimensions{d};
3875  const_cast<Variable*>(var)->setDimensions(dimensions);
3876  }
3877  }
3878 }
3879 
3881 {
3882  int colonLevel = 1;
3883  while (nullptr != (tok = tok->next())) {
3884  if (tok->str() == "?") {
3885  ++colonLevel;
3886  } else if (tok->str() == ":") {
3887  --colonLevel;
3888  if (colonLevel == 0) {
3889  tok = tok->next();
3890  break;
3891  }
3892  }
3893  if (tok->link() && Token::Match(tok, "[(<]"))
3894  tok = tok->link();
3895  else if (Token::Match(tok->next(), "[{};)]"))
3896  break;
3897  }
3898  if (colonLevel > 0) // Ticket #5214: Make sure the ':' matches the proper '?'
3899  return nullptr;
3900  return tok;
3901 }
3902 
3903 // Skips until the colon at the end of the case label, the argument must point to the "case" token.
3904 // In case of success returns the colon token.
3905 // In case of failure returns the token that caused the error.
3907 {
3908  assert(tok->str() == "case");
3909  while (nullptr != (tok = tok->next())) {
3910  if (Token::Match(tok, "(|["))
3911  tok = tok->link();
3912  else if (tok->str() == "?") {
3913  Token * tok1 = skipTernaryOp(tok);
3914  if (!tok1)
3915  return tok;
3916  tok = tok1;
3917  }
3918  if (Token::Match(tok, "[:{};]"))
3919  return tok;
3920  }
3921  return nullptr;
3922 }
3923 
3925 {
3926  if (tok->str() != ")")
3927  return nullptr;
3928 
3929  tok = Tokenizer::isFunctionHead(tok, ":{");
3930 
3931  if (Token::Match(tok, ": %name% [({]")) {
3932  while (Token::Match(tok, "[:,] %name% [({]"))
3933  tok = tok->linkAt(2)->next();
3934  }
3935 
3936  return (tok && tok->str() == "{") ? tok : nullptr;
3937 }
3938 
3939 
3940 /** simplify labels and case|default in the code: add a ";" if not already in.*/
3941 
3943 {
3944  const bool cpp = isCPP();
3945  bool executablescope = false;
3946  int indentLevel = 0;
3947  for (Token *tok = list.front(); tok; tok = tok->next()) {
3948  // Simplify labels in the executable scope..
3949  auto *start = const_cast<Token *>(startOfExecutableScope(tok));
3950  if (start) {
3951  tok = start;
3952  executablescope = true;
3953  }
3954 
3955  if (!executablescope)
3956  continue;
3957 
3958  if (tok->str() == "{") {
3959  if (tok->previous()->str() == "=")
3960  tok = tok->link();
3961  else
3962  ++indentLevel;
3963  } else if (tok->str() == "}") {
3964  --indentLevel;
3965  if (indentLevel == 0) {
3966  executablescope = false;
3967  continue;
3968  }
3969  } else if (Token::Match(tok, "(|["))
3970  tok = tok->link();
3971 
3972  if (Token::Match(tok, "[;{}:] case")) {
3973  tok = skipCaseLabel(tok->next());
3974  if (!tok)
3975  break;
3976  if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next())
3977  syntaxError(tok);
3978  if (tok->next()->str() != ";" && tok->next()->str() != "case")
3979  tok->insertToken(";");
3980  else
3981  tok = tok->previous();
3982  } else if (Token::Match(tok, "[;{}] %name% : !!;")) {
3983  if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) {
3984  tok = tok->tokAt(2);
3985  tok->insertToken(";");
3986  }
3987  }
3988  }
3989 }
3990 
3991 
3993 {
3994  for (Token* tok = list.front(); tok; tok = tok->next()) {
3995  if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
3996  const MathLib::bigint start = MathLib::toBigNumber(tok->strAt(1));
3998  end = std::min(start + 50, end); // Simplify it 50 times at maximum
3999  if (start < end) {
4000  tok = tok->tokAt(2);
4001  tok->str(":");
4002  tok->insertToken("case");
4003  for (MathLib::bigint i = end-1; i > start; i--) {
4004  tok->insertToken(":");
4005  tok->insertToken(std::to_string(i));
4006  tok->insertToken("case");
4007  }
4008  }
4009  }
4010  }
4011 }
4012 
4014 {
4015  for (auto *tok = list.front(); tok; tok = tok->next())
4016  tok->scopeInfo(nullptr);
4017 
4018  std::string nextScopeNameAddition;
4019  std::shared_ptr<ScopeInfo2> primaryScope = std::make_shared<ScopeInfo2>("", nullptr);
4020  list.front()->scopeInfo(std::move(primaryScope));
4021 
4022  for (Token* tok = list.front(); tok; tok = tok->next()) {
4023  if (tok == list.front() || !tok->scopeInfo()) {
4024  if (tok != list.front())
4025  tok->scopeInfo(tok->previous()->scopeInfo());
4026 
4027  if (Token::Match(tok, "using namespace %name% ::|<|;")) {
4028  std::string usingNamespaceName;
4029  for (const Token* namespaceNameToken = tok->tokAt(2);
4030  namespaceNameToken && namespaceNameToken->str() != ";";
4031  namespaceNameToken = namespaceNameToken->next()) {
4032  usingNamespaceName += namespaceNameToken->str();
4033  usingNamespaceName += " ";
4034  }
4035  if (!usingNamespaceName.empty())
4036  usingNamespaceName.pop_back();
4037  tok->scopeInfo()->usingNamespaces.insert(std::move(usingNamespaceName));
4038  } else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
4039  for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
4040  if (Token::Match(nameTok, ";|<")) {
4041  nextScopeNameAddition = "";
4042  break;
4043  }
4044  nextScopeNameAddition.append(nameTok->str());
4045  nextScopeNameAddition.append(" ");
4046  }
4047  if (!nextScopeNameAddition.empty())
4048  nextScopeNameAddition.pop_back();
4049  }
4050 
4051  if (Token::simpleMatch(tok, "{")) {
4052  // This might be the opening of a member function
4053  Token *tok1 = tok;
4054  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4055  tok1 = tok1->previous();
4056  if (tok1->previous() && tok1->strAt(-1) == ")") {
4057  bool member = true;
4058  tok1 = tok1->linkAt(-1);
4059  if (Token::Match(tok1->previous(), "throw|noexcept")) {
4060  tok1 = tok1->previous();
4061  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4062  tok1 = tok1->previous();
4063  if (tok1->strAt(-1) != ")")
4064  member = false;
4065  } else if (Token::Match(tok->tokAt(-2), ":|, %name%")) {
4066  tok1 = tok1->tokAt(-2);
4067  if (tok1->strAt(-1) != ")")
4068  member = false;
4069  }
4070  if (member) {
4071  if (tok1->strAt(-1) == ">")
4072  tok1 = tok1->previous()->findOpeningBracket();
4073  if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
4074  tok1 = tok1->tokAt(-2);
4075  std::string scope = tok1->strAt(-1);
4076  while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
4077  scope = tok1->strAt(-3) + " :: " + scope;
4078  tok1 = tok1->tokAt(-2);
4079  }
4080 
4081  if (!nextScopeNameAddition.empty() && !scope.empty())
4082  nextScopeNameAddition += " :: ";
4083  nextScopeNameAddition += scope;
4084  }
4085  }
4086  }
4087 
4088  // New scope is opening, record it here
4089  std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(tok->scopeInfo()->name, tok->link(), tok->scopeInfo()->usingNamespaces);
4090 
4091  if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty())
4092  newScopeInfo->name.append(" :: ");
4093  newScopeInfo->name.append(nextScopeNameAddition);
4094  nextScopeNameAddition = "";
4095 
4096  if (tok->link())
4097  tok->link()->scopeInfo(tok->scopeInfo());
4098  tok->scopeInfo(std::move(newScopeInfo));
4099  }
4100  }
4101  }
4102 }
4103 
4105 {
4106  if (isC())
4107  return;
4108 
4109  const std::time_t maxTime = mSettings.templateMaxTime > 0 ? std::time(nullptr) + mSettings.templateMaxTime : 0;
4111  maxTime);
4112 }
4113 //---------------------------------------------------------------------------
4114 
4115 
4116 namespace {
4117  /** Class used in Tokenizer::setVarIdPass1 */
4118  class VariableMap {
4119  private:
4120  std::unordered_map<std::string, nonneg int> mVariableId;
4121  std::unordered_map<std::string, nonneg int> mVariableId_global;
4122  std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
4123  mutable nonneg int mVarId{};
4124  public:
4125  VariableMap() = default;
4126  void enterScope();
4127  bool leaveScope();
4128  void addVariable(const std::string& varname, bool globalNamespace);
4129  bool hasVariable(const std::string& varname) const {
4130  return mVariableId.find(varname) != mVariableId.end();
4131  }
4132 
4133  const std::unordered_map<std::string, nonneg int>& map(bool global) const {
4134  return global ? mVariableId_global : mVariableId;
4135  }
4136  nonneg int& getVarId() {
4137  return mVarId;
4138  }
4139  };
4140 }
4141 
4142 
4143 void VariableMap::enterScope()
4144 {
4145  mScopeInfo.emplace(/*std::vector<std::pair<std::string, nonneg int>>()*/);
4146 }
4147 
4148 bool VariableMap::leaveScope()
4149 {
4150  if (mScopeInfo.empty())
4151  return false;
4152 
4153  for (const std::pair<std::string, nonneg int>& outerVariable : mScopeInfo.top()) {
4154  if (outerVariable.second != 0)
4155  mVariableId[outerVariable.first] = outerVariable.second;
4156  else
4157  mVariableId.erase(outerVariable.first);
4158  }
4159  mScopeInfo.pop();
4160  return true;
4161 }
4162 
4163 void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
4164 {
4165  if (mScopeInfo.empty()) {
4166  mVariableId[varname] = ++mVarId;
4167  if (globalNamespace)
4168  mVariableId_global[varname] = mVariableId[varname];
4169  return;
4170  }
4171  std::unordered_map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
4172  if (it == mVariableId.end()) {
4173  mScopeInfo.top().emplace_back(varname, 0);
4174  mVariableId[varname] = ++mVarId;
4175  if (globalNamespace)
4176  mVariableId_global[varname] = mVariableId[varname];
4177  return;
4178  }
4179  mScopeInfo.top().emplace_back(varname, it->second);
4180  it->second = ++mVarId;
4181 }
4182 
4183 static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope)
4184 {
4185  const Token* const tok1 = tok;
4186  Token* tok2 = tok;
4187  if (!tok2->isName())
4188  return false;
4189 
4190  nonneg int typeCount = 0;
4191  nonneg int singleNameCount = 0;
4192  bool hasstruct = false; // Is there a "struct" or "class"?
4193  bool bracket = false;
4194  bool ref = false;
4195  while (tok2) {
4196  if (tok2->isName()) {
4197  if (Token::simpleMatch(tok2, "alignas (")) {
4198  tok2 = tok2->linkAt(1)->next();
4199  continue;
4200  }
4201  if (tok2->isCpp() && Token::Match(tok2, "namespace|public|private|protected"))
4202  return false;
4203  if (tok2->isCpp() && Token::simpleMatch(tok2, "decltype (")) {
4204  typeCount = 1;
4205  tok2 = tok2->linkAt(1)->next();
4206  continue;
4207  }
4208  if (Token::Match(tok2, "struct|union|enum") || (tok2->isCpp() && Token::Match(tok2, "class|typename"))) {
4209  hasstruct = true;
4210  typeCount = 0;
4211  singleNameCount = 0;
4212  } else if (Token::Match(tok2, "const|extern")) {
4213  // just skip "const", "extern"
4214  } else if (!hasstruct && variableMap.map(false).count(tok2->str()) && tok2->previous()->str() != "::") {
4215  ++typeCount;
4216  tok2 = tok2->next();
4217  if (!tok2 || tok2->str() != "::")
4218  break;
4219  } else {
4220  if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
4221  ++typeCount;
4222  ++singleNameCount;
4223  }
4224  } else if (tok2->isCpp() && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
4225  Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
4226  const Token *start = tok;
4227  if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/"))
4228  return false;
4229  Token* const closingBracket = tok2->findClosingBracket();
4230  if (closingBracket == nullptr) { /* Ticket #8151 */
4231  throw tok2;
4232  }
4233  tok2 = closingBracket;
4234  if (tok2->str() != ">")
4235  break;
4236  singleNameCount = 1;
4237  if (Token::Match(tok2, "> %name% %or%|%oror%|&&|&|^|+|-|*|/") && !Token::Match(tok2, "> const [*&]"))
4238  return false;
4239  if (Token::Match(tok2, "> %name% )")) {
4240  if (Token::Match(tok2->linkAt(2)->previous(), "if|for|while ("))
4241  return false;
4242  if (!Token::Match(tok2->linkAt(2)->previous(), "%name%|] ("))
4243  return false;
4244  }
4245  } else if (Token::Match(tok2, "&|&&")) {
4246  ref = !bracket;
4247  } else if (singleNameCount >= 1 && Token::Match(tok2, "( [*&]") && Token::Match(tok2->link(), ") (|[")) {
4248  for (const Token* tok3 = tok2->tokAt(2); Token::Match(tok3, "!!)"); tok3 = tok3->next()) {
4249  if (Token::Match(tok3, "(|["))
4250  tok3 = tok3->link();
4251  if (tok3->str() == ",")
4252  return false;
4253  }
4254  bracket = true; // Skip: Seems to be valid pointer to array or function pointer
4255  } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]")) {
4256  bracket = true;
4257  } else if (singleNameCount >= 1 && tok2->previous() && tok2->previous()->isStandardType() && Token::Match(tok2, "( *|&| %name% ) ;")) {
4258  bracket = true;
4259  } else if (tok2->str() == "::") {
4260  singleNameCount = 0;
4261  } else if (tok2->str() != "*" && tok2->str() != "...") {
4262  break;
4263  }
4264  tok2 = tok2->next();
4265  }
4266 
4267  if (tok2) {
4268  bool isLambdaArg = false;
4269  {
4270  const Token *tok3 = tok->previous();
4271  if (tok3 && tok3->str() == ",") {
4272  while (tok3 && !Token::Match(tok3,";|(|[|{")) {
4273  if (Token::Match(tok3, ")|]"))
4274  tok3 = tok3->link();
4275  tok3 = tok3->previous();
4276  }
4277 
4278  if (tok3 && executableScope && Token::Match(tok3->previous(), "%name% (")) {
4279  const Token *fdecl = tok3->previous();
4280  int count = 0;
4281  while (Token::Match(fdecl, "%name%|*")) {
4282  fdecl = fdecl->previous();
4283  count++;
4284  }
4285  if (!Token::Match(fdecl, "[;{}] %name%") || count <= 1)
4286  return false;
4287  }
4288  }
4289 
4290  if (tok3 && tok3->isCpp() && Token::simpleMatch(tok3->previous(), "] (") &&
4291  (Token::simpleMatch(tok3->link(), ") {") || Token::Match(tok3->link(), ") . %name%")))
4292  isLambdaArg = true;
4293  }
4294 
4295 
4296  tok = tok2;
4297 
4298  // In executable scopes, references must be assigned
4299  // Catching by reference is an exception
4300  if (executableScope && ref && !isLambdaArg) {
4301  if (Token::Match(tok2, "(|=|{|:"))
4302  ; // reference is assigned => ok
4303  else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
4304  return false; // not catching by reference => not declaration
4305  }
4306  }
4307 
4308  // Check if array declaration is valid (#2638)
4309  // invalid declaration: AAA a[4] = 0;
4310  if (typeCount >= 2 && executableScope && Token::Match(tok2, ")| [")) {
4311  const Token *tok3 = tok2->str() == ")" ? tok2->next() : tok2;
4312  while (tok3 && tok3->str() == "[") {
4313  tok3 = tok3->link()->next();
4314  }
4315  if (Token::Match(tok3, "= %num%"))
4316  return false;
4317  if (bracket && Token::Match(tok1->previous(), "[(,]") && Token::Match(tok3, "[,)]"))
4318  return false;
4319  }
4320 
4321  return (typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
4322 }
4323 
4324 
4325 static void setVarIdStructMembers(Token *&tok1,
4326  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4327  nonneg int &varId)
4328 {
4329  Token *tok = tok1;
4330 
4331  if (Token::Match(tok, "%name% = { . %name% =|{")) {
4332  const nonneg int struct_varid = tok->varId();
4333  if (struct_varid == 0)
4334  return;
4335 
4336  std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4337 
4338  tok = tok->tokAt(3);
4339  while (tok->str() != "}") {
4340  if (Token::Match(tok, "{|[|("))
4341  tok = tok->link();
4342  if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
4343  tok = tok->next();
4344  const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4345  if (it == members.end()) {
4346  members[tok->str()] = ++varId;
4347  tok->varId(varId);
4348  } else {
4349  tok->varId(it->second);
4350  }
4351  }
4352  tok = tok->next();
4353  }
4354 
4355  return;
4356  }
4357 
4358  while (Token::Match(tok->next(), ")| . %name% !!(")) {
4359  // Don't set varid for trailing return type
4360  if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-1), "%name%|]") &&
4361  Tokenizer::isFunctionHead(tok->linkAt(1), "{|;")) {
4362  tok = tok->tokAt(3);
4363  continue;
4364  }
4365  const nonneg int struct_varid = tok->varId();
4366  tok = tok->tokAt(2);
4367  if (struct_varid == 0)
4368  continue;
4369 
4370  if (tok->str() == ".")
4371  tok = tok->next();
4372 
4373  // Don't set varid for template function
4375  break;
4376 
4377  std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4378  const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4379  if (it == members.end()) {
4380  members[tok->str()] = ++varId;
4381  tok->varId(varId);
4382  } else {
4383  tok->varId(it->second);
4384  }
4385  }
4386  // tok can't be null
4387  tok1 = tok;
4388 }
4389 
4390 static bool setVarIdClassDeclaration(Token* const startToken,
4391  VariableMap& variableMap,
4392  const nonneg int scopeStartVarId,
4393  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers)
4394 {
4395  // end of scope
4396  const Token* const endToken = startToken->link();
4397 
4398  // determine class name
4399  std::string className;
4400  for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
4401  if (!tok->isName() && tok->str() != ":")
4402  break;
4403  if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
4404  className = tok->next()->str();
4405  break;
4406  }
4407  }
4408 
4409  // replace varids..
4410  int indentlevel = 0;
4411  bool initList = false;
4412  bool inEnum = false;
4413  const Token *initListArgLastToken = nullptr;
4414  for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
4415  if (!tok)
4416  return false;
4417  if (initList) {
4418  if (tok == initListArgLastToken)
4419  initListArgLastToken = nullptr;
4420  else if (!initListArgLastToken &&
4421  Token::Match(tok->previous(), "%name%|>|>> {|(") &&
4422  Token::Match(tok->link(), "}|) ,|{"))
4423  initListArgLastToken = tok->link();
4424  }
4425  if (tok->str() == "{") {
4426  inEnum = isEnumStart(tok);
4427  if (initList && !initListArgLastToken)
4428  initList = false;
4429  ++indentlevel;
4430  } else if (tok->str() == "}") {
4431  --indentlevel;
4432  inEnum = false;
4433  } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
4434  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4435  if (it != variableMap.map(false).end()) {
4436  tok->varId(it->second);
4437  }
4438  } else if (tok->isName() && tok->varId() <= scopeStartVarId) {
4439  if (indentlevel > 0 || initList) {
4440  if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
4441  continue;
4442  if (!tok->next())
4443  return false;
4444  if (tok->next()->str() == "::") {
4445  if (tok->str() == className)
4446  tok = tok->tokAt(2);
4447  else
4448  continue;
4449  }
4450 
4451  if (!inEnum) {
4452  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4453  if (it != variableMap.map(false).end()) {
4454  tok->varId(it->second);
4455  setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4456  }
4457  }
4458  }
4459  } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
4460  initList = true;
4461  }
4462  return true;
4463 }
4464 
4465 
4466 
4467 // Update the variable ids..
4468 // Parse each function..
4469 void Tokenizer::setVarIdClassFunction(const std::string &classname,
4470  Token * const startToken,
4471  const Token * const endToken,
4472  const std::map<std::string, nonneg int> &varlist,
4473  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4474  nonneg int &varId_)
4475 {
4476  const auto pos = classname.rfind(' '); // TODO handle multiple scopes
4477  const std::string lastScope = classname.substr(pos == std::string::npos ? 0 : pos + 1);
4478  for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
4479  if (tok2->varId() != 0 || !tok2->isName())
4480  continue;
4481  if (Token::Match(tok2->tokAt(-2), ("!!" + lastScope + " ::").c_str()))
4482  continue;
4483  if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
4484  continue;
4485  if (Token::Match(tok2->tokAt(-2), "!!this .") && !Token::simpleMatch(tok2->tokAt(-5), "( * this ) ."))
4486  continue;
4487  if (Token::Match(tok2, "%name% ::"))
4488  continue;
4489 
4490  const std::map<std::string, nonneg int>::const_iterator it = varlist.find(tok2->str());
4491  if (it != varlist.end()) {
4492  tok2->varId(it->second);
4493  setVarIdStructMembers(tok2, structMembers, varId_);
4494  }
4495  }
4496 }
4497 
4498 
4499 
4501 {
4502  // Clear all variable ids
4503  for (Token *tok = list.front(); tok; tok = tok->next()) {
4504  if (tok->isName())
4505  tok->varId(0);
4506  }
4507 
4508  setVarIdPass1();
4509 
4510  setPodTypes();
4511 
4512  setVarIdPass2();
4513 }
4514 
4515 
4516 // Variable declarations can't start with "return" etc.
4517 #define NOTSTART_C "NOT", "case", "default", "goto", "not", "return", "sizeof", "typedef"
4518 static const std::unordered_set<std::string> notstart_c = { NOTSTART_C };
4519 static const std::unordered_set<std::string> notstart_cpp = { NOTSTART_C,
4520  "delete", "friend", "new", "throw", "using", "virtual", "explicit", "const_cast", "dynamic_cast", "reinterpret_cast", "static_cast", "template"
4521 };
4522 
4524 {
4525  // Variable declarations can't start with "return" etc.
4526  const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
4527 
4528  VariableMap variableMap;
4529  std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
4530 
4531  std::stack<VarIdScopeInfo> scopeStack;
4532 
4533  scopeStack.emplace(/*VarIdScopeInfo()*/);
4534  std::stack<const Token *> functionDeclEndStack;
4535  const Token *functionDeclEndToken = nullptr;
4536  bool initlist = false;
4537  bool inlineFunction = false;
4538  for (Token *tok = list.front(); tok; tok = tok->next()) {
4539  if (tok->isOp())
4540  continue;
4541  if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
4542  Token* closingBracket = tok->next()->findClosingBracket();
4543  if (closingBracket)
4544  tok = closingBracket;
4545  continue;
4546  }
4547 
4548  if (tok == functionDeclEndToken) {
4549  functionDeclEndStack.pop();
4550  functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
4551  if (tok->str() == ":")
4552  initlist = true;
4553  else if (tok->str() == ";") {
4554  if (!variableMap.leaveScope())
4555  cppcheckError(tok);
4556  } else if (tok->str() == "{") {
4557  scopeStack.emplace(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/ false, variableMap.getVarId());
4558 
4559  // check if this '{' is a start of an "if" body
4560  const Token * ifToken = tok->previous();
4561  if (ifToken && ifToken->str() == ")")
4562  ifToken = ifToken->link();
4563  else
4564  ifToken = nullptr;
4565  if (ifToken)
4566  ifToken = ifToken->previous();
4567  if (ifToken && ifToken->str() == "if") {
4568  // open another scope to differentiate between variables declared in the "if" condition and in the "if" body
4569  variableMap.enterScope();
4570  }
4571  }
4572  } else if (!initlist && tok->str()=="(") {
4573  const Token * newFunctionDeclEnd = nullptr;
4574  if (!scopeStack.top().isExecutable)
4575  newFunctionDeclEnd = isFunctionHead(tok, "{:;");
4576  else {
4577  const Token* tokenLinkNext = tok->link()->next();
4578  if (Token::simpleMatch(tokenLinkNext, ".")) { // skip trailing return type
4579  tokenLinkNext = tokenLinkNext->next();
4580  while (Token::Match(tokenLinkNext, "%name%|::")) {
4581  tokenLinkNext = tokenLinkNext->next();
4582  if (Token::simpleMatch(tokenLinkNext, "<") && tokenLinkNext->link())
4583  tokenLinkNext = tokenLinkNext->link()->next();
4584  }
4585  }
4586  if (tokenLinkNext && tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
4587  newFunctionDeclEnd = tokenLinkNext;
4588  }
4589  if (newFunctionDeclEnd && newFunctionDeclEnd != functionDeclEndToken) {
4590  functionDeclEndStack.push(newFunctionDeclEnd);
4591  functionDeclEndToken = newFunctionDeclEnd;
4592  variableMap.enterScope();
4593  }
4594  } else if (Token::Match(tok, "{|}")) {
4595  inlineFunction = false;
4596 
4597  const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
4598 
4599  // parse anonymous namespaces as part of the current scope
4600  if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
4601  !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(") && Token::Match(startToken->link(), "} ,|{|)"))) {
4602 
4603  if (tok->str() == "{") {
4604  bool isExecutable;
4605  const Token *prev = tok->previous();
4606  while (Token::Match(prev, "%name%|."))
4607  prev = prev->previous();
4608  const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] (");
4609  if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) ||
4610  (initlist && tok->strAt(-1) == "}")) {
4611  isExecutable = true;
4612  } else {
4613  isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
4615  if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
4616  variableMap.enterScope();
4617  }
4618  initlist = false;
4619  scopeStack.emplace(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), variableMap.getVarId());
4620  } else { /* if (tok->str() == "}") */
4621  bool isNamespace = false;
4622  for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) {
4623  if (tok1->str() == "namespace") {
4624  isNamespace = true;
4625  break;
4626  }
4627  }
4628  // Set variable ids in class declaration..
4629  if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
4630  if (!setVarIdClassDeclaration(tok->link(),
4631  variableMap,
4632  scopeStack.top().startVarid,
4633  structMembers)) {
4634  syntaxError(nullptr);
4635  }
4636  }
4637 
4638  if (!scopeStack.top().isStructInit) {
4639  variableMap.leaveScope();
4640 
4641  // check if this '}' is an end of an "else" body or an "if" body without an "else" part
4642  const Token * ifToken = startToken->previous();
4643  if (ifToken && ifToken->str() == ")")
4644  ifToken = ifToken->link()->previous();
4645  else
4646  ifToken = nullptr;
4647  if (startToken->strAt(-1) == "else" || (ifToken && ifToken->str() == "if" && tok->strAt(1) != "else")) {
4648  // leave the extra scope used to differentiate between variables declared in the "if" condition and in the "if" body
4649  variableMap.leaveScope();
4650  }
4651  }
4652 
4653  scopeStack.pop();
4654  if (scopeStack.empty()) { // should be impossible
4655  scopeStack.emplace(/*VarIdScopeInfo()*/);
4656  }
4657  }
4658  }
4659  }
4660 
4661  if ((!scopeStack.top().isStructInit &&
4662  (tok == list.front() ||
4663  Token::Match(tok, "[;{}]") ||
4664  (tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
4665  (tok->str() == "," && (!scopeStack.top().isExecutable || inlineFunction || !tok->previous()->varId())) ||
4666  (tok->isName() && endsWith(tok->str(), ':')))) ||
4667  (tok->str() == "(" && isFunctionHead(tok, "{"))) {
4668 
4669  // No variable declarations in sizeof
4670  if (Token::simpleMatch(tok->previous(), "sizeof (")) {
4671  continue;
4672  }
4673 
4674  if (Settings::terminated())
4675  return;
4676 
4677  // locate the variable name..
4678  Token* tok2 = (tok->isName()) ? tok : tok->next();
4679 
4680  // private: protected: public: etc
4681  while (tok2 && endsWith(tok2->str(), ':')) {
4682  tok2 = tok2->next();
4683  }
4684  if (!tok2)
4685  break;
4686 
4687  // Variable declaration can't start with "return", etc
4688  if (notstart.find(tok2->str()) != notstart.end())
4689  continue;
4690 
4691  if (!isC() && Token::simpleMatch(tok2, "const new"))
4692  continue;
4693 
4694  bool decl;
4695  if (isCPP() && mSettings.standards.cpp >= Standards::CPP17 && Token::Match(tok, "[(;{}] const| auto &|&&| [")) {
4696  // Structured bindings
4697  tok2 = Token::findsimplematch(tok, "[");
4698  if ((Token::simpleMatch(tok->previous(), "for (") && Token::simpleMatch(tok2->link(), "] :")) ||
4699  Token::simpleMatch(tok2->link(), "] =")) {
4700  while (tok2 && tok2->str() != "]") {
4701  if (Token::Match(tok2, "%name% [,]]"))
4702  variableMap.addVariable(tok2->str(), false);
4703  tok2 = tok2->next();
4704  }
4705  continue;
4706  }
4707  }
4708 
4709  try { /* Ticket #8151 */
4710  decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable);
4711  } catch (const Token * errTok) {
4712  syntaxError(errTok);
4713  }
4714 
4715  if (tok->str() == "(" && isFunctionHead(tok, "{") && scopeStack.top().isExecutable)
4716  inlineFunction = true;
4717 
4718  if (decl) {
4719  if (isCPP()) {
4720  if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
4721  for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
4722  if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
4723  declTok->varId(variableMap.map(false).find(declTok->str())->second);
4724  }
4725  }
4726  }
4727 
4728  const Token* prev2 = tok2->previous();
4729  if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
4730  ;
4731  else if (Token::Match(prev2, "%type% :") && tok->strAt(-1) == "for")
4732  ;
4733  else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
4734  // In C++ , a variable can't be called operator+ or something like that.
4735  if (prev2->isCpp() &&
4736  prev2->isOperatorKeyword())
4737  continue;
4738 
4739  const Token *tok3 = tok2->next();
4740  if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
4741  if (!scopeStack.top().isExecutable) {
4742  // Detecting initializations with () in non-executable scope is hard and often impossible to be done safely. Thus, only treat code as a variable that definitely is one.
4743  decl = false;
4744  bool rhs = false;
4745  for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
4746  if (tok3->str() == "=") {
4747  rhs = true;
4748  continue;
4749  }
4750 
4751  if (tok3->str() == ",") {
4752  rhs = false;
4753  continue;
4754  }
4755 
4756  if (rhs)
4757  continue;
4758 
4759  if (tok3->isLiteral() ||
4760  (tok3->isName() && (variableMap.hasVariable(tok3->str()) ||
4761  (tok3->strAt(-1) == "(" && Token::simpleMatch(tok3->next(), "(") && !Token::simpleMatch(tok3->linkAt(1)->next(), "(")))) ||
4762  tok3->isOp() ||
4763  tok3->str() == "(" ||
4764  notstart.find(tok3->str()) != notstart.end()) {
4765  decl = true;
4766  break;
4767  }
4768  }
4769  }
4770  } else
4771  decl = false;
4772  } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
4773  if (tok2->link() != tok2->next() && // add value-initialized variable T x{};
4774  (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:")))
4775  continue;
4776  } else
4777  decl = false;
4778 
4779  if (decl) {
4780  if (isC() && Token::Match(prev2->previous(), "&|&&"))
4781  syntaxErrorC(prev2, prev2->strAt(-2) + prev2->strAt(-1) + " " + prev2->str());
4782  variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
4783 
4784  if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
4785  for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
4786  if (Token::Match(tok3, "[([]"))
4787  tok3 = tok3->link();
4788  if (Token::Match(tok3, ", %name% [,=;]"))
4789  variableMap.addVariable(tok3->next()->str(), false);
4790  }
4791  }
4792 
4793  // set varid for template parameters..
4794  tok = tok->next();
4795  while (Token::Match(tok, "%name%|::"))
4796  tok = tok->next();
4797  if (tok && tok->str() == "<") {
4798  const Token *end = tok->findClosingBracket();
4799  while (tok != end) {
4800  if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
4801  Token::Match(tok->tokAt(-1), ":: %name%"))) {
4802  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4803  if (it != variableMap.map(false).end())
4804  tok->varId(it->second);
4805  }
4806  tok = tok->next();
4807  }
4808  }
4809 
4810  tok = tok2->previous();
4811  }
4812  }
4813  }
4814 
4815  if (tok->isName() && !tok->isKeyword() && !tok->isStandardType()) {
4816  // don't set variable id after a struct|enum|union
4817  if (Token::Match(tok->previous(), "struct|enum|union") || (tok->isCpp() && tok->strAt(-1) == "class"))
4818  continue;
4819 
4820  bool globalNamespace = false;
4821  if (!isC()) {
4822  if (tok->previous() && tok->previous()->str() == "::") {
4823  if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
4824  continue;
4825  globalNamespace = true;
4826  }
4827  if (tok->next() && tok->next()->str() == "::")
4828  continue;
4829  if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
4830  continue;
4831  }
4832 
4833  // function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
4834  if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) {
4835  bool par = false;
4836  const Token* start;
4837  Token* end;
4838 
4839  // search begin of function declaration
4840  for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
4841  if (start->str() == "(") {
4842  if (par)
4843  break;
4844  par = true;
4845  }
4846  if (Token::Match(start, "[(,]")) {
4847  if (!Token::Match(start, "[(,] %type% %name%|*|&"))
4848  break;
4849  }
4850  if (start->varId() > 0)
4851  break;
4852  }
4853 
4854  // search end of function declaration
4855  for (end = tok->next(); Token::Match(end, "%name%|*|&|,|[|]|%num%"); end = end->next()) {}
4856 
4857  // there are tokens which can't appear at the begin of a function declaration such as "return"
4858  const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();
4859 
4860  // now check if it is a function declaration
4861  if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword) {
4862  // function declaration => don't set varid
4863  tok = end;
4864  continue;
4865  }
4866  }
4867 
4868  if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
4869  !Token::simpleMatch(tok->next(), ": ;")) {
4870  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
4871  if (it != variableMap.map(globalNamespace).end()) {
4872  tok->varId(it->second);
4873  setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4874  }
4875  }
4876  } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) {
4877  // Don't set varid after a :: or . token
4878  tok = tok->next();
4879  } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
4880  do {
4881  tok = tok->next();
4882  } while (tok && (tok->isName() || tok->str() == ","));
4883  if (!tok)
4884  break;
4885  tok = tok->previous();
4886  }
4887  }
4888 
4889  mVarId = variableMap.getVarId();
4890 }
4891 
4892 namespace {
4893  struct Member {
4894  Member(std::list<std::string> s, std::list<const Token *> ns, Token *t) : usingnamespaces(std::move(ns)), scope(std::move(s)), tok(t) {}
4895  std::list<const Token *> usingnamespaces;
4896  std::list<std::string> scope;
4897  Token *tok;
4898  };
4899 }
4900 
4901 static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
4902 {
4903  std::string ret;
4904  for (const ScopeInfo2 &si : scopeInfo)
4905  ret += (ret.empty() ? "" : " :: ") + (si.name);
4906  return ret;
4907 }
4908 
4909 static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
4910 {
4911  std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.cbegin();
4912 
4913  // Current scope..
4914  for (std::list<std::string>::const_iterator it = scope.cbegin(); it != scope.cend(); ++it) {
4915  if (scopeIt == scopeInfo.cend() || scopeIt->name != *it)
4916  return nullptr;
4917  ++scopeIt;
4918  }
4919 
4920  // using namespace..
4921  if (nsToken) {
4922  while (Token::Match(nsToken, "%name% ::")) {
4923  if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
4924  nsToken = nsToken->tokAt(2);
4925  ++scopeIt;
4926  } else {
4927  return nullptr;
4928  }
4929  }
4930  if (!Token::Match(nsToken, "%name% ;"))
4931  return nullptr;
4932  if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
4933  return nullptr;
4934  ++scopeIt;
4935  }
4936 
4937  // Parse member tokens..
4938  while (scopeIt != scopeInfo.end()) {
4939  if (!Token::Match(memberToken, "%name% ::|<"))
4940  return nullptr;
4941  if (memberToken->str() != scopeIt->name)
4942  return nullptr;
4943  if (memberToken->next()->str() == "<") {
4944  memberToken = memberToken->next()->findClosingBracket();
4945  if (!Token::simpleMatch(memberToken, "> ::"))
4946  return nullptr;
4947  }
4948  memberToken = memberToken->tokAt(2);
4949  ++scopeIt;
4950  }
4951 
4952  return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
4953 }
4954 
4955 static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
4956 {
4957  if (scopeInfo.empty())
4958  return nullptr;
4959 
4960  // Does this member match without "using namespace"..
4961  Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
4962  if (ret)
4963  return ret;
4964 
4965  // Try to match member using the "using namespace ..." namespaces..
4966  for (const Token *ns : member.usingnamespaces) {
4967  ret = matchMemberName(member.scope, ns, member.tok, scopeInfo);
4968  if (ret)
4969  return ret;
4970  }
4971 
4972  return nullptr;
4973 }
4974 
4975 static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
4976 {
4977  Token *tok = matchMemberName(var, scopeInfo);
4978  if (Token::Match(tok, "%name%")) {
4979  if (!tok->next() || tok->strAt(1) != "(" || (tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
4980  return tok;
4981  }
4982  return nullptr;
4983 }
4984 
4985 static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
4986 {
4987  Token *tok = matchMemberName(func, scopeInfo);
4988  return Token::Match(tok, "~| %name% (") ? tok : nullptr;
4989 }
4990 
4991 template<typename T>
4992 static T* skipInitializerList(T* tok)
4993 {
4994  T* const start = tok;
4995  while (Token::Match(tok, "[:,] ::| %name%")) {
4996  tok = tok->tokAt(tok->strAt(1) == "::" ? 1 : 2);
4997  while (Token::Match(tok, ":: %name%"))
4998  tok = tok->tokAt(2);
4999  if (!Token::Match(tok, "[({<]") || !tok->link())
5000  return start;
5001  const bool isTemplate = tok->str() == "<";
5002  tok = tok->link()->next();
5003  if (isTemplate && tok && tok->link())
5004  tok = tok->link()->next();
5005  }
5006  return tok;
5007 }
5008 
5010 {
5011  std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
5012 
5013  // Member functions and variables in this source
5014  std::list<Member> allMemberFunctions;
5015  std::list<Member> allMemberVars;
5016  if (!isC()) {
5017  std::map<const Token *, std::string> endOfScope;
5018  std::list<std::string> scope;
5019  std::list<const Token *> usingnamespaces;
5020  for (Token *tok = list.front(); tok; tok = tok->next()) {
5021  if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
5022  if (Token::Match(tok, "using namespace %name% ::|;")) {
5023  Token *endtok = tok->tokAt(2);
5024  while (Token::Match(endtok, "%name% ::"))
5025  endtok = endtok->tokAt(2);
5026  if (Token::Match(endtok, "%name% ;"))
5027  usingnamespaces.push_back(tok->tokAt(2));
5028  tok = endtok;
5029  continue;
5030  }
5031  if (Token::Match(tok, "namespace %name% {")) {
5032  scope.push_back(tok->strAt(1));
5033  endOfScope[tok->linkAt(2)] = tok->strAt(1);
5034  }
5035  }
5036 
5037  if (tok->str() == "}") {
5038  const std::map<const Token *, std::string>::iterator it = endOfScope.find(tok);
5039  if (it != endOfScope.end())
5040  scope.remove(it->second);
5041  }
5042 
5043  Token* const tok1 = tok;
5044  if (Token::Match(tok, "%name% :: ~| %name%"))
5045  tok = tok->next();
5046  else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5047  tok = tok->next()->findClosingBracket()->next();
5048  else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean ||
5049  Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") ||
5050  (!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
5051  continue;
5052 
5053  if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
5054  continue;
5055 
5056  while (Token::Match(tok, ":: ~| %name%")) {
5057  tok = tok->next();
5058  if (tok->str() == "~")
5059  tok = tok->next();
5060  else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5061  tok = tok->next()->findClosingBracket()->next();
5062  else if (Token::Match(tok, "%name% ::"))
5063  tok = tok->next();
5064  else
5065  break;
5066  }
5067  if (!tok->next())
5068  syntaxError(tok);
5069  if (Token::Match(tok, "%name% (") && !(tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
5070  allMemberFunctions.emplace_back(scope, usingnamespaces, tok1);
5071  else
5072  allMemberVars.emplace_back(scope, usingnamespaces, tok1);
5073  }
5074  }
5075 
5076  std::list<ScopeInfo2> scopeInfo;
5077 
5078  // class members..
5079  std::map<std::string, std::map<std::string, nonneg int>> varsByClass;
5080  for (Token *tok = list.front(); tok; tok = tok->next()) {
5081  while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
5082  scopeInfo.pop_back();
5083 
5084  if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<"))
5085  continue;
5086 
5087  const std::string &scopeName(getScopeName(scopeInfo));
5088  const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
5089 
5090  std::list<const Token*> classnameTokens{ tok->next() };
5091  Token* tokStart = tok->tokAt(2);
5092  while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") {
5093  if (tokStart->str() == "<") {
5094  // skip the template part
5095  Token* closeTok = tokStart->findClosingBracket();
5096  if (!closeTok)
5097  syntaxError(tok);
5098  tokStart = closeTok->next();
5099  } else {
5100  classnameTokens.push_back(tokStart->next());
5101  tokStart = tokStart->tokAt(2);
5102  }
5103  }
5104 
5105  std::string classname;
5106  for (const Token *it : classnameTokens)
5107  classname += (classname.empty() ? "" : " :: ") + it->str();
5108 
5109  std::map<std::string, nonneg int> &thisClassVars = varsByClass[scopeName2 + classname];
5110  while (Token::Match(tokStart, ":|::|,|%name%")) {
5111  if (Token::Match(tokStart, "%name% <")) { // TODO: why skip templates?
5112  tokStart = tokStart->next()->findClosingBracket();
5113  if (tokStart)
5114  tokStart = tokStart->next();
5115  continue;
5116  }
5117  if (Token::Match(tokStart, "%name% ,|{")) {
5118  std::string baseClassName = tokStart->str();
5119  const Token* baseStart = tokStart;
5120  while (Token::Match(baseStart->tokAt(-2), "%name% ::")) { // build base class name
5121  baseClassName.insert(0, baseStart->strAt(-2) + " :: ");
5122  baseStart = baseStart->tokAt(-2);
5123  }
5124  std::string scopeName3(scopeName2);
5125  while (!scopeName3.empty()) {
5126  const std::string name = scopeName3 + baseClassName;
5127  if (varsByClass.find(name) != varsByClass.end()) {
5128  baseClassName = name;
5129  break;
5130  }
5131  // Remove last scope name
5132  if (scopeName3.size() <= 8)
5133  break;
5134  scopeName3.erase(scopeName3.size() - 4);
5135  const std::string::size_type pos = scopeName3.rfind(" :: ");
5136  if (pos == std::string::npos)
5137  break;
5138  scopeName3.erase(pos + 4);
5139  }
5140  const std::map<std::string, nonneg int>& baseClassVars = varsByClass[baseClassName];
5141  thisClassVars.insert(baseClassVars.cbegin(), baseClassVars.cend());
5142  }
5143  tokStart = tokStart->next();
5144  }
5145  if (!Token::simpleMatch(tokStart, "{"))
5146  continue;
5147 
5148  // What member variables are there in this class?
5149  std::transform(classnameTokens.cbegin(), classnameTokens.cend(), std::back_inserter(scopeInfo), [&](const Token* tok) {
5150  return ScopeInfo2(tok->str(), tokStart->link());
5151  });
5152 
5153  for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
5154  // skip parentheses..
5155  if (tok2->link()) {
5156  if (tok2->str() == "(") {
5157  Token *funcstart = const_cast<Token*>(isFunctionHead(tok2, "{"));
5158  if (funcstart) {
5159  setVarIdClassFunction(scopeName2 + classname, funcstart, funcstart->link(), thisClassVars, structMembers, mVarId);
5160  tok2 = funcstart->link();
5161  continue;
5162  }
5163  }
5164  if (tok2->str() == "{" && !Token::simpleMatch(tok2->previous(), "union")) {
5165  if (tok2->strAt(-1) == ")")
5166  setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, mVarId);
5167  tok2 = tok2->link();
5168  } else if (Token::Match(tok2, "( %name%|)") && !Token::Match(tok2->link(), "(|[")) {
5169  tok2 = tok2->link();
5170 
5171  // Skip initialization list
5172  if (Token::simpleMatch(tok2, ") :"))
5173  tok2 = skipInitializerList(tok2->next());
5174  }
5175  }
5176 
5177  // Found a member variable..
5178  else if (tok2->varId() > 0)
5179  thisClassVars[tok2->str()] = tok2->varId();
5180  }
5181 
5182  // Are there any member variables in this class?
5183  if (thisClassVars.empty())
5184  continue;
5185 
5186  // Member variables
5187  for (const Member &var : allMemberVars) {
5188  Token *tok2 = matchMemberVarName(var, scopeInfo);
5189  if (!tok2)
5190  continue;
5191  if (tok2->varId() == 0)
5192  tok2->varId(thisClassVars[tok2->str()]);
5193  }
5194 
5195  if (isC() || tok->str() == "namespace")
5196  continue;
5197 
5198  // Set variable ids in member functions for this class..
5199  for (const Member &func : allMemberFunctions) {
5200  Token *tok2 = matchMemberFunctionName(func, scopeInfo);
5201  if (!tok2)
5202  continue;
5203 
5204  if (tok2->str() == "~")
5205  tok2 = tok2->linkAt(2);
5206  else
5207  tok2 = tok2->linkAt(1);
5208 
5209  // If this is a function implementation.. add it to funclist
5210  Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
5211  if (start) {
5212  setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, mVarId);
5213  }
5214 
5215  if (Token::Match(tok2, ") %name% ("))
5216  tok2 = tok2->linkAt(2);
5217 
5218  // constructor with initializer list
5219  if (!Token::Match(tok2, ") : ::| %name%"))
5220  continue;
5221 
5222  Token *tok3 = tok2;
5223  while (Token::Match(tok3, "[)}] [,:]")) {
5224  tok3 = tok3->tokAt(2);
5225  if (Token::Match(tok3, ":: %name%"))
5226  tok3 = tok3->next();
5227  while (Token::Match(tok3, "%name% :: %name%"))
5228  tok3 = tok3->tokAt(2);
5229  if (!Token::Match(tok3, "%name% (|{|<"))
5230  break;
5231 
5232  // set varid
5233  const std::map<std::string, nonneg int>::const_iterator varpos = thisClassVars.find(tok3->str());
5234  if (varpos != thisClassVars.end())
5235  tok3->varId(varpos->second);
5236 
5237  // goto end of var
5238  if (tok3->strAt(1) == "<") {
5239  tok3 = tok3->next()->findClosingBracket();
5240  if (tok3 && tok3->next() && tok3->next()->link())
5241  tok3 = tok3->next()->link();
5242  } else
5243  tok3 = tok3->linkAt(1);
5244  }
5245  if (Token::Match(tok3, ")|} {")) {
5246  setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, structMembers, mVarId);
5247  }
5248  }
5249  }
5250 }
5251 
5252 static void linkBrackets(const Tokenizer & tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token * const token, const char open, const char close)
5253 {
5254  if (token->str()[0] == open) {
5255  links.push(token);
5256  type.push(token);
5257  } else if (token->str()[0] == close) {
5258  if (links.empty()) {
5259  // Error, { and } don't match.
5260  tokenizer.unmatchedToken(token);
5261  }
5262  if (type.top()->str()[0] != open) {
5263  tokenizer.unmatchedToken(type.top());
5264  }
5265  type.pop();
5266 
5267  Token::createMutualLinks(links.top(), token);
5268  links.pop();
5269  }
5270 }
5271 
5273 {
5274  std::stack<const Token*> type;
5275  std::stack<Token*> links1;
5276  std::stack<Token*> links2;
5277  std::stack<Token*> links3;
5278  for (Token *token = list.front(); token; token = token->next()) {
5279  if (token->link()) {
5280  token->link(nullptr);
5281  }
5282 
5283  linkBrackets(*this, type, links1, token, '{', '}');
5284 
5285  linkBrackets(*this, type, links2, token, '(', ')');
5286 
5287  linkBrackets(*this, type, links3, token, '[', ']');
5288  }
5289 
5290  if (!links1.empty()) {
5291  // Error, { and } don't match.
5292  unmatchedToken(links1.top());
5293  }
5294 
5295  if (!links2.empty()) {
5296  // Error, ( and ) don't match.
5297  unmatchedToken(links2.top());
5298  }
5299 
5300  if (!links3.empty()) {
5301  // Error, [ and ] don't match.
5302  unmatchedToken(links3.top());
5303  }
5304 }
5305 
5307 {
5308  if (isC())
5309  return;
5310 
5311  bool isStruct = false;
5312 
5313  std::stack<Token*> type;
5314  std::stack<Token*> templateTokens;
5315  for (Token *token = list.front(); token; token = token->next()) {
5316  if (Token::Match(token, "%name%|> %name% [:<]"))
5317  isStruct = true;
5318  else if (Token::Match(token, "[;{}]"))
5319  isStruct = false;
5320 
5321  if (token->link()) {
5322  if (Token::Match(token, "{|[|("))
5323  type.push(token);
5324  else if (!type.empty() && Token::Match(token, "}|]|)")) {
5325  while (type.top()->str() == "<") {
5326  if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
5327  templateTokens.pop();
5328  type.pop();
5329  }
5330  type.pop();
5331  }
5332  } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
5333  if (Token::Match(token, "&& [,>]"))
5334  continue;
5335  // If there is some such code: A<B||C>..
5336  // Then this is probably a template instantiation if either "B" or "C" has comparisons
5337  if (token->tokType() == Token::eLogicalOp && !type.empty() && type.top()->str() == "<") {
5338  const Token *prev = token->previous();
5339  bool foundComparison = false;
5340  while (Token::Match(prev, "%name%|%num%|%str%|%cop%|)|]") && prev != type.top()) {
5341  if (prev->str() == ")" || prev->str() == "]")
5342  prev = prev->link();
5343  else if (prev->tokType() == Token::eLogicalOp)
5344  break;
5345  else if (prev->isComparisonOp())
5346  foundComparison = true;
5347  prev = prev->previous();
5348  }
5349  if (prev == type.top() && foundComparison)
5350  continue;
5351  const Token *next = token->next();
5352  foundComparison = false;
5353  while (Token::Match(next, "%name%|%num%|%str%|%cop%|(|[") && next->str() != ">") {
5354  if (next->str() == "(" || next->str() == "[")
5355  next = next->link();
5356  else if (next->tokType() == Token::eLogicalOp)
5357  break;
5358  else if (next->isComparisonOp())
5359  foundComparison = true;
5360  next = next->next();
5361  }
5362  if (next && next->str() == ">" && foundComparison)
5363  continue;
5364  }
5365 
5366  while (!type.empty() && type.top()->str() == "<") {
5367  const Token* end = type.top()->findClosingBracket();
5368  if (Token::Match(end, "> %comp%|;|.|=|{|(|::"))
5369  break;
5370  // Variable declaration
5371  if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
5372  break;
5373  type.pop();
5374  }
5375  } else if (token->str() == "<" &&
5376  ((token->previous() && (token->previous()->isTemplate() ||
5377  (token->previous()->isName() && !token->previous()->varId()) ||
5378  (token->strAt(-1) == "]" && (!Token::Match(token->linkAt(-1)->previous(), "%name%|)") || token->linkAt(-1)->previous()->isKeyword())) ||
5379  (token->strAt(-1) == ")" && token->linkAt(-1)->strAt(-1) == "operator"))) ||
5380  Token::Match(token->next(), ">|>>"))) {
5381  type.push(token);
5382  if (token->previous()->str() == "template")
5383  templateTokens.push(token);
5384  } else if (token->str() == ">" || token->str() == ">>") {
5385  if (type.empty() || type.top()->str() != "<") // < and > don't match.
5386  continue;
5387  Token * const top1 = type.top();
5388  type.pop();
5389  Token * const top2 = type.empty() ? nullptr : type.top();
5390  type.push(top1);
5391  if (!top2 || top2->str() != "<") {
5392  if (token->str() == ">>")
5393  continue;
5394  if (!Token::Match(token->next(), "%name%|%cop%|%assign%|::|,|(|)|{|}|;|[|]|:|.|=|?|...") &&
5395  !Token::Match(token->next(), "&& %name% ="))
5396  continue;
5397  }
5398 
5399  if (token->str() == ">>" && top1 && top2) {
5400  type.pop();
5401  type.pop();
5402  // Split the angle brackets
5403  token->str(">");
5404  Token::createMutualLinks(top1, token->insertTokenBefore(">"));
5405  Token::createMutualLinks(top2, token);
5406  if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
5407  templateTokens.pop();
5408  templateTokens.pop();
5409  }
5410  } else {
5411  type.pop();
5412  if (Token::Match(token, "> %name%") && !token->next()->isKeyword() &&
5413  Token::Match(top1->tokAt(-2), "%op% %name% <") && top1->strAt(-2) != "<" &&
5414  (templateTokens.empty() || top1 != templateTokens.top()))
5415  continue;
5416  Token::createMutualLinks(top1, token);
5417  if (!templateTokens.empty() && top1 == templateTokens.top())
5418  templateTokens.pop();
5419  }
5420  }
5421  }
5422 }
5423 
5425 {
5426  if (isC())
5427  return;
5428  for (Token* tok = list.front(); tok; tok = tok->next()) {
5429  if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast")) {
5430  if (!Token::simpleMatch(tok->next(), "<") || !Token::simpleMatch(tok->linkAt(1), "> ("))
5431  syntaxError(tok);
5432  tok = tok->linkAt(1)->next();
5433  tok->isCast(true);
5434  }
5435  }
5436 
5437 }
5438 
5440 {
5441  for (Token *tok = list.front(); tok; tok = tok->next()) {
5442  if (!Token::Match(tok, "sizeof !!("))
5443  continue;
5444  if (tok->next()->isLiteral() || Token::Match(tok->next(), "%name%|*|~|!|&")) {
5445  Token *endToken = tok->next();
5446  while (Token::simpleMatch(endToken, "* *"))
5447  endToken = endToken->next();
5448  while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
5449  if (Token::Match(endToken->next(), "(|["))
5450  endToken = endToken->linkAt(1);
5451  else
5452  endToken = endToken->next();
5453  }
5454 
5455  // Add ( after sizeof and ) behind endToken
5456  tok->insertToken("(");
5457  endToken->insertToken(")");
5458  Token::createMutualLinks(tok->next(), endToken->next());
5459  }
5460  }
5461 }
5462 
5463 bool Tokenizer::simplifyTokenList1(const char FileName[])
5464 {
5465  if (Settings::terminated())
5466  return false;
5467 
5468  // if MACRO
5469  for (Token *tok = list.front(); tok; tok = tok->next()) {
5470  if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
5471  if (Token::simpleMatch(tok, "for each")) {
5472  // 'for each ( )' -> 'asm ( )'
5473  tok->str("asm");
5474  tok->deleteNext();
5475  } else if (tok->strAt(1) == "constexpr") {
5476  tok->deleteNext();
5477  tok->isConstexpr(true);
5478  } else {
5479  syntaxError(tok);
5480  }
5481  }
5482  }
5483 
5484  // Is there C++ code in C file?
5485  validateC();
5486 
5487  // Combine strings and character literals, e.g. L"string", L'c', "string1" "string2"
5489 
5490  // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
5491  simplifySQL();
5492 
5493  createLinks();
5494 
5495  // Simplify debug intrinsics
5496  simplifyDebug();
5497 
5498  removePragma();
5499 
5500  // Simplify the C alternative tokens (and, or, etc.)
5502 
5504 
5506 
5507  // Remove __asm..
5508  simplifyAsm();
5509 
5510  // foo < bar < >> => foo < bar < > >
5511  if (isCPP() || mSettings.daca)
5513 
5514  // Remove extra "template" tokens that are not used by cppcheck
5516 
5518 
5519  // @..
5520  simplifyAt();
5521 
5522  // Remove __declspec()
5523  simplifyDeclspec();
5524 
5525  // Remove "inline", "register", and "restrict"
5526  simplifyKeyword();
5527 
5528  // Remove [[attribute]]
5530 
5531  // remove __attribute__((?))
5533 
5534  // Bail out if code is garbage
5535  if (mTimerResults) {
5536  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mSettings.showtime, mTimerResults);
5537  findGarbageCode();
5538  } else {
5539  findGarbageCode();
5540  }
5541 
5543 
5544  // if (x) MACRO() ..
5545  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5546  if (Token::simpleMatch(tok, "if (")) {
5547  tok = tok->next()->link();
5548  if (Token::Match(tok, ") %name% (") &&
5549  tok->next()->isUpperCaseName() &&
5550  Token::Match(tok->linkAt(2), ") {|else")) {
5551  syntaxError(tok->next());
5552  }
5553  }
5554  }
5555 
5556  if (Settings::terminated())
5557  return false;
5558 
5559  // convert C++17 style nested namespaces to old style namespaces
5561 
5562  // convert c++20 coroutines
5564 
5565  // simplify namespace aliases
5567 
5568  // simplify cppcheck attributes __cppcheck_?__(?)
5570 
5571  // Combine tokens..
5572  combineOperators();
5573 
5574  // combine "- %num%"
5576 
5577  // remove extern "C" and extern "C" {}
5578  if (isCPP())
5579  simplifyExternC();
5580 
5581  // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
5583 
5584  // check for simple syntax errors..
5585  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5586  if (Token::simpleMatch(tok, "> struct {") &&
5587  Token::simpleMatch(tok->linkAt(2), "} ;")) {
5588  syntaxError(tok);
5589  }
5590  }
5591 
5592  if (!simplifyAddBraces())
5593  return false;
5594 
5596 
5597  // Simplify: 0[foo] -> *(foo)
5598  for (Token* tok = list.front(); tok; tok = tok->next()) {
5599  if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
5600  tok->str("*");
5601  tok->next()->str("(");
5602  tok->linkAt(1)->str(")");
5603  }
5604  }
5605 
5606  if (Settings::terminated())
5607  return false;
5608 
5609  validate();
5610 
5611  // simplify simple calculations inside <..>
5612  if (isCPP()) {
5613  Token *lt = nullptr;
5614  for (Token *tok = list.front(); tok; tok = tok->next()) {
5615  if (Token::Match(tok, "[;{}]"))
5616  lt = nullptr;
5617  else if (Token::Match(tok, "%type% <"))
5618  lt = tok->next();
5619  else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
5620  const Token * const end = tok;
5621  for (tok = lt; tok != end; tok = tok->next()) {
5622  if (tok->isNumber())
5624  }
5625  lt = tok->next();
5626  }
5627  }
5628  }
5629 
5630  // Convert K&R function declarations to modern C
5631  simplifyVarDecl(true);
5633 
5634  // simplify case ranges (gcc extension)
5636 
5637  // simplify labels and 'case|default'-like syntaxes
5639 
5640  if (!isC() && !mSettings.library.markupFile(FileName)) {
5642  }
5643 
5644  if (Settings::terminated())
5645  return false;
5646 
5647  // remove calling conventions __cdecl, __stdcall..
5649 
5651 
5652  // remove some unhandled macros in global scope
5654 
5655  // remove undefined macro in class definition:
5656  // class DLLEXPORT Fred { };
5657  // class Fred FINAL : Base { };
5659 
5660  // That call here fixes #7190
5661  validate();
5662 
5663  // remove unnecessary member qualification..
5665 
5666  // convert Microsoft memory functions
5668 
5669  // convert Microsoft string functions
5671 
5672  if (Settings::terminated())
5673  return false;
5674 
5675  // remove Borland stuff..
5676  simplifyBorland();
5677 
5678  // syntax error: enum with typedef in it
5680 
5681  // Add parentheses to ternary operator where necessary
5683 
5684  // Change initialisation of variable to assignment
5685  simplifyInitVar();
5686 
5687  // Split up variable declarations.
5688  simplifyVarDecl(false);
5689 
5691 
5693 
5694  // typedef..
5695  if (mTimerResults) {
5696  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mSettings.showtime, mTimerResults);
5697  simplifyTypedef();
5698  } else {
5699  simplifyTypedef();
5700  }
5701 
5702  // using A = B;
5703  while (simplifyUsing())
5704  ;
5705 
5706  // Add parentheses to ternary operator where necessary
5707  // TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
5708  // If typedef handling is refactored and moved to symboldatabase someday we can remove this
5710 
5711  // class x y {
5713  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5714  if (Token::Match(tok, "class %type% %type% [:{]")) {
5716  }
5717  }
5718  }
5719 
5720  // catch bad typedef canonicalization
5721  //
5722  // to reproduce bad typedef, download upx-ucl from:
5723  // http://packages.debian.org/sid/upx-ucl
5724  // analyse the file src/stub/src/i386-linux.elf.interp-main.c
5725  validate();
5726 
5727  // The simplify enum have inner loops
5728  if (Settings::terminated())
5729  return false;
5730 
5731  // Put ^{} statements in asm()
5732  simplifyAsm2();
5733 
5734  // When the assembly code has been cleaned up, no @ is allowed
5735  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5736  if (tok->str() == "(") {
5737  const Token *tok1 = tok;
5738  tok = tok->link();
5739  if (!tok)
5740  syntaxError(tok1);
5741  } else if (tok->str() == "@") {
5742  syntaxError(tok);
5743  }
5744  }
5745 
5746  // Order keywords "static" and "const"
5748 
5749  // convert platform dependent types to standard types
5750  // 32 bits: size_t -> unsigned long
5751  // 64 bits: size_t -> unsigned long long
5753 
5754  // collapse compound standard types into a single token
5755  // unsigned long long int => long (with _isUnsigned=true,_isLong=true)
5757 
5758  if (Settings::terminated())
5759  return false;
5760 
5761  // simplify bit fields..
5763 
5764  if (Settings::terminated())
5765  return false;
5766 
5767  // struct simplification "struct S {} s; => struct S { } ; S s ;
5769 
5770  if (Settings::terminated())
5771  return false;
5772 
5773  // x = ({ 123; }); => { x = 123; }
5775 
5776  if (Settings::terminated())
5777  return false;
5778 
5780 
5781  // Collapse operator name tokens into single token
5782  // operator = => operator=
5784 
5785  // Remove redundant parentheses
5787 
5788  if (isCPP()) {
5790 
5791  // Handle templates..
5792  if (mTimerResults) {
5793  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mSettings.showtime, mTimerResults);
5795  } else {
5797  }
5798 
5799  // The simplifyTemplates have inner loops
5800  if (Settings::terminated())
5801  return false;
5802 
5803  validate(); // #6847 - invalid code
5804  }
5805 
5806  // Simplify pointer to standard types (C only)
5808 
5809  // simplify function pointers
5811 
5812  // Change initialisation of variable to assignment
5813  simplifyInitVar();
5814 
5815  // Split up variable declarations.
5816  simplifyVarDecl(false);
5817 
5818  elseif();
5819 
5820  validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
5821 
5822  if (mTimerResults) {
5823  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mSettings.showtime, mTimerResults);
5824  setVarId();
5825  } else {
5826  setVarId();
5827  }
5828 
5829  // Link < with >
5830  createLinks2();
5831 
5832  // Mark C++ casts
5833  markCppCasts();
5834 
5835  // specify array size
5836  arraySize();
5837 
5838  // The simplify enum might have inner loops
5839  if (Settings::terminated())
5840  return false;
5841 
5842  // Add std:: in front of std classes, when using namespace std; was given
5844 
5845  // Change initialisation of variable to assignment
5846  simplifyInitVar();
5847 
5849 
5851 
5853 
5855 
5857 
5859 
5861 
5863 
5865 
5866  validate();
5867 
5868  list.front()->assignIndexes();
5869 
5870  return true;
5871 }
5872 //---------------------------------------------------------------------------
5873 
5874 void Tokenizer::printDebugOutput(int simplification) const
5875 {
5876  const bool debug = (simplification != 1U && mSettings.debugSimplified) ||
5877  (simplification != 2U && mSettings.debugnormal);
5878 
5879  if (debug && list.front()) {
5880  list.front()->printOut(nullptr, list.getFiles());
5881 
5882  if (mSettings.xml)
5883  std::cout << "<debug>" << std::endl;
5884 
5885  if (mSymbolDatabase) {
5886  if (mSettings.xml)
5887  mSymbolDatabase->printXml(std::cout);
5888  else if (mSettings.verbose) {
5889  mSymbolDatabase->printOut("Symbol database");
5890  }
5891  }
5892 
5893  if (mSettings.verbose)
5895 
5896  list.front()->printValueFlow(mSettings.xml, std::cout);
5897 
5898  if (mSettings.xml)
5899  std::cout << "</debug>" << std::endl;
5900  }
5901 
5902  if (mSymbolDatabase && simplification == 2U && mSettings.debugwarnings) {
5904 
5905  // the typeStartToken() should come before typeEndToken()
5906  for (const Variable *var : mSymbolDatabase->variableList()) {
5907  if (!var)
5908  continue;
5909 
5910  const Token * typetok = var->typeStartToken();
5911  while (typetok && typetok != var->typeEndToken())
5912  typetok = typetok->next();
5913 
5914  if (typetok != var->typeEndToken()) {
5915  reportError(var->typeStartToken(),
5917  "debug",
5918  "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + std::to_string(var->typeStartToken()->linenr()));
5919  }
5920  }
5921  }
5922 }
5923 
5924 void Tokenizer::dump(std::ostream &out) const
5925 {
5926  // Create a xml data dump.
5927  // The idea is not that this will be readable for humans. It's a
5928  // data dump that 3rd party tools could load and get useful info from.
5929 
5930  std::string outs;
5931 
5932  std::set<const Library::Container*> containers;
5933 
5934  outs += " <directivelist>";
5935  outs += '\n';
5936  for (const Directive &dir : mDirectives) {
5937  outs += " <directive ";
5938  outs += "file=\"";
5940  outs += "\" ";
5941  outs += "linenr=\"";
5942  outs += std::to_string(dir.linenr);
5943  outs += "\" ";
5944  // str might contain characters such as '"', '<' or '>' which
5945  // could result in invalid XML, so run it through toxml().
5946  outs += "str=\"";
5947  outs += ErrorLogger::toxml(dir.str);
5948  outs +="\"/>";
5949  outs += '\n';
5950  }
5951  outs += " </directivelist>";
5952  outs += '\n';
5953 
5954  // tokens..
5955  outs += " <tokenlist>";
5956  outs += '\n';
5957  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5958  outs += " <token id=\"";
5959  outs += id_string(tok);
5960  outs += "\" file=\"";
5961  outs += ErrorLogger::toxml(list.file(tok));
5962  outs += "\" linenr=\"";
5963  outs += std::to_string(tok->linenr());
5964  outs += "\" column=\"";
5965  outs += std::to_string(tok->column());
5966  outs += "\"";
5967 
5968  outs += " str=\"";
5969  outs += ErrorLogger::toxml(tok->str());
5970  outs += '\"';
5971 
5972  outs += " scope=\"";
5973  outs += id_string(tok->scope());
5974  outs += '\"';
5975  if (tok->isName()) {
5976  outs += " type=\"name\"";
5977  if (tok->isUnsigned())
5978  outs += " isUnsigned=\"true\"";
5979  else if (tok->isSigned())
5980  outs += " isSigned=\"true\"";
5981  } else if (tok->isNumber()) {
5982  outs += " type=\"number\"";
5983  if (MathLib::isInt(tok->str()))
5984  outs += " isInt=\"true\"";
5985  if (MathLib::isFloat(tok->str()))
5986  outs += " isFloat=\"true\"";
5987  } else if (tok->tokType() == Token::eString) {
5988  outs += " type=\"string\" strlen=\"";
5989  outs += std::to_string(Token::getStrLength(tok));
5990  outs += '\"';
5991  }
5992  else if (tok->tokType() == Token::eChar)
5993  outs += " type=\"char\"";
5994  else if (tok->isBoolean())
5995  outs += " type=\"boolean\"";
5996  else if (tok->isOp()) {
5997  outs += " type=\"op\"";
5998  if (tok->isArithmeticalOp())
5999  outs += " isArithmeticalOp=\"true\"";
6000  else if (tok->isAssignmentOp())
6001  outs += " isAssignmentOp=\"true\"";
6002  else if (tok->isComparisonOp())
6003  outs += " isComparisonOp=\"true\"";
6004  else if (tok->tokType() == Token::eLogicalOp)
6005  outs += " isLogicalOp=\"true\"";
6006  }
6007  if (tok->isCast())
6008  outs += " isCast=\"true\"";
6009  if (tok->isExternC())
6010  outs += " externLang=\"C\"";
6011  if (tok->isExpandedMacro())
6012  outs += " macroName=\"" + tok->getMacroName() + "\"";
6013  if (tok->isTemplateArg())
6014  outs += " isTemplateArg=\"true\"";
6015  if (tok->isRemovedVoidParameter())
6016  outs += " isRemovedVoidParameter=\"true\"";
6017  if (tok->isSplittedVarDeclComma())
6018  outs += " isSplittedVarDeclComma=\"true\"";
6019  if (tok->isSplittedVarDeclEq())
6020  outs += " isSplittedVarDeclEq=\"true\"";
6021  if (tok->isImplicitInt())
6022  outs += " isImplicitInt=\"true\"";
6023  if (tok->isComplex())
6024  outs += " isComplex=\"true\"";
6025  if (tok->isRestrict())
6026  outs += " isRestrict=\"true\"";
6027  if (tok->isAtomic())
6028  outs += " isAtomic=\"true\"";
6029  if (tok->isAttributeExport())
6030  outs += " isAttributeExport=\"true\"";
6031  if (tok->isAttributeMaybeUnused())
6032  outs += " isAttributeMaybeUnused=\"true\"";
6033  if (tok->isAttributeUnused())
6034  outs += " isAttributeUnused=\"true\"";
6035  if (tok->link()) {
6036  outs += " link=\"";
6037  outs += id_string(tok->link());
6038  outs += '\"';
6039  }
6040  if (tok->varId() > 0) {
6041  outs += " varId=\"";
6042  outs += std::to_string(tok->varId());
6043  outs += '\"';
6044  }
6045  if (tok->exprId() > 0) {
6046  outs += " exprId=\"";
6047  outs += std::to_string(tok->exprId());
6048  outs += '\"';
6049  }
6050  if (tok->variable()) {
6051  outs += " variable=\"";
6052  outs += id_string(tok->variable());
6053  outs += '\"';
6054  }
6055  if (tok->function()) {
6056  outs += " function=\"";
6057  outs += id_string(tok->function());
6058  outs += '\"';
6059  }
6060  if (!tok->values().empty()) {
6061  outs += " values=\"";
6062  outs += id_string(&tok->values());
6063  outs += '\"';
6064  }
6065  if (tok->type()) {
6066  outs += " type-scope=\"";
6067  outs += id_string(tok->type()->classScope);
6068  outs += '\"';
6069  }
6070  if (tok->astParent()) {
6071  outs += " astParent=\"";
6072  outs += id_string(tok->astParent());
6073  outs += '\"';
6074  }
6075  if (tok->astOperand1()) {
6076  outs += " astOperand1=\"";
6077  outs += id_string(tok->astOperand1());
6078  outs += '\"';
6079  }
6080  if (tok->astOperand2()) {
6081  outs += " astOperand2=\"";
6082  outs += id_string(tok->astOperand2());
6083  outs += '\"';
6084  }
6085  if (!tok->originalName().empty()) {
6086  outs += " originalName=\"";
6087  outs += tok->originalName();
6088  outs += '\"';
6089  }
6090  if (tok->valueType()) {
6091  const std::string vt = tok->valueType()->dump();
6092  if (!vt.empty()) {
6093  outs += ' ';
6094  outs += vt;
6095  }
6096  containers.insert(tok->valueType()->container);
6097  }
6098  if (!tok->varId() && tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) {
6099  if (mSettings.library.isnoreturn(tok))
6100  outs += " noreturn=\"true\"";
6101  }
6102 
6103  outs += "/>";
6104  outs += '\n';
6105  }
6106  outs += " </tokenlist>";
6107  outs += '\n';
6108 
6109  out << outs;
6110  outs.clear();
6111 
6112  if (mSymbolDatabase)
6113  mSymbolDatabase->printXml(out);
6114 
6115  containers.erase(nullptr);
6116  if (!containers.empty()) {
6117  outs += " <containers>";
6118  outs += '\n';
6119  for (const Library::Container* c: containers) {
6120  outs += " <container id=\"";
6121  outs += id_string(c);
6122  outs += "\" array-like-index-op=\"";
6123  outs += bool_to_string(c->arrayLike_indexOp);
6124  outs += "\" ";
6125  outs += "std-string-like=\"";
6126  outs += bool_to_string(c->stdStringLike);
6127  outs += "\"/>";
6128  outs += '\n';
6129  }
6130  outs += " </containers>";
6131  outs += '\n';
6132  }
6133 
6134  if (list.front())
6135  list.front()->printValueFlow(true, out);
6136 
6137  if (!mTypedefInfo.empty()) {
6138  outs += " <typedef-info>";
6139  outs += '\n';
6140  for (const TypedefInfo &typedefInfo: mTypedefInfo) {
6141  outs += " <info";
6142 
6143  outs += " name=\"";
6144  outs += typedefInfo.name;
6145  outs += "\"";
6146 
6147  outs += " file=\"";
6148  outs += ErrorLogger::toxml(typedefInfo.filename);
6149  outs += "\"";
6150 
6151  outs += " line=\"";
6152  outs += std::to_string(typedefInfo.lineNumber);
6153  outs += "\"";
6154 
6155  outs += " column=\"";
6156  outs += std::to_string(typedefInfo.column);
6157  outs += "\"";
6158 
6159  outs += " used=\"";
6160  outs += std::to_string(typedefInfo.used?1:0);
6161  outs += "\"";
6162 
6163  outs += "/>";
6164  outs += '\n';
6165  }
6166  outs += " </typedef-info>";
6167  outs += '\n';
6168  }
6169  outs += mTemplateSimplifier->dump();
6170 
6171  out << outs;
6172 }
6173 
6175 {
6177  // Full analysis. All information in the headers are kept.
6178  return;
6179 
6180  const bool checkHeaders = mSettings.checkHeaders;
6181  const bool removeUnusedIncludedFunctions = !mSettings.checkHeaders;
6182  const bool removeUnusedIncludedClasses = !mSettings.checkHeaders;
6183  const bool removeUnusedIncludedTemplates = !mSettings.checkUnusedTemplates || !mSettings.checkHeaders;
6184  const bool removeUnusedTemplates = !mSettings.checkUnusedTemplates;
6185 
6186  // checkHeaders:
6187  //
6188  // If it is true then keep all code in the headers. It's possible
6189  // to remove unused types/variables if false positives / false
6190  // negatives can be avoided.
6191  //
6192  // If it is false, then we want to remove selected stuff from the
6193  // headers but not *everything*. The intention here is to not damage
6194  // the analysis of the source file. You should get all warnings in
6195  // the source file. You should not get false positives.
6196 
6197  // functions and types to keep
6198  std::set<std::string> keep;
6199  for (const Token *tok = list.front(); tok; tok = tok->next()) {
6200  if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
6201  const Token *closingBracket = tok->next()->findClosingBracket();
6202  if (Token::Match(closingBracket, "> class|struct %name% {"))
6203  tok = closingBracket->linkAt(3);
6204  }
6205 
6206  if (!tok->isName() || tok->isKeyword())
6207  continue;
6208 
6209  if (!checkHeaders && tok->fileIndex() != 0)
6210  continue;
6211 
6212  if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
6213  keep.insert(tok->str());
6214  continue;
6215  }
6216 
6217  if (Token::Match(tok, "%name% %name%|::|*|&|<")) {
6218  keep.insert(tok->str());
6219  }
6220  }
6221 
6222  const std::set<std::string> functionStart{"static", "const", "unsigned", "signed", "void", "bool", "char", "short", "int", "long", "float", "*"};
6223 
6224  for (Token *tok = list.front(); tok; tok = tok->next()) {
6225  const bool isIncluded = (tok->fileIndex() != 0);
6226 
6227  // Remove executable code
6228  if (isIncluded && !mSettings.checkHeaders && tok->str() == "{") {
6229  // TODO: We probably need to keep the executable code if this function is called from the source file.
6230  const Token *prev = tok->previous();
6231  while (prev && prev->isName())
6232  prev = prev->previous();
6233  if (Token::simpleMatch(prev, ")")) {
6234  // Replace all tokens from { to } with a ";".
6235  Token::eraseTokens(tok,tok->link()->next());
6236  tok->str(";");
6237  tok->link(nullptr);
6238  }
6239  }
6240 
6241  if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
6242  // Remove unused function declarations
6243  if (isIncluded && removeUnusedIncludedFunctions) {
6244  while (true) {
6245  Token *start = tok;
6246  while (start && functionStart.find(start->str()) != functionStart.end())
6247  start = start->next();
6248  if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
6249  Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
6250  tok->deleteThis();
6251  } else
6252  break;
6253  }
6254  }
6255 
6256  if (isIncluded && removeUnusedIncludedClasses) {
6257  if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
6258  // Remove this class/struct
6259  const Token *endToken = tok->tokAt(2);
6260  if (endToken->str() == ":") {
6261  endToken = endToken->next();
6262  while (Token::Match(endToken, "%name%|,"))
6263  endToken = endToken->next();
6264  }
6265  if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
6266  Token::eraseTokens(tok, endToken->link()->next());
6267  tok->deleteThis();
6268  }
6269  }
6270  }
6271 
6272  if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
6273  if (Token::Match(tok, "template < %name%")) {
6274  const Token *closingBracket = tok->next()->findClosingBracket();
6275  if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6276  const Token *endToken = closingBracket->tokAt(3);
6277  if (endToken->str() == ":") {
6278  endToken = endToken->next();
6279  while (Token::Match(endToken, "%name%|,"))
6280  endToken = endToken->next();
6281  }
6282  if (endToken && endToken->str() == "{")
6283  endToken = endToken->link()->next();
6284  if (endToken && endToken->str() == ";") {
6285  Token::eraseTokens(tok, endToken);
6286  tok->deleteThis();
6287  }
6288  } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6289  const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
6290  Token::eraseTokens(tok, endToken);
6291  tok->deleteThis();
6292  }
6293  }
6294  }
6295  }
6296  }
6297 }
6298 
6300 {
6301  if (isCPP()) {
6302  for (Token *tok = list.front(); tok; tok = tok->next()) {
6303  if (Token::Match(tok, "%name%|>|) .|:: template %name%")) {
6304  tok->next()->deleteNext();
6305  Token* templateName = tok->tokAt(2);
6306  while (Token::Match(templateName, "%name%|::")) {
6307  templateName->isTemplate(true);
6308  templateName = templateName->next();
6309  }
6310  if (!templateName)
6311  syntaxError(tok);
6312  if (Token::Match(templateName->previous(), "operator %op%|(")) {
6313  templateName->isTemplate(true);
6314  if (templateName->str() == "(" && templateName->link())
6315  templateName->link()->isTemplate(true);
6316  }
6317  }
6318  }
6319  }
6320 }
6321 
6322 static std::string getExpression(const Token *tok)
6323 {
6324  std::string line;
6325  for (const Token *prev = tok->previous(); prev && !Token::Match(prev, "[;{}]"); prev = prev->previous())
6326  line = prev->str() + " " + line;
6327  line += "!!!" + tok->str() + "!!!";
6328  for (const Token *next = tok->next(); next && !Token::Match(next, "[;{}]"); next = next->next())
6329  line += " " + next->str();
6330  return line;
6331 }
6332 
6334 {
6335  std::vector<std::pair<std::string, int>> vars;
6336 
6337  int scopeLevel = 0;
6338  for (Token *tok = list.front(); tok; tok = tok->next()) {
6339  if (tok->str() == "{")
6340  ++scopeLevel;
6341  else if (tok->str() == "}") {
6342  vars.erase(std::remove_if(vars.begin(), vars.end(), [scopeLevel](const std::pair<std::string, int>& v) {
6343  return v.second == scopeLevel;
6344  }), vars.end());
6345  --scopeLevel;
6346  }
6347  if (Token::Match(tok, "[;{}] %type% %type% [;,=]") && tok->next()->isStandardType())
6348  vars.emplace_back(tok->strAt(2), scopeLevel);
6349 
6350  // Ticket #6181: normalize C++11 template parameter list closing syntax
6351  if (tok->previous() && tok->str() == "<" && TemplateSimplifier::templateParameters(tok) && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6352  return v.first == tok->previous()->str();
6353  })) {
6354  Token *endTok = tok->findClosingBracket();
6355  if (check) {
6356  if (Token::Match(endTok, ">>|>>="))
6357  reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6358  continue;
6359  }
6360  if (endTok && endTok->str() == ">>") {
6361  endTok->str(">");
6362  endTok->insertToken(">");
6363  } else if (endTok && endTok->str() == ">>=") {
6364  endTok->str(">");
6365  endTok->insertToken("=");
6366  endTok->insertToken(">");
6367  }
6368  } else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <") && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6369  return v.first == tok->next()->str();
6370  })) {
6371  Token *endTok = tok->tokAt(2)->findClosingBracket();
6372  if (check) {
6373  if (Token::simpleMatch(endTok, ">>"))
6374  reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6375  continue;
6376  }
6377  if (Token::Match(endTok, ">> ;|{|%type%")) {
6378  endTok->str(">");
6379  endTok->insertToken(">");
6380  }
6381  }
6382  }
6383 }
6384 
6386 {
6387  for (Token *tok = list.front(); tok; tok = tok->next()) {
6388  if (tok->str() == "(") {
6389  tok = tok->link();
6390  if (Token::Match(tok, ") %type% {") &&
6391  !tok->next()->isStandardType() &&
6392  !tok->next()->isKeyword() &&
6393  !Token::Match(tok->next(), "override|final") &&
6394  tok->next()->isUpperCaseName())
6395  tok->deleteNext();
6396  }
6397 
6398  if (Token::Match(tok, "%type%") && tok->isUpperCaseName() &&
6399  (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) {
6400  const Token *tok2 = tok->next();
6401  if (tok2 && tok2->str() == "(")
6402  tok2 = tok2->link()->next();
6403 
6404  // Several unknown macros...
6405  while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName())
6406  tok2 = tok2->linkAt(1)->next();
6407 
6408  if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") &&
6409  !Token::Match(tok2, "requires|namespace|class|struct|union|private:|protected:|public:"))
6410  unknownMacroError(tok);
6411 
6412  if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{"))
6413  unknownMacroError(tok);
6414 
6415  // remove unknown macros before namespace|class|struct|union
6416  if (Token::Match(tok2, "namespace|class|struct|union")) {
6417  // is there a "{" for?
6418  const Token *tok3 = tok2;
6419  while (tok3 && !Token::Match(tok3,"[;{}()]"))
6420  tok3 = tok3->next();
6421  if (tok3 && tok3->str() == "{") {
6422  Token::eraseTokens(tok, tok2);
6423  tok->deleteThis();
6424  }
6425  continue;
6426  }
6427 
6428  // replace unknown macros before foo(
6429  /*
6430  if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) {
6431  std::string typeName;
6432  for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next())
6433  typeName += tok3->str();
6434  Token::eraseTokens(tok, tok2);
6435  tok->str(typeName);
6436  }
6437  */
6438  // remove unknown macros before foo::foo(
6439  if (Token::Match(tok2, "%type% :: %type%")) {
6440  const Token *tok3 = tok2;
6441  while (Token::Match(tok3, "%type% :: %type% ::"))
6442  tok3 = tok3->tokAt(2);
6443  if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) {
6444  Token::eraseTokens(tok, tok2);
6445  tok->deleteThis();
6446  }
6447  continue;
6448  }
6449  }
6450 
6451  // Skip executable scopes
6452  if (tok->str() == "{") {
6453  const Token *prev = tok->previous();
6454  while (prev && prev->isName())
6455  prev = prev->previous();
6456  if (prev && prev->str() == ")")
6457  tok = tok->link();
6458  }
6459  }
6460 }
6461 
6462 //---------------------------------------------------------------------------
6463 
6465 {
6466  if (isC() && mSettings.standards.c == Standards::C89)
6467  return;
6469  return;
6470  for (Token *tok = list.front(); tok; tok = tok->next()) {
6471  while (Token::simpleMatch(tok, "_Pragma (")) {
6472  Token::eraseTokens(tok, tok->linkAt(1)->next());
6473  tok->deleteThis();
6474  }
6475  }
6476 }
6477 
6478 //---------------------------------------------------------------------------
6479 
6481 {
6482  for (Token *tok = list.front(); tok; tok = tok->next()) {
6483  if (!Token::Match(tok, "class|struct %name% %name% final| {|:"))
6484  continue;
6485 
6486  const bool nextIsUppercase = tok->next()->isUpperCaseName();
6487  const bool afterNextIsUppercase = tok->tokAt(2)->isUpperCaseName();
6488  if (nextIsUppercase && !afterNextIsUppercase)
6489  tok->deleteNext();
6490  else if (!nextIsUppercase && afterNextIsUppercase)
6491  tok->next()->deleteNext();
6492  }
6493 }
6494 
6495 //---------------------------------------------------------------------------
6496 
6498 {
6499  if (!isCPP())
6500  return;
6501  for (Token *tok = list.front(); tok; tok = tok->next()) {
6502  if (tok->str() != ")")
6503  continue;
6504  const Token *macro = tok->link() ? tok->link()->previous() : nullptr;
6505  if (!macro || !macro->isName())
6506  continue;
6507  if (Token::simpleMatch(tok, ") try") && !Token::Match(macro, "if|for|while"))
6508  tok->insertToken(";");
6509  else if (Token::simpleMatch(tok, ") using"))
6510  tok->insertToken(";");
6511  }
6512 }
6513 //---------------------------------------------------------------------------
6514 
6516 {
6517  if (isC())
6518  return;
6519 
6520  bool goback = false;
6521  for (Token *tok = list.front(); tok; tok = tok ? tok->next() : nullptr) {
6522  if (goback) {
6523  tok = tok->previous();
6524  goback = false;
6525  }
6526  if (Token::Match(tok, "(|[|{")) {
6527  tok = tok->link();
6528  continue;
6529  }
6530  if (!Token::Match(tok, "namespace %name%| {"))
6531  continue;
6532  const bool isAnonymousNS = tok->strAt(1) == "{";
6533  if (tok->strAt(3 - isAnonymousNS) == "}") {
6534  tok->deleteNext(3 - isAnonymousNS); // remove '%name%| { }'
6535  if (!tok->previous()) {
6536  // remove 'namespace' or replace it with ';' if isolated
6537  tok->deleteThis();
6538  goback = true;
6539  } else { // '%any% namespace %any%'
6540  tok = tok->previous(); // goto previous token
6541  tok->deleteNext(); // remove next token: 'namespace'
6542  if (tok->str() == "{") {
6543  // Go back in case we were within a namespace that's empty now
6544  tok = tok->tokAt(-2) ? tok->tokAt(-2) : tok->previous();
6545  goback = true;
6546  }
6547  }
6548  } else {
6549  tok = tok->tokAt(2 - isAnonymousNS);
6550  }
6551  }
6552 }
6553 
6555 {
6556  for (Token *tok = list.front(); tok; tok = tok->next()) {
6557  if (tok->link() && tok->str() == "(") {
6558  tok = tok->link();
6559  continue;
6560  }
6561  for (;;) {
6562  if (Token::simpleMatch(tok, "; ;")) {
6563  tok->deleteNext();
6564  } else if (Token::simpleMatch(tok, "; { ; }")) {
6565  tok->deleteNext(3);
6566  } else {
6567  break;
6568  }
6569  }
6570  }
6571 }
6572 
6573 
6575 {
6576  for (Token *tok = list.front(); tok; tok = tok->next()) {
6577  Token const * tokRet=simplifyAddBracesToCommand(tok);
6578  if (!tokRet)
6579  return false;
6580  }
6581  return true;
6582 }
6583 
6585 {
6586  Token * tokEnd=tok;
6587  if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6588  tokEnd=simplifyAddBracesPair(tok,true);
6589  } else if (tok->str()=="while") {
6590  Token *tokPossibleDo=tok->previous();
6591  if (Token::simpleMatch(tok->previous(), "{"))
6592  tokPossibleDo = nullptr;
6593  else if (Token::simpleMatch(tokPossibleDo,"}"))
6594  tokPossibleDo = tokPossibleDo->link();
6595  if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6596  tokEnd=simplifyAddBracesPair(tok,true);
6597  } else if (tok->str()=="do") {
6598  tokEnd=simplifyAddBracesPair(tok,false);
6599  if (tokEnd!=tok) {
6600  // walk on to next token, i.e. "while"
6601  // such that simplifyAddBracesPair does not close other braces
6602  // before the "while"
6603  if (tokEnd) {
6604  tokEnd=tokEnd->next();
6605  if (!tokEnd || tokEnd->str()!="while") // no while
6606  syntaxError(tok);
6607  }
6608  }
6609  } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6610  tokEnd=simplifyAddBracesPair(tok,true);
6611  if (!tokEnd)
6612  return nullptr;
6613  if (tokEnd->strAt(1) == "else") {
6614  Token * tokEndNextNext= tokEnd->tokAt(2);
6615  if (!tokEndNextNext || tokEndNextNext->str() == "}")
6616  syntaxError(tokEndNextNext);
6617  if (tokEndNextNext->str() == "if")
6618  // do not change "else if ..." to "else { if ... }"
6619  tokEnd=simplifyAddBracesToCommand(tokEndNextNext);
6620  else
6621  tokEnd=simplifyAddBracesPair(tokEnd->next(),false);
6622  }
6623  }
6624 
6625  return tokEnd;
6626 }
6627 
6628 Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition)
6629 {
6630  Token * tokCondition=tok->next();
6631  if (!tokCondition) // Missing condition
6632  return tok;
6633 
6634  Token *tokAfterCondition=tokCondition;
6635  if (commandWithCondition) {
6636  if (tokCondition->str()=="(")
6637  tokAfterCondition=tokCondition->link();
6638  else
6639  syntaxError(tok); // Bad condition
6640 
6641  if (!tokAfterCondition || tokAfterCondition->strAt(1) == "]")
6642  syntaxError(tok); // Bad condition
6643 
6644  tokAfterCondition=tokAfterCondition->next();
6645  if (!tokAfterCondition || Token::Match(tokAfterCondition, ")|}|,")) {
6646  // No tokens left where to add braces around
6647  return tok;
6648  }
6649  }
6650  // Skip labels
6651  Token * tokStatement = tokAfterCondition;
6652  while (true) {
6653  if (Token::Match(tokStatement, "%name% :"))
6654  tokStatement = tokStatement->tokAt(2);
6655  else if (tokStatement->str() == "case") {
6656  tokStatement = skipCaseLabel(tokStatement);
6657  if (!tokStatement)
6658  return tok;
6659  if (tokStatement->str() != ":")
6660  syntaxError(tokStatement);
6661  tokStatement = tokStatement->next();
6662  } else
6663  break;
6664  if (!tokStatement)
6665  return tok;
6666  }
6667  Token * tokBracesEnd=nullptr;
6668  if (tokStatement->str() == "{") {
6669  // already surrounded by braces
6670  if (tokStatement != tokAfterCondition) {
6671  // Move the opening brace before labels
6672  Token::move(tokStatement, tokStatement, tokAfterCondition->previous());
6673  }
6674  tokBracesEnd = tokStatement->link();
6675  } else if (Token::simpleMatch(tokStatement, "try {") &&
6676  Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) {
6677  tokAfterCondition->previous()->insertToken("{");
6678  Token * tokOpenBrace = tokAfterCondition->previous();
6679  Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1);
6680  if (!tokEnd) {
6681  syntaxError(tokStatement);
6682  }
6683  tokEnd->insertToken("}");
6684  Token * tokCloseBrace = tokEnd->next();
6685 
6686  Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
6687  tokBracesEnd = tokCloseBrace;
6688  } else {
6689  Token * tokEnd = simplifyAddBracesToCommand(tokStatement);
6690  if (!tokEnd) // Ticket #4887
6691  return tok;
6692  if (tokEnd->str()!="}") {
6693  // Token does not end with brace
6694  // Look for ; to add own closing brace after it
6695  while (tokEnd && !Token::Match(tokEnd, ";|)|}")) {
6696  if (tokEnd->tokType()==Token::eBracket || tokEnd->str() == "(") {
6697  tokEnd = tokEnd->link();
6698  if (!tokEnd) {
6699  // Inner bracket does not close
6700  return tok;
6701  }
6702  }
6703  tokEnd=tokEnd->next();
6704  }
6705  if (!tokEnd || tokEnd->str() != ";") {
6706  // No trailing ;
6707  if (tokStatement->isUpperCaseName())
6708  unknownMacroError(tokStatement);
6709  else
6710  syntaxError(tokStatement);
6711  }
6712  }
6713 
6714  tokAfterCondition->previous()->insertToken("{");
6715  Token * tokOpenBrace=tokAfterCondition->previous();
6716 
6717  tokEnd->insertToken("}");
6718  Token * tokCloseBrace=tokEnd->next();
6719 
6720  Token::createMutualLinks(tokOpenBrace,tokCloseBrace);
6721  tokBracesEnd=tokCloseBrace;
6722  }
6723 
6724  return tokBracesEnd;
6725 }
6726 
6728 {
6729  for (Token *tok = list.front(); tok; tok = tok->next()) {
6730  if (tok->link() && Token::Match(tok, "{|[|(")) {
6731  tok = tok->link();
6732  }
6733 
6734  // Find the function e.g. foo( x ) or foo( x, y )
6735  else if (Token::Match(tok, "%name% ( %name% [,)]") &&
6736  !(tok->strAt(-1) == ":" || tok->strAt(-1) == "," || tok->strAt(-1) == "::")) {
6737  // We have found old style function, now we need to change it
6738 
6739  // First step: Get list of argument names in parentheses
6740  std::map<std::string, Token *> argumentNames;
6741  bool bailOut = false;
6742  Token * tokparam = nullptr;
6743 
6744  //take count of the function name..
6745  const std::string& funcName(tok->str());
6746 
6747  //floating token used to check for parameters
6748  Token *tok1 = tok;
6749 
6750  while (nullptr != (tok1 = tok1->tokAt(2))) {
6751  if (!Token::Match(tok1, "%name% [,)]")) {
6752  bailOut = true;
6753  break;
6754  }
6755 
6756  //same parameters: take note of the parameter
6757  if (argumentNames.find(tok1->str()) != argumentNames.end())
6758  tokparam = tok1;
6759  else if (tok1->str() != funcName)
6760  argumentNames[tok1->str()] = tok1;
6761  else {
6762  if (tok1->next()->str() == ")") {
6763  if (tok1->previous()->str() == ",") {
6764  tok1 = tok1->tokAt(-2);
6765  tok1->deleteNext(2);
6766  } else {
6767  tok1 = tok1->previous();
6768  tok1->deleteNext();
6769  bailOut = true;
6770  break;
6771  }
6772  } else {
6773  tok1 = tok1->tokAt(-2);
6774  tok1->next()->deleteNext(2);
6775  }
6776  }
6777 
6778  if (tok1->next()->str() == ")") {
6779  tok1 = tok1->tokAt(2);
6780  //expect at least a type name after round brace..
6781  if (!tok1 || !tok1->isName())
6782  bailOut = true;
6783  break;
6784  }
6785  }
6786 
6787  //goto '('
6788  tok = tok->next();
6789 
6790  if (bailOut) {
6791  tok = tok->link();
6792  continue;
6793  }
6794 
6795  tok1 = tok->link()->next();
6796 
6797  // there should be the sequence '; {' after the round parentheses
6798  for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) {
6799  if (Token::simpleMatch(tok2, "; {"))
6800  break;
6801  if (tok2->str() == "{") {
6802  bailOut = true;
6803  break;
6804  }
6805  }
6806 
6807  if (bailOut) {
6808  tok = tok->link();
6809  continue;
6810  }
6811 
6812  // Last step: check out if the declarations between ')' and '{' match the parameters list
6813  std::map<std::string, Token *> argumentNames2;
6814 
6815  while (tok1 && tok1->str() != "{") {
6816  if (Token::Match(tok1, "(|)")) {
6817  bailOut = true;
6818  break;
6819  }
6820  if (tok1->str() == ";") {
6821  if (tokparam) {
6822  syntaxError(tokparam);
6823  }
6824  Token *tok2 = tok1->previous();
6825  while (tok2->str() == "]")
6826  tok2 = tok2->link()->previous();
6827 
6828  //it should be a name..
6829  if (!tok2->isName()) {
6830  bailOut = true;
6831  break;
6832  }
6833 
6834  if (argumentNames2.find(tok2->str()) != argumentNames2.end()) {
6835  //same parameter names...
6836  syntaxError(tok1);
6837  } else
6838  argumentNames2[tok2->str()] = tok2;
6839 
6840  if (argumentNames.find(tok2->str()) == argumentNames.end()) {
6841  //non-matching parameter... bailout
6842  bailOut = true;
6843  break;
6844  }
6845  }
6846  tok1 = tok1->next();
6847  }
6848 
6849  if (bailOut || !tok1) {
6850  tok = tok->link();
6851  continue;
6852  }
6853 
6854  //the two containers may not hold the same size...
6855  //in that case, the missing parameters are defined as 'int'
6856  if (argumentNames.size() != argumentNames2.size()) {
6857  //move back 'tok1' to the last ';'
6858  tok1 = tok1->previous();
6859  for (const std::pair<const std::string, Token *>& argumentName : argumentNames) {
6860  if (argumentNames2.find(argumentName.first) == argumentNames2.end()) {
6861  //add the missing parameter argument declaration
6862  tok1->insertToken(";");
6863  tok1->insertToken(argumentName.first);
6864  //register the change inside argumentNames2
6865  argumentNames2[argumentName.first] = tok1->next();
6866  tok1->insertToken("int");
6867  }
6868  }
6869  }
6870 
6871  while (tok->str() != ")") {
6872  //initialize start and end tokens to be moved
6873  Token *declStart = argumentNames2[tok->next()->str()];
6874  Token *declEnd = declStart;
6875  while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")")
6876  declStart = declStart->previous();
6877  while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{")
6878  declEnd = declEnd->next();
6879 
6880  //remove ';' after declaration
6881  declEnd->deleteNext();
6882 
6883  //replace the parameter name in the parentheses with all the declaration
6884  Token::replace(tok->next(), declStart, declEnd);
6885 
6886  //since there are changes to tokens, put tok where tok1 is
6887  tok = declEnd->next();
6888 
6889  //fix up line number
6890  if (tok->str() == ",")
6891  tok->linenr(tok->previous()->linenr());
6892  }
6893  //goto forward and continue
6894  tok = tok->next()->link();
6895  }
6896  }
6897 }
6898 
6900 {
6901  if (!isC())
6902  return;
6903 
6904  for (Token *tok = list.front(); tok; tok = tok->next()) {
6905  if (!Token::Match(tok, "& %name% [ 0 ] !!["))
6906  continue;
6907 
6908  if (!Token::Match(tok->previous(), "[,(=]"))
6909  continue;
6910 
6911  // Remove '[ 0 ]' suffix
6912  Token::eraseTokens(tok->next(), tok->tokAt(5));
6913  // Remove '&' prefix
6914  tok = tok->previous();
6915  if (!tok)
6916  break;
6917  tok->deleteNext();
6918  }
6919 }
6920 
6922 {
6923  for (Token *tok = list.front(); tok; tok = tok->next()) {
6924  // #2873 - do not simplify function pointer usage here:
6925  // (void)(xy(*p)(0));
6926  if (Token::simpleMatch(tok, ") (")) {
6927  tok = tok->next()->link();
6928  continue;
6929  }
6930 
6931  // check for function pointer cast
6932  if (Token::Match(tok, "( %type% %type%| *| *| ( * ) (") ||
6933  Token::Match(tok, "static_cast < %type% %type%| *| *| ( * ) (")) {
6934  Token *tok1 = tok;
6935 
6936  if (tok1->isCpp() && tok1->str() == "static_cast")
6937  tok1 = tok1->next();
6938 
6939  tok1 = tok1->next();
6940 
6941  if (Token::Match(tok1->next(), "%type%"))
6942  tok1 = tok1->next();
6943 
6944  while (tok1->next()->str() == "*")
6945  tok1 = tok1->next();
6946 
6947  // check that the cast ends
6948  if (!Token::Match(tok1->linkAt(4), ") )|>"))
6949  continue;
6950 
6951  // ok simplify this function pointer cast to an ordinary pointer cast
6952  tok1->deleteNext();
6953  tok1->next()->deleteNext();
6954  Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next());
6955  continue;
6956  }
6957 
6958  // check for start of statement
6959  if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
6960  continue;
6961 
6962  if (Token::Match(tok, "delete|else|return|throw|typedef"))
6963  continue;
6964 
6965  while (Token::Match(tok, "%type%|:: %type%|::"))
6966  tok = tok->next();
6967 
6968  Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
6969  while (Token::Match(tok2, "*|&"))
6970  tok2 = tok2->next();
6971  if (!tok2 || tok2->str() != "(")
6972  continue;
6973  while (Token::Match(tok2, "(|:: %type%"))
6974  tok2 = tok2->tokAt(2);
6975  if (!Token::Match(tok2, "(|:: * *| %name%"))
6976  continue;
6977  tok2 = tok2->tokAt(2);
6978  if (tok2->str() == "*")
6979  tok2 = tok2->next();
6980  while (Token::Match(tok2, "%type%|:: %type%|::"))
6981  tok2 = tok2->next();
6982 
6983  if (!Token::Match(tok2, "%name% ) (") &&
6984  !Token::Match(tok2, "%name% [ ] ) (") &&
6985  !(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
6986  continue;
6987 
6988  while (tok && tok->str() != "(")
6989  tok = tok->next();
6990 
6991  // check that the declaration ends
6992  if (!tok || !tok->link() || !tok->link()->next()) {
6993  syntaxError(nullptr);
6994  }
6995  Token *endTok = tok->link()->next()->link();
6996  if (Token::simpleMatch(endTok, ") throw ("))
6997  endTok = endTok->linkAt(2);
6998  if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
6999  continue;
7000 
7001  while (Token::Match(endTok->next(), "const|volatile"))
7002  endTok->deleteNext();
7003 
7004  // ok simplify this function pointer to an ordinary pointer
7005  if (Token::simpleMatch(tok->link()->previous(), ") )")) {
7006  // Function returning function pointer
7007  // void (*dostuff(void))(void) {}
7008  Token::eraseTokens(tok->link(), endTok->next());
7009  tok->link()->deleteThis();
7010  tok->deleteThis();
7011  } else {
7012  Token::eraseTokens(tok->link()->linkAt(1), endTok->next());
7013 
7014  // remove variable names
7015  int indent = 0;
7016  for (Token* tok3 = tok->link()->tokAt(2); Token::Match(tok3, "%name%|*|&|[|(|)|::|,|<"); tok3 = tok3->next()) {
7017  if (tok3->str() == ")" && --indent < 0)
7018  break;
7019  if (tok3->str() == "<" && tok3->link())
7020  tok3 = tok3->link();
7021  else if (Token::Match(tok3, "["))
7022  tok3 = tok3->link();
7023  else if (tok3->str() == "(") {
7024  tok3 = tok3->link();
7025  if (Token::simpleMatch(tok3, ") (")) {
7026  tok3 = tok3->next();
7027  ++indent;
7028  } else
7029  break;
7030  }
7031  if (Token::Match(tok3, "%type%|*|&|> %name% [,)[]"))
7032  tok3->deleteNext();
7033  }
7034 
7035  // TODO Keep this info
7036  while (Token::Match(tok, "( %type% ::"))
7037  tok->deleteNext(2);
7038  }
7039  }
7040 }
7041 
7042 void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
7043 {
7044  simplifyVarDecl(list.front(), nullptr, only_k_r_fpar);
7045 }
7046 
7047 void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
7048 {
7049  const bool isCPP11 = isCPP() && (mSettings.standards.cpp >= Standards::CPP11);
7050 
7051  // Split up variable declarations..
7052  // "int a=4;" => "int a; a=4;"
7053  bool finishedwithkr = true;
7054  bool scopeDecl = false;
7055  for (Token *tok = tokBegin; tok != tokEnd; tok = tok->next()) {
7056  if (Token::Match(tok, "{|;"))
7057  scopeDecl = false;
7058  if (isCPP()) {
7059  if (Token::Match(tok, "class|struct|namespace|union"))
7060  scopeDecl = true;
7061  if (Token::Match(tok, "decltype|noexcept (")) {
7062  tok = tok->next()->link();
7063  // skip decltype(...){...}
7064  if (tok && Token::simpleMatch(tok->previous(), ") {"))
7065  tok = tok->link();
7066  } else if (Token::simpleMatch(tok, "= {") ||
7067  (!scopeDecl && Token::Match(tok, "%name%|> {") &&
7068  !Token::Match(tok, "else|try|do|const|constexpr|override|volatile|noexcept"))) {
7069  if (!tok->next()->link())
7070  syntaxError(tokBegin);
7071  // Check for lambdas before skipping
7072  if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type
7073  // TODO: support lambda without parameter clause?
7074  Token* lambdaStart = tok->linkAt(-2)->previous();
7075  if (Token::simpleMatch(lambdaStart, "]"))
7076  lambdaStart = lambdaStart->link();
7077  Token* lambdaEnd = findLambdaEndScope(lambdaStart);
7078  if (lambdaEnd)
7079  simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7080  } else {
7081  for (Token* tok2 = tok->next(); tok2 != tok->next()->link(); tok2 = tok2->next()) {
7082  Token* lambdaEnd = findLambdaEndScope(tok2);
7083  if (!lambdaEnd)
7084  continue;
7085  simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7086  }
7087  }
7088  tok = tok->next()->link();
7089  }
7090 
7091  } else if (Token::simpleMatch(tok, "= {")) {
7092  tok = tok->next()->link();
7093  }
7094  if (!tok) {
7095  syntaxError(tokBegin);
7096  }
7097  if (only_k_r_fpar && finishedwithkr) {
7098  if (Token::Match(tok, "(|[|{")) {
7099  tok = tok->link();
7100  if (tok->next() && Token::Match(tok, ") !!{"))
7101  tok = tok->next();
7102  else
7103  continue;
7104  } else
7105  continue;
7106  } else if (tok->str() == "(") {
7107  if (isCPP()) {
7108  for (Token * tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
7109  if (Token::Match(tok2, "[(,] [")) {
7110  // lambda function at tok2->next()
7111  // find start of lambda body
7112  Token * lambdaBody = tok2;
7113  while (lambdaBody && lambdaBody != tok2->link() && lambdaBody->str() != "{")
7114  lambdaBody = lambdaBody->next();
7115  if (lambdaBody && lambdaBody != tok2->link() && lambdaBody->link())
7116  simplifyVarDecl(lambdaBody, lambdaBody->link()->next(), only_k_r_fpar);
7117  }
7118  }
7119  }
7120  tok = tok->link();
7121  }
7122 
7123  if (!tok)
7124  syntaxError(nullptr); // #7043 invalid code
7125  if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:"))
7126  continue;
7127  if (Token::simpleMatch(tok, "template <"))
7128  continue;
7129 
7130  Token *type0 = tok;
7131  if (!Token::Match(type0, "::|extern| %type%"))
7132  continue;
7133  if (Token::Match(type0, "else|return|public:|protected:|private:"))
7134  continue;
7135  if (isCPP11 && type0->str() == "using")
7136  continue;
7137  if (type0->isCpp() && Token::Match(type0, "namespace|delete"))
7138  continue;
7139 
7140  bool isconst = false;
7141  bool isstatic = false;
7142  Token *tok2 = type0;
7143  int typelen = 1;
7144 
7145  if (Token::Match(tok2, "::|extern")) {
7146  tok2 = tok2->next();
7147  typelen++;
7148  }
7149 
7150  //check if variable is declared 'const' or 'static' or both
7151  while (tok2) {
7152  if (!Token::Match(tok2, "const|static|constexpr") && Token::Match(tok2, "%type% const|static")) {
7153  tok2 = tok2->next();
7154  ++typelen;
7155  }
7156 
7157  if (Token::Match(tok2, "const|constexpr"))
7158  isconst = true;
7159 
7160  else if (Token::Match(tok2, "static|constexpr"))
7161  isstatic = true;
7162 
7163  else if (Token::Match(tok2, "%type% :: %type%")) {
7164  tok2 = tok2->next();
7165  ++typelen;
7166  }
7167 
7168  else
7169  break;
7170 
7171  if (tok2->strAt(1) == "*")
7172  break;
7173 
7174  if (Token::Match(tok2->next(), "& %name% ,"))
7175  break;
7176 
7177  tok2 = tok2->next();
7178  ++typelen;
7179  }
7180 
7181  // strange looking variable declaration => don't split up.
7182  if (Token::Match(tok2, "%type% *|&| %name% , %type% *|&| %name%"))
7183  continue;
7184 
7185  if (Token::Match(tok2, "struct|union|class %type%")) {
7186  tok2 = tok2->next();
7187  ++typelen;
7188  }
7189 
7190  // check for qualification..
7191  if (Token::Match(tok2, ":: %type%")) {
7192  ++typelen;
7193  tok2 = tok2->next();
7194  }
7195 
7196  //skip combinations of templates and namespaces
7197  while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
7198  if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
7199  tok2 = nullptr;
7200  break;
7201  }
7202  typelen += 2;
7203  tok2 = tok2->tokAt(2);
7204  if (tok2 && tok2->previous()->str() == "::")
7205  continue;
7206  int indentlevel = 0;
7207  int parens = 0;
7208 
7209  for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
7210  ++typelen;
7211 
7212  if (!parens && tok3->str() == "<") {
7213  ++indentlevel;
7214  } else if (!parens && tok3->str() == ">") {
7215  if (indentlevel == 0) {
7216  tok2 = tok3->next();
7217  break;
7218  }
7219  --indentlevel;
7220  } else if (!parens && tok3->str() == ">>") {
7221  if (indentlevel <= 1) {
7222  tok2 = tok3->next();
7223  break;
7224  }
7225  indentlevel -= 2;
7226  } else if (tok3->str() == "(") {
7227  ++parens;
7228  } else if (tok3->str() == ")") {
7229  if (!parens) {
7230  tok2 = nullptr;
7231  break;
7232  }
7233  --parens;
7234  } else if (tok3->str() == ";") {
7235  break;
7236  }
7237  }
7238 
7239  if (Token::Match(tok2, ":: %type%")) {
7240  ++typelen;
7241  tok2 = tok2->next();
7242  }
7243 
7244  // east const
7245  if (Token::simpleMatch(tok2, "const"))
7246  isconst = true;
7247  }
7248 
7249  //pattern: "%type% *| ... *| const| %name% ,|="
7250  if (Token::Match(tok2, "%type%") ||
7251  (tok2 && tok2->previous() && tok2->previous()->str() == ">")) {
7252  Token *varName = tok2;
7253  if (!tok2->previous() || tok2->previous()->str() != ">")
7254  varName = varName->next();
7255  else
7256  --typelen;
7257  if (isCPP() && Token::Match(varName, "public:|private:|protected:|using"))
7258  continue;
7259  //skip all the pointer part
7260  bool isPointerOrRef = false;
7261  while (Token::simpleMatch(varName, "*") || Token::Match(varName, "& %name% ,")) {
7262  isPointerOrRef = true;
7263  varName = varName->next();
7264  }
7265 
7266  while (Token::Match(varName, "%type% %type%")) {
7267  if (varName->str() != "const" && varName->str() != "volatile") {
7268  ++typelen;
7269  }
7270  varName = varName->next();
7271  }
7272  // Function pointer
7273  if (Token::simpleMatch(varName, "( *") &&
7274  Token::Match(varName->link()->previous(), "%name% ) (") &&
7275  Token::simpleMatch(varName->link()->linkAt(1), ") =")) {
7276  Token *endDecl = varName->link()->linkAt(1);
7277  varName = varName->link()->previous();
7278  endDecl->insertToken(";");
7279  endDecl = endDecl->next();
7280  endDecl->next()->isSplittedVarDeclEq(true);
7281  endDecl->insertToken(varName->str());
7282  endDecl->next()->setMacroName(varName->getMacroName());
7283  continue;
7284  }
7285  //non-VLA case
7286  if (Token::Match(varName, "%name% ,|=")) {
7287  if (varName->str() != "operator") {
7288  tok2 = varName->next(); // The ',' or '=' token
7289 
7290  if (tok2->str() == "=" && (isstatic || (isconst && !isPointerOrRef))) {
7291  //do not split const non-pointer variables..
7292  while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7293  if (Token::Match(tok2, "{|(|["))
7294  tok2 = tok2->link();
7295  const Token *tok3 = tok2;
7296  if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
7297  tok2 = tok2->findClosingBracket();
7298  }
7299  if (!tok2)
7300  syntaxError(tok3); // #6881 invalid code
7301  tok2 = tok2->next();
7302  }
7303  if (tok2 && tok2->str() == ";")
7304  tok2 = nullptr;
7305  }
7306  } else
7307  tok2 = nullptr;
7308  }
7309 
7310  //VLA case
7311  else if (Token::Match(varName, "%name% [")) {
7312  tok2 = varName->next();
7313 
7314  while (Token::Match(tok2->link(), "] ,|=|["))
7315  tok2 = tok2->link()->next();
7316  if (!Token::Match(tok2, "=|,"))
7317  tok2 = nullptr;
7318  if (tok2 && tok2->str() == "=") {
7319  while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7320  if (Token::Match(tok2, "{|(|["))
7321  tok2 = tok2->link();
7322  tok2 = tok2->next();
7323  }
7324  if (tok2 && tok2->str() == ";")
7325  tok2 = nullptr;
7326  }
7327  }
7328 
7329  // brace initialization
7330  else if (Token::Match(varName, "%name% {")) {
7331  tok2 = varName->next();
7332  tok2 = tok2->link();
7333  if (tok2)
7334  tok2 = tok2->next();
7335  if (tok2 && tok2->str() != ",")
7336  tok2 = nullptr;
7337  }
7338 
7339  // function declaration
7340  else if (Token::Match(varName, "%name% (")) {
7341  Token* commaTok = varName->linkAt(1)->next();
7342  while (Token::Match(commaTok, "const|noexcept|override|final")) {
7343  commaTok = commaTok->next();
7344  if (Token::Match(commaTok, "( true|false )"))
7345  commaTok = commaTok->link()->next();
7346  }
7347  tok2 = Token::simpleMatch(commaTok, ",") ? commaTok : nullptr;
7348  }
7349 
7350  else
7351  tok2 = nullptr;
7352  } else {
7353  tok2 = nullptr;
7354  }
7355 
7356  if (!tok2) {
7357  if (only_k_r_fpar)
7358  finishedwithkr = false;
7359  continue;
7360  }
7361 
7362  if (tok2->str() == ",") {
7363  tok2->str(";");
7364  tok2->isSplittedVarDeclComma(true);
7365  //TODO: should we have to add also template '<>' links?
7366  TokenList::insertTokens(tok2, type0, typelen);
7367  }
7368 
7369  else {
7370  Token *eq = tok2;
7371 
7372  while (tok2) {
7373  if (Token::Match(tok2, "{|(|["))
7374  tok2 = tok2->link();
7375 
7376  else if (!isC() && tok2->str() == "<" && ((tok2->previous()->isName() && !tok2->previous()->varId()) || tok2->strAt(-1) == "]"))
7377  tok2 = tok2->findClosingBracket();
7378 
7379  else if (std::strchr(";,", tok2->str()[0])) {
7380  // "type var =" => "type var; var ="
7381  const Token *varTok = type0->tokAt(typelen);
7382  while (Token::Match(varTok, "%name%|*|& %name%|*|&"))
7383  varTok = varTok->next();
7384  if (!varTok)
7385  syntaxError(tok2); // invalid code
7386  TokenList::insertTokens(eq, varTok, 2);
7387  eq->str(";");
7388  eq->isSplittedVarDeclEq(true);
7389 
7390  // "= x, " => "= x; type "
7391  if (tok2->str() == ",") {
7392  tok2->str(";");
7393  tok2->isSplittedVarDeclComma(true);
7394  TokenList::insertTokens(tok2, type0, typelen);
7395  }
7396  break;
7397  }
7398  if (tok2)
7399  tok2 = tok2->next();
7400  }
7401  }
7402  finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{");
7403  }
7404 }
7405 
7407 {
7408  // This function will simplify the token list so that the qualifiers "extern", "static"
7409  // and "const" appear in the same order as in the array below.
7410  const std::string qualifiers[] = {"extern", "static", "const"};
7411 
7412  // Move 'const' before all other qualifiers and types and then
7413  // move 'static' before all other qualifiers and types, ...
7414  for (Token *tok = list.front(); tok; tok = tok->next()) {
7415  bool continue2 = false;
7416  for (int i = 0; i < sizeof(qualifiers)/sizeof(qualifiers[0]); i++) {
7417 
7418  // Keep searching for a qualifier
7419  if (!tok->next() || tok->next()->str() != qualifiers[i])
7420  continue;
7421 
7422  // Look backwards to find the beginning of the declaration
7423  Token* leftTok = tok;
7424  bool behindOther = false;
7425  for (; leftTok; leftTok = leftTok->previous()) {
7426  for (int j = 0; j <= i; j++) {
7427  if (leftTok->str() == qualifiers[j]) {
7428  behindOther = true;
7429  break;
7430  }
7431  }
7432  if (behindOther)
7433  break;
7434  if (isCPP() && Token::simpleMatch(leftTok, ">")) {
7435  Token* opening = leftTok->findOpeningBracket();
7436  if (opening) {
7437  leftTok = opening;
7438  continue;
7439  }
7440  }
7441  if (!Token::Match(leftTok, "%type%|struct|::") ||
7442  (isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator|template"))) {
7443  break;
7444  }
7445  }
7446 
7447  // The token preceding the declaration should indicate the start of a declaration
7448  if (leftTok == tok)
7449  continue;
7450 
7451  if (leftTok && !behindOther && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:")) {
7452  continue2 = true;
7453  break;
7454  }
7455 
7456  // Move the qualifier to the left-most position in the declaration
7457  tok->deleteNext();
7458  if (!leftTok) {
7459  list.front()->insertToken(qualifiers[i]);
7460  list.front()->swapWithNext();
7461  tok = list.front();
7462  } else if (leftTok->next()) {
7463  leftTok->next()->insertTokenBefore(qualifiers[i]);
7464  tok = leftTok->next();
7465  } else {
7466  leftTok->insertToken(qualifiers[i]);
7467  tok = leftTok;
7468  }
7469  }
7470  if (continue2)
7471  continue;
7472  }
7473 }
7474 
7476 {
7477  for (Token *tok = list.front(); tok; tok = tok->next()) {
7478  if (Token::Match(tok, "%name% = %name% = %num%|%name% ;")) {
7479  // skip intermediate assignments
7480  Token *tok2 = tok->previous();
7481  while (tok2 &&
7482  tok2->str() == "=" &&
7483  Token::Match(tok2->previous(), "%name%")) {
7484  tok2 = tok2->tokAt(-2);
7485  }
7486 
7487  if (!tok2 || tok2->str() != ";") {
7488  continue;
7489  }
7490 
7491  Token *stopAt = tok->tokAt(2);
7492  const Token *valueTok = stopAt->tokAt(2);
7493  const std::string& value(valueTok->str());
7494  tok2 = tok2->next();
7495 
7496  while (tok2 != stopAt) {
7497  tok2->next()->insertToken(";");
7498  tok2->next()->insertToken(value);
7499  tok2 = tok2->tokAt(4);
7500  }
7501  }
7502  }
7503 }
7504 
7505 // Binary operators simplification map
7506 static const std::unordered_map<std::string, std::string> cAlternativeTokens = {
7507  std::make_pair("and", "&&")
7508  , std::make_pair("and_eq", "&=")
7509  , std::make_pair("bitand", "&")
7510  , std::make_pair("bitor", "|")
7511  , std::make_pair("not_eq", "!=")
7512  , std::make_pair("or", "||")
7513  , std::make_pair("or_eq", "|=")
7514  , std::make_pair("xor", "^")
7515  , std::make_pair("xor_eq", "^=")
7516 };
7517 
7518 // Simplify the C alternative tokens:
7519 // and => &&
7520 // and_eq => &=
7521 // bitand => &
7522 // bitor => |
7523 // compl => ~
7524 // not => !
7525 // not_eq => !=
7526 // or => ||
7527 // or_eq => |=
7528 // xor => ^
7529 // xor_eq => ^=
7531 {
7532  /* executable scope level */
7533  int executableScopeLevel = 0;
7534 
7535  std::vector<Token *> alt;
7536  bool replaceAll = false; // replace all or none
7537 
7538  for (Token *tok = list.front(); tok; tok = tok->next()) {
7539  if (tok->str() == ")") {
7540  if (const Token *end = isFunctionHead(tok, "{")) {
7541  ++executableScopeLevel;
7542  tok = const_cast<Token *>(end);
7543  continue;
7544  }
7545  }
7546 
7547  if (tok->str() == "{") {
7548  if (executableScopeLevel > 0)
7549  ++executableScopeLevel;
7550  continue;
7551  }
7552 
7553  if (tok->str() == "}") {
7554  if (executableScopeLevel > 0)
7555  --executableScopeLevel;
7556  continue;
7557  }
7558 
7559  if (!tok->isName())
7560  continue;
7561 
7562  const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7563  if (cOpIt != cAlternativeTokens.end()) {
7564  alt.push_back(tok);
7565 
7566  // Is this a variable declaration..
7567  if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]"))
7568  return false;
7569 
7570  if (!Token::Match(tok->previous(), "%name%|%num%|%char%|)|]|> %name% %name%|%num%|%char%|%op%|("))
7571  continue;
7572  if (Token::Match(tok->next(), "%assign%|%or%|%oror%|&&|*|/|%|^") && !Token::Match(tok->previous(), "%num%|%char%|) %name% *"))
7573  continue;
7574  if (executableScopeLevel == 0 && Token::Match(tok, "%name% (")) {
7575  const Token *start = tok;
7576  while (Token::Match(start, "%name%|*"))
7577  start = start->previous();
7578  if (!start || Token::Match(start, "[;}]"))
7579  continue;
7580  }
7581  replaceAll = true;
7582  } else if (Token::Match(tok, "not|compl")) {
7583  alt.push_back(tok);
7584 
7585  if ((Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) && !Token::Match(tok->next(), ".|->")) {
7586  replaceAll = true;
7587  continue;
7588  }
7589 
7590  // Don't simplify 'not p;' (in case 'not' is a type)
7591  if (!Token::Match(tok->next(), "%name%|(") ||
7592  Token::Match(tok->previous(), "[;{}]") ||
7593  (executableScopeLevel == 0U && tok->strAt(-1) == "("))
7594  continue;
7595 
7596  replaceAll = true;
7597  }
7598  }
7599 
7600  if (!replaceAll)
7601  return false;
7602 
7603  for (Token *tok: alt) {
7604  const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7605  if (cOpIt != cAlternativeTokens.end())
7606  tok->str(cOpIt->second);
7607  else if (tok->str() == "not")
7608  tok->str("!");
7609  else
7610  tok->str("~");
7611  }
7612 
7613  return !alt.empty();
7614 }
7615 
7616 // int i(0); => int i; i = 0;
7617 // int i(0), j; => int i; i = 0; int j;
7619 {
7620  if (isC())
7621  return;
7622 
7623  for (Token *tok = list.front(); tok; tok = tok->next()) {
7624  if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]")))
7625  continue;
7626 
7627  if (tok->str() == "return")
7628  continue;
7629 
7630  if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ;")) {
7631  tok = initVar(tok);
7632  } else if (Token::Match(tok, "%type% *| %name% ( %type% (")) {
7633  const Token* tok2 = tok->tokAt(2);
7634  if (!tok2->link())
7635  tok2 = tok2->next();
7636  if (!tok2->link() || (tok2->link()->strAt(1) == ";" && !Token::simpleMatch(tok2->linkAt(2), ") (")))
7637  tok = initVar(tok);
7638  } else if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ,") && tok->str() != "new") {
7639  Token *tok1 = tok->tokAt(5);
7640  while (tok1->str() != ",")
7641  tok1 = tok1->next();
7642  tok1->str(";");
7643 
7644  const int numTokens = (Token::Match(tok, "class|struct|union")) ? 2U : 1U;
7645  TokenList::insertTokens(tok1, tok, numTokens);
7646  tok = initVar(tok);
7647  }
7648  }
7649 }
7650 
7652 {
7653  // call constructor of class => no simplification
7654  if (Token::Match(tok, "class|struct|union")) {
7655  if (tok->strAt(2) != "*")
7656  return tok;
7657 
7658  tok = tok->next();
7659  } else if (!tok->isStandardType() && tok->str() != "auto" && tok->next()->str() != "*")
7660  return tok;
7661 
7662  // goto variable name..
7663  tok = tok->next();
7664  if (tok->str() == "*")
7665  tok = tok->next();
7666 
7667  // sizeof is not a variable name..
7668  if (tok->str() == "sizeof")
7669  return tok;
7670 
7671  // check initializer..
7672  if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void")
7673  return tok;
7674  if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0)
7675  return tok;
7676 
7677  // insert '; var ='
7678  tok->insertToken(";");
7679  tok->next()->insertToken(tok->str());
7680  tok->tokAt(2)->varId(tok->varId());
7681  tok = tok->tokAt(2);
7682  tok->insertToken("=");
7683 
7684  // goto '('..
7685  tok = tok->tokAt(2);
7686 
7687  // delete ')'
7688  tok->link()->deleteThis();
7689 
7690  // delete this
7691  tok->deleteThis();
7692 
7693  return tok;
7694 }
7695 
7697 {
7698  for (Token *tok = list.front(); tok; tok = tok->next()) {
7699  if (tok->str() != "else")
7700  continue;
7701 
7702  if (!Token::Match(tok->previous(), ";|}"))
7703  syntaxError(tok->previous());
7704 
7705  if (!Token::Match(tok->next(), "%name%"))
7706  continue;
7707 
7708  if (tok->strAt(1) != "if")
7709  unknownMacroError(tok->next());
7710 
7711  for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
7712  if (Token::Match(tok2, "(|{|["))
7713  tok2 = tok2->link();
7714 
7715  if (Token::Match(tok2, "}|;")) {
7716  if (tok2->next() && tok2->next()->str() != "else") {
7717  tok->insertToken("{");
7718  tok2->insertToken("}");
7719  Token::createMutualLinks(tok->next(), tok2->next());
7720  break;
7721  }
7722  }
7723  }
7724  }
7725 }
7726 
7727 
7729 {
7731  return;
7732 
7733  const bool forInit = (mSettings.standards.cpp >= Standards::CPP20);
7734 
7735  for (Token *tok = list.front(); tok; tok = tok->next()) {
7736  if (!Token::Match(tok, "if|switch|for ("))
7737  continue;
7738 
7739  Token *semicolon = tok->tokAt(2);
7740  while (!Token::Match(semicolon, "[;)]")) {
7741  if (Token::Match(semicolon, "(|{|[") && semicolon->link())
7742  semicolon = semicolon->link();
7743  semicolon = semicolon->next();
7744  }
7745  if (semicolon->str() != ";")
7746  continue;
7747 
7748  if (tok->str() == "for") {
7749  if (!forInit)
7750  continue;
7751 
7752  // Is it a for range..
7753  const Token *tok2 = semicolon->next();
7754  bool rangeFor = false;
7755  while (!Token::Match(tok2, "[;)]")) {
7756  if (tok2->str() == "(")
7757  tok2 = tok2->link();
7758  else if (!rangeFor && tok2->str() == "?")
7759  break;
7760  else if (tok2->str() == ":")
7761  rangeFor = true;
7762  tok2 = tok2->next();
7763  }
7764  if (!rangeFor || tok2->str() != ")")
7765  continue;
7766  }
7767 
7768  Token *endpar = tok->linkAt(1);
7769  if (!Token::simpleMatch(endpar, ") {"))
7770  continue;
7771 
7772  Token *endscope = endpar->linkAt(1);
7773  if (Token::simpleMatch(endscope, "} else {"))
7774  endscope = endscope->linkAt(2);
7775 
7776  // Simplify, the initialization expression is broken out..
7777  semicolon->insertToken(tok->str());
7778  semicolon->next()->insertToken("(");
7779  Token::createMutualLinks(semicolon->next()->next(), endpar);
7780  tok->deleteNext();
7781  tok->str("{");
7782  endscope->insertToken("}");
7783  Token::createMutualLinks(tok, endscope->next());
7784  tok->isSimplifiedScope(true);
7785  }
7786 }
7787 
7788 
7790 {
7791  bool ret = false;
7792  for (Token *tok = list.front(); tok; tok = tok->next()) {
7793  if (tok->str() != "(")
7794  continue;
7795 
7796  if (tok->isCpp() && Token::simpleMatch(tok->previous(), "} (")) {
7797  const Token* plp = tok->previous()->link()->previous();
7798  if (Token::Match(plp, "%name%|>|] {") || (Token::simpleMatch(plp, ")") && Token::simpleMatch(plp->link()->previous(), "]")))
7799  continue;
7800  }
7801 
7802  if (Token::simpleMatch(tok, "( {"))
7803  continue;
7804 
7805  if (Token::Match(tok->link(), ") %num%")) {
7806  tok = tok->link();
7807  continue;
7808  }
7809 
7810  // Do not simplify if there is comma inside parentheses..
7811  if (Token::Match(tok->previous(), "%op% (") || Token::Match(tok->link(), ") %op%")) {
7812  bool innerComma = false;
7813  for (const Token *inner = tok->link()->previous(); inner != tok; inner = inner->previous()) {
7814  if (inner->str() == ")")
7815  inner = inner->link();
7816  if (inner->str() == ",") {
7817  innerComma = true;
7818  break;
7819  }
7820  }
7821  if (innerComma)
7822  continue;
7823  }
7824 
7825  // !!operator = ( x ) ;
7826  if (tok->strAt(-2) != "operator" &&
7827  tok->previous() && tok->previous()->str() == "=" &&
7828  tok->next() && tok->next()->str() != "{" &&
7829  Token::simpleMatch(tok->link(), ") ;")) {
7830  tok->link()->deleteThis();
7831  tok->deleteThis();
7832  continue;
7833  }
7834 
7835  while (Token::simpleMatch(tok, "( (") &&
7836  tok->link() && tok->link()->previous() == tok->next()->link()) {
7837  // We have "(( *something* ))", remove the inner
7838  // parentheses
7839  tok->deleteNext();
7840  tok->link()->tokAt(-2)->deleteNext();
7841  ret = true;
7842  }
7843 
7844  if (isCPP() && Token::Match(tok->tokAt(-2), "[;{}=(] new (") && Token::Match(tok->link(), ") [;,{}[]")) {
7845  // Remove the parentheses in "new (type)" constructs
7846  tok->link()->deleteThis();
7847  tok->deleteThis();
7848  ret = true;
7849  }
7850 
7851  if (Token::Match(tok->previous(), "! ( %name% )")) {
7852  // Remove the parentheses
7853  tok->deleteThis();
7854  tok->deleteNext();
7855  ret = true;
7856  }
7857 
7858  if (Token::Match(tok->previous(), "[(,;{}] ( %name% ) .")) {
7859  // Remove the parentheses
7860  tok->deleteThis();
7861  tok->deleteNext();
7862  ret = true;
7863  }
7864 
7865  if (Token::Match(tok->previous(), "[(,;{}] ( %name% (") && !tok->next()->isKeyword() &&
7866  tok->link()->previous() == tok->linkAt(2)) {
7867  // We have "( func ( *something* ))", remove the outer
7868  // parentheses
7869  tok->link()->deleteThis();
7870  tok->deleteThis();
7871  ret = true;
7872  }
7873 
7874  if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %name% ) ;")) {
7875  // We have "( delete [| ]| var )", remove the outer
7876  // parentheses
7877  tok->link()->deleteThis();
7878  tok->deleteThis();
7879  ret = true;
7880  }
7881 
7882  if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
7883  Token::Match(tok->previous(), "delete|; (") &&
7884  (tok->previous()->str() != "delete" || tok->next()->varId() > 0) &&
7885  Token::Match(tok->link(), ") ;|,")) {
7886  tok->link()->deleteThis();
7887  tok->deleteThis();
7888  ret = true;
7889  }
7890 
7891  if (Token::Match(tok->previous(), "[(!*;{}] ( %name% )") &&
7892  (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]")) && !tok->next()->isStandardType()) {
7893  // We have "( var )", remove the parentheses
7894  tok->deleteThis();
7895  tok->deleteNext();
7896  ret = true;
7897  }
7898 
7899  while (Token::Match(tok->previous(), "[;{}[(,!*] ( %name% .")) {
7900  Token *tok2 = tok->tokAt(2);
7901  while (Token::Match(tok2, ". %name%")) {
7902  tok2 = tok2->tokAt(2);
7903  }
7904  if (tok2 != tok->link())
7905  break;
7906  // We have "( var . var . ... . var )", remove the parentheses
7907  tok = tok->previous();
7908  tok->deleteNext();
7909  tok2->deleteThis();
7910  ret = true;
7911  }
7912 
7913  while (Token::Match(tok->previous(), "[{([,] ( !!{") &&
7914  Token::Match(tok->link(), ") [;,])]") &&
7915  !Token::simpleMatch(tok->tokAt(-2), "operator ,") && // Ticket #5709
7916  !Token::findsimplematch(tok, ",", tok->link())) {
7917  // We have "( ... )", remove the parentheses
7918  tok->link()->deleteThis();
7919  tok->deleteThis();
7920  ret = true;
7921  }
7922 
7923  if (Token::simpleMatch(tok->previous(), ", (") &&
7924  Token::simpleMatch(tok->link(), ") =")) {
7925  tok->link()->deleteThis();
7926  tok->deleteThis();
7927  ret = true;
7928  }
7929 
7930  // Simplify "!!operator !!%name%|)|]|>|>> ( %num%|%bool% ) %op%|;|,|)"
7931  if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") &&
7932  tok->strAt(-2) != "operator" &&
7933  tok->previous() &&
7934  !Token::Match(tok->previous(), "%name%|)|]") &&
7935  (!(isCPP() && Token::Match(tok->previous(),">|>>")))) {
7936  tok->link()->deleteThis();
7937  tok->deleteThis();
7938  ret = true;
7939  }
7940 
7941  if (Token::Match(tok->previous(), "*|& ( %name% )")) {
7942  // We may have a variable declaration looking like "type_name *(var_name)"
7943  Token *tok2 = tok->tokAt(-2);
7944  while (Token::Match(tok2, "%type%|static|const|extern") && tok2->str() != "operator") {
7945  tok2 = tok2->previous();
7946  }
7947  if (tok2 && !Token::Match(tok2, "[;,{]")) {
7948  // Not a variable declaration
7949  } else {
7950  tok->deleteThis();
7951  tok->deleteNext();
7952  }
7953  }
7954  }
7955  return ret;
7956 }
7957 
7959 {
7960  static const std::unordered_map<std::string, std::string> intrinsics = {
7961  { "__has_nothrow_assign", "has_nothrow_assign" },
7962  { "__has_nothrow_constructor", "has_nothrow_constructor" },
7963  { "__has_nothrow_copy", "has_nothrow_copy" },
7964  { "__has_trivial_assign", "has_trivial_assign" },
7965  { "__has_trivial_constructor", "has_trivial_constructor" },
7966  { "__has_trivial_copy", "has_trivial_copy" },
7967  { "__has_trivial_destructor", "has_trivial_destructor" },
7968  { "__has_virtual_destructor", "has_virtual_destructor" },
7969  { "__is_abstract", "is_abstract" },
7970  { "__is_aggregate", "is_aggregate" },
7971  { "__is_assignable", "is_assignable" },
7972  { "__is_base_of", "is_base_of" },
7973  { "__is_class", "is_class" },
7974  { "__is_constructible", "is_constructible" },
7975  { "__is_convertible_to", "is_convertible_to" },
7976  { "__is_destructible", "is_destructible" },
7977  { "__is_empty", "is_empty" },
7978  { "__is_enum", "is_enum" },
7979  { "__is_final", "is_final" },
7980  { "__is_nothrow_assignable", "is_nothrow_assignable" },
7981  { "__is_nothrow_constructible", "is_nothrow_constructible" },
7982  { "__is_nothrow_destructible", "is_nothrow_destructible" },
7983  { "__is_pod", "is_pod" },
7984  { "__is_polymorphic", "is_polymorphic" },
7985  { "__is_trivially_assignable", "is_trivially_assignable" },
7986  { "__is_trivially_constructible", "is_trivially_constructible" },
7987  { "__is_union", "is_union" },
7988  };
7989  for (Token *tok = list.front(); tok; tok = tok->next()) {
7990  if (!Token::Match(tok, "%name% ("))
7991  continue;
7992  auto p = intrinsics.find(tok->str());
7993  if (p == intrinsics.end())
7994  continue;
7995  Token * end = tok->next()->link();
7996  Token * prev = tok->previous();
7997  tok->str(p->second);
7998  prev->insertToken("::");
7999  prev->insertToken("std");
8000  tok->next()->str("<");
8001  end->str(">");
8002  end->insertToken("}");
8003  end->insertToken("{");
8004  Token::createMutualLinks(end->tokAt(1), end->tokAt(2));
8005  }
8006 }
8007 
8008 //---------------------------------------------------------------------------
8009 // Helper functions for handling the tokens list
8010 //---------------------------------------------------------------------------
8011 
8012 //---------------------------------------------------------------------------
8013 
8014 bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
8015 {
8016  std::string unknownFunc;
8017  const bool ret = mSettings.library.isScopeNoReturn(endScopeToken,&unknownFunc);
8018  if (!unknownFunc.empty() && mSettings.summaryReturn.find(unknownFunc) != mSettings.summaryReturn.end()) {
8019  return false;
8020  }
8021  if (unknown)
8022  *unknown = !unknownFunc.empty();
8023  if (!unknownFunc.empty() && mSettings.checkLibrary) {
8024  bool warn = true;
8025  if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
8026  const Token * const ftok = endScopeToken->linkAt(-2)->previous();
8027  if (ftok && (ftok->type() || ftok->function() || ftok->variable())) // constructor call
8028  warn = false;
8029  }
8030 
8031  if (warn) {
8032  reportError(endScopeToken->previous(),
8034  "checkLibraryNoReturn",
8035  "--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
8036  }
8037  }
8038  return ret;
8039 }
8040 
8041 //---------------------------------------------------------------------------
8042 
8043 void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
8044 {
8045  printDebugOutput(0);
8046  throw InternalError(tok, code.empty() ? "syntax error" : "syntax error: " + code, InternalError::SYNTAX);
8047 }
8048 
8049 void Tokenizer::unmatchedToken(const Token *tok) const
8050 {
8051  printDebugOutput(0);
8052  throw InternalError(tok,
8053  "Unmatched '" + tok->str() + "'. Configuration: '" + mConfiguration + "'.",
8055 }
8056 
8057 void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
8058 {
8059  printDebugOutput(0);
8060  throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
8061 }
8062 
8063 void Tokenizer::unknownMacroError(const Token *tok1) const
8064 {
8065  printDebugOutput(0);
8066  throw InternalError(tok1, "There is an unknown macro here somewhere. Configuration is required. If " + tok1->str() + " is a macro then please configure it.", InternalError::UNKNOWN_MACRO);
8067 }
8068 
8070 {
8071  reportError(tok,
8073  "class_X_Y",
8074  "The code '" +
8075  tok->str() + " " +
8076  tok->strAt(1) + " " +
8077  tok->strAt(2) + " " +
8078  tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
8079 }
8080 
8081 void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string &macroName) const
8082 {
8083  reportError(tok,
8085  "macroWithSemicolon",
8086  "Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
8087 }
8088 
8089 void Tokenizer::cppcheckError(const Token *tok) const
8090 {
8091  printDebugOutput(0);
8092  throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL);
8093 }
8094 
8095 void Tokenizer::unhandledCharLiteral(const Token *tok, const std::string& msg) const
8096 {
8097  std::string s = tok ? (" " + tok->str()) : "";
8098  for (int i = 0; i < s.size(); ++i) {
8099  if ((unsigned char)s[i] >= 0x80)
8100  s.clear();
8101  }
8102 
8103  reportError(tok,
8105  "nonStandardCharLiteral",
8106  "Non-standard character literal" + s + ". " + msg);
8107 }
8108 
8109 /**
8110  * Helper function to check whether number is equal to integer constant X
8111  * or floating point pattern X.0
8112  * @param s the string to check
8113  * @param intConstant the integer constant to check against
8114  * @param floatConstant the string with stringified float constant to check against
8115  * @return true in case s is equal to X or X.0 and false otherwise.
8116  */
8117 static bool isNumberOneOf(const std::string &s, MathLib::bigint intConstant, const char* floatConstant)
8118 {
8119  if (MathLib::isInt(s)) {
8120  if (MathLib::toBigNumber(s) == intConstant)
8121  return true;
8122  } else if (MathLib::isFloat(s)) {
8123  if (MathLib::toString(MathLib::toDoubleNumber(s)) == floatConstant)
8124  return true;
8125  }
8126  return false;
8127 }
8128 
8129 // ------------------------------------------------------------------------
8130 // Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
8131 // @param s the string to check
8132 // @return true in case s is one and false otherwise.
8133 // ------------------------------------------------------------------------
8134 bool Tokenizer::isOneNumber(const std::string &s)
8135 {
8136  if (!MathLib::isPositive(s))
8137  return false;
8138  return isNumberOneOf(s, 1L, "1.0");
8139 }
8140 // ------------------------------------------------------------------------
8142 {
8144  return;
8145  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8146  if (!Token::Match(tok, "%name% ("))
8147  continue;
8148  if (tok->isControlFlowKeyword())
8149  continue;
8150  for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
8151  if (tok2->str() == ";") {
8152  macroWithSemicolonError(tok, tok->str());
8153  break;
8154  }
8155  if (Token::Match(tok2, "(|{"))
8156  tok2 = tok2->link();
8157  }
8158  }
8159 }
8160 
8162 {
8163  if (isCPP())
8164  return;
8165  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8166  // That might trigger false positives, but it's much faster to have this truncated pattern
8167  if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
8168  syntaxErrorC(tok, "C++ cast <...");
8169  // Template function..
8170  if (Token::Match(tok, "%name% < %name% > (")) {
8171  const Token *tok2 = tok->tokAt(5);
8172  while (tok2 && !Token::Match(tok2, "[()]"))
8173  tok2 = tok2->next();
8174  if (Token::simpleMatch(tok2, ") {"))
8175  syntaxErrorC(tok, tok->str() + '<' + tok->strAt(2) + ">() {}");
8176  }
8177  if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
8178  continue;
8179  if (Token::Match(tok, "using namespace %name% ;"))
8180  syntaxErrorC(tok, "using namespace " + tok->strAt(2));
8181  if (Token::Match(tok, "template < class|typename %name% [,>]"))
8182  syntaxErrorC(tok, "template<...");
8183  if (Token::Match(tok, "%name% :: %name%"))
8184  syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8185  if (Token::Match(tok, "class|namespace %name% [:{]"))
8186  syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8187  }
8188 }
8189 
8191 {
8192  std::stack<const Token *> linkTokens;
8193  const Token *lastTok = nullptr;
8194  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8195  lastTok = tok;
8196  if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) {
8197  if (tok->link() == nullptr)
8198  cppcheckError(tok);
8199 
8200  linkTokens.push(tok);
8201  }
8202 
8203  else if (Token::Match(tok, "[})]]") || (Token::Match(tok, ">|>>") && tok->link())) {
8204  if (tok->link() == nullptr)
8205  cppcheckError(tok);
8206 
8207  if (linkTokens.empty())
8208  cppcheckError(tok);
8209 
8210  if (tok->link() != linkTokens.top())
8211  cppcheckError(tok);
8212 
8213  if (tok != tok->link()->link())
8214  cppcheckError(tok);
8215 
8216  linkTokens.pop();
8217  }
8218 
8219  else if (tok->link() != nullptr)
8220  cppcheckError(tok);
8221  }
8222 
8223  if (!linkTokens.empty())
8224  cppcheckError(linkTokens.top());
8225 
8226  // Validate that the Tokenizer::list.back() is updated correctly during simplifications
8227  if (lastTok != list.back())
8228  cppcheckError(lastTok);
8229 }
8230 
8231 static const Token *findUnmatchedTernaryOp(const Token * const begin, const Token * const end, int depth = 0)
8232 {
8233  std::stack<const Token *> ternaryOp;
8234  for (const Token *tok = begin; tok != end && tok->str() != ";"; tok = tok->next()) {
8235  if (tok->str() == "?")
8236  ternaryOp.push(tok);
8237  else if (!ternaryOp.empty() && tok->str() == ":")
8238  ternaryOp.pop();
8239  else if (depth < 100 && Token::Match(tok,"(|[")) {
8240  const Token *inner = findUnmatchedTernaryOp(tok->next(), tok->link(), depth+1);
8241  if (inner)
8242  return inner;
8243  tok = tok->link();
8244  }
8245  }
8246  return ternaryOp.empty() ? nullptr : ternaryOp.top();
8247 }
8248 
8249 static bool isCPPAttribute(const Token * tok)
8250 {
8251  return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
8252 }
8253 
8254 static bool isAlignAttribute(const Token * tok)
8255 {
8256  return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
8257 }
8258 
8259 template<typename T>
8260 static T* skipCPPOrAlignAttribute(T * tok)
8261 {
8262  if (isCPPAttribute(tok))
8263  return tok->link();
8264  if (isAlignAttribute(tok)) {
8265  return tok->next()->link();
8266  }
8267  return tok;
8268 }
8269 
8270 static bool isNonMacro(const Token* tok)
8271 {
8272  if (tok->isKeyword() || tok->isStandardType())
8273  return true;
8274  if (cAlternativeTokens.count(tok->str()) > 0)
8275  return true;
8276  if (startsWith(tok->str(), "__")) // attribute/annotation
8277  return true;
8278  if (Token::simpleMatch(tok, "alignas ("))
8279  return true;
8280  return false;
8281 }
8282 
8284 {
8285  // Report unknown macros used in expressions "%name% %num%"
8286  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8287  if (Token::Match(tok, "%name% %num%")) {
8288  // A keyword is not an unknown macro
8289  if (tok->isKeyword())
8290  continue;
8291 
8292  if (Token::Match(tok->previous(), "%op%|("))
8293  unknownMacroError(tok);
8294  }
8295  }
8296 
8297  // Report unknown macros before } "{ .. if (x) MACRO }"
8298  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8299  if (Token::Match(tok, ")|; %name% } !!)")) {
8300  if (tok->link() && !Token::simpleMatch(tok->link()->tokAt(-1), "if"))
8301  continue;
8302  const Token* prev = tok->linkAt(2);
8303  while (Token::simpleMatch(prev, "{"))
8304  prev = prev->previous();
8305  if (Token::Match(prev, ";|)"))
8306  unknownMacroError(tok->next());
8307  }
8308  }
8309 
8310  // Report unknown macros that contain several statements "MACRO(a;b;c)"
8311  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8312  if (!Token::Match(tok, "%name% ("))
8313  continue;
8314  if (!tok->isUpperCaseName())
8315  continue;
8316  const Token *endTok = tok->linkAt(1);
8317  for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8318  if (Token::Match(inner, "[[({]"))
8319  inner = inner->link();
8320  else if (inner->str() == ";")
8321  unknownMacroError(tok);
8322  }
8323  }
8324 
8325  // Report unknown macros that contain struct initialization "MACRO(a, .b=3)"
8326  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8327  if (!Token::Match(tok, "%name% ("))
8328  continue;
8329  const Token *endTok = tok->linkAt(1);
8330  for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8331  if (Token::Match(inner, "[[({]"))
8332  inner = inner->link();
8333  else if (Token::Match(inner->previous(), "[,(] . %name% =|{"))
8334  unknownMacroError(tok);
8335  }
8336  }
8337 
8338  // Report unknown macros in non-executable scopes..
8339  std::set<std::string> possible;
8340  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8341  // Skip executable scopes..
8342  if (tok->str() == "{") {
8343  const Token *prev = tok->previous();
8344  while (prev && prev->isName())
8345  prev = prev->previous();
8346  if (prev && prev->str() == ")")
8347  tok = tok->link();
8348  else
8349  possible.clear();
8350  } else if (tok->str() == "}")
8351  possible.clear();
8352 
8353  if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
8354  // A keyword is not an unknown macro
8355  if (tok->isKeyword())
8356  continue;
8357 
8358  const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
8359  const Token *bodyEnd = tok->link();
8360  for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) {
8361  if (Token::Match(tok2, "if|switch|for|while|return"))
8362  unknownMacroError(tok);
8363  }
8364  } else if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::Match(tok->linkAt(1), ") %name% (") && Token::Match(tok->linkAt(1)->linkAt(2), ") [;{]")) {
8365  if (!(tok->linkAt(1)->next() && tok->linkAt(1)->next()->isKeyword())) { // e.g. noexcept(true)
8366  if (possible.count(tok->str()) == 0)
8367  possible.insert(tok->str());
8368  else
8369  unknownMacroError(tok);
8370  }
8371  } else if (isCPP() && Token::Match(tok, "public|private|protected %name% :")) {
8372  unknownMacroError(tok->next());
8373  }
8374  }
8375 
8376  // String concatenation with unknown macros
8377  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8378  if ((Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) ||
8379  (Token::Match(tok, "%str% %name% %str%") && !(startsWith(tok->strAt(1), "PRI") || startsWith(tok->strAt(1), "SCN")))) { // TODO: implement macros in std.cfg
8380  if (tok->next()->isKeyword())
8381  continue;
8382  unknownMacroError(tok->next());
8383  }
8384  if (Token::Match(tok, "[(,] %name% (") && Token::Match(tok->linkAt(2), ") %name% %name%|,|)")) {
8385  if (tok->next()->isKeyword() || tok->linkAt(2)->next()->isKeyword())
8386  continue;
8387  if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
8388  continue;
8389  if (startsWith(tok->next()->str(), "__")) // attribute/annotation
8390  continue;
8391  unknownMacroError(tok->next());
8392  }
8393  }
8394 
8395  // Report unknown macros without commas or operators inbetween statements: MACRO1() MACRO2()
8396  for (const Token* tok = tokens(); tok; tok = tok->next()) {
8397  if (!Token::Match(tok, "%name% ("))
8398  continue;
8399  if (isNonMacro(tok) && !tok->isStandardType())
8400  continue;
8401 
8402  const Token* endTok = tok->linkAt(1);
8403  if (!Token::Match(endTok, ") %name% (|."))
8404  continue;
8405 
8406  const Token* tok2 = endTok->next();
8407  if (isNonMacro(tok2))
8408  continue;
8409 
8410  if (tok2->next()->str() == "(") {
8411  if (Token::Match(tok->previous(), "%name%|::|>"))
8412  continue;
8413  }
8414 
8415  unknownMacroError(tok->isStandardType() ? tok2 : tok);
8416  }
8417 }
8418 
8419 void Tokenizer::findGarbageCode() const
8420 {
8421  const bool isCPP11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
8422 
8423  static const std::unordered_set<std::string> nonConsecutiveKeywords{ "break",
8424  "continue",
8425  "for",
8426  "goto",
8427  "if",
8428  "return",
8429  "switch",
8430  "throw",
8431  "typedef",
8432  "while" };
8433 
8434  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8435  // initialization: = {
8436  if (Token::simpleMatch(tok, "= {") && Token::simpleMatch(tok->linkAt(1), "} ("))
8437  syntaxError(tok->linkAt(1));
8438 
8439  // Inside [] there can't be ; or various keywords
8440  else if (tok->str() == "[") {
8441  for (const Token* inner = tok->next(); inner != tok->link(); inner = inner->next()) {
8442  if (Token::Match(inner, "(|[|{"))
8443  inner = inner->link();
8444  else if (Token::Match(inner, ";|goto|return|typedef"))
8445  syntaxError(inner);
8446  }
8447  }
8448 
8449  // array assignment
8450  else if (Token::Match(tok, "%assign% [") && Token::simpleMatch(tok->linkAt(1), "] ;"))
8451  syntaxError(tok, tok->str() + "[...];");
8452 
8453  else if (Token::Match(tok, "[({<] %assign%"))
8454  syntaxError(tok);
8455 
8456  else if (Token::Match(tok, "[`\\@]"))
8457  syntaxError(tok);
8458 
8459  // UNKNOWN_MACRO(return)
8460  if (tok->isKeyword() && Token::Match(tok, "throw|return )") && Token::Match(tok->linkAt(1)->previous(), "%name% ("))
8461  unknownMacroError(tok->linkAt(1)->previous());
8462 
8463  // UNKNOWN_MACRO(return)
8464  else if (Token::Match(tok, "%name% throw|return") && std::isupper(tok->str()[0]))
8465  unknownMacroError(tok);
8466 
8467  // Assign/increment/decrement literal
8468  else if (Token::Match(tok, "!!) %num%|%str%|%char% %assign%|++|--")) {
8469  if (!isCPP() || mSettings.standards.cpp < Standards::CPP20 || !Token::Match(tok->previous(), "%name% : %num% ="))
8470  syntaxError(tok, tok->next()->str() + " " + tok->strAt(2));
8471  }
8472  else if (Token::simpleMatch(tok, ") return") && !Token::Match(tok->link()->previous(), "if|while|for (")) {
8473  if (tok->link()->previous() && tok->link()->previous()->isUpperCaseName())
8474  unknownMacroError(tok->link()->previous());
8475  else
8476  syntaxError(tok);
8477  }
8478 
8479  if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for|switch")) { // if|while|for|switch (EXPR) { ... }
8480  if (tok->previous() && !Token::Match(tok->previous(), "%name%|:|;|{|}|)")) {
8481  if (Token::Match(tok->previous(), "[,(]")) {
8482  const Token *prev = tok->previous();
8483  while (prev && prev->str() != "(") {
8484  if (prev->str() == ")")
8485  prev = prev->link();
8486  prev = prev->previous();
8487  }
8488  if (prev && Token::Match(prev->previous(), "%name% ("))
8489  unknownMacroError(prev->previous());
8490  }
8491  if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if"))
8492  syntaxError(tok);
8493  }
8494  if (!Token::Match(tok->next(), "( !!)"))
8495  syntaxError(tok);
8496  if (tok->str() != "for") {
8497  if (isGarbageExpr(tok->next(), tok->linkAt(1), isCPP() && (mSettings.standards.cpp>=Standards::cppstd_t::CPP17)))
8498  syntaxError(tok);
8499  }
8500  }
8501 
8502  // keyword keyword
8503  if (tok->isKeyword() && nonConsecutiveKeywords.count(tok->str()) != 0) {
8504  if (Token::Match(tok, "%name% %name%") && nonConsecutiveKeywords.count(tok->next()->str()) == 1)
8505  syntaxError(tok);
8506  const Token* prev = tok;
8507  while (prev && prev->isName())
8508  prev = prev->previous();
8509  if (Token::Match(prev, "%op%|%num%|%str%|%char%")) {
8510  if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if") &&
8511  !Token::simpleMatch(tok->tokAt(-2), "extern \"C\"") &&
8512  !Token::simpleMatch(prev, "> typedef"))
8513  syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str()));
8514  }
8515  }
8516  }
8517 
8518  // invalid struct declaration
8519  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8520  if (Token::Match(tok, "struct|class|enum %name%| {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
8521  const Token *tok2 = tok->linkAt(tok->next()->isName() ? 2 : 1);
8522  if (Token::Match(tok2, "} %op%")) {
8523  tok2 = tok2->next();
8524  if (!Token::Match(tok2, "*|&|&&"))
8525  syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
8526  while (Token::Match(tok2, "*|&|&&"))
8527  tok2 = tok2->next();
8528  if (!Token::Match(tok2, "%name%"))
8529  syntaxError(tok2, "Unexpected token '" + (tok2 ? tok2->str() : "") + "'");
8530  }
8531  }
8532  if (Token::Match(tok, "enum : %num%| {"))
8533  syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'");
8534  }
8535 
8536  // Keywords in global scope
8537  static const std::unordered_set<std::string> nonGlobalKeywords{"break",
8538  "continue",
8539  "for",
8540  "goto",
8541  "if",
8542  "return",
8543  "switch",
8544  "while",
8545  "try",
8546  "catch"};
8547  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8548  if (tok->str() == "{")
8549  tok = tok->link();
8550  else if (tok->isKeyword() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
8551  syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
8552  }
8553 
8554  // case keyword must be inside switch
8555  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8556  if (Token::simpleMatch(tok, "switch (")) {
8557  if (Token::simpleMatch(tok->linkAt(1), ") {")) {
8558  tok = tok->linkAt(1)->linkAt(1);
8559  continue;
8560  }
8561  const Token *switchToken = tok;
8562  tok = tok->linkAt(1);
8563  if (!tok)
8564  syntaxError(switchToken);
8565  // Look for the end of the switch statement, i.e. the first semi-colon or '}'
8566  for (; tok; tok = tok->next()) {
8567  if (tok->str() == "{") {
8568  tok = tok->link();
8569  }
8570  if (Token::Match(tok, ";|}")) {
8571  // We're at the end of the switch block
8572  if (tok->str() == "}" && tok->strAt(-1) == ":") // Invalid case
8573  syntaxError(switchToken);
8574  break;
8575  }
8576  }
8577  if (!tok)
8578  break;
8579  } else if (tok->str() == "(") {
8580  tok = tok->link();
8581  } else if (tok->str() == "case") {
8582  syntaxError(tok);
8583  }
8584  }
8585 
8586  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8587  if (!Token::simpleMatch(tok, "for (")) // find for loops
8588  continue;
8589  // count number of semicolons
8590  int semicolons = 0, colons = 0;
8591  const Token* const startTok = tok;
8592  tok = tok->next()->link()->previous(); // find ")" of the for-loop
8593  // walk backwards until we find the beginning (startTok) of the for() again
8594  for (; tok != startTok; tok = tok->previous()) {
8595  if (tok->str() == ";") { // do the counting
8596  semicolons++;
8597  } else if (tok->str() == ":") {
8598  colons++;
8599  } else if (tok->str() == ")") { // skip pairs of ( )
8600  tok = tok->link();
8601  }
8602  }
8603  // if we have an invalid number of semicolons inside for( ), assume syntax error
8604  if (semicolons > 2)
8605  syntaxError(tok);
8606  if (semicolons == 1 && !(isCPP() && mSettings.standards.cpp >= Standards::CPP20))
8607  syntaxError(tok);
8608  if (semicolons == 0 && colons == 0)
8609  syntaxError(tok);
8610  }
8611 
8612  // Operators without operands..
8613  const Token *templateEndToken = nullptr;
8614  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8615  if (!templateEndToken) {
8616  if (tok->str() == "<" && isCPP())
8617  templateEndToken = tok->findClosingBracket();
8618  } else {
8619  if (templateEndToken == tok)
8620  templateEndToken = nullptr;
8621  if (Token::Match(tok, "> %cop%"))
8622  continue;
8623  }
8624  // skip C++ attributes [[...]]
8625  if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok))) {
8626  tok = skipCPPOrAlignAttribute(tok);
8627  continue;
8628  }
8629  {
8630  bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
8631  bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
8632  if (isCPP()) {
8633  match1 = match1 || Token::Match(tok, "throw|decltype|typeof");
8634  match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
8635  }
8636  if (match1 && !tok->isIncDecOp()) {
8637  match2 = match2 || Token::Match(tok->next(), "%assign%");
8638  }
8639  if (match1 && match2)
8640  syntaxError(tok);
8641  }
8642  if (Token::Match(tok, "%or%|%oror%|~|^|!|%comp%|+|-|/|%")) {
8643  std::string code;
8644  if (Token::Match(tok->next(), ")|]|}"))
8645  code = tok->str() + tok->next()->str();
8646  if (Token::simpleMatch(tok->next(), "( )"))
8647  code = tok->str() + "()";
8648  if (!code.empty()) {
8649  if (isC() || (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")))
8650  syntaxError(tok, code);
8651  }
8652  }
8653  if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
8654  syntaxError(tok);
8655  if (Token::Match(tok, "%assign% typename|class %assign%"))
8656  syntaxError(tok);
8657  if (Token::Match(tok, "%assign% [;)}]") && (!isCPP() || !Token::simpleMatch(tok->previous(), "operator")))
8658  syntaxError(tok);
8659  if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%"))
8660  syntaxError(tok);
8661  if (Token::Match(tok, "[;([{] %comp%|%oror%|%or%|%|/"))
8662  syntaxError(tok);
8663  if (Token::Match(tok, "%cop%|= ]") && !(isCPP() && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]")))
8664  syntaxError(tok);
8665  if (Token::Match(tok, "[+-] [;,)]}]") && !(isCPP() && Token::simpleMatch(tok->previous(), "operator")))
8666  syntaxError(tok);
8667  if (Token::simpleMatch(tok, ",") &&
8668  !Token::Match(tok->tokAt(-2), "[ = , &|%name%")) {
8669  if (Token::Match(tok->previous(), "(|[|{|<|%assign%|%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|::|sizeof"))
8670  syntaxError(tok);
8671  if (isCPP() && Token::Match(tok->previous(), "throw|decltype|typeof"))
8672  syntaxError(tok);
8673  if (Token::Match(tok->next(), ")|]|>|%assign%|%or%|%oror%|==|!=|/|>=|<=|&&"))
8674  syntaxError(tok);
8675  }
8676  if ((!isCPP() || !Token::simpleMatch(tok->previous(), "operator")) && Token::Match(tok, "[,;] ,"))
8677  syntaxError(tok);
8678  if (Token::simpleMatch(tok, ".") &&
8679  !Token::simpleMatch(tok->previous(), ".") &&
8680  !Token::simpleMatch(tok->next(), ".") &&
8681  !Token::Match(tok->previous(), "{|, . %name% =|.|[|{") &&
8682  !Token::Match(tok->previous(), ", . %name%")) {
8683  if (!Token::Match(tok->previous(), "%name%|)|]|>|}"))
8684  syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8685  if (!Token::Match(tok->next(), "%name%|*|~"))
8686  syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8687  }
8688  if (Token::Match(tok, "[!|+-/%^~] )|]"))
8689  syntaxError(tok);
8690  if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
8691  syntaxError(tok, tok->str() + " " + tok->strAt(1));
8692  if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") ||
8693  (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator"))))
8694  syntaxError(tok);
8695  if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">")
8696  syntaxError(tok);
8697  if (Token::Match(tok, "^ %op%") && !Token::Match(tok->next(), "[>*+-!~]"))
8698  syntaxError(tok);
8699  if (Token::Match(tok, ": [)]=]"))
8700  syntaxError(tok);
8701  if (Token::Match(tok, "typedef [,;]"))
8702  syntaxError(tok);
8703  if (Token::Match(tok, "! %comp%"))
8704  syntaxError(tok);
8705  if (Token::Match(tok, "] %name%") && (!isCPP() || !(tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), "delete ["))))
8706  syntaxError(tok);
8707 
8708  if (tok->link() && Token::Match(tok, "[([]") && (!tok->tokAt(-1) || !tok->tokAt(-1)->isControlFlowKeyword())) {
8709  const Token* const end = tok->link();
8710  for (const Token* inner = tok->next(); inner != end; inner = inner->next()) {
8711  if (inner->str() == "{")
8712  inner = inner->link();
8713  else if (inner->str() == ";") {
8714  if (tok->tokAt(-1) && tok->tokAt(-1)->isUpperCaseName())
8715  unknownMacroError(tok->tokAt(-1));
8716  else
8717  syntaxError(inner);
8718  }
8719  }
8720  }
8721  }
8722 
8723  // ternary operator without :
8724  if (const Token *ternaryOp = findUnmatchedTernaryOp(tokens(), nullptr))
8725  syntaxError(ternaryOp);
8726 
8727  // Code must not start with an arithmetical operand
8728  if (Token::Match(list.front(), "%cop%"))
8729  syntaxError(list.front());
8730 
8731  // Code must end with } ; ) NAME
8732  if (!Token::Match(list.back(), "%name%|;|}|)"))
8733  syntaxError(list.back());
8734  if (list.back()->str() == ")" && !Token::Match(list.back()->link()->previous(), "%name%|> ("))
8735  syntaxError(list.back());
8736  for (const Token *end = list.back(); end && end->isName(); end = end->previous()) {
8737  if (Token::Match(end, "void|char|short|int|long|float|double|const|volatile|static|inline|struct|class|enum|union|template|sizeof|case|break|continue|typedef"))
8738  syntaxError(list.back());
8739  }
8740  if ((list.back()->str()==")" || list.back()->str()=="}") && list.back()->previous() && list.back()->previous()->isControlFlowKeyword())
8741  syntaxError(list.back()->previous());
8742 
8743  // Garbage templates..
8744  if (isCPP()) {
8745  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8746  if (!Token::simpleMatch(tok, "template <"))
8747  continue;
8748  if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) {
8749  if (tok->previous()->isUpperCaseName())
8750  unknownMacroError(tok->previous());
8751  else
8752  syntaxError(tok);
8753  }
8754  const Token * const tok1 = tok;
8755  tok = tok->next()->findClosingBracket();
8756  if (!tok)
8757  syntaxError(tok1);
8758  if (!Token::Match(tok, ">|>> ::|...| %name%") &&
8759  !Token::Match(tok, ">|>> [ [ %name%") &&
8760  !Token::Match(tok, "> >|*"))
8761  syntaxError(tok->next() ? tok->next() : tok1);
8762  }
8763  }
8764 
8765  // Objective C/C++
8766  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8767  if (Token::Match(tok, "[;{}] [ %name% %name% ] ;"))
8768  syntaxError(tok->next());
8769  }
8770 }
8771 
8772 
8773 bool Tokenizer::isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
8774 {
8775  for (const Token *tok = start; tok != end; tok = tok->next()) {
8776  if (tok->isControlFlowKeyword())
8777  return true;
8778  if (!allowSemicolon && tok->str() == ";")
8779  return true;
8780  if (tok->str() == "{")
8781  tok = tok->link();
8782  }
8783  return false;
8784 }
8785 
8786 std::string Tokenizer::simplifyString(const std::string &source)
8787 {
8788  std::string str = source;
8789 
8790  for (std::string::size_type i = 0; i + 1U < str.size(); ++i) {
8791  if (str[i] != '\\')
8792  continue;
8793 
8794  int c = 'a'; // char
8795  int sz = 0; // size of stringdata
8796  if (str[i+1] == 'x') {
8797  sz = 2;
8798  while (sz < 4 && std::isxdigit((unsigned char)str[i+sz]))
8799  sz++;
8800  if (sz > 2) {
8801  std::istringstream istr(str.substr(i+2, sz-2));
8802  istr >> std::hex >> c;
8803  }
8804  } else if (MathLib::isOctalDigit(str[i+1])) {
8805  sz = 2;
8806  while (sz < 4 && MathLib::isOctalDigit(str[i+sz]))
8807  sz++;
8808  std::istringstream istr(str.substr(i+1, sz-1));
8809  istr >> std::oct >> c;
8810  str = str.replace(i, sz, std::string(1U, (char)c));
8811  continue;
8812  }
8813 
8814  if (sz <= 2)
8815  i++;
8816  else if (i+sz < str.size())
8817  str.replace(i, sz, std::string(1U, (char)c));
8818  else
8819  str.replace(i, str.size() - i - 1U, "a");
8820  }
8821 
8822  return str;
8823 }
8824 
8826 {
8827  if (!isCPP())
8828  return;
8829 
8830  for (Token * tok = list.front(); tok; tok = tok->next()) {
8831  if (!Token::Match(tok, "try {|:"))
8832  continue;
8833  if (!isFunctionHead(tok->previous(), "try"))
8834  continue;
8835 
8836  Token* tryStartToken = skipInitializerList(tok->next());
8837 
8838  if (!Token::simpleMatch(tryStartToken, "{"))
8839  syntaxError(tryStartToken, "Invalid function-try-catch block code. Did not find '{' for try body.");
8840 
8841  // find the end of the last catch block
8842  Token * const tryEndToken = tryStartToken->link();
8843  Token * endToken = tryEndToken;
8844  while (Token::simpleMatch(endToken, "} catch (")) {
8845  endToken = endToken->linkAt(2)->next();
8846  if (!endToken)
8847  break;
8848  if (endToken->str() != "{") {
8849  endToken = nullptr;
8850  break;
8851  }
8852  endToken = endToken->link();
8853  }
8854  if (!endToken || endToken == tryEndToken)
8855  continue;
8856 
8857  tok->previous()->insertToken("{");
8858  endToken->insertToken("}");
8859  Token::createMutualLinks(tok->previous(), endToken->next());
8860  }
8861 }
8862 
8863 static bool isAnonymousEnum(const Token* tok)
8864 {
8865  if (!Token::Match(tok, "enum {|:"))
8866  return false;
8867  if (tok->index() > 2 && Token::Match(tok->tokAt(-3), "using %name% ="))
8868  return false;
8869  const Token* end = tok->next();
8870  if (end->str() == ":") {
8871  end = end->next();
8872  while (Token::Match(end, "%name%|::"))
8873  end = end->next();
8874  }
8875  return end && Token::Match(end->link(), "} (| %type%| )| [,;[({=]");
8876 }
8877 
8879 {
8880  const bool cpp = isCPP();
8881 
8882  // A counter that is used when giving unique names for anonymous structs.
8883  int count = 0;
8884 
8885  // Add names for anonymous structs
8886  for (Token *tok = list.front(); tok; tok = tok->next()) {
8887  if (!tok->isName())
8888  continue;
8889  // check for anonymous struct/union
8890  if (Token::Match(tok, "struct|union {")) {
8891  if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) {
8892  tok->insertToken("Anonymous" + std::to_string(count++));
8893  }
8894  }
8895  // check for derived anonymous class/struct
8896  else if (cpp && Token::Match(tok, "class|struct :")) {
8897  const Token *tok1 = Token::findsimplematch(tok, "{");
8898  if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) {
8899  tok->insertToken("Anonymous" + std::to_string(count++));
8900  }
8901  }
8902  // check for anonymous enum
8903  else if (isAnonymousEnum(tok)) {
8904  Token *start = tok->strAt(1) == ":" ? tok->linkAt(3) : tok->linkAt(1);
8905  if (start && Token::Match(start->next(), "( %type% )")) {
8906  start->next()->link()->deleteThis();
8907  start->next()->deleteThis();
8908  }
8909  tok->insertToken("Anonymous" + std::to_string(count++));
8910  }
8911  }
8912 
8913  // "{" token for current scope
8914  std::stack<const Token*> scopeStart;
8915  const Token* functionEnd = nullptr;
8916 
8917  for (Token *tok = list.front(); tok; tok = tok->next()) {
8918 
8919  // check for start of scope and determine if it is in a function
8920  if (tok->str() == "{") {
8921  scopeStart.push(tok);
8922  if (!functionEnd && Token::Match(tok->previous(), "const|)"))
8923  functionEnd = tok->link();
8924  }
8925 
8926  // end of scope
8927  else if (tok->str() == "}") {
8928  if (!scopeStart.empty())
8929  scopeStart.pop();
8930  if (tok == functionEnd)
8931  functionEnd = nullptr;
8932  }
8933 
8934  // check for named struct/union
8935  else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
8936  Token *start = tok;
8937  while (Token::Match(start->previous(), "%type%"))
8938  start = start->previous();
8939  const Token * const type = tok->next();
8940  Token *next = tok->tokAt(2);
8941 
8942  while (next && !Token::Match(next, "[{;]"))
8943  next = next->next();
8944  if (!next || next->str() == ";")
8945  continue;
8946  Token* after = next->link();
8947  if (!after)
8948  break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8949 
8950  // check for named type
8951  if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
8952  after->insertToken(";");
8953  after = after->next();
8954  while (!Token::Match(start, "struct|class|union|enum")) {
8955  after->insertToken(start->str());
8956  after = after->next();
8957  start->deleteThis();
8958  }
8959  tok = start;
8960  if (!after)
8961  break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8962  after->insertToken(type->str());
8963  if (start->str() != "class") {
8964  after->insertToken(start->str());
8965  after = after->next();
8966  }
8967 
8968  after = after->tokAt(2);
8969 
8970  if (Token::Match(after, "( %type% )")) {
8971  after->link()->deleteThis();
8972  after->deleteThis();
8973  }
8974 
8975  // check for initialization
8976  if (Token::Match(after, "%any% (|{")) {
8977  after->insertToken("=");
8978  after = after->next();
8979  const bool isEnum = start->str() == "enum";
8980  if (!isEnum && cpp) {
8981  after->insertToken(type->str());
8982  after = after->next();
8983  }
8984 
8985  if (isEnum) {
8986  if (Token::Match(after->next(), "{ !!}")) {
8987  after->next()->str("(");
8988  after->linkAt(1)->str(")");
8989  }
8990  }
8991  }
8992  }
8993  }
8994 
8995  // check for anonymous struct/union
8996  else {
8997  // unnamed anonymous struct/union so possibly remove it
8998  bool done = false;
8999  while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
9000  done = true;
9001 
9002  // is this a class/struct/union scope?
9003  bool isClassStructUnionScope = false;
9004  if (!scopeStart.empty()) {
9005  for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
9006  if (Token::Match(tok2, "class|struct|union")) {
9007  isClassStructUnionScope = true;
9008  break;
9009  }
9010  }
9011  }
9012 
9013  // remove unnamed anonymous struct/union
9014  // * not in class/struct/union scopes
9015  if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
9016  tok->linkAt(1)->previous()->deleteNext(2);
9017  tok->deleteNext();
9018  tok->deleteThis();
9019  done = false;
9020  }
9021  }
9022  }
9023  }
9024 }
9025 
9027 {
9028  const bool windows = mSettings.platform.isWindows();
9029 
9030  for (Token *tok = list.front(); tok; tok = tok->next()) {
9031  while (Token::Match(tok, "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near") || (windows && Token::Match(tok, "WINAPI|APIENTRY|CALLBACK"))) {
9032  tok->deleteThis();
9033  }
9034  }
9035 }
9036 
9037 static bool isAttribute(const Token* tok, bool gcc) {
9038  return gcc ? Token::Match(tok, "__attribute__|__attribute (") : Token::Match(tok, "__declspec|_declspec (");
9039 }
9040 
9041 static Token* getTokenAfterAttributes(Token* tok, bool gccattr) {
9042  Token* after = tok;
9043  while (isAttribute(after, gccattr))
9044  after = after->linkAt(1)->next();
9045  return after;
9046 }
9047 
9048 Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
9049  if (!Token::Match(tok, "%name% ("))
9050  return nullptr;
9051  Token* const after = getTokenAfterAttributes(tok, gccattr);
9052  if (!after)
9053  syntaxError(tok);
9054 
9055  if (Token::Match(after, "%name%|*|&|(")) {
9056  Token *ftok = after;
9057  while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
9058  if (ftok->str() == "<") {
9059  ftok = ftok->findClosingBracket();
9060  if (!ftok)
9061  break;
9062  }
9063  ftok = ftok->next();
9064  }
9065  if (Token::simpleMatch(ftok, "( *"))
9066  ftok = ftok->tokAt(2);
9067  if (Token::Match(ftok, "%name% (|)"))
9068  return ftok;
9069  } else if (Token::Match(after, "[;{=:]")) {
9070  Token *prev = tok->previous();
9071  while (Token::Match(prev, "%name%"))
9072  prev = prev->previous();
9073  if (Token::simpleMatch(prev, ")")) {
9074  if (Token::Match(prev->link()->previous(), "%name% ("))
9075  return prev->link()->previous();
9076  if (Token::Match(prev->link()->tokAt(-2), "%name% ) ("))
9077  return prev->link()->tokAt(-2);
9078  }
9079  if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
9080  return prev->link()->tokAt(-2);
9081  if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
9082  return tok->previous();
9083  }
9084  return nullptr;
9085 }
9086 
9088 {
9089  for (Token *tok = list.front(); tok; tok = tok->next()) {
9090  while (isAttribute(tok, false)) {
9091  if (Token::Match(tok->tokAt(2), "noreturn|nothrow|dllexport")) {
9092  Token *functok = getAttributeFuncTok(tok, false);
9093  if (functok) {
9094  if (tok->strAt(2) == "noreturn")
9095  functok->isAttributeNoreturn(true);
9096  else if (tok->strAt(2) == "nothrow")
9097  functok->isAttributeNothrow(true);
9098  else
9099  functok->isAttributeExport(true);
9100  }
9101  } else if (tok->strAt(2) == "property")
9102  tok->next()->link()->insertToken("__property");
9103 
9104  Token::eraseTokens(tok, tok->next()->link()->next());
9105  tok->deleteThis();
9106  }
9107  }
9108 }
9109 
9111 {
9112  for (Token *tok = list.front(); tok; tok = tok->next()) {
9113  if (!tok->isKeyword() && Token::Match(tok, "%type% (") && !mSettings.library.isNotLibraryFunction(tok)) {
9114  if (mSettings.library.isFunctionConst(tok->str(), true))
9115  tok->isAttributePure(true);
9116  if (mSettings.library.isFunctionConst(tok->str(), false))
9117  tok->isAttributeConst(true);
9118  }
9119  while (isAttribute(tok, true)) {
9120  Token *functok = getAttributeFuncTok(tok, true);
9121 
9122  for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
9123  if (Token::Match(attr, "%name% ("))
9124  attr = attr->linkAt(1);
9125 
9126  if (Token::Match(attr, "[(,] constructor|__constructor__ [,()]")) {
9127  if (!functok)
9128  syntaxError(tok);
9129  functok->isAttributeConstructor(true);
9130  }
9131 
9132  else if (Token::Match(attr, "[(,] destructor|__destructor__ [,()]")) {
9133  if (!functok)
9134  syntaxError(tok);
9135  functok->isAttributeDestructor(true);
9136  }
9137 
9138  else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
9139  Token *vartok = nullptr;
9140  Token *after = getTokenAfterAttributes(tok, true);
9141 
9142  // check if after variable name
9143  if (Token::Match(after, ";|=")) {
9144  Token *prev = tok->previous();
9145  while (Token::simpleMatch(prev, "]"))
9146  prev = prev->link()->previous();
9147  if (Token::Match(prev, "%type%"))
9148  vartok = prev;
9149  }
9150 
9151  // check if before variable name
9152  else if (Token::Match(after, "%type%"))
9153  vartok = after;
9154 
9155  if (vartok) {
9156  const std::string &attribute(attr->next()->str());
9157  if (attribute.find("unused") != std::string::npos)
9158  vartok->isAttributeUnused(true);
9159  else
9160  vartok->isAttributeUsed(true);
9161  }
9162  }
9163 
9164  else if (Token::Match(attr, "[(,] pure|__pure__|const|__const__|noreturn|__noreturn__|nothrow|__nothrow__|warn_unused_result [,)]")) {
9165  if (!functok)
9166  syntaxError(tok);
9167 
9168  const std::string &attribute(attr->next()->str());
9169  if (attribute.find("pure") != std::string::npos)
9170  functok->isAttributePure(true);
9171  else if (attribute.find("const") != std::string::npos)
9172  functok->isAttributeConst(true);
9173  else if (attribute.find("noreturn") != std::string::npos)
9174  functok->isAttributeNoreturn(true);
9175  else if (attribute.find("nothrow") != std::string::npos)
9176  functok->isAttributeNothrow(true);
9177  else if (attribute.find("warn_unused_result") != std::string::npos)
9178  functok->isAttributeNodiscard(true);
9179  }
9180 
9181  else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
9182  tok->previous()->isAttributePacked(true);
9183 
9184  else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )"))
9185  functok->isAttributeExport(true);
9186  }
9187 
9188  Token::eraseTokens(tok, tok->linkAt(1)->next());
9189  tok->deleteThis();
9190  }
9191  }
9192 }
9193 
9195 {
9196  for (Token *tok = list.front(); tok; tok = tok->next()) {
9197  if (tok->str() != "(")
9198  continue;
9199  if (!tok->previous())
9200  continue;
9201  const std::string &attr = tok->previous()->str();
9202  if (!startsWith(attr, "__cppcheck_"))
9203  continue;
9204  if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
9205  continue;
9206 
9207  Token *vartok = tok->link();
9208  while (Token::Match(vartok->next(), "%name%|*|&|::")) {
9209  vartok = vartok->next();
9210  if (Token::Match(vartok, "%name% (") && startsWith(vartok->str(),"__cppcheck_"))
9211  vartok = vartok->linkAt(1);
9212  }
9213 
9214  if (vartok->isName()) {
9215  if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
9216  vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9217  MathLib::toBigNumber(tok->next()->str()));
9218  else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
9219  vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9220  MathLib::toBigNumber(tok->next()->str()));
9221  }
9222 
9223  // Delete cppcheck attribute..
9224  if (tok->tokAt(-2)) {
9225  tok = tok->tokAt(-2);
9226  Token::eraseTokens(tok, tok->linkAt(2)->next());
9227  } else {
9228  tok = tok->previous();
9229  Token::eraseTokens(tok, tok->linkAt(1)->next());
9230  tok->str(";");
9231  }
9232  }
9233 }
9234 
9236 {
9238  return;
9239 
9240  for (Token *tok = list.front(); tok;) {
9241  if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
9242  tok = tok->next();
9243  continue;
9244  }
9245  if (isCPPAttribute(tok)) {
9246  if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
9247  Token * head = skipCPPOrAlignAttribute(tok)->next();
9248  while (isCPPAttribute(head) || isAlignAttribute(head))
9249  head = skipCPPOrAlignAttribute(head)->next();
9250  while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
9251  head = head->next();
9252  if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9253  head->previous()->isAttributeNoreturn(true);
9254  }
9255  } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
9256  Token * head = skipCPPOrAlignAttribute(tok)->next();
9257  while (isCPPAttribute(head) || isAlignAttribute(head))
9258  head = skipCPPOrAlignAttribute(head)->next();
9259  while (Token::Match(head, "%name%|::|*|&|<|>|,"))
9260  head = head->next();
9261  if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9262  head->previous()->isAttributeNodiscard(true);
9263  }
9264  } else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
9265  Token* head = skipCPPOrAlignAttribute(tok)->next();
9266  while (isCPPAttribute(head) || isAlignAttribute(head))
9267  head = skipCPPOrAlignAttribute(head)->next();
9268  head->isAttributeMaybeUnused(true);
9269  } else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
9270  const Token *vartok = tok->tokAt(4);
9271  if (vartok->str() == ":")
9272  vartok = vartok->next();
9273  Token *argtok = tok->tokAt(-2);
9274  while (argtok && argtok->str() != "(") {
9275  if (argtok->str() == vartok->str())
9276  break;
9277  if (argtok->str() == ")")
9278  argtok = argtok->link();
9279  argtok = argtok->previous();
9280  }
9281  if (argtok && argtok->str() == vartok->str()) {
9282  if (vartok->next()->str() == ">=")
9283  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9284  MathLib::toBigNumber(vartok->strAt(2)));
9285  else if (vartok->next()->str() == ">")
9286  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9287  MathLib::toBigNumber(vartok->strAt(2)) + 1);
9288  else if (vartok->next()->str() == "<=")
9289  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9290  MathLib::toBigNumber(vartok->strAt(2)));
9291  else if (vartok->next()->str() == "<")
9292  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9293  MathLib::toBigNumber(vartok->strAt(2)) - 1);
9294  }
9295  }
9296  } else {
9297  if (Token::simpleMatch(tok, "alignas (")) {
9298  // alignment requirements could be checked here
9299  }
9300  }
9301  Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
9302  tok->deleteThis();
9303  }
9304 }
9305 
9307 {
9309  for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
9310  if (Token::simpleMatch(tok, "<= >")) {
9311  tok->str("<=>");
9312  tok->deleteNext();
9313  }
9314  }
9315  }
9316 }
9317 
9318 static const std::unordered_set<std::string> keywords = {
9319  "inline"
9320  , "_inline"
9321  , "__inline"
9322  , "__forceinline"
9323  , "register"
9324  , "__restrict"
9325  , "__restrict__"
9326  , "__thread"
9327 };
9328 // Remove "inline", "register", "restrict", "override", "static" and "constexpr"
9329 // "restrict" keyword
9330 // - New to 1999 ANSI/ISO C standard
9331 // - Not in C++ standard yet
9333 {
9334  // FIXME: There is a risk that "keywords" are removed by mistake. This
9335  // code should be fixed so it doesn't remove variables etc. Nonstandard
9336  // keywords should be defined with a library instead. For instance the
9337  // linux kernel code at least uses "_inline" as struct member name at some
9338  // places.
9339 
9340  const bool c99 = isC() && mSettings.standards.c >= Standards::C99;
9341  const bool cpp11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
9342  const bool cpp20 = isCPP() && mSettings.standards.cpp >= Standards::CPP20;
9343 
9344  for (Token *tok = list.front(); tok; tok = tok->next()) {
9345  if (keywords.find(tok->str()) != keywords.end()) {
9346  // Don't remove struct members
9347  if (!Token::simpleMatch(tok->previous(), ".")) {
9348  const bool isinline = (tok->str().find("inline") != std::string::npos);
9349  const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
9350  if (isinline || isrestrict) {
9351  for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9352  if (isinline)
9353  temp->isInline(true);
9354  if (isrestrict)
9355  temp->isRestrict(true);
9356  }
9357  }
9358  tok->deleteThis(); // Simplify..
9359  }
9360  }
9361 
9362  if (isC() || mSettings.standards.cpp == Standards::CPP03) {
9363  if (tok->str() == "auto")
9364  tok->deleteThis();
9365  }
9366 
9367  // simplify static keyword:
9368  // void foo( int [ static 5 ] ); ==> void foo( int [ 5 ] );
9369  if (Token::Match(tok, "[ static %num%"))
9370  tok->deleteNext();
9371 
9372  if (c99) {
9373  auto getTypeTokens = [tok]() {
9374  std::vector<Token*> ret;
9375  for (Token *temp = tok; Token::Match(temp, "%name%"); temp = temp->previous()) {
9376  if (!temp->isKeyword())
9377  ret.emplace_back(temp);
9378  }
9379  for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9380  if (!temp->isKeyword())
9381  ret.emplace_back(temp);
9382  }
9383  return ret;
9384  };
9385 
9386  if (tok->str() == "restrict") {
9387  for (Token* temp: getTypeTokens())
9388  temp->isRestrict(true);
9389  tok->deleteThis();
9390  }
9391 
9393  while (tok->str() == "_Atomic") {
9394  for (Token* temp: getTypeTokens())
9395  temp->isAtomic(true);
9396  tok->deleteThis();
9397  }
9398  }
9399  }
9400 
9401  else if (cpp11) {
9402  if (cpp20 && tok->str() == "consteval") {
9403  tok->originalName(tok->str());
9404  tok->str("constexpr");
9405  } else if (cpp20 && tok->str() == "constinit") {
9406  tok->deleteThis();
9407  }
9408 
9409  // final:
9410  // 1) struct name final { }; <- struct is final
9411  if (Token::Match(tok->previous(), "struct|class|union %type%")) {
9412  Token* finalTok = tok->next();
9413  if (tok->isUpperCaseName() && Token::Match(finalTok, "%type%") && finalTok->str() != "final") {
9414  tok = finalTok;
9415  finalTok = finalTok->next();
9416  }
9417  if (Token::simpleMatch(finalTok, "<")) { // specialization
9418  finalTok = finalTok->findClosingBracket();
9419  if (finalTok)
9420  finalTok = finalTok->next();
9421  }
9422  if (Token::Match(finalTok, "final [:{]")) {
9423  finalTok->deleteThis();
9424  tok->previous()->isFinalType(true);
9425  }
9426  }
9427 
9428  // noexcept -> noexcept(true)
9429  // 2) void f() noexcept; -> void f() noexcept(true);
9430  else if (Token::Match(tok, ") const|override|final| noexcept :|{|;|,|const|override|final")) {
9431  // Insertion is done in inverse order
9432  // The brackets are linked together accordingly afterwards
9433  Token* tokNoExcept = tok->next();
9434  while (tokNoExcept->str() != "noexcept")
9435  tokNoExcept = tokNoExcept->next();
9436  tokNoExcept->insertToken(")");
9437  Token * braceEnd = tokNoExcept->next();
9438  tokNoExcept->insertToken("true");
9439  tokNoExcept->insertToken("(");
9440  Token * braceStart = tokNoExcept->next();
9441  tok = tok->tokAt(3);
9442  Token::createMutualLinks(braceStart, braceEnd);
9443  }
9444 
9445  // 3) thread_local -> static
9446  // on single thread thread_local has the effect of static
9447  else if (tok->str() == "thread_local") {
9448  tok->originalName(tok->str());
9449  tok->str("static");
9450  }
9451  }
9452  }
9453 }
9454 
9455 static Token* setTokenDebug(Token* start, TokenDebug td)
9456 {
9457  if (!start->link())
9458  return nullptr;
9459  Token* end = start->link();
9460  start->deleteThis();
9461  for (Token* tok = start; tok != end; tok = tok->next()) {
9462  tok->setTokenDebug(td);
9463  }
9464  end->deleteThis();
9465  return end;
9466 }
9467 
9469 {
9471  return;
9472  static const std::unordered_map<std::string, TokenDebug> m = {{"debug_valueflow", TokenDebug::ValueFlow},
9473  {"debug_valuetype", TokenDebug::ValueType}};
9474  for (Token* tok = list.front(); tok; tok = tok->next()) {
9475  if (!Token::Match(tok, "%name% ("))
9476  continue;
9477  auto it = m.find(tok->str());
9478  if (it != m.end()) {
9479  tok->deleteThis();
9480  tok = setTokenDebug(tok, it->second);
9481  }
9482  }
9483 }
9484 
9486 {
9487  for (Token *tok = list.front(); tok; tok = tok->next()) {
9488  if (Token::Match(tok, "[;{}] %name% = ( {")) {
9489  const std::string &varname = tok->next()->str();
9490 
9491  // goto the "} )"
9492  int indentlevel = 0;
9493  Token *tok2 = tok;
9494  while (nullptr != (tok2 = tok2->next())) {
9495  if (Token::Match(tok2, "(|{"))
9496  ++indentlevel;
9497  else if (Token::Match(tok2, ")|}")) {
9498  if (indentlevel <= 2)
9499  break;
9500  --indentlevel;
9501  } else if (indentlevel == 2 && tok2->str() == varname && Token::Match(tok2->previous(), "%type%|*"))
9502  // declaring variable in inner scope with same name as lhs variable
9503  break;
9504  }
9505  if (indentlevel == 2 && Token::simpleMatch(tok2, "} )")) {
9506  tok2 = tok2->tokAt(-3);
9507  if (Token::Match(tok2, "[;{}] %num%|%name% ;")) {
9508  tok2->insertToken("=");
9509  tok2->insertToken(tok->next()->str());
9510  tok2->next()->varId(tok->next()->varId());
9511  tok->deleteNext(3);
9512  tok2->tokAt(5)->deleteNext();
9513  }
9514  }
9515  }
9516  }
9517 }
9518 
9519 // Remove __asm..
9521 {
9522  std::string instruction;
9523  for (Token *tok = list.front(); tok; tok = tok->next()) {
9524  if (Token::Match(tok, "__asm|_asm|asm {") &&
9525  tok->next()->link()->next()) {
9526  instruction = tok->tokAt(2)->stringifyList(tok->next()->link());
9527  Token::eraseTokens(tok, tok->next()->link()->next());
9528  }
9529 
9530  else if (Token::Match(tok, "asm|__asm|__asm__ volatile|__volatile|__volatile__| (")) {
9531  // Goto "("
9532  Token *partok = tok->next();
9533  if (partok->str() != "(")
9534  partok = partok->next();
9535  instruction = partok->next()->stringifyList(partok->link());
9536  Token::eraseTokens(tok, partok->link()->next());
9537  }
9538 
9539  else if (Token::Match(tok, "_asm|__asm")) {
9540  Token *endasm = tok->next();
9541  const Token *firstSemiColon = nullptr;
9542  int comment = 0;
9543  while (Token::Match(endasm, "%num%|%name%|,|:|;") || (endasm && endasm->linenr() == comment)) {
9544  if (Token::Match(endasm, "_asm|__asm|__endasm"))
9545  break;
9546  if (endasm->str() == ";") {
9547  comment = endasm->linenr();
9548  if (!firstSemiColon)
9549  firstSemiColon = endasm;
9550  }
9551  endasm = endasm->next();
9552  }
9553  if (Token::simpleMatch(endasm, "__endasm")) {
9554  instruction = tok->next()->stringifyList(endasm);
9555  Token::eraseTokens(tok, endasm->next());
9556  if (!Token::simpleMatch(tok->next(), ";"))
9557  tok->insertToken(";");
9558  } else if (firstSemiColon) {
9559  instruction = tok->next()->stringifyList(firstSemiColon);
9560  Token::eraseTokens(tok, firstSemiColon);
9561  } else if (!endasm) {
9562  instruction = tok->next()->stringifyList(endasm);
9563  Token::eraseTokens(tok, endasm);
9564  tok->insertToken(";");
9565  } else
9566  continue;
9567  }
9568 
9569  else
9570  continue;
9571 
9572  if (Token::Match(tok->previous(), ") %name% %name% (")) {
9573  tok->deleteThis();
9574  continue;
9575  }
9576 
9577  // insert "asm ( "instruction" )"
9578  tok->str("asm");
9579  if (tok->strAt(1) != ";" && tok->strAt(1) != "{")
9580  tok->insertToken(";");
9581  tok->insertToken(")");
9582  tok->insertToken("\"" + instruction + "\"");
9583  tok->insertToken("(");
9584 
9585  tok = tok->next();
9586  Token::createMutualLinks(tok, tok->tokAt(2));
9587 
9588  //move the new tokens in the same line as ";" if available
9589  tok = tok->tokAt(2);
9590  if (tok->next() && tok->next()->str() == ";" &&
9591  tok->next()->linenr() != tok->linenr()) {
9592  const int endposition = tok->next()->linenr();
9593  tok = tok->tokAt(-3);
9594  for (int i = 0; i < 4; ++i) {
9595  tok = tok->next();
9596  tok->linenr(endposition);
9597  }
9598  }
9599  }
9600 }
9601 
9603 {
9604  // Block declarations: ^{}
9605  // A C extension used to create lambda like closures.
9606 
9607  // Put ^{} statements in asm()
9608  for (Token *tok = list.front(); tok; tok = tok->next()) {
9609  if (tok->str() != "^")
9610  continue;
9611 
9612  if (Token::simpleMatch(tok, "^ {") || (Token::simpleMatch(tok->linkAt(1), ") {") && tok->strAt(-1) != "operator")) {
9613  Token * start = tok;
9614  while (start && !Token::Match(start, "[,(;{}=]")) {
9615  if (start->link() && Token::Match(start, ")|]|>"))
9616  start = start->link();
9617  start = start->previous();
9618  }
9619 
9620  const Token *last = tok->next()->link();
9621  if (Token::simpleMatch(last, ") {"))
9622  last = last->linkAt(1);
9623  last = last->next();
9624  while (last && !Token::Match(last, "%cop%|,|;|{|}|)")) {
9625  if (Token::Match(last, "(|["))
9626  last = last->link();
9627  last = last->next();
9628  }
9629 
9630  if (start && last) {
9631  std::string asmcode;
9632  while (start->next() != last) {
9633  asmcode += start->next()->str();
9634  start->deleteNext();
9635  }
9636  if (last->str() == "}")
9637  start->insertToken(";");
9638  start->insertToken(")");
9639  start->insertToken("\"" + asmcode + "\"");
9640  start->insertToken("(");
9641  start->insertToken("asm");
9642  start->tokAt(2)->link(start->tokAt(4));
9643  start->tokAt(4)->link(start->tokAt(2));
9644  tok = start->tokAt(4);
9645  }
9646  }
9647  }
9648 }
9649 
9650 void Tokenizer::simplifyAt()
9651 {
9652  std::set<std::string> var;
9653 
9654  for (Token *tok = list.front(); tok; tok = tok->next()) {
9655  if (Token::Match(tok, "%name%|] @ %num%|%name%|%str%|(")) {
9656  const Token *end = tok->tokAt(2);
9657  if (end->isLiteral())
9658  end = end->next();
9659  else if (end->str() == "(") {
9660  int par = 0;
9661  while ((end = end->next()) != nullptr) {
9662  if (end->str() == "(")
9663  par++;
9664  else if (end->str() == ")") {
9665  if (--par < 0)
9666  break;
9667  }
9668  }
9669  end = end ? end->next() : nullptr;
9670  } else if (var.find(end->str()) != var.end())
9671  end = end->next();
9672  else
9673  continue;
9674 
9675  if (Token::Match(end, ": %num% ;"))
9676  end = end->tokAt(2);
9677 
9678  if (Token::Match(end, "[;=]")) {
9679  if (tok->isName())
9680  var.insert(tok->str());
9681  tok->isAtAddress(true);
9682  Token::eraseTokens(tok, end);
9683  }
9684  }
9685 
9686  // keywords in compiler from cosmic software for STM8
9687  // TODO: Should use platform configuration.
9688  if (Token::Match(tok, "@ builtin|eeprom|far|inline|interrupt|near|noprd|nostack|nosvf|packed|stack|svlreg|tiny|vector")) {
9689  tok->str(tok->next()->str() + "@");
9690  tok->deleteNext();
9691  }
9692  }
9693 }
9694 
9695 // Simplify bitfields
9697 {
9698  bool goback = false;
9699  for (Token *tok = list.front(); tok; tok = tok->next()) {
9700  if (goback) {
9701  goback = false;
9702  tok = tok->previous();
9703  }
9704  Token *last = nullptr;
9705 
9706  if (Token::simpleMatch(tok, "for ("))
9707  tok = tok->linkAt(1);
9708 
9709  if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
9710  continue;
9711 
9712  bool isEnum = false;
9713  if (tok->str() == "}") {
9714  const Token *type = tok->link()->previous();
9715  while (type && type->isName()) {
9716  if (type->str() == "enum") {
9717  isEnum = true;
9718  break;
9719  }
9720  type = type->previous();
9721  }
9722  }
9723 
9724  if (Token::Match(tok->next(), "const| %type% %name% :") &&
9725  !Token::Match(tok->next(), "case|public|protected|private|class|struct") &&
9726  !Token::simpleMatch(tok->tokAt(2), "default :")) {
9727  Token *tok1 = (tok->next()->str() == "const") ? tok->tokAt(3) : tok->tokAt(2);
9728  if (Token::Match(tok1, "%name% : %num% [;=]"))
9729  tok1->setBits(MathLib::toBigNumber(tok1->strAt(2)));
9730  if (tok1 && tok1->tokAt(2) &&
9731  (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
9732  !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
9733  while (tok1->next() && !Token::Match(tok1->next(), "[;,)]{}=]")) {
9734  if (Token::Match(tok1->next(), "[([]"))
9735  Token::eraseTokens(tok1, tok1->next()->link());
9736  tok1->deleteNext();
9737  }
9738 
9739  last = tok1->next();
9740  }
9741  } else if (isEnum && Token::Match(tok, "} %name%| : %num% ;")) {
9742  if (tok->next()->str() == ":") {
9743  tok->deleteNext(2);
9744  tok->insertToken("Anonymous");
9745  } else {
9746  tok->next()->deleteNext(2);
9747  }
9748  } else if (Token::Match(tok->next(), "const| %type% : %num%|%bool% ;") &&
9749  tok->next()->str() != "default") {
9750  const int offset = (tok->next()->str() == "const") ? 1 : 0;
9751  if (!Token::Match(tok->tokAt(3 + offset), "[{};()]")) {
9752  tok->deleteNext(4 + offset);
9753  goback = true;
9754  }
9755  }
9756 
9757  if (last && last->str() == ",") {
9758  Token * tok1 = last;
9759  tok1->str(";");
9760 
9761  const Token *const tok2 = tok->next();
9762  tok1->insertToken(tok2->str());
9763  tok1 = tok1->next();
9764  tok1->isSigned(tok2->isSigned());
9765  tok1->isUnsigned(tok2->isUnsigned());
9766  tok1->isLong(tok2->isLong());
9767  }
9768  }
9769 }
9770 
9771 static bool isStdContainerOrIterator(const Token* tok, const Settings& settings)
9772 {
9773  const Library::Container* ctr = settings.library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true);
9774  return ctr && startsWith(ctr->startPattern, "std ::");
9775 }
9776 
9777 static bool isStdSmartPointer(const Token* tok, const Settings& settings)
9778 {
9779  const Library::SmartPointer* ptr = settings.library.detectSmartPointer(tok, /*withoutStd*/ true);
9780  return ptr && startsWith(ptr->name, "std::");
9781 }
9782 
9783 // Add std:: in front of std classes, when using namespace std; was given
9785 {
9786  if (!isCPP())
9787  return;
9788 
9789  std::set<std::string> userFunctions;
9790 
9791  for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
9792  bool insert = false;
9793  if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
9794  skipEnumBody(tok);
9795  }
9796  if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId())
9797  continue;
9798  if (Token::Match(tok->previous(), ".|::|namespace"))
9799  continue;
9800  if (Token::simpleMatch(tok->next(), "(")) {
9801  if (isFunctionHead(tok->next(), "{"))
9802  userFunctions.insert(tok->str());
9803  else if (isFunctionHead(tok->next(), ";")) {
9804  const Token *start = tok;
9805  while (Token::Match(start->previous(), "%type%|*|&"))
9806  start = start->previous();
9807  if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
9808  userFunctions.insert(tok->str());
9809  }
9810  if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str()))
9811  insert = true;
9812  } else if (Token::simpleMatch(tok->next(), "<") &&
9813  (isStdContainerOrIterator(tok, mSettings) || isStdSmartPointer(tok, mSettings)))
9814  insert = true;
9815  else if (mSettings.library.hasAnyTypeCheck("std::" + tok->str()) ||
9816  mSettings.library.podtype("std::" + tok->str()) ||
9817  isStdContainerOrIterator(tok, mSettings))
9818  insert = true;
9819 
9820  if (insert) {
9821  tok->previous()->insertToken("std");
9822  tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
9823  tok->previous()->fileIndex(tok->fileIndex());
9824  tok->previous()->insertToken("::");
9825  }
9826  }
9827 
9828  for (Token* tok = list.front(); tok; tok = tok->next()) {
9829  if (Token::simpleMatch(tok, "using namespace std ;")) {
9830  Token::eraseTokens(tok, tok->tokAt(4));
9831  tok->deleteThis();
9832  }
9833  }
9834 }
9835 
9836 
9838 {
9839  // skip if not Windows
9840  if (!mSettings.platform.isWindows())
9841  return;
9842 
9843  for (Token *tok = list.front(); tok; tok = tok->next()) {
9844  if (tok->strAt(1) != "(")
9845  continue;
9846 
9847  if (Token::Match(tok, "CopyMemory|RtlCopyMemory|RtlCopyBytes")) {
9848  tok->str("memcpy");
9849  } else if (Token::Match(tok, "MoveMemory|RtlMoveMemory")) {
9850  tok->str("memmove");
9851  } else if (Token::Match(tok, "FillMemory|RtlFillMemory|RtlFillBytes")) {
9852  // FillMemory(dst, len, val) -> memset(dst, val, len)
9853  tok->str("memset");
9854 
9855  Token *tok1 = tok->tokAt(2);
9856  if (tok1)
9857  tok1 = tok1->nextArgument(); // Second argument
9858  if (tok1) {
9859  Token *tok2 = tok1->nextArgument(); // Third argument
9860 
9861  if (tok2)
9862  Token::move(tok1->previous(), tok2->tokAt(-2), tok->next()->link()->previous()); // Swap third with second argument
9863  }
9864  } else if (Token::Match(tok, "ZeroMemory|RtlZeroMemory|RtlZeroBytes|RtlSecureZeroMemory")) {
9865  // ZeroMemory(dst, len) -> memset(dst, 0, len)
9866  tok->str("memset");
9867 
9868  Token *tok1 = tok->tokAt(2);
9869  if (tok1)
9870  tok1 = tok1->nextArgument(); // Second argument
9871 
9872  if (tok1) {
9873  tok1 = tok1->previous();
9874  tok1->insertToken("0");
9875  tok1 = tok1->next();
9876  tok1->insertToken(",");
9877  }
9878  } else if (Token::simpleMatch(tok, "RtlCompareMemory")) {
9879  // RtlCompareMemory(src1, src2, len) -> memcmp(src1, src2, len)
9880  tok->str("memcmp");
9881  // For the record, when memcmp returns 0, both strings are equal.
9882  // When RtlCompareMemory returns len, both strings are equal.
9883  // It might be needed to improve this replacement by something
9884  // like ((len - memcmp(src1, src2, len)) % (len + 1)) to
9885  // respect execution path (if required)
9886  }
9887  }
9888 }
9889 
9890 namespace {
9891  struct triplet {
9892  triplet(const char* m, const char* u) : mbcs(m), unicode(u) {}
9893  std::string mbcs, unicode;
9894  };
9895 
9896  const std::map<std::string, triplet> apis = {
9897  std::make_pair("_topen", triplet("open", "_wopen")),
9898  std::make_pair("_tsopen_s", triplet("_sopen_s", "_wsopen_s")),
9899  std::make_pair("_tfopen", triplet("fopen", "_wfopen")),
9900  std::make_pair("_tfopen_s", triplet("fopen_s", "_wfopen_s")),
9901  std::make_pair("_tfreopen", triplet("freopen", "_wfreopen")),
9902  std::make_pair("_tfreopen_s", triplet("freopen_s", "_wfreopen_s")),
9903  std::make_pair("_tcscat", triplet("strcat", "wcscat")),
9904  std::make_pair("_tcschr", triplet("strchr", "wcschr")),
9905  std::make_pair("_tcscmp", triplet("strcmp", "wcscmp")),
9906  std::make_pair("_tcsdup", triplet("strdup", "wcsdup")),
9907  std::make_pair("_tcscpy", triplet("strcpy", "wcscpy")),
9908  std::make_pair("_tcslen", triplet("strlen", "wcslen")),
9909  std::make_pair("_tcsncat", triplet("strncat", "wcsncat")),
9910  std::make_pair("_tcsncpy", triplet("strncpy", "wcsncpy")),
9911  std::make_pair("_tcsnlen", triplet("strnlen", "wcsnlen")),
9912  std::make_pair("_tcsrchr", triplet("strrchr", "wcsrchr")),
9913  std::make_pair("_tcsstr", triplet("strstr", "wcsstr")),
9914  std::make_pair("_tcstok", triplet("strtok", "wcstok")),
9915  std::make_pair("_ftprintf", triplet("fprintf", "fwprintf")),
9916  std::make_pair("_tprintf", triplet("printf", "wprintf")),
9917  std::make_pair("_stprintf", triplet("sprintf", "swprintf")),
9918  std::make_pair("_sntprintf", triplet("_snprintf", "_snwprintf")),
9919  std::make_pair("_ftscanf", triplet("fscanf", "fwscanf")),
9920  std::make_pair("_tscanf", triplet("scanf", "wscanf")),
9921  std::make_pair("_stscanf", triplet("sscanf", "swscanf")),
9922  std::make_pair("_ftprintf_s", triplet("fprintf_s", "fwprintf_s")),
9923  std::make_pair("_tprintf_s", triplet("printf_s", "wprintf_s")),
9924  std::make_pair("_stprintf_s", triplet("sprintf_s", "swprintf_s")),
9925  std::make_pair("_sntprintf_s", triplet("_snprintf_s", "_snwprintf_s")),
9926  std::make_pair("_ftscanf_s", triplet("fscanf_s", "fwscanf_s")),
9927  std::make_pair("_tscanf_s", triplet("scanf_s", "wscanf_s")),
9928  std::make_pair("_stscanf_s", triplet("sscanf_s", "swscanf_s"))
9929  };
9930 }
9931 
9933 {
9934  // skip if not Windows
9935  if (!mSettings.platform.isWindows())
9936  return;
9937 
9938  const bool ansi = mSettings.platform.type == Platform::Type::Win32A;
9939  for (Token *tok = list.front(); tok; tok = tok->next()) {
9940  if (tok->strAt(1) != "(")
9941  continue;
9942 
9943  const std::map<std::string, triplet>::const_iterator match = apis.find(tok->str());
9944  if (match!=apis.end()) {
9945  tok->str(ansi ? match->second.mbcs : match->second.unicode);
9946  tok->originalName(match->first);
9947  } else if (Token::Match(tok, "_T|_TEXT|TEXT ( %char%|%str% )")) {
9948  tok->deleteNext();
9949  tok->deleteThis();
9950  tok->deleteNext();
9951  if (!ansi) {
9952  tok->isLong(true);
9953  if (tok->str()[0] != 'L')
9954  tok->str("L" + tok->str());
9955  }
9956  while (Token::Match(tok->next(), "_T|_TEXT|TEXT ( %char%|%str% )")) {
9957  tok->next()->deleteNext();
9958  tok->next()->deleteThis();
9959  tok->next()->deleteNext();
9960  tok->concatStr(tok->next()->str());
9961  tok->deleteNext();
9962  }
9963  }
9964  }
9965 }
9966 
9967 // Remove Borland code
9969 {
9970  // skip if not Windows
9971  if (!mSettings.platform.isWindows())
9972  return;
9973  if (isC())
9974  return;
9975  for (Token *tok = list.front(); tok; tok = tok->next()) {
9976  if (Token::Match(tok, "( __closure * %name% )")) {
9977  tok->deleteNext();
9978  }
9979  }
9980 
9981  // I think that these classes are always declared at the outer scope
9982  // I save some time by ignoring inner classes.
9983  for (Token *tok = list.front(); tok; tok = tok->next()) {
9984  if (tok->str() == "{" && !Token::Match(tok->tokAt(-2), "namespace %type%")) {
9985  tok = tok->link();
9986  if (!tok)
9987  break;
9988  } else if (Token::Match(tok, "class %name% :|{")) {
9989  while (tok && tok->str() != "{" && tok->str() != ";")
9990  tok = tok->next();
9991  if (!tok)
9992  break;
9993  if (tok->str() == ";")
9994  continue;
9995 
9996  const Token* end = tok->link()->next();
9997  for (Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
9998  if (tok2->str() == "__property" &&
9999  Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) {
10000  while (tok2->next() && !Token::Match(tok2->next(), "{|;"))
10001  tok2->deleteNext();
10002  tok2->deleteThis();
10003  if (tok2->str() == "{") {
10004  Token::eraseTokens(tok2, tok2->link());
10005  tok2->deleteNext();
10006  tok2->deleteThis();
10007 
10008  // insert "; __property ;"
10009  tok2->previous()->insertToken(";");
10010  tok2->previous()->insertToken("__property");
10011  tok2->previous()->insertToken(";");
10012  }
10013  }
10014  }
10015  }
10016  }
10017 }
10018 
10020 {
10021  if (!mSymbolDatabase)
10024 }
10025 
10026 bool Tokenizer::operatorEnd(const Token * tok)
10027 {
10028  if (tok && tok->str() == ")") {
10029  if (isFunctionHead(tok, "{|;|?|:|["))
10030  return true;
10031 
10032  tok = tok->next();
10033  while (tok && !Token::Match(tok, "[=;{),]")) {
10034  if (Token::Match(tok, "const|volatile|override")) {
10035  tok = tok->next();
10036  } else if (tok->str() == "noexcept") {
10037  tok = tok->next();
10038  if (tok && tok->str() == "(") {
10039  tok = tok->link()->next();
10040  }
10041  } else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
10042  tok = tok->next()->link()->next();
10043  }
10044  // unknown macros ") MACRO {" and ") MACRO(...) {"
10045  else if (tok->isUpperCaseName()) {
10046  tok = tok->next();
10047  if (tok && tok->str() == "(") {
10048  tok = tok->link()->next();
10049  }
10050  } else if (Token::Match(tok, "%op% !!(") ||
10051  (Token::Match(tok, "%op% (") && !isFunctionHead(tok->next(), "{")))
10052  break;
10053  else
10054  return false;
10055  }
10056 
10057  return true;
10058  }
10059 
10060  return false;
10061 }
10062 
10064 {
10065  if (isC())
10066  return;
10067 
10068  for (Token *tok = list.front(); tok; tok = tok->next()) {
10069  if (Token::Match(tok, "using|:: operator %op%|%name% ;")) {
10070  tok->next()->str("operator" + tok->strAt(2));
10071  tok->next()->deleteNext();
10072  continue;
10073  }
10074 
10075  if (tok->str() != "operator")
10076  continue;
10077  // operator op
10078  if (Token::Match(tok, "operator %op% (") && !operatorEnd(tok->linkAt(2))) {
10079  tok->str(tok->str() + tok->next()->str());
10080  tok->deleteNext();
10081  continue;
10082  }
10083  std::string op;
10084  Token *par = tok->next();
10085  bool done = false;
10086  while (!done && par) {
10087  done = true;
10088  if (par->isName()) {
10089  op += par->str();
10090  par = par->next();
10091  // merge namespaces eg. 'operator std :: string () const {'
10092  if (Token::Match(par, ":: %name%|%op%|.")) {
10093  op += par->str();
10094  par = par->next();
10095  }
10096  done = false;
10097  } else if (Token::Match(par, ".|%op%|,")) {
10098  // check for operator in template
10099  if (par->str() == "," && !op.empty())
10100  break;
10101  if (!(Token::Match(par, "<|>") && !op.empty())) {
10102  op += par->str() == "." ? par->originalName() : par->str();
10103  par = par->next();
10104  done = false;
10105  }
10106  } else if (Token::simpleMatch(par, "[ ]")) {
10107  op += "[]";
10108  par = par->tokAt(2);
10109  done = false;
10110  } else if (Token::Match(par, "( *| )")) {
10111  // break out and simplify..
10112  if (operatorEnd(par->next()))
10113  break;
10114 
10115  while (par->str() != ")") {
10116  op += par->str();
10117  par = par->next();
10118  }
10119  op += ")";
10120  par = par->next();
10121  if (Token::simpleMatch(par, "...")) {
10122  op.clear();
10123  par = nullptr;
10124  break;
10125  }
10126  done = false;
10127  } else if (Token::Match(par, "\"\" %name% )| (|;|<")) {
10128  op += "\"\"";
10129  op += par->strAt(1);
10130  par = par->tokAt(2);
10131  if (par->str() == ")") {
10132  par->link()->deleteThis();
10133  par = par->next();
10134  par->deletePrevious();
10135  tok = par->tokAt(-3);
10136  }
10137  done = true;
10138  } else if (par->str() == "::") {
10139  op += par->str();
10140  par = par->next();
10141  done = false;
10142  } else if (par->str() == ";" || par->str() == ")") {
10143  done = true;
10144  } else if (par->str() != "(") {
10145  syntaxError(par, "operator");
10146  }
10147  }
10148 
10149  const bool returnsRef = Token::simpleMatch(par, "( & (") && tok->next()->isName();
10150  if (par && !op.empty()) {
10151  if (returnsRef) {
10152  par->next()->insertToken("operator" + op)->isOperatorKeyword(true);
10153  tok->deleteThis();
10154  }
10155  else {
10156  tok->str("operator" + op);
10157  Token::eraseTokens(tok, par);
10158  }
10159  }
10160 
10161  if (!op.empty() && !returnsRef)
10162  tok->isOperatorKeyword(true);
10163  }
10164 
10165  for (Token *tok = list.front(); tok; tok = tok->next()) {
10166  if (Token::Match(tok, "%op% %str% %name%")) {
10167  const std::string name = tok->strAt(2);
10168  Token * const str = tok->next();
10169  str->deleteNext();
10170  tok->insertToken("operator\"\"" + name);
10171  tok = tok->next();
10172  tok->isOperatorKeyword(true);
10173  tok->insertToken("(");
10174  str->insertToken(")");
10175  Token::createMutualLinks(tok->next(), str->next());
10176  str->insertToken(std::to_string(Token::getStrLength(str)));
10177  str->insertToken(",");
10178  }
10179  }
10180 
10181  if (mSettings.debugwarnings) {
10182  const Token *tok = list.front();
10183 
10184  while ((tok = Token::findsimplematch(tok, "operator")) != nullptr) {
10185  reportError(tok, Severity::debug, "debug",
10186  "simplifyOperatorName: found unsimplified operator name");
10187  tok = tok->next();
10188  }
10189  }
10190 }
10191 
10193 {
10194  if (isC())
10195  return;
10196  std::set<std::string> classNames;
10197  std::set<nonneg int> classVars;
10198  for (Token *tok = list.front(); tok; tok = tok->next()) {
10199  if (!tok->isName())
10200  continue;
10201 
10202  if (Token::simpleMatch(tok, "this ) (") && Token::simpleMatch(tok->tokAt(-2), "( *")) {
10203  tok = tok->next();
10204  tok->insertToken("operator()");
10205  tok->insertToken(".");
10206  continue;
10207  }
10208 
10209  // Get classes that have operator() member
10210  if (Token::Match(tok, "class|struct %name% [:{]")) {
10211  int indent = 0;
10212  for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
10213  if (tok2->str() == "}")
10214  break;
10215  if (indent == 0 && tok2->str() == ";")
10216  break;
10217  if (tok2->str() == "{") {
10218  if (indent == 0)
10219  ++indent;
10220  else
10221  tok2 = tok2->link();
10222  } else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
10223  classNames.insert(tok->strAt(1));
10224  break;
10225  }
10226  }
10227  }
10228 
10229  // Get variables that have operator() member
10230  if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
10231  tok = tok->next();
10232  while (!tok->isName())
10233  tok = tok->next();
10234  classVars.insert(tok->varId());
10235  }
10236 
10237  // Simplify operator() calls
10238  if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
10239  // constructor init list..
10240  if (Token::Match(tok->previous(), "[:,]")) {
10241  const Token *start = tok->previous();
10242  while (Token::simpleMatch(start, ",")) {
10243  if (Token::simpleMatch(start->previous(), ")"))
10244  start = start->linkAt(-1);
10245  else
10246  break;
10247  if (Token::Match(start->previous(), "%name%"))
10248  start = start->tokAt(-2);
10249  else
10250  break;
10251  }
10252  const Token *after = tok->linkAt(1);
10253  while (Token::Match(after, ")|} , %name% (|{"))
10254  after = after->linkAt(3);
10255 
10256  // Do not simplify initlist
10257  if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
10258  continue;
10259  }
10260 
10261  tok->insertToken("operator()");
10262  tok->insertToken(".");
10263  }
10264  }
10265 }
10266 
10267 // remove unnecessary member qualification..
10269 {
10270  if (isC())
10271  return;
10272 
10273  std::vector<Space> classInfo;
10274  for (Token *tok = list.front(); tok; tok = tok->next()) {
10275  if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
10276  (!tok->previous() || tok->previous()->str() != "enum")) {
10277  Space info;
10278  info.isNamespace = tok->str() == "namespace";
10279  tok = tok->next();
10280  info.className = tok->str();
10281  tok = tok->next();
10282  while (tok && tok->str() != "{")
10283  tok = tok->next();
10284  if (!tok)
10285  return;
10286  info.bodyEnd = tok->link();
10287  classInfo.push_back(std::move(info));
10288  } else if (!classInfo.empty()) {
10289  if (tok == classInfo.back().bodyEnd)
10290  classInfo.pop_back();
10291  else if (tok->str() == classInfo.back().className &&
10292  !classInfo.back().isNamespace && tok->previous()->str() != ":" &&
10293  (Token::Match(tok, "%type% :: ~| %type% (") ||
10294  Token::Match(tok, "%type% :: operator"))) {
10295  const Token *tok1 = tok->tokAt(3);
10296  if (tok->strAt(2) == "operator") {
10297  // check for operator ()
10298  if (tok1->str() == "(")
10299  tok1 = tok1->next();
10300 
10301  while (tok1 && tok1->str() != "(") {
10302  if (tok1->str() == ";")
10303  break;
10304  tok1 = tok1->next();
10305  }
10306  if (!tok1 || tok1->str() != "(")
10307  continue;
10308  } else if (tok->strAt(2) == "~")
10309  tok1 = tok1->next();
10310 
10311  if (!tok1 || !Token::Match(tok1->link(), ") const| {|;|:")) {
10312  continue;
10313  }
10314 
10315  const bool isConstructorOrDestructor =
10316  Token::Match(tok, "%type% :: ~| %type%") && (tok->strAt(2) == tok->str() || (tok->strAt(2) == "~" && tok->strAt(3) == tok->str()));
10317  if (!isConstructorOrDestructor) {
10318  bool isPrependedByType = Token::Match(tok->previous(), "%type%");
10319  if (!isPrependedByType) {
10320  const Token* tok2 = tok->tokAt(-2);
10321  isPrependedByType = Token::Match(tok2, "%type% *|&");
10322  }
10323  if (!isPrependedByType) {
10324  const Token* tok3 = tok->tokAt(-3);
10325  isPrependedByType = Token::Match(tok3, "%type% * *|&");
10326  }
10327  if (!isPrependedByType) {
10328  // It's not a constructor declaration and it's not a function declaration so
10329  // this is a function call which can have all the qualifiers just fine - skip.
10330  continue;
10331  }
10332  }
10333  }
10334  }
10335  }
10336 }
10337 
10338 void Tokenizer::printUnknownTypes() const
10339 {
10340  if (!mSymbolDatabase)
10341  return;
10342 
10343  std::vector<std::pair<std::string, const Token *>> unknowns;
10344 
10345  for (int i = 1; i <= mVarId; ++i) {
10347  if (!var)
10348  continue;
10349  // is unknown type?
10350  if (var->type() || var->typeStartToken()->isStandardType())
10351  continue;
10352 
10353  std::string name;
10354  const Token * nameTok;
10355 
10356  // single token type?
10357  if (var->typeStartToken() == var->typeEndToken()) {
10358  nameTok = var->typeStartToken();
10359  name = nameTok->str();
10360  }
10361 
10362  // complicated type
10363  else {
10364  const Token *tok = var->typeStartToken();
10365  int level = 0;
10366 
10367  nameTok = tok;
10368 
10369  while (tok) {
10370  // skip pointer and reference part of type
10371  if (level == 0 && Token::Match(tok, "*|&"))
10372  break;
10373 
10374  name += tok->str();
10375 
10376  if (Token::Match(tok, "struct|union|enum"))
10377  name += " ";
10378 
10379  // pointers and references are OK in template
10380  else if (tok->str() == "<")
10381  ++level;
10382  else if (tok->str() == ">")
10383  --level;
10384 
10385  if (tok == var->typeEndToken())
10386  break;
10387 
10388  tok = tok->next();
10389  }
10390  }
10391 
10392  unknowns.emplace_back(std::move(name), nameTok);
10393  }
10394 
10395  if (!unknowns.empty()) {
10396  std::string last;
10397  int count = 0;
10398 
10399  for (auto it = unknowns.cbegin(); it != unknowns.cend(); ++it) {
10400  // skip types is std namespace because they are not interesting
10401  if (it->first.find("std::") != 0) {
10402  if (it->first != last) {
10403  last = it->first;
10404  count = 1;
10405  reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10406  } else {
10407  if (count < 3) // limit same type to 3
10408  reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10409  count++;
10410  }
10411  }
10412  }
10413  }
10414 }
10415 
10417 {
10418  // http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
10419  // "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
10420  // The AST parser relies on this function to add such parentheses where necessary.
10421  for (Token* tok = list.front(); tok; tok = tok->next()) {
10422  if (tok->str() == "?") {
10423  bool parenthesesNeeded = false;
10424  int depth = 0;
10425  Token* tok2 = tok->next();
10426  for (; tok2; tok2 = tok2->next()) {
10427  if (tok2->link() && Token::Match(tok2, "[|(|<"))
10428  tok2 = tok2->link();
10429  else if (tok2->str() == ":") {
10430  if (depth == 0)
10431  break;
10432  depth--;
10433  } else if (tok2->str() == ";" || (tok2->link() && tok2->str() != "{" && tok2->str() != "}"))
10434  break;
10435  else if (tok2->str() == ",")
10436  parenthesesNeeded = true;
10437  else if (tok2->str() == "<")
10438  parenthesesNeeded = true;
10439  else if (tok2->str() == "?") {
10440  depth++;
10441  parenthesesNeeded = true;
10442  }
10443  }
10444  if (parenthesesNeeded && tok2 && tok2->str() == ":") {
10445  tok->insertToken("(");
10446  tok2->insertTokenBefore(")");
10447  Token::createMutualLinks(tok->next(), tok2->previous());
10448  }
10449  }
10450  }
10451 }
10452 
10453 void Tokenizer::reportError(const Token* tok, const Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10454 {
10455  const std::list<const Token*> callstack(1, tok);
10456  reportError(callstack, severity, id, msg, inconclusive);
10457 }
10458 
10459 void Tokenizer::reportError(const std::list<const Token*>& callstack, Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10460 {
10461  const ErrorMessage errmsg(callstack, &list, severity, id, msg, inconclusive ? Certainty::inconclusive : Certainty::normal);
10462  mErrorLogger.reportErr(errmsg);
10463 }
10464 
10466 {
10467  for (Token *tok = list.front(); tok; tok = tok->next()) {
10468  if (!tok->isName() || tok->varId())
10469  continue;
10470 
10471  // pod type
10472  const Library::PodType *podType = mSettings.library.podtype(tok->str());
10473  if (podType) {
10474  const Token *prev = tok->previous();
10475  while (prev && prev->isName())
10476  prev = prev->previous();
10477  if (prev && !Token::Match(prev, ";|{|}|,|("))
10478  continue;
10479  tok->isStandardType(true);
10480  }
10481  }
10482 }
10483 
10484 const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
10485 {
10486  const Token *tokLastEnd = nullptr;
10487  for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr; tok = tok->next()) {
10488  if (tokLastEnd == nullptr && tok->str() == ";")
10489  tokLastEnd = tok;
10490  else if (tok->str() == "__CPPCHECK_EMBEDDED_SQL_EXEC__") {
10491  if (Token::simpleMatch(tok->tokAt(-2), "END - __CPPCHECK_EMBEDDED_SQL_EXEC__ ;"))
10492  return tok->next();
10493  return tokLastEnd;
10494  } else if (Token::Match(tok, "{|}|==|&&|!|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|~"))
10495  break; // We are obviously outside the SQL block
10496  }
10497 
10498  return tokLastEnd;
10499 }
10500 
10502 {
10503  if (!isCPP())
10504  return;
10505 
10506  for (Token *tok = list.front(); tok; tok = tok->next()) {
10507  if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
10508  Token * tok2 = tok->tokAt(2);
10509 
10510  // validate syntax
10511  while (Token::Match(tok2, ":: %name%"))
10512  tok2 = tok2->tokAt(2);
10513 
10514  if (!tok2 || tok2->str() != "{")
10515  return; // syntax error
10516 
10517  std::stack<Token *> links;
10518  tok2 = tok->tokAt(2);
10519 
10520  while (tok2->str() == "::") {
10521  links.push(tok2);
10522  tok2->str("{");
10523  tok2->insertToken("namespace");
10524  tok2 = tok2->tokAt(3);
10525  }
10526 
10527  tok = tok2;
10528 
10529  if (!links.empty() && tok2->str() == "{") {
10530  tok2 = tok2->link();
10531  while (!links.empty()) {
10532  tok2->insertToken("}");
10533  tok2 = tok2->next();
10534  Token::createMutualLinks(links.top(), tok2);
10535  links.pop();
10536  }
10537  }
10538  }
10539  }
10540 }
10541 
10543 {
10545  return;
10546  for (Token *tok = list.front(); tok; tok = tok->next()) {
10547  if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await"))
10548  continue;
10549  Token *end = tok->next();
10550  while (end && end->str() != ";") {
10551  if (Token::Match(end, "[({[]"))
10552  end = end->link();
10553  else if (Token::Match(end, "[)]}]"))
10554  break;
10555  end = end->next();
10556  }
10557  if (Token::simpleMatch(end, ";")) {
10558  tok->insertToken("(");
10559  end->previous()->insertToken(")");
10560  Token::createMutualLinks(tok->next(), end->previous());
10561  }
10562  }
10563 }
10564 
10565 static bool sameTokens(const Token *first, const Token *last, const Token *other)
10566 {
10567  while (other && first->str() == other->str()) {
10568  if (first == last)
10569  return true;
10570  first = first->next();
10571  other = other->next();
10572  }
10573 
10574  return false;
10575 }
10576 
10577 static bool alreadyHasNamespace(const Token *first, const Token *last, const Token *end)
10578 {
10579  while (end && last->str() == end->str()) {
10580  if (first == last)
10581  return true;
10582  last = last->previous();
10583  end = end->previous();
10584  }
10585 
10586  return false;
10587 }
10588 
10589 static Token * deleteAlias(Token * tok)
10590 {
10592 
10593  // delete first token
10594  tok->deleteThis();
10595 
10596  // delete ';' if not last token
10597  tok->deleteThis();
10598 
10599  return tok;
10600 }
10601 
10603 {
10604  if (!isCPP())
10605  return;
10606 
10607  int scope = 0;
10608 
10609  for (Token *tok = list.front(); tok; tok = tok->next()) {
10610  bool isPrev{};
10611  if (tok->str() == "{")
10612  scope++;
10613  else if (tok->str() == "}")
10614  scope--;
10615  else if (Token::Match(tok, "namespace %name% =") || (isPrev = Token::Match(tok->previous(), "namespace %name% ="))) {
10616  if (isPrev)
10617  tok = tok->previous();
10618  if (tok->tokAt(-1) && !Token::Match(tok->tokAt(-1), "[;{}]"))
10619  syntaxError(tok->tokAt(-1));
10620  const std::string name(tok->next()->str());
10621  Token * tokNameStart = tok->tokAt(3);
10622  Token * tokNameEnd = tokNameStart;
10623 
10624  while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";") {
10625  if (tokNameEnd->str() == "(") {
10626  if (tokNameEnd->previous()->isName())
10627  unknownMacroError(tokNameEnd->previous());
10628  else
10629  syntaxError(tokNameEnd);
10630  }
10631  tokNameEnd = tokNameEnd->next();
10632  }
10633 
10634  if (!tokNameEnd)
10635  return; // syntax error
10636 
10637  int endScope = scope;
10638  Token * tokLast = tokNameEnd->next();
10639  if (!tokLast)
10640  return;
10641  Token * tokNext = tokLast->next();
10642  Token * tok2 = tokNext;
10643 
10644  while (tok2 && endScope >= scope) {
10645  if (Token::simpleMatch(tok2, "{"))
10646  endScope++;
10647  else if (Token::simpleMatch(tok2, "}"))
10648  endScope--;
10649  else if (tok2->str() == name) {
10650  if (Token::Match(tok2->previous(), "namespace %name% =")) {
10651  // check for possible duplicate aliases
10652  if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
10653  // delete duplicate
10654  tok2 = deleteAlias(tok2->previous());
10655  continue;
10656  }
10657  // conflicting declaration (syntax error)
10658  // cppcheck-suppress duplicateBranch - remove when TODO below is addressed
10659  if (endScope == scope) {
10660  // delete conflicting declaration
10661  tok2 = deleteAlias(tok2->previous());
10662  }
10663 
10664  // new declaration
10665  else {
10666  // TODO: use the new alias in this scope
10667  tok2 = deleteAlias(tok2->previous());
10668  }
10669  continue;
10670  }
10671 
10672  if (tok2->strAt(1) == "::" && !alreadyHasNamespace(tokNameStart, tokNameEnd, tok2)) {
10673  if (Token::simpleMatch(tok2->tokAt(-1), "::") && tokNameStart->str() == "::")
10674  tok2->deletePrevious();
10675  tok2->str(tokNameStart->str());
10676  Token * tok3 = tokNameStart;
10677  while (tok3 != tokNameEnd) {
10678  tok2->insertToken(tok3->next()->str());
10679  tok2 = tok2->next();
10680  tok3 = tok3->next();
10681  }
10682  }
10683  }
10684  tok2 = tok2->next();
10685  }
10686 
10687  if (tok->previous() && tokNext) {
10688  Token::eraseTokens(tok->previous(), tokNext);
10689  tok = tokNext->previous();
10690  } else if (tok->previous()) {
10691  Token::eraseTokens(tok->previous(), tokLast);
10692  tok = tokLast;
10693  } else if (tokNext) {
10694  Token::eraseTokens(tok, tokNext);
10695  tok->deleteThis();
10696  } else {
10697  Token::eraseTokens(tok, tokLast);
10698  tok->deleteThis();
10699  }
10700  }
10701  }
10702 }
10703 
10704 void Tokenizer::setDirectives(std::list<Directive> directives)
10705 {
10706  mDirectives = std::move(directives);
10707 }
10708 
10709 bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
10710 {
10711  const auto& directives = mDirectives;
10712  return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10713  return startsWith(d.str, "#if") &&
10714  d.linenr >= start->linenr() &&
10715  d.linenr <= end->linenr() &&
10716  start->fileIndex() < list.getFiles().size() &&
10717  d.file == list.getFiles()[start->fileIndex()];
10718  });
10719 }
10720 
10721 bool Tokenizer::isPacked(const Token * bodyStart) const
10722 {
10723  const auto& directives = mDirectives;
10724  // TODO: should this return true if the #pragma exists in any line before the start token?
10725  return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10726  return d.linenr < bodyStart->linenr() && d.str == "#pragma pack(1)" && d.file == list.getFiles().front();
10727  });
10728 }
static bool match(const Token *tok, const std::string &rhs)
Definition: astutils.cpp:342
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
static std::string toxml(const std::string &str)
Convert XML-sensitive characters into XML entities.
virtual void reportProgress(const std::string &filename, const char stage[], const std::size_t value)
Report progress to client.
Definition: errorlogger.h:241
File name and line number.
Definition: errorlogger.h:55
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
std::string startPattern
Definition: library.h:234
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
Definition: library.cpp:1241
const SmartPointer * detectSmartPointer(const Token *tok, bool withoutStd=false) const
Definition: library.cpp:1702
bool hasAnyTypeCheck(const std::string &typeName) const
Definition: library.cpp:1741
bool isnoreturn(const Token *ftok) const
Definition: library.cpp:1542
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const
Definition: library.cpp:1141
const PodType * podtype(const std::string &name) const
Definition: library.h:447
bool markupFile(const std::string &path) const
Definition: library.cpp:1577
bool isNotLibraryFunction(const Token *ftok) const
Definition: library.cpp:1270
bool matchArguments(const Token *ftok, const std::string &functionName) const
Definition: library.cpp:1285
bool isFunctionConst(const std::string &functionName, bool pure) const
Definition: library.cpp:1518
static std::string toString(T value)=delete
static biguint toBigUNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:289
long long bigint
Definition: mathlib.h:68
static bool isOctalDigit(char c)
Return true if given character is 0,1,2,3,4,5,6 or 7.
Definition: mathlib.cpp:1272
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:368
static bool isFloat(const std::string &str)
Definition: mathlib.cpp:535
static bool isInt(const std::string &str)
Definition: mathlib.cpp:1007
static double toDoubleNumber(const std::string &str)
for conversion of numeric literals
Definition: mathlib.cpp:487
unsigned long long biguint
Definition: mathlib.h:69
static bool isPositive(const std::string &str)
Definition: mathlib.cpp:643
static std::string getRelativePath(const std::string &absolutePath, const std::vector< std::string > &basePaths)
Create a relative path from an absolute one, if absolute path is inside the basePaths.
Definition: path.cpp:181
std::size_t sizeof_bool
bits in long long
Definition: platform.h:92
std::size_t sizeof_long_long
Definition: platform.h:96
std::size_t sizeof_long_double
Definition: platform.h:99
std::size_t sizeof_short
Definition: platform.h:93
std::size_t sizeof_int
Definition: platform.h:94
std::size_t sizeof_pointer
Definition: platform.h:102
std::size_t sizeof_size_t
Definition: platform.h:101
bool isWindows() const
Returns true if platform type is Windows.
Definition: platform.h:142
std::size_t sizeof_float
Definition: platform.h:97
Type type
platform type
Definition: platform.h:118
std::size_t sizeof_double
Definition: platform.h:98
std::size_t sizeof_long
Definition: platform.h:95
std::size_t sizeof_wchar_t
Definition: platform.h:100
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
bool checkLibrary
Check for incomplete info in library files?
Definition: settings.h:135
bool checkHeaders
Check code in the headers, this is on by default but can be turned off to save CPU.
Definition: settings.h:132
std::vector< std::string > basePaths
Paths used as base for conversion to relative paths.
Definition: settings.h:118
bool xml
write XML results (–xml)
Definition: settings.h:401
bool checkConfiguration
Is the 'configuration checking' wanted?
Definition: settings.h:127
static bool terminated()
termination requested?
Definition: settings.h:449
Library library
Library.
Definition: settings.h:237
std::size_t typedefMaxTime
The maximum time in seconds for the typedef simplification.
Definition: settings.h:383
std::string buildDir
–cppcheck-build-dir.
Definition: settings.h:121
std::set< std::string > summaryReturn
Definition: settings.h:453
Platform platform
Definition: settings.h:255
bool debugnormal
Is –debug-normal given?
Definition: settings.h:174
bool daca
Are we running from DACA script?
Definition: settings.h:171
bool verbose
Is –verbose given?
Definition: settings.h:398
SHOWTIME_MODES showtime
show timing information (–showtime=file|summary|top5)
Definition: settings.h:363
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
std::size_t templateMaxTime
The maximum time in seconds for the template instantiation.
Definition: settings.h:380
bool debugSimplified
Is –debug-simplified given?
Definition: settings.h:177
bool checkUnusedTemplates
Check unused/uninstantiated templates.
Definition: settings.h:147
bool debugwarnings
Is –debug-warnings given?
Definition: settings.h:183
Standards standards
Struct contains standards settings.
Definition: settings.h:366
bool isEnabled(T flag) const
Definition: settings.h:66
const Variable * getVariableFromVarId(nonneg int varId) const
const std::vector< const Variable * > & variableList() const
void setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens=nullptr)
Set valuetype in provided tokenlist.
void validate() const
void printXml(std::ostream &out) const
void setArrayDimensionsUsingValueFlow()
Set array dimensions when valueflow analysis is completed.
void printOut(const char *title=nullptr) const
Simplify templates from the preprocessed and partially simplified code.
void simplifyTemplates(const std::time_t maxtime)
Simplify templates.
static Token * findTemplateDeclarationEnd(Token *tok)
Find last token of a template declaration.
void checkComplicatedSyntaxErrorsInTemplates()
static unsigned int templateParameters(const Token *tok)
is the token pointing at a template parameters block < int , 3 > => yes
static bool simplifyNumericCalculations(Token *tok, bool isTemplate=true)
Simplify constant calculations such as "1+2" => "3".
const std::string & dump() const
Definition: timer.h:70
static Token * copyTokens(Token *dest, const Token *first, const Token *last, bool one_line=true)
Copy tokens.
Definition: tokenlist.cpp:264
void createAst() const
Create abstract syntax tree.
const Token * back() const
get last token of list
Definition: tokenlist.h:128
void simplifyPlatformTypes()
Convert platform dependent types to standard types.
const std::string & file(const Token *tok) const
get filename for given token
static void insertTokens(Token *dest, const Token *src, nonneg int n)
Definition: tokenlist.cpp:304
void simplifyStdType()
Collapse compound standard types into a single token.
const std::vector< std::string > & getFiles() const
Get filenames (the sourcefile + the files it include).
Definition: tokenlist.h:141
const Token * front() const
get first token of list
Definition: tokenlist.h:119
void validateAst(bool print) const
Check abstract syntax tree.
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
bool isRemovedVoidParameter() const
Definition: token.h:650
void str(T &&s)
Definition: token.h:179
nonneg int index() const
Definition: token.h:1247
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:722
bool isConstexpr() const
Definition: token.h:594
bool isSimplifiedScope() const
Definition: token.h:664
void deleteThis()
Remove the contents for this token from the token list.
Definition: token.cpp:363
nonneg int exprId() const
Definition: token.h:883
bool isKeyword() const
Definition: token.h:358
void setMacroName(std::string name)
Definition: token.h:758
const std::string & originalName() const
Definition: token.h:1193
void setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type type, MathLib::bigint value)
Definition: token.h:536
bool isName() const
Definition: token.h:361
void printOut(const char *title=nullptr) const
For debugging purposes, prints token and all tokens followed by it.
Definition: token.cpp:1291
bool isAttributeUsed() const
Definition: token.h:482
bool isTemplate() const
Definition: token.h:657
bool addValue(const ValueFlow::Value &value)
Add token value.
Definition: token.cpp:2262
bool isUnsigned() const
Definition: token.h:424
bool hasKnownIntValue() const
Definition: token.cpp:2553
static void replace(Token *replaceThis, Token *start, Token *end)
Replace token replaceThis with tokens between start and end, including start and end.
Definition: token.cpp:380
MathLib::bigint getKnownIntValue() const
Definition: token.h:1218
bool isSimplifiedTypedef() const
Definition: token.h:580
bool isExpandedMacro() const
Definition: token.h:455
void concatStr(std::string const &b)
Concatenate two (quoted) strings.
Definition: token.cpp:246
bool isTemplateArg() const
Is current token a template argument?
Definition: token.h:748
void setTokenDebug(TokenDebug td)
Definition: token.h:1478
bool isArithmeticalOp() const
Definition: token.h:395
std::string stringifyList(const stringifyOptions &options, const std::vector< std::string > *fileNames=nullptr, const Token *end=nullptr) const
Definition: token.cpp:1371
bool isBoolean() const
Definition: token.h:404
bool isUpperCaseName() const
Definition: token.cpp:237
static void createMutualLinks(Token *begin, Token *end)
Links two elements against each other.
Definition: token.cpp:1282
bool isAttributeDestructor() const
Definition: token.h:470
bool isCpp() const
Definition: token.cpp:2752
nonneg int progressValue() const
Get progressValue (0 - 100)
Definition: token.h:1150
bool isNameOnly() const
Definition: token.h:364
bool isControlFlowKeyword() const
Definition: token.h:546
void setBits(const unsigned char b)
Definition: token.h:703
static nonneg int getStrLength(const Token *tok)
Definition: token.cpp:811
bool isFinalType() const
Definition: token.h:671
bool isImplicitInt() const
Definition: token.h:622
const ValueType * valueType() const
Definition: token.h:331
const std::string & strAt(int index) const
Definition: token.cpp:457
bool isAttributeUnused() const
Definition: token.h:476
static void assignProgressValues(Token *tok)
Calculate progress values for all tokens.
Definition: token.cpp:2341
void astOperand1(Token *tok)
Definition: token.cpp:1490
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
bool isExternC() const
Definition: token.h:601
nonneg int varId() const
Definition: token.h:870
static void move(Token *srcStart, Token *srcEnd, Token *newLocation)
Move srcStart and srcEnd tokens and all tokens between them into new a location.
Definition: token.cpp:868
bool isSigned() const
Definition: token.h:430
const Token * findClosingBracket() const
Returns the closing bracket of opening '<'.
Definition: token.cpp:951
bool isCast() const
Definition: token.h:458
bool isSplittedVarDeclComma() const
Definition: token.h:608
bool isIncDecOp() const
Definition: token.h:407
bool isLiteral() const
Definition: token.h:368
bool isAttributeNodiscard() const
Definition: token.h:524
void assignIndexes()
Definition: token.cpp:2351
bool isAttributeExport() const
Definition: token.h:512
bool isOperatorKeyword() const
Definition: token.h:549
void printValueFlow(bool xml, std::ostream &out) const
Definition: token.cpp:1798
bool isAttributeConstructor() const
Definition: token.h:464
void setRemovedVoidParameter(bool b)
Definition: token.h:653
static nonneg int getStrArraySize(const Token *tok)
Definition: token.cpp:841
bool isOp() const
Definition: token.h:380
void scopeInfo(std::shared_ptr< ScopeInfo2 > newScopeInfo)
Definition: token.cpp:2544
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
Definition: token.h:763
const Token * tokAt(int index) const
Definition: token.cpp:427
Token * insertTokenBefore(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string &macroNameStr=emptyString)
Definition: token.h:857
void deleteNext(nonneg int count=1)
Unlink and delete the next 'count' tokens.
Definition: token.cpp:279
Token * insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string &macroNameStr=emptyString, bool prepend=false)
Insert new token after this token.
Definition: token.cpp:1139
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1502
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
bool isLong() const
Definition: token.h:443
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:447
@ eKeyword
Definition: token.h:161
@ eString
Definition: token.h:162
@ eChar
Definition: token.h:162
@ eBoolean
Definition: token.h:162
@ eLogicalOp
Definition: token.h:163
@ eBracket
Definition: token.h:164
@ eIncDecOp
Definition: token.h:163
void printAst(bool verbose, bool xml, const std::vector< std::string > &fileNames, std::ostream &out) const
Definition: token.cpp:1715
Token * previous()
Definition: token.h:862
bool isComplex() const
Definition: token.h:555
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2367
bool isAssignmentOp() const
Definition: token.h:401
bool isSplittedVarDeclEq() const
Definition: token.h:615
static void eraseTokens(Token *begin, const Token *end)
Delete tokens between begin and end.
Definition: token.cpp:1272
nonneg int linenr() const
Definition: token.h:816
bool isStandardType() const
Definition: token.h:449
const Token * nextArgumentBeforeCreateLinks2() const
Definition: token.cpp:913
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
bool isAttributeMaybeUnused() const
Definition: token.h:530
bool isRestrict() const
Definition: token.h:643
bool isComparisonOp() const
Definition: token.h:398
Token * next()
Definition: token.h:830
bool isInline() const
Definition: token.h:629
const std::list< ValueFlow::Value > & values() const
Definition: token.h:1197
bool isAttributeNoreturn() const
Definition: token.h:500
bool isAttributeConst() const
Definition: token.h:494
const Token * nextArgument() const
Definition: token.cpp:903
void swapWithNext()
Swap the contents of this token with the next token.
Definition: token.cpp:319
bool isAtomic() const
Definition: token.h:636
const Token * findOpeningBracket() const
Definition: token.cpp:1016
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
nonneg int fileIndex() const
Definition: token.h:809
bool isAttributePacked() const
Definition: token.h:518
bool isAttributeNothrow() const
Definition: token.h:506
std::string getMacroName() const
Definition: token.h:755
void deletePrevious(nonneg int count=1)
Unlink and delete the previous 'count' tokens.
Definition: token.cpp:299
nonneg int column() const
Definition: token.h:823
bool isAttributePure() const
Definition: token.h:488
void astParent(Token *tok)
Definition: token.cpp:1471
bool isAtAddress() const
Definition: token.h:567
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
bool isScopeNoReturn(const Token *endScopeToken, bool *unknown=nullptr) const
Check if inner scope ends with a call to a noreturn function.
Definition: tokenize.cpp:8014
nonneg int sizeOfType(const Token *type) const
Calculates sizeof value for given type.
Definition: tokenize.cpp:191
void setVarIdPass1()
Definition: tokenize.cpp:4523
void simplifyLabelsCaseDefault()
Simplify labels and 'case|default' syntaxes.
Definition: tokenize.cpp:3942
void simplifyRoundCurlyParentheses()
Definition: tokenize.cpp:3639
void simplifyOverloadedOperators()
simplify overloaded operators: 'obj(123)' => 'obj .
void simplifyMicrosoftStringFunctions()
Convert Microsoft string functions _tcscpy -> strcpy.
std::string mConfiguration
E.g.
Definition: tokenize.h:657
void simplifyIfSwitchForInit()
Simplify C++17/C++20 if/switch/for initialization expression.
Definition: tokenize.cpp:7728
void simplifyBitfields()
Simplify bitfields - the field width is removed as we don't use it.
void fillTypeSizes()
Definition: tokenize.cpp:3480
NORETURN void unknownMacroError(const Token *tok1) const
Warn about unknown macro(s), configuration is recommended.
Definition: tokenize.cpp:8063
void splitTemplateRightAngleBrackets(bool check)
Split up template right angle brackets.
Definition: tokenize.cpp:6333
Token * deleteInvalidTypedef(Token *typeDef)
Definition: tokenize.cpp:368
void printDebugOutput(int simplification) const
print –debug output if debug flags match the simplification: 0=unknown/both simplifications 1=1st sim...
Definition: tokenize.cpp:5874
void elseif()
Simplify "if else".
Definition: tokenize.cpp:7696
void simplifyRedundantConsecutiveBraces()
Definition: tokenize.cpp:3711
void removeMacrosInGlobalScope()
Remove macros in global scope.
Definition: tokenize.cpp:6385
void simplifyHeadersAndUnusedTemplates()
If –check-headers=no has been given; then remove unneeded code in headers.
Definition: tokenize.cpp:6174
void calculateScopes()
Definition: tokenize.cpp:4013
void simplifyTemplates()
Simplify templates.
Definition: tokenize.cpp:4104
void simplifyUsingError(const Token *usingStart, const Token *usingEnd)
Definition: tokenize.cpp:3362
bool isPacked(const Token *bodyStart) const
void removePragma()
Definition: tokenize.cpp:6464
void setVarIdPass2()
Definition: tokenize.cpp:5009
const Token * tokens() const
Definition: tokenize.h:592
void simplifyAttribute()
Remove __attribute__ ((?))
void simplifyExternC()
Definition: tokenize.cpp:3613
static const Token * findSQLBlockEnd(const Token *tokSQLStart)
Find end of SQL (or PL/SQL) block.
void simplifyNamespaceAliases()
Convert namespace aliases.
void simplifyInitVar()
Simplify variable initialization '; int *p(0);' => '; int *p = 0;'.
Definition: tokenize.cpp:7618
static bool isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
Detect garbage expression.
void simplifySQL()
Definition: tokenize.cpp:3660
void removeUnnecessaryQualification()
Remove unnecessary member qualification.
void simplifyVarDecl(const bool only_k_r_fpar)
Simplify variable declarations (split up)
Definition: tokenize.cpp:7042
static bool isOneNumber(const std::string &s)
Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
Definition: tokenize.cpp:8134
void simplifyTypedef()
typedef A mytype; mytype c;
Definition: tokenize.cpp:1053
void createSymbolDatabase()
void prepareTernaryOpForAST()
Prepare ternary operators with parentheses so that the AST can be created.
bool simplifyTokens1(const std::string &configuration)
Definition: tokenize.cpp:3378
static std::string simplifyString(const std::string &source)
Modify strings in the token list by replacing hex and oct values.
bool simplifyTokenList1(const char FileName[])
Basic simplification of tokenlist.
Definition: tokenize.cpp:5463
void simplifyFunctionTryCatch()
Simplify function level try blocks: Convert "void f() try {} catch (int) {}" to "void f() { try {} ca...
void simplifyDoublePlusAndDoubleMinus()
Definition: tokenize.cpp:3726
void removeExtraTemplateKeywords()
Remove extra "template" keywords that are not used by Cppcheck.
Definition: tokenize.cpp:6299
void simplifyTypedefLHS()
Move typedef token to the left og the expression.
Definition: tokenize.cpp:568
std::list< Directive > mDirectives
Definition: tokenize.h:671
void simplifyCaseRange()
simplify case ranges (gcc extension)
Definition: tokenize.cpp:3992
ErrorLogger & mErrorLogger
errorlogger
Definition: tokenize.h:648
bool simplifyRedundantParentheses()
Remove redundant parentheses:
Definition: tokenize.cpp:7789
void simplifyTypedefCpp()
Definition: tokenize.cpp:1145
void addSemicolonAfterUnknownMacro()
Definition: tokenize.cpp:6497
void simplifyCppcheckAttribute()
Remove __cppcheck__ ((?))
Token * getAttributeFuncTok(Token *tok, bool gccattr) const
Get function token for a attribute.
Tokenizer(const Settings &settings, ErrorLogger &errorLogger)
Definition: tokenize.cpp:160
void simplifyEmptyNamespaces()
Simplify useless C++ empty namespaces, like: 'namespace name% { }'.
Definition: tokenize.cpp:6515
void findGarbageCode() const
Detect garbage code and call syntaxError() if found.
Token * simplifyAddBracesPair(Token *tok, bool commandWithCondition)
Add pair of braces to an single if-block, else-block, for-block, etc.
Definition: tokenize.cpp:6628
void simplifyMicrosoftMemoryFunctions()
Convert Microsoft memory functions CopyMemory(dst, src, len) -> memcpy(dst, src, len) FillMemory(dst,...
void setVarId()
Set variable id.
Definition: tokenize.cpp:4500
void setDirectives(std::list< Directive > directives)
void simplifyAssignmentBlock()
Simplify assignment where rhs is a block : "x=({123;});" => "{x=123;}".
void findComplicatedSyntaxErrorsInTemplates()
Definition: tokenize.cpp:3461
std::map< std::string, int > mTypeSize
sizeof information for known types
Definition: tokenize.h:660
friend class SymbolDatabase
Definition: tokenize.h:48
TokenList list
Token list: stores all tokens.
Definition: tokenize.h:590
void simplifyNamespaceStd()
Add std:: in front of std classes, when using namespace std; was given.
static Token * initVar(Token *tok)
Definition: tokenize.cpp:7651
Token * simplifyAddBracesToCommand(Token *tok)
Add braces to an if-block, for-block, etc.
Definition: tokenize.cpp:6584
nonneg int mVarId
variable count
Definition: tokenize.h:674
static bool isMemberFunction(const Token *openParen)
Definition: tokenize.cpp:2810
void simplifyKeyword()
Remove keywords "volatile", "inline", "register", and "restrict".
void macroWithSemicolonError(const Token *tok, const std::string &macroName) const
Definition: tokenize.cpp:8081
nonneg int mUnnamedCount
unnamed count "Unnamed0", "Unnamed1", "Unnamed2", ...
Definition: tokenize.h:677
bool isC() const
Is the code C.
Definition: tokenize.h:64
void simplifyUsingToTypedef()
Definition: tokenize.cpp:545
bool simplifyAddBraces()
Add braces to an if-block, for-block, etc.
Definition: tokenize.cpp:6574
void unhandled_macro_class_x_y(const Token *tok) const
Report that there is an unhandled "class x y {" code.
Definition: tokenize.cpp:8069
void reportUnknownMacros() const
Detect unknown macros and throw unknownMacro.
Definition: tokenize.cpp:8283
void arraySize()
Insert array size where it isn't given.
Definition: tokenize.cpp:3768
void createLinks2()
Setup links between < and >.
Definition: tokenize.cpp:5306
static void setVarIdClassFunction(const std::string &classname, Token *const startToken, const Token *const endToken, const std::map< std::string, nonneg int > &varlist, std::map< nonneg int, std::map< std::string, nonneg int >> &structMembers, nonneg int &varId_)
Definition: tokenize.cpp:4469
const Settings & mSettings
settings
Definition: tokenize.h:645
void simplifyParameterVoid()
Definition: tokenize.cpp:3701
void sizeofAddParentheses()
Add parentheses for sizeof: sizeof x => sizeof(x)
Definition: tokenize.cpp:5439
void dump(std::ostream &out) const
Definition: tokenize.cpp:5924
void validateC() const
Is there C++ code in C file?
Definition: tokenize.cpp:8161
static bool operatorEnd(const Token *tok)
void simplifyStaticConst()
Simplify the location of "static" and "const" qualifiers in a variable declaration or definition.
Definition: tokenize.cpp:7406
void simplifyDeclspec()
Remove __declspec()
void createLinks()
Setup links for tokens so that one can call Token::link().
Definition: tokenize.cpp:5272
NORETURN void cppcheckError(const Token *tok) const
Send error message to error logger about internal bug.
Definition: tokenize.cpp:8089
void markCppCasts()
Set isCast() for C++ casts.
Definition: tokenize.cpp:5424
NORETURN void unmatchedToken(const Token *tok) const
Syntax error.
Definition: tokenize.cpp:8049
void simplifyPointerToStandardType()
Simplify pointer to standard type (C only)
Definition: tokenize.cpp:6899
void simplifySpaceshipOperator()
Simplify c++20 spaceship operator.
void combineStringAndCharLiterals()
Definition: tokenize.cpp:3574
void printUnknownTypes() const
Output list of unknown types.
void simplifyBorland()
Remove Borland code.
TemplateSimplifier *const mTemplateSimplifier
Definition: tokenize.h:653
void removeRedundantSemicolons()
Reduces "; ;" to ";", except in "( ; ; )".
Definition: tokenize.cpp:6554
void simplifyCallingConvention()
Remove calling convention.
void arraySizeAfterValueFlow()
Definition: tokenize.cpp:3841
void simplifyFunctionPointers()
Simplify function pointers.
Definition: tokenize.cpp:6921
void setPodTypes()
Set pod types.
void unsupportedTypedef(const Token *tok) const
Definition: tokenize.cpp:337
void reportError(const Token *tok, const Severity severity, const std::string &id, const std::string &msg, bool inconclusive=false) const
report error message
void simplifyAsm()
Remove __asm.
void combineOperators()
Definition: tokenize.cpp:3498
const Token * processFunc(const Token *tok2, bool inOperator) const
Definition: tokenize.cpp:480
void simplifyDebug()
static const Token * isFunctionHead(const Token *tok, const std::string &endsWith)
is token pointing at function head?
Definition: tokenize.cpp:96
bool simplifyCAlternativeTokens()
Simplify the 'C Alternative Tokens' Examples: "if(s and t)" => "if(s && t)" "while((r bitand s) and n...
Definition: tokenize.cpp:7530
void simplifyAt()
Simplify @… (compiler extension)
void concatenateNegativeNumberAndAnyPositive()
Definition: tokenize.cpp:3597
bool simplifyUsing()
Definition: tokenize.cpp:2854
void validate() const
assert that tokens are ok - used during debugging for example to catch problems in simplifyTokenList1...
Definition: tokenize.cpp:8190
bool isCPP() const
Is the code CPP.
Definition: tokenize.h:69
bool hasIfdef(const Token *start, const Token *end) const
NORETURN void syntaxErrorC(const Token *tok, const std::string &what) const
Syntax error.
Definition: tokenize.cpp:8057
void simplifyStructDecl()
Struct simplification "struct S { } s;" => "struct S { }; S s;".
SymbolDatabase * mSymbolDatabase
Symbol database that all checks etc can use.
Definition: tokenize.h:651
bool duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const
Definition: tokenize.cpp:219
void simplifyTypeIntrinsics()
Definition: tokenize.cpp:7958
static const Token * startOfExecutableScope(const Token *tok)
Helper function to check for start of function execution scope.
Definition: tokenize.cpp:3924
void simplifyAsm2()
asm heuristics, Put ^{} statements in asm()
void simplifyOperatorName()
Collapse operator name tokens into single token operator = => operator=.
std::vector< TypedefInfo > mTypedefInfo
Definition: tokenize.h:669
void removeMacroInClassDef()
Remove undefined macro in class definition: class DLLEXPORT Fred { }; class Fred FINAL : Base { };.
Definition: tokenize.cpp:6480
void simplifyCoroutines()
Simplify coroutines - just put parentheses around arguments for co_* keywords so they can be handled ...
NORETURN void syntaxError(const Token *tok, const std::string &code=emptyString) const
Syntax error.
Definition: tokenize.cpp:8043
void checkForEnumsWithTypedef()
Definition: tokenize.cpp:3467
TimerResults * mTimerResults
TimerResults.
Definition: tokenize.h:682
void simplifyNestedNamespace()
Convert C++17 style nested namespace to older style.
void simplifyArrayAccessSyntax()
Definition: tokenize.cpp:3687
void unhandledCharLiteral(const Token *tok, const std::string &msg) const
Definition: tokenize.cpp:8095
void simplifyCPPAttribute()
Remove [[attribute]] (C++11, C23) from TokenList.
void simplifyVariableMultipleAssign()
Simplify multiple assignments.
Definition: tokenize.cpp:7475
void checkConfiguration() const
Check configuration (unknown macros etc)
Definition: tokenize.cpp:8141
void simplifyFunctionParameters()
Simplify functions like "void f(x) int x; {" into "void f(int x) {".
Definition: tokenize.cpp:6727
Information about a class type.
void setKnown()
Definition: vfvalue.h:349
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
std::string dump() const
Information about a member variable.
const Type * type() const
Get Type pointer of known type.
const Token * typeEndToken() const
Get type end token.
const Token * typeStartToken() const
Get type start token.
static const std::string emptyString
Definition: config.h:127
#define nonneg
Definition: config.h:138
static void replace(std::string &source, const std::unordered_map< std::string, std::string > &substitutionMap)
Severity
enum class for severity.
Definition: errortypes.h:63
Token * findLambdaEndScope(Token *tok)
Definition: token.cpp:2720
@ portability
Portability warning.
@ debug
Debug message.
@ information
Checking information.
CPPCHECKLIB std::string create(const Tokenizer &tokenizer, const std::string &cfg)
Definition: summaries.cpp:37
void setValues(TokenList &tokenlist, SymbolDatabase &symboldatabase, ErrorLogger &errorLogger, const Settings &settings, TimerResultsIntf *timerResults)
Perform valueflow analysis.
Definition: valueflow.cpp:9604
Array dimension information.
MathLib::bigint num
(assumed) dimension length when size is a number, 0 if not known
A preprocessor directive Each preprocessor directive (#include, #define, #undef, #if,...
Definition: preprocessor.h:49
Simple container to be thrown when internal error is detected.
Definition: errortypes.h:36
unsigned int size
Definition: library.h:443
std::string name
Definition: library.h:434
enum Standards::cstd_t c
enum Standards::cppstd_t cpp
std::string filename
Definition: tokenize.h:664
std::string name
Definition: tokenize.h:663
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
Definition: token.cpp:1742
TokenDebug
Definition: token.h:60
static std::string getExpression(const Token *tok)
Definition: tokenize.cpp:6322
static Token * splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
Definition: tokenize.cpp:406
static void setVarIdStructMembers(Token *&tok1, std::map< nonneg int, std::map< std::string, nonneg int >> &structMembers, nonneg int &varId)
Definition: tokenize.cpp:4325
static Token * skipTernaryOp(Token *tok)
Definition: tokenize.cpp:3880
static Token * matchMemberFunctionName(const Member &func, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4985
static const std::unordered_set< std::string > notstart_cpp
Definition: tokenize.cpp:4519
static bool isCPPAttribute(const Token *tok)
Definition: tokenize.cpp:8249
static const std::unordered_map< std::string, std::string > cAlternativeTokens
Definition: tokenize.cpp:7506
static bool isClassStructUnionEnumStart(const Token *tok)
is tok the start brace { of a class, struct, union, or enum
Definition: tokenize.cpp:148
static bool setVarIdParseDeclaration(Token *&tok, const VariableMap &variableMap, bool executableScope)
Definition: tokenize.cpp:4183
static unsigned int tokDistance(const Token *tok1, const Token *tok2)
Definition: tokenize.cpp:2844
static Token * matchMemberName(const std::list< std::string > &scope, const Token *nsToken, Token *memberToken, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4909
static T * skipCPPOrAlignAttribute(T *tok)
Definition: tokenize.cpp:8260
static const Token * findUnmatchedTernaryOp(const Token *const begin, const Token *const end, int depth=0)
Definition: tokenize.cpp:8231
static Token * matchMemberVarName(const Member &var, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4975
static T * skipInitializerList(T *tok)
Definition: tokenize.cpp:4992
static bool isEnumStart(const Token *tok)
Return whether tok is the "{" that starts an enumerator list.
Definition: tokenize.cpp:79
static const std::unordered_set< std::string > notstart_c
Definition: tokenize.cpp:4518
static bool isEnumScope(const Token *tok)
Definition: tokenize.cpp:1133
#define NOTSTART_C
Definition: tokenize.cpp:4517
static std::string getScopeName(const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4901
static bool isNonMacro(const Token *tok)
Definition: tokenize.cpp:8270
static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
Definition: tokenize.cpp:2817
static void linkBrackets(const Tokenizer &tokenizer, std::stack< const Token * > &type, std::stack< Token * > &links, Token *const token, const char open, const char close)
Definition: tokenize.cpp:5252
static bool setVarIdClassDeclaration(Token *const startToken, VariableMap &variableMap, const nonneg int scopeStartVarId, std::map< nonneg int, std::map< std::string, nonneg int >> &structMembers)
Definition: tokenize.cpp:4390
static bool isAlignAttribute(const Token *tok)
Definition: tokenize.cpp:8254
static Token * skipCaseLabel(Token *tok)
Definition: tokenize.cpp:3906
static void skipEnumBody(T *&tok)
Definition: tokenize.cpp:87
static bool isNumberOneOf(const std::string &s, MathLib::bigint intConstant, const char *floatConstant)
Helper function to check whether number is equal to integer constant X or floating point pattern X....
Definition: tokenize.cpp:8117
static bool isStringLiteral(const std::string &str)
Definition: utils.h:159
static std::string id_string(const void *p)
Definition: utils.h:340
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
bool endsWith(const std::string &str, char c)
Definition: utils.h:110
static const char * bool_to_string(bool b)
Definition: utils.h:345