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 "astutils.h"
23 #include "errorlogger.h"
24 #include "errortypes.h"
25 #include "library.h"
26 #include "mathlib.h"
27 #include "path.h"
28 #include "platform.h"
29 #include "preprocessor.h"
30 #include "settings.h"
31 #include "standards.h"
32 #include "summaries.h"
33 #include "symboldatabase.h"
34 #include "templatesimplifier.h"
35 #include "timer.h"
36 #include "token.h"
37 #include "utils.h"
38 #include "valueflow.h"
39 #include "vfvalue.h"
40 
41 #include <algorithm>
42 #include <cassert>
43 #include <cctype>
44 #include <cstdlib>
45 #include <cstring>
46 #include <ctime>
47 #include <iostream>
48 #include <iterator>
49 #include <exception>
50 #include <memory>
51 #include <set>
52 #include <sstream>
53 #include <stack>
54 #include <stdexcept>
55 #include <unordered_map>
56 #include <unordered_set>
57 #include <utility>
58 #include <vector>
59 
60 #include <simplecpp.h>
61 
62 //---------------------------------------------------------------------------
63 
64 namespace {
65  // local struct used in setVarId
66  // in order to store information about the scope
67  struct VarIdScopeInfo {
68  VarIdScopeInfo() = default;
69  VarIdScopeInfo(bool isExecutable, bool isStructInit, bool isEnum, nonneg int startVarid)
70  : isExecutable(isExecutable), isStructInit(isStructInit), isEnum(isEnum), startVarid(startVarid) {}
71 
72  const bool isExecutable{};
73  const bool isStructInit{};
74  const bool isEnum{};
75  const nonneg int startVarid{};
76  };
77 }
78 
79 /** Return whether tok is the "{" that starts an enumerator list */
80 static bool isEnumStart(const Token* tok)
81 {
82  if (!tok || tok->str() != "{")
83  return false;
84  return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum") || Token::Match(tok->tokAt(-3), "enum class %name%");
85 }
86 
87 template<typename T>
88 static void skipEnumBody(T *&tok)
89 {
90  T *defStart = tok;
91  while (Token::Match(defStart, "%name%|::|:"))
92  defStart = defStart->next();
93  if (defStart && defStart->str() == "{")
94  tok = defStart->link()->next();
95 }
96 
97 const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith)
98 {
99  if (!tok)
100  return nullptr;
101  if (tok->str() == "(")
102  tok = tok->link();
103  if (tok->str() != ")")
104  return nullptr;
105  if (!tok->isCpp() && !Token::Match(tok->link()->previous(), "%name%|)"))
106  return nullptr;
107  if (Token::Match(tok, ") ;|{|[")) {
108  tok = tok->next();
109  while (tok && tok->str() == "[" && tok->link()) {
110  if (endsWith.find(tok->str()) != std::string::npos)
111  return tok;
112  tok = tok->link()->next();
113  }
114  return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
115  }
116  if (tok->isCpp() && tok->str() == ")") {
117  tok = tok->next();
118  while (Token::Match(tok, "const|noexcept|override|final|volatile|mutable|&|&& !!(") ||
119  (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
120  tok = tok->next();
121  if (tok && tok->str() == ")")
122  tok = tok->next();
123  while (tok && tok->str() == "[")
124  tok = tok->link()->next();
125  if (Token::Match(tok, "throw|noexcept ("))
126  tok = tok->linkAt(1)->next();
127  if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
128  tok = tok->linkAt(1)->next();
129  if (tok && tok->originalName() == "->") { // trailing return type
130  for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
131  if (tok->link() && Token::Match(tok, "<|[|("))
132  tok = tok->link();
133  }
134  while (Token::Match(tok, "override|final !!(") ||
135  (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
136  tok = tok->next();
137  if (Token::Match(tok, "= 0|default|delete ;"))
138  tok = tok->tokAt(2);
139  if (tok && tok->str() == ":" && !Token::Match(tok->next(), "%name%|::"))
140  return nullptr;
141  return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
142  }
143  return nullptr;
144 }
145 
146 /**
147  * is tok the start brace { of a class, struct, union, or enum
148  */
149 static bool isClassStructUnionEnumStart(const Token * tok)
150 {
151  if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
152  return false;
153  const Token * tok2 = tok->previous();
154  while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
155  tok2 = tok2->previous();
156  return Token::Match(tok2, "class|struct|union|enum");
157 }
158 
159 //---------------------------------------------------------------------------
160 
161 Tokenizer::Tokenizer(const Settings &settings, ErrorLogger &errorLogger) :
162  list(&settings),
163  mSettings(settings),
164  mErrorLogger(errorLogger),
165  mTemplateSimplifier(new TemplateSimplifier(*this))
166 {}
167 
169 {
170  delete mSymbolDatabase;
171  delete mTemplateSimplifier;
172 }
173 
174 
175 //---------------------------------------------------------------------------
176 // SizeOfType - gives the size of a type
177 //---------------------------------------------------------------------------
178 
179 nonneg int Tokenizer::sizeOfType(const std::string& type) const
180 {
181  const std::map<std::string, int>::const_iterator it = mTypeSize.find(type);
182  if (it == mTypeSize.end()) {
183  const Library::PodType* podtype = mSettings.library.podtype(type);
184  if (!podtype)
185  return 0;
186 
187  return podtype->size;
188  }
189  return it->second;
190 }
191 
192 nonneg int Tokenizer::sizeOfType(const Token *type) const
193 {
194  if (!type || type->str().empty())
195  return 0;
196 
197  if (type->tokType() == Token::eString)
198  return Token::getStrLength(type) + 1U;
199 
200  const std::map<std::string, int>::const_iterator it = mTypeSize.find(type->str());
201  if (it == mTypeSize.end()) {
202  const Library::PodType* podtype = mSettings.library.podtype(type->str());
203  if (!podtype)
204  return 0;
205 
206  return podtype->size;
207  }
208  if (type->isLong()) {
209  if (type->str() == "double")
211  if (type->str() == "long")
213  }
214 
215  return it->second;
216 }
217 //---------------------------------------------------------------------------
218 
219 // check if this statement is a duplicate definition
220 bool Tokenizer::duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const
221 {
222  // check for an end of definition
223  Token * tok = tokPtr;
224  if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) {
225  Token * end = tok->next();
226 
227  if (end->str() == "[") {
228  if (!end->link())
229  syntaxError(end); // invalid code
230  end = end->link()->next();
231  } else if (end->str() == ",") {
232  // check for derived class
233  if (Token::Match(tok->previous(), "public|private|protected"))
234  return false;
235 
236  // find end of definition
237  while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
238  if (end->next()->str() == "(")
239  end = end->linkAt(1);
240 
241  end = (end)?end->next():nullptr;
242  }
243  if (end)
244  end = end->next();
245  } else if (end->str() == "(") {
246  if (startsWith(tok->previous()->str(), "operator"))
247  // conversion operator
248  return false;
249  if (tok->previous()->str() == "typedef")
250  // typedef of function returning this type
251  return false;
252  if (Token::Match(tok->previous(), "public:|private:|protected:"))
253  return false;
254  if (tok->previous()->str() == ">") {
255  if (!Token::Match(tok->tokAt(-2), "%type%"))
256  return false;
257 
258  if (!Token::Match(tok->tokAt(-3), ",|<"))
259  return false;
260 
261  tokPtr = end->link();
262  return true;
263  }
264  }
265 
266  if (end) {
267  if (Token::simpleMatch(end, ") {")) { // function parameter ?
268  // look backwards
269  if (Token::Match(tok->previous(), "%type%") &&
270  !Token::Match(tok->previous(), "return|new|const|struct")) {
271  // duplicate definition so skip entire function
272  tokPtr = end->next()->link();
273  return true;
274  }
275  } else if (end->str() == ">") { // template parameter ?
276  // look backwards
277  if (Token::Match(tok->previous(), "%type%") &&
278  !Token::Match(tok->previous(), "return|new|const|volatile")) {
279  // duplicate definition so skip entire template
280  while (end && end->str() != "{")
281  end = end->next();
282  if (end) {
283  tokPtr = end->link();
284  return true;
285  }
286  }
287  } else {
288  // look backwards
289  if (Token::Match(tok->previous(), "typedef|}|>") ||
290  (end->str() == ";" && tok->previous()->str() == ",") ||
291  (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
292  (Token::Match(tok->previous(), "%type%") &&
293  (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
294  !Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
295  // scan backwards for the end of the previous statement
296  while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
297  if (tok->previous()->str() == "}") {
298  tok = tok->previous()->link();
299  } else if (tok->previous()->str() == "typedef") {
300  return true;
301  } else if (tok->previous()->str() == "enum") {
302  return true;
303  } else if (tok->previous()->str() == "struct") {
304  if (tok->strAt(-2) == "typedef" &&
305  tok->next()->str() == "{" &&
306  typeDef->strAt(3) != "{") {
307  // declaration after forward declaration
308  return true;
309  }
310  if (tok->next()->str() == "{")
311  return true;
312  if (Token::Match(tok->next(), ")|*"))
313  return true;
314  if (tok->next()->str() == name->str())
315  return true;
316  if (tok->next()->str() != ";")
317  return true;
318  return false;
319  } else if (tok->previous()->str() == "union") {
320  return tok->next()->str() != ";";
321  } else if (tok->isCpp() && tok->previous()->str() == "class") {
322  return tok->next()->str() != ";";
323  }
324  if (tok)
325  tok = tok->previous();
326  }
327 
328  if (tokPtr->strAt(1) != "(" || !Token::Match(tokPtr->linkAt(1), ") .|(|["))
329  return true;
330  }
331  }
332  }
333  }
334 
335  return false;
336 }
337 
338 void Tokenizer::unsupportedTypedef(const Token *tok) const
339 {
341  return;
342 
343  std::ostringstream str;
344  const Token *tok1 = tok;
345  int level = 0;
346  while (tok) {
347  if (level == 0 && tok->str() == ";")
348  break;
349  if (tok->str() == "{")
350  ++level;
351  else if (tok->str() == "}") {
352  if (level == 0)
353  break;
354  --level;
355  }
356 
357  if (tok != tok1)
358  str << " ";
359  str << tok->str();
360  tok = tok->next();
361  }
362  if (tok)
363  str << " ;";
364 
365  reportError(tok1, Severity::debug, "simplifyTypedef",
366  "Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
367 }
368 
370 {
371  Token *tok = nullptr;
372 
373  // remove typedef but leave ;
374  while (typeDef->next()) {
375  if (typeDef->next()->str() == ";") {
376  typeDef->deleteNext();
377  break;
378  }
379  if (typeDef->next()->str() == "{")
380  Token::eraseTokens(typeDef, typeDef->linkAt(1));
381  else if (typeDef->next()->str() == "}")
382  break;
383  typeDef->deleteNext();
384  }
385 
386  if (typeDef != list.front()) {
387  tok = typeDef->previous();
388  tok->deleteNext();
389  } else {
390  list.front()->deleteThis();
391  tok = list.front();
392  }
393 
394  return tok;
395 }
396 
397 namespace {
398  struct Space {
399  std::string className;
400  const Token* bodyEnd{}; // for body contains typedef define
401  const Token* bodyEnd2{}; // for body contains typedef using
402  bool isNamespace{};
403  std::set<std::string> recordTypes;
404  };
405 }
406 
407 static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
408 {
409  std::string name;
410  std::set<std::string> qualifiers;
411 
412  while (Token::Match(tok->next(), "const|volatile")) {
413  qualifiers.insert(tok->next()->str());
414  tok->deleteNext();
415  }
416 
417  // skip "class|struct|union|enum"
418  Token *tok1 = tok->tokAt(2);
419 
420  const bool hasName = Token::Match(tok1, "%name%");
421 
422  // skip name
423  if (hasName) {
424  name = tok1->str();
425  tok1 = tok1->next();
426  }
427 
428  // skip base classes if present
429  if (tok1->str() == ":") {
430  tok1 = tok1->next();
431  while (tok1 && tok1->str() != "{")
432  tok1 = tok1->next();
433  if (!tok1)
434  return nullptr;
435  }
436 
437  // skip to end
438  tok1 = tok1->link();
439 
440  if (!hasName) { // unnamed
441  if (tok1->next()) {
442  // use typedef name if available
443  if (Token::Match(tok1->next(), "%type%"))
444  name = tok1->next()->str();
445  else // create a unique name
446  name = "Unnamed" + std::to_string((*unnamedCount)++);
447  tok->next()->insertToken(name);
448  } else
449  return nullptr;
450  }
451 
452  tok1->insertToken(";");
453  tok1 = tok1->next();
454 
455  if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
456  tok->deleteThis();
457  tok1->deleteThis();
458  return nullptr;
459  }
460  tok1->insertToken("typedef");
461  tok1 = tok1->next();
462  Token * tok3 = tok1;
463  for (const std::string &qualifier : qualifiers) {
464  tok1->insertToken(qualifier);
465  tok1 = tok1->next();
466  }
467  tok1->insertToken(tok->next()->str()); // struct, union or enum
468  tok1 = tok1->next();
469  tok1->insertToken(name);
470  tok->deleteThis();
471  tok = tok3;
472 
473  return tok;
474 }
475 
476 /* This function is called when processing function related typedefs.
477  * If simplifyTypedef generates an "Internal Error" message and the
478  * code that generated it deals in some way with functions, then this
479  * function will probably need to be extended to handle a new function
480  * related pattern */
481 const Token *Tokenizer::processFunc(const Token *tok2, bool inOperator) const
482 {
483  if (tok2->next() && tok2->next()->str() != ")" &&
484  tok2->next()->str() != ",") {
485  // skip over tokens for some types of canonicalization
486  if (Token::Match(tok2->next(), "( * %type% ) ("))
487  tok2 = tok2->linkAt(5);
488  else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
489  tok2 = tok2->linkAt(6);
490  else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
491  tok2 = tok2->tokAt(5);
492  else if (Token::Match(tok2->next(), "* ( %type% [") &&
493  Token::Match(tok2->linkAt(4), "] ) ;|="))
494  tok2 = tok2->linkAt(4)->next();
495  else if (Token::Match(tok2->next(), "* ( * %type% ("))
496  tok2 = tok2->linkAt(5)->next();
497  else if (Token::simpleMatch(tok2->next(), "* [") &&
498  Token::simpleMatch(tok2->linkAt(2), "] ;"))
499  tok2 = tok2->next();
500  else {
501  if (tok2->next()->str() == "(")
502  tok2 = tok2->next()->link();
503  else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
504  tok2 = tok2->next();
505 
506  while (Token::Match(tok2, "*|&") &&
507  !Token::Match(tok2->next(), ")|>"))
508  tok2 = tok2->next();
509 
510  // skip over namespace
511  while (Token::Match(tok2, "%name% ::"))
512  tok2 = tok2->tokAt(2);
513 
514  if (!tok2)
515  return nullptr;
516 
517  if (tok2->str() == "(" &&
518  tok2->link()->next() &&
519  tok2->link()->next()->str() == "(") {
520  tok2 = tok2->link();
521 
522  if (tok2->next()->str() == "(")
523  tok2 = tok2->next()->link();
524  }
525 
526  // skip over typedef parameter
527  if (tok2->next() && tok2->next()->str() == "(") {
528  tok2 = tok2->next()->link();
529  if (!tok2->next())
530  syntaxError(tok2);
531 
532  if (tok2->next()->str() == "(")
533  tok2 = tok2->next()->link();
534  }
535  }
536  }
537  }
538  return tok2;
539 }
540 
541 Token *Tokenizer::processFunc(Token *tok2, bool inOperator)
542 {
543  return const_cast<Token*>(processFunc(const_cast<const Token*>(tok2), inOperator));
544 }
545 
547 {
549  return;
550 
551  for (Token *tok = list.front(); tok; tok = tok->next()) {
552  // using a::b; => typedef a::b b;
553  if ((Token::Match(tok, "[;{}] using %name% :: %name% ::|;") && !tok->tokAt(2)->isKeyword()) ||
554  (Token::Match(tok, "[;{}] using :: %name% :: %name% ::|;") && !tok->tokAt(3)->isKeyword())) {
555  Token *endtok = tok->tokAt(5);
556  if (Token::Match(endtok, "%name%"))
557  endtok = endtok->next();
558  while (Token::Match(endtok, ":: %name%"))
559  endtok = endtok->tokAt(2);
560  if (endtok && endtok->str() == ";") {
561  tok->next()->str("typedef");
562  endtok = endtok->previous();
563  endtok->insertToken(endtok->str());
564  }
565  }
566  }
567 }
568 
570 {
571  if (!list.front())
572  return;
573 
574  for (Token* tok = list.front()->next(); tok; tok = tok->next()) {
575  if (tok->str() == "typedef") {
576  bool doSimplify = !Token::Match(tok->previous(), ";|{|}|:|public:|private:|protected:");
577  if (doSimplify && Token::simpleMatch(tok->previous(), ")") && Token::Match(tok->linkAt(-1)->previous(), "if|for|while"))
578  doSimplify = false;
579  bool haveStart = false;
580  Token* start{};
581  if (!doSimplify && Token::simpleMatch(tok->previous(), "}")) {
582  start = tok->linkAt(-1)->previous();
583  while (Token::Match(start, "%name%")) {
584  if (Token::Match(start, "class|struct|union|enum")) {
585  start = start->previous();
586  doSimplify = true;
587  haveStart = true;
588  break;
589  }
590  start = start->previous();
591  }
592  }
593  if (doSimplify) {
594  if (!haveStart) {
595  start = tok;
596  while (start && !Token::Match(start, "[;{}]"))
597  start = start->previous();
598  }
599  if (start)
600  start = start->next();
601  else
602  start = list.front();
603  start->insertTokenBefore(tok->str());
604  tok->deleteThis();
605  }
606  }
607  }
608 }
609 
610 namespace {
611  class TypedefSimplifier {
612  private:
613  Token* mTypedefToken; // The "typedef" token
614  Token* mEndToken{nullptr}; // Semicolon
615  std::pair<Token*, Token*> mRangeType;
616  std::pair<Token*, Token*> mRangeTypeQualifiers;
617  std::pair<Token*, Token*> mRangeAfterVar;
618  Token* mNameToken{nullptr};
619  bool mFail = false;
620  bool mReplaceFailed = false;
621  bool mUsed = false;
622 
623  public:
624  explicit TypedefSimplifier(Token* typedefToken) : mTypedefToken(typedefToken) {
625  Token* start = typedefToken->next();
626  if (Token::simpleMatch(start, "typename"))
627  start = start->next();
628 
629  // TODO handle unnamed structs etc
630  if (Token::Match(start, "const| enum|struct|union|class %name%| {")) {
631  const std::pair<Token*, Token*> rangeBefore(start, Token::findsimplematch(start, "{"));
632 
633  // find typedef name token
634  Token* nameToken = rangeBefore.second->link()->next();
635  while (Token::Match(nameToken, "%name%|* %name%|*"))
636  nameToken = nameToken->next();
637  const std::pair<Token*, Token*> rangeQualifiers(rangeBefore.second->link()->next(), nameToken);
638 
639  if (Token::Match(nameToken, "%name% ;")) {
640  if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {"))
641  rangeBefore.second->previous()->insertToken(nameToken->str());
642  mRangeType = rangeBefore;
643  mRangeTypeQualifiers = rangeQualifiers;
644  Token* typeName = rangeBefore.second->previous();
645  if (typeName->isKeyword()) {
646  // TODO typeName->insertToken("T:" + std::to_string(num++));
647  typeName->insertToken(nameToken->str());
648  }
649  mNameToken = nameToken;
650  mEndToken = nameToken->next();
651  return;
652  }
653  }
654 
655  for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) {
656  if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) {
657  mRangeType.first = start;
658  mRangeType.second = type;
659  mNameToken = type;
660  mEndToken = mNameToken->next();
661  return;
662  }
663  if (type != start && Token::Match(type, "%name% [")) {
664  Token* end = type->linkAt(1);
665  while (Token::simpleMatch(end, "] ["))
666  end = end->linkAt(1);
667  if (!Token::simpleMatch(end, "] ;"))
668  break;
669  mRangeType.first = start;
670  mRangeType.second = type;
671  mNameToken = type;
672  mEndToken = end->next();
673  mRangeAfterVar.first = mNameToken->next();
674  mRangeAfterVar.second = mEndToken;
675  return;
676  }
677  if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) {
678  mNameToken = type->linkAt(1)->previous();
679  mEndToken = type->linkAt(1)->linkAt(1)->next();
680  mRangeType.first = start;
681  mRangeType.second = mNameToken;
682  mRangeAfterVar.first = mNameToken->next();
683  mRangeAfterVar.second = mEndToken;
684  return;
685  }
686  if (Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
687  mNameToken = type;
688  mEndToken = type->linkAt(1)->next();
689  mRangeType.first = start;
690  mRangeType.second = type;
691  mRangeAfterVar.first = mNameToken->next();
692  mRangeAfterVar.second = mEndToken;
693  return;
694  }
695  }
696  // TODO: handle all typedefs
697  if ((false))
698  printTypedef(typedefToken);
699  mFail = true;
700  }
701 
702  const Token* getTypedefToken() const {
703  return mTypedefToken;
704  }
705 
706  bool isUsed() const {
707  return mUsed;
708  }
709 
710  bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
711  if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
712  return false;
713  const auto it = m.find(mTypedefToken->strAt(2));
714  if (it == m.end())
715  return false;
716  return Token::Match(it->second.mNameToken, "%name% (");
717  }
718 
719  bool fail() const {
720  return mFail;
721  }
722 
723  bool replaceFailed() const {
724  return mReplaceFailed;
725  }
726 
727  bool isStructEtc() const {
728  return mRangeType.second && mRangeType.second->str() == "{";
729  }
730 
731  std::string name() const {
732  return mNameToken ? mNameToken->str() : "";
733  }
734 
735  void replace(Token* tok) {
736  if (tok == mNameToken)
737  return;
738 
739  mUsed = true;
740 
741  // Special handling for T() when T is a pointer
742  if (Token::Match(tok, "%name% ( )")) {
743  bool pointerType = false;
744  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
745  if (type->str() == "*" || type->str() == "&") {
746  pointerType = true;
747  break;
748  }
749  }
750  for (const Token* type = mRangeTypeQualifiers.first; type != mRangeTypeQualifiers.second; type = type->next()) {
751  if (type->str() == "*" || type->str() == "&") {
752  pointerType = true;
753  break;
754  }
755  }
756  if (pointerType) {
757  tok->deleteThis();
758  tok->next()->insertToken("0");
759  Token* tok2 = insertTokens(tok, mRangeType);
760  insertTokens(tok2, mRangeTypeQualifiers);
761  return;
762  }
763  }
764 
765  // Special handling of function pointer cast
766  const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
767  if (isFunctionPointer && isCast(tok->previous())) {
768  tok->insertToken("*");
769  insertTokens(tok, std::pair<Token*, Token*>(mRangeType.first, mNameToken->linkAt(1)));
770  tok->deleteThis();
771  return;
772  }
773 
774  // Inherited type => skip "struct" / "class"
775  if (Token::Match(mRangeType.first, "const| struct|class %name% {") && Token::Match(tok->previous(), "public|protected|private|<")) {
776  tok->originalName(tok->str());
777  tok->str(mRangeType.second->previous()->str());
778  return;
779  }
780 
781  if (Token::Match(tok, "%name% ::")) {
782  if (Token::Match(mRangeType.first, "const| struct|class %name% %name% ;")) {
783  tok->originalName(tok->str());
784  tok->str(mRangeType.second->previous()->str());
785  } else {
786  mReplaceFailed = true;
787  }
788  return;
789  }
790 
791  // pointer => move "const"
792  if (Token::simpleMatch(tok->previous(), "const")) {
793  bool pointerType = false;
794  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
795  if (type->str() == "*") {
796  pointerType = true;
797  break;
798  }
799  }
800  if (pointerType) {
801  tok->insertToken("const");
802  tok->next()->column(tok->column());
803  tok->next()->setMacroName(tok->previous()->getMacroName());
804  tok->deletePrevious();
805  }
806  }
807 
808  // Do not duplicate class/struct/enum/union
809  if (Token::Match(tok->previous(), "enum|union|struct|class")) {
810  bool found = false;
811  const std::string &kw = tok->previous()->str();
812  for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
813  if (type->str() == kw) {
814  found = true;
815  break;
816  }
817  }
818  if (found)
819  tok->deletePrevious();
820  else {
821  mReplaceFailed = true;
822  return;
823  }
824  }
825 
826  // don't add class|struct|union in inheritance list
827  auto rangeType = mRangeType;
828  if (Token::Match(tok->previous(), "public|private|protected")) {
829  while (Token::Match(rangeType.first, "const|class|struct|union"))
830  rangeType.first = rangeType.first->next();
831  }
832 
833  Token* const tok2 = insertTokens(tok, rangeType);
834  Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
835 
836  tok2->originalName(tok->str());
837  tok3->originalName(tok->str());
838  Token *after = tok3;
839  while (Token::Match(after, "%name%|*|&|&&|::"))
840  after = after->next();
841  if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
842  while (Token::Match(after, "(|["))
843  after = after->link()->next();
844  if (after) {
845  tok3->insertToken("(");
846  after->previous()->insertToken(")");
847  Token::createMutualLinks(tok3->next(), after->previous());
848  }
849  }
850 
851  bool useAfterVarRange = true;
852  if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
853  if (Token::Match(after->previous(), "%name% ( !!*")) {
854  useAfterVarRange = false;
855  // Function return type => replace array with "*"
856  for (const Token* a = mRangeAfterVar.first; Token::simpleMatch(a, "["); a = a->link()->next())
857  tok3->insertToken("*");
858  } else if (Token::Match(after->previous(), "%name% ( * %name% ) [")) {
859  after = after->linkAt(4)->next();
860  } else {
861  Token* prev = after->previous();
862  if (prev->isName() && prev != tok3)
863  prev = prev->previous();
864  if (Token::Match(prev, "*|&|&&") && prev != tok3) {
865  while (Token::Match(prev, "*|&|&&") && prev != tok3)
866  prev = prev->previous();
867  prev->insertToken("(");
868  after->previous()->insertToken(")");
869  }
870  }
871  }
872 
873  if (isFunctionPointer) {
874  if (Token::Match(after, "( * %name% ) ("))
875  after = after->link()->linkAt(1)->next();
876  else if (after->str() == "(") {
877  useAfterVarRange = false;
878  if (Token::simpleMatch(tok3->previous(), "( *"))
879  tok3->deletePrevious();
880  }
881  else if (after->str() == "[") {
882  while (after && after->str() == "[")
883  after = after->link()->next();
884  }
885  }
886  else {
887  while (Token::simpleMatch(after, "["))
888  after = after->link()->next();
889  }
890 
891  if (!after)
892  throw InternalError(tok, "Failed to simplify typedef. Is the code valid?");
893 
894  Token* const tok4 = useAfterVarRange ? insertTokens(after->previous(), mRangeAfterVar)->next() : tok3->next();
895 
896  tok->deleteThis();
897 
898  // Unsplit variable declarations
899  if (tok4 && tok4->isSplittedVarDeclEq() &&
900  ((tok4->isCpp() && Token::Match(tok4->tokAt(-2), "&|&& %name% ;")) || Token::Match(tok4->previous(), "] ; %name% = {"))) {
901  tok4->deleteNext();
902  tok4->deleteThis();
903  }
904 
905  // Set links
906  std::stack<Token*> brackets;
907  for (; tok != tok4; tok = tok->next()) {
908  if (Token::Match(tok, "[{([]"))
909  brackets.push(tok);
910  else if (Token::Match(tok, "[})]]")) {
911  Token::createMutualLinks(brackets.top(), tok);
912  brackets.pop();
913  }
914  }
915  }
916 
917  void removeDeclaration() {
918  if (Token::simpleMatch(mRangeType.second, "{")) {
919  while (Token::Match(mTypedefToken, "typedef|const"))
920  mTypedefToken->deleteThis();
921  Token::eraseTokens(mRangeType.second->link(), mEndToken);
922  } else {
923  Token::eraseTokens(mTypedefToken, mEndToken);
924  mTypedefToken->deleteThis();
925  }
926  }
927 
928  static int canReplaceStatic(const Token* tok) {
929  if (!Token::Match(tok, "%name% %name%|*|&|&&|;|(|)|,|::")) {
930  if (Token::Match(tok->previous(), "( %name% =") && Token::Match(tok->linkAt(-1), ") %name%|{") && !tok->tokAt(-2)->isKeyword())
931  return true;
932  if (Token::Match(tok->previous(), ", %name% ="))
933  return true;
934  if (Token::Match(tok->previous(), "new %name% ["))
935  return true;
936  if (Token::Match(tok->previous(), "< %name%") && tok->previous()->findClosingBracket())
937  return true;
938  if (Token::Match(tok->previous(), ", %name% >|>>")) {
939  for (const Token* prev = tok->previous(); prev; prev = prev->previous()) {
940  if (Token::Match(prev, "[;{}(]"))
941  break;
942  if (prev->str() == "<" && prev->findClosingBracket() == tok->next())
943  return true;
944  if (prev->str() == ")")
945  prev = prev->link();
946  }
947  return true;
948  }
949  if (Token::Match(tok->previous(), "public|protected|private"))
950  return true;
951  if (Token::Match(tok->previous(), ", %name% :")) {
952  bool isGeneric = false;
953  for (; tok; tok = tok->previous()) {
954  if (Token::Match(tok, ")|]"))
955  tok = tok->link();
956  else if (Token::Match(tok, "[;{}(]")) {
957  isGeneric = Token::simpleMatch(tok->previous(), "_Generic (");
958  break;
959  }
960  }
961  return isGeneric;
962  }
963  return false;
964  }
965  return -1;
966  }
967 
968  bool canReplace(const Token* tok) {
969  if (mNameToken == tok)
970  return false;
971  if (!Token::Match(tok->previous(), "%name%|;|{|}|(|,|<") && !Token::Match(tok->previous(), "!!. %name% ("))
972  return false;
973  {
974  const int res = canReplaceStatic(tok);
975  if (res == 0 || res == 1)
976  return res != 0;
977  }
978  if (Token::Match(tok->previous(), "%name%") && !tok->previous()->isKeyword())
979  return false;
980  if (Token::simpleMatch(tok->next(), "(") && Token::Match(tok->linkAt(1), ") %name%|{"))
981  return false;
982  if (Token::Match(tok->previous(), "struct|union|class|enum %name% %name%") &&
983  Token::simpleMatch(mRangeType.second, "{") &&
984  tok->str() != mRangeType.second->previous()->str())
985  return true;
986  if (Token::Match(tok->previous(), "; %name% ;"))
987  return false;
988  if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
989  return true;
990  for (const Token* after = tok->next(); after; after = after->next()) {
991  if (Token::Match(after, "%name%|::|&|*|&&"))
992  continue;
993  if (after->str() == "<" && after->link())
994  break;
995  if (after->isNumber())
996  return false;
997  if (after->isComparisonOp() || after->isArithmeticalOp())
998  return false;
999  break;
1000  }
1001  for (const Token* before = tok->previous(); before; before = before->previous()) {
1002  if (Token::Match(before, "[+-*/&|~!]"))
1003  return false;
1004  if (Token::Match(before, "struct|union|class|enum") || before->isStandardType())
1005  return false;
1006  if (before->str() == "::")
1007  return false;
1008  if (before->isName())
1009  continue;
1010  break;
1011  }
1012  return true;
1013  }
1014 
1015  Token* endToken() const {
1016  return mEndToken;
1017  }
1018 
1019  private:
1020  static bool isCast(const Token* tok) {
1021  if (Token::Match(tok, "( %name% ) (|%name%"))
1022  return !tok->tokAt(2)->isKeyword();
1023  if (Token::Match(tok, "< %name% > (") && tok->previous() && endsWith(tok->previous()->str(), "_cast", 5))
1024  return true;
1025  return false;
1026  }
1027 
1028  static Token* insertTokens(Token* to, std::pair<Token*,Token*> range) {
1029  for (const Token* from = range.first; from != range.second; from = from->next()) {
1030  to->insertToken(from->str());
1031  to->next()->column(to->column());
1032  to = to->next();
1033  to->isSimplifiedTypedef(true);
1034  to->isExternC(from->isExternC());
1035  }
1036  return to;
1037  }
1038 
1039  static void printTypedef(const Token *tok) {
1040  int indent = 0;
1041  while (tok && (indent > 0 || tok->str() != ";")) {
1042  if (tok->str() == "{")
1043  ++indent;
1044  else if (tok->str() == "}")
1045  --indent;
1046  std::cout << " " << tok->str();
1047  tok = tok->next();
1048  }
1049  std::cout << "\n";
1050  }
1051  };
1052 }
1053 
1055 {
1056  // Simplify global typedefs that are not redefined with the fast 1-pass simplification.
1057  // Then use the slower old typedef simplification.
1058  std::map<std::string, int> numberOfTypedefs;
1059  for (Token* tok = list.front(); tok; tok = tok->next()) {
1060  if (tok->str() == "typedef") {
1061  TypedefSimplifier ts(tok);
1062  if (!ts.fail())
1063  numberOfTypedefs[ts.name()]++;
1064  continue;
1065  }
1066  }
1067 
1068  int indentlevel = 0;
1069  std::map<std::string, TypedefSimplifier> typedefs;
1070  for (Token* tok = list.front(); tok; tok = tok->next()) {
1071  if (!tok->isName()) {
1072  if (tok->str()[0] == '{')
1073  ++indentlevel;
1074  else if (tok->str()[0] == '}')
1075  --indentlevel;
1076  continue;
1077  }
1078 
1079  if (indentlevel == 0 && tok->str() == "typedef") {
1080  TypedefSimplifier ts(tok);
1081  if (!ts.fail() && numberOfTypedefs[ts.name()] == 1 &&
1082  (numberOfTypedefs.find(ts.getTypedefToken()->strAt(1)) == numberOfTypedefs.end() || ts.getTypedefToken()->strAt(2) == "(")) {
1083  if (mSettings.severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
1084  reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
1085  "It is unspecified behavior to const qualify a function type.");
1086  typedefs.emplace(ts.name(), ts);
1087  if (!ts.isStructEtc())
1088  tok = ts.endToken();
1089  }
1090  continue;
1091  }
1092 
1093  auto it = typedefs.find(tok->str());
1094  if (it != typedefs.end() && it->second.canReplace(tok)) {
1095  std::set<std::string> r;
1096  while (it != typedefs.end() && r.insert(tok->str()).second) {
1097  it->second.replace(tok);
1098  it = typedefs.find(tok->str());
1099  }
1100  } else if (tok->str() == "enum") {
1101  while (Token::Match(tok, "%name%|:|::"))
1102  tok = tok->next();
1103  if (!tok)
1104  break;
1105  if (tok->str() == "{")
1106  tok = tok->link();
1107  }
1108  }
1109 
1110  if (!typedefs.empty())
1111  {
1112  // remove typedefs
1113  for (auto &t: typedefs) {
1114  if (!t.second.replaceFailed()) {
1115  const Token* const typedefToken = t.second.getTypedefToken();
1116  TypedefInfo typedefInfo;
1117  typedefInfo.name = t.second.name();
1118  typedefInfo.filename = list.file(typedefToken);
1119  typedefInfo.lineNumber = typedefToken->linenr();
1120  typedefInfo.column = typedefToken->column();
1121  typedefInfo.used = t.second.isUsed();
1122  mTypedefInfo.push_back(std::move(typedefInfo));
1123 
1124  t.second.removeDeclaration();
1125  }
1126  }
1127 
1128  while (Token::Match(list.front(), "; %any%"))
1129  list.front()->deleteThis();
1130  }
1131 
1133 }
1134 
1135 static bool isEnumScope(const Token* tok)
1136 {
1137  if (!Token::simpleMatch(tok, "{"))
1138  return false;
1139  tok = tok->previous();
1140  while (tok && !tok->isKeyword() && Token::Match(tok, "%name%|::|:"))
1141  tok = tok->previous();
1142  if (Token::simpleMatch(tok, "class"))
1143  tok = tok->previous();
1144  return Token::simpleMatch(tok, "enum");
1145 }
1146 
1148 {
1149  bool isNamespace = false;
1150  std::string className, fullClassName;
1151  bool hasClass = false;
1152  bool goback = false;
1153 
1154  // add global namespace
1155  std::vector<Space> spaceInfo(1);
1156 
1157  // Convert "using a::b;" to corresponding typedef statements
1159 
1160  const std::time_t maxTime = mSettings.typedefMaxTime > 0 ? std::time(nullptr) + mSettings.typedefMaxTime: 0;
1161 
1162  for (Token *tok = list.front(); tok; tok = tok->next()) {
1163  if (!list.getFiles().empty())
1164  mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
1165 
1166  if (Settings::terminated())
1167  return;
1168 
1169  if (maxTime > 0 && std::time(nullptr) > maxTime) {
1170  if (mSettings.debugwarnings) {
1171  ErrorMessage::FileLocation loc(list.getFiles()[0], 0, 0);
1172  ErrorMessage errmsg({std::move(loc)},
1173  emptyString,
1175  "Typedef simplification instantiation maximum time exceeded",
1176  "typedefMaxTime",
1178  mErrorLogger.reportErr(errmsg);
1179  }
1180  return;
1181  }
1182 
1183  if (goback) {
1184  //jump back once, see the comment at the end of the function
1185  goback = false;
1186  tok = tok->previous();
1187  }
1188 
1189  if (tok->str() != "typedef") {
1190  if (Token::simpleMatch(tok, "( typedef")) {
1191  // Skip typedefs inside parentheses (#2453 and #4002)
1192  tok = tok->next();
1193  } else if (Token::Match(tok, "class|struct|namespace %any%") &&
1194  (!tok->previous() || tok->previous()->str() != "enum")) {
1195  isNamespace = (tok->str() == "namespace");
1196  hasClass = true;
1197  className = tok->next()->str();
1198  const Token *tok1 = tok->next();
1199  fullClassName = className;
1200  while (Token::Match(tok1, "%name% :: %name%")) {
1201  tok1 = tok1->tokAt(2);
1202  fullClassName += " :: " + tok1->str();
1203  }
1204  } else if (hasClass && tok->str() == ";") {
1205  hasClass = false;
1206  } else if (hasClass && tok->str() == "{") {
1207  if (!isNamespace)
1208  spaceInfo.back().recordTypes.insert(fullClassName);
1209 
1210  Space info;
1211  info.isNamespace = isNamespace;
1212  info.className = className;
1213  info.bodyEnd = tok->link();
1214  info.bodyEnd2 = tok->link();
1215  spaceInfo.push_back(std::move(info));
1216 
1217  hasClass = false;
1218  } else if (spaceInfo.size() > 1 && tok->str() == "}" && spaceInfo.back().bodyEnd == tok) {
1219  spaceInfo.pop_back();
1220  }
1221  continue;
1222  }
1223 
1224  // pull struct, union, enum or class definition out of typedef
1225  // use typedef name for unnamed struct, union, enum or class
1226  const Token* tokClass = tok->next();
1227  while (Token::Match(tokClass, "const|volatile"))
1228  tokClass = tokClass->next();
1229  if (Token::Match(tokClass, "struct|enum|union|class %type%| {|:")) {
1231  if (!tok1)
1232  continue;
1233  tok = tok1;
1234  }
1235 
1236  /** @todo add support for union */
1237  if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
1238  tok->deleteNext(3);
1239  tok->deleteThis();
1240  if (tok->next())
1241  tok->deleteThis();
1242  //now the next token to process is 'tok', not 'tok->next()';
1243  goback = true;
1244  continue;
1245  }
1246 
1247  Token *typeName;
1248  Token *typeStart = nullptr;
1249  Token *typeEnd = nullptr;
1250  Token *argStart = nullptr;
1251  Token *argEnd = nullptr;
1252  Token *arrayStart = nullptr;
1253  Token *arrayEnd = nullptr;
1254  Token *specStart = nullptr;
1255  Token *specEnd = nullptr;
1256  Token *typeDef = tok;
1257  Token *argFuncRetStart = nullptr;
1258  Token *argFuncRetEnd = nullptr;
1259  Token *funcStart = nullptr;
1260  Token *funcEnd = nullptr;
1261  Token *tokOffset = tok->next();
1262  bool function = false;
1263  bool functionPtr = false;
1264  bool functionRetFuncPtr = false;
1265  bool functionPtrRetFuncPtr = false;
1266  bool ptrToArray = false;
1267  bool refToArray = false;
1268  bool ptrMember = false;
1269  bool typeOf = false;
1270  Token *namespaceStart = nullptr;
1271  Token *namespaceEnd = nullptr;
1272 
1273  // check for invalid input
1274  if (!tokOffset || tokOffset->isControlFlowKeyword())
1275  syntaxError(tok);
1276 
1277  if (tokOffset->str() == "::") {
1278  typeStart = tokOffset;
1279  tokOffset = tokOffset->next();
1280 
1281  while (Token::Match(tokOffset, "%type% ::"))
1282  tokOffset = tokOffset->tokAt(2);
1283 
1284  typeEnd = tokOffset;
1285 
1286  if (Token::Match(tokOffset, "%type%"))
1287  tokOffset = tokOffset->next();
1288  } else if (Token::Match(tokOffset, "%type% ::")) {
1289  typeStart = tokOffset;
1290 
1291  do {
1292  tokOffset = tokOffset->tokAt(2);
1293  } while (Token::Match(tokOffset, "%type% ::"));
1294 
1295  typeEnd = tokOffset;
1296 
1297  if (Token::Match(tokOffset, "%type%"))
1298  tokOffset = tokOffset->next();
1299  } else if (Token::Match(tokOffset, "%type%")) {
1300  typeStart = tokOffset;
1301 
1302  while (Token::Match(tokOffset, "const|struct|enum %type%") ||
1303  (tokOffset->next() && tokOffset->next()->isStandardType() && !Token::Match(tokOffset->next(), "%name% ;")))
1304  tokOffset = tokOffset->next();
1305 
1306  typeEnd = tokOffset;
1307  if (!Token::Match(tokOffset->next(), "%name% ;"))
1308  tokOffset = tokOffset->next();
1309 
1310  while (Token::Match(tokOffset, "%type%") &&
1311  (tokOffset->isStandardType() || Token::Match(tokOffset, "unsigned|signed")) &&
1312  !Token::Match(tokOffset->next(), "%name% ;")) {
1313  typeEnd = tokOffset;
1314  tokOffset = tokOffset->next();
1315  }
1316 
1317  bool atEnd = false;
1318  while (!atEnd) {
1319  if (tokOffset && tokOffset->str() == "::") {
1320  typeEnd = tokOffset;
1321  tokOffset = tokOffset->next();
1322  }
1323 
1324  if (Token::Match(tokOffset, "%type%") &&
1325  tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
1326  typeEnd = tokOffset;
1327  tokOffset = tokOffset->next();
1328  } else if (Token::simpleMatch(tokOffset, "const (")) {
1329  typeEnd = tokOffset;
1330  tokOffset = tokOffset->next();
1331  atEnd = true;
1332  } else
1333  atEnd = true;
1334  }
1335  } else
1336  continue; // invalid input
1337 
1338  // check for invalid input
1339  if (!tokOffset)
1340  syntaxError(tok);
1341 
1342  // check for template
1343  if (!isC() && tokOffset->str() == "<") {
1344  typeEnd = tokOffset->findClosingBracket();
1345 
1346  while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
1347  typeEnd = typeEnd->tokAt(2);
1348 
1349  if (!typeEnd) {
1350  // internal error
1351  return;
1352  }
1353 
1354  while (Token::Match(typeEnd->next(), "const|volatile"))
1355  typeEnd = typeEnd->next();
1356 
1357  tok = typeEnd;
1358  tokOffset = tok->next();
1359  }
1360 
1361  std::list<std::string> pointers;
1362  // check for pointers and references
1363  while (Token::Match(tokOffset, "*|&|&&|const")) {
1364  pointers.push_back(tokOffset->str());
1365  tokOffset = tokOffset->next();
1366  }
1367 
1368  // check for invalid input
1369  if (!tokOffset)
1370  syntaxError(tok);
1371 
1372  if (tokOffset->isName() && !tokOffset->isKeyword()) {
1373  // found the type name
1374  typeName = tokOffset;
1375  tokOffset = tokOffset->next();
1376 
1377  // check for array
1378  while (tokOffset && tokOffset->str() == "[") {
1379  if (!arrayStart)
1380  arrayStart = tokOffset;
1381  arrayEnd = tokOffset->link();
1382  tokOffset = arrayEnd->next();
1383  }
1384 
1385  // check for end or another
1386  if (Token::Match(tokOffset, ";|,"))
1387  tok = tokOffset;
1388 
1389  // or a function typedef
1390  else if (tokOffset && tokOffset->str() == "(") {
1391  Token *tokOffset2 = nullptr;
1392  if (Token::Match(tokOffset, "( *|%name%")) {
1393  tokOffset2 = tokOffset->next();
1394  if (tokOffset2->str() == "typename")
1395  tokOffset2 = tokOffset2->next();
1396  while (Token::Match(tokOffset2, "%type% ::"))
1397  tokOffset2 = tokOffset2->tokAt(2);
1398  }
1399 
1400  // unhandled typedef, skip it and continue
1401  if (typeName->str() == "void") {
1402  unsupportedTypedef(typeDef);
1403  tok = deleteInvalidTypedef(typeDef);
1404  if (tok == list.front())
1405  //now the next token to process is 'tok', not 'tok->next()';
1406  goback = true;
1407  continue;
1408  }
1409 
1410  // function pointer
1411  if (Token::Match(tokOffset2, "* %name% ) (")) {
1412  // name token wasn't a name, it was part of the type
1413  typeEnd = typeEnd->next();
1414  functionPtr = true;
1415  funcStart = funcEnd = tokOffset2; // *
1416  tokOffset = tokOffset2->tokAt(3); // (
1417  typeName = tokOffset->tokAt(-2);
1418  argStart = tokOffset;
1419  argEnd = tokOffset->link();
1420  tok = argEnd->next();
1421  }
1422 
1423  // function
1424  else if (isFunctionHead(tokOffset->link(), ";,")) {
1425  function = true;
1426  if (tokOffset->link()->next()->str() == "const") {
1427  specStart = tokOffset->link()->next();
1428  specEnd = specStart;
1429  }
1430  argStart = tokOffset;
1431  argEnd = tokOffset->link();
1432  tok = argEnd->next();
1433  if (specStart)
1434  tok = tok->next();
1435  }
1436 
1437  // syntax error
1438  else
1439  syntaxError(tok);
1440  }
1441 
1442  // unhandled typedef, skip it and continue
1443  else {
1444  unsupportedTypedef(typeDef);
1445  tok = deleteInvalidTypedef(typeDef);
1446  if (tok == list.front())
1447  //now the next token to process is 'tok', not 'tok->next()';
1448  goback = true;
1449  continue;
1450  }
1451  }
1452 
1453  // typeof: typedef typeof ( ... ) type;
1454  else if (Token::simpleMatch(tokOffset->previous(), "typeof (") &&
1455  Token::Match(tokOffset->link(), ") %type% ;")) {
1456  argStart = tokOffset;
1457  argEnd = tokOffset->link();
1458  typeName = tokOffset->link()->next();
1459  tok = typeName->next();
1460  typeOf = true;
1461  }
1462 
1463  // function: typedef ... ( ... type )( ... );
1464  // typedef ... (( ... type )( ... ));
1465  // typedef ... ( * ( ... type )( ... ));
1466  else if (tokOffset->str() == "(" && (
1467  (tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
1468  Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
1469  (Token::simpleMatch(tokOffset, "( (") &&
1470  tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
1471  Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
1472  (Token::simpleMatch(tokOffset, "( * (") &&
1473  tokOffset->linkAt(2) && Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
1474  Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
1475  if (tokOffset->next()->str() == "(")
1476  tokOffset = tokOffset->next();
1477  else if (Token::simpleMatch(tokOffset, "( * (")) {
1478  pointers.emplace_back("*");
1479  tokOffset = tokOffset->tokAt(2);
1480  }
1481 
1482  if (tokOffset->link()->strAt(-2) == "*")
1483  functionPtr = true;
1484  else
1485  function = true;
1486  funcStart = tokOffset->next();
1487  tokOffset = tokOffset->link();
1488  funcEnd = tokOffset->tokAt(-2);
1489  typeName = tokOffset->previous();
1490  argStart = tokOffset->next();
1491  argEnd = tokOffset->next()->link();
1492  if (!argEnd)
1493  syntaxError(argStart);
1494 
1495  tok = argEnd->next();
1496  Token *spec = tok;
1497  if (Token::Match(spec, "const|volatile")) {
1498  specStart = spec;
1499  specEnd = spec;
1500  while (Token::Match(spec->next(), "const|volatile")) {
1501  specEnd = spec->next();
1502  spec = specEnd;
1503  }
1504  tok = specEnd->next();
1505  }
1506  if (!tok)
1507  syntaxError(specEnd);
1508 
1509  if (tok->str() == ")")
1510  tok = tok->next();
1511  }
1512 
1513  else if (Token::Match(tokOffset, "( %type% (")) {
1514  function = true;
1515  if (tokOffset->link()->next()) {
1516  tok = tokOffset->link()->next();
1517  tokOffset = tokOffset->tokAt(2);
1518  typeName = tokOffset->previous();
1519  argStart = tokOffset;
1520  argEnd = tokOffset->link();
1521  } else {
1522  // internal error
1523  continue;
1524  }
1525  }
1526 
1527  // pointer to function returning pointer to function
1528  else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
1529  Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
1530  Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
1531  functionPtrRetFuncPtr = true;
1532 
1533  tokOffset = tokOffset->tokAt(6);
1534  typeName = tokOffset->tokAt(-2);
1535  argStart = tokOffset;
1536  argEnd = tokOffset->link();
1537  if (!argEnd)
1538  syntaxError(arrayStart);
1539 
1540  argFuncRetStart = argEnd->tokAt(2);
1541  argFuncRetEnd = argFuncRetStart->link();
1542  if (!argFuncRetEnd)
1543  syntaxError(argFuncRetStart);
1544 
1545  tok = argFuncRetEnd->next();
1546  }
1547 
1548  // function returning pointer to function
1549  else if (Token::Match(tokOffset, "( * %type% (") &&
1550  Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
1551  Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
1552  functionRetFuncPtr = true;
1553 
1554  tokOffset = tokOffset->tokAt(3);
1555  typeName = tokOffset->previous();
1556  argStart = tokOffset;
1557  argEnd = tokOffset->link();
1558 
1559  argFuncRetStart = argEnd->tokAt(2);
1560  if (!argFuncRetStart)
1561  syntaxError(tokOffset);
1562 
1563  argFuncRetEnd = argFuncRetStart->link();
1564  if (!argFuncRetEnd)
1565  syntaxError(tokOffset);
1566 
1567  tok = argFuncRetEnd->next();
1568  } else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
1569  functionRetFuncPtr = true;
1570 
1571  tokOffset = tokOffset->tokAt(5);
1572  typeName = tokOffset->tokAt(-2);
1573  argStart = tokOffset;
1574  argEnd = tokOffset->link();
1575  if (!argEnd)
1576  syntaxError(arrayStart);
1577 
1578  argFuncRetStart = argEnd->tokAt(2);
1579  if (!argFuncRetStart)
1580  syntaxError(tokOffset);
1581 
1582  argFuncRetEnd = argFuncRetStart->link();
1583  if (!argFuncRetEnd)
1584  syntaxError(tokOffset);
1585 
1586  tok = argFuncRetEnd->next();
1587  }
1588 
1589  // pointer/reference to array
1590  else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
1591  ptrToArray = (tokOffset->next()->str() == "*");
1592  refToArray = !ptrToArray;
1593  tokOffset = tokOffset->tokAt(2);
1594  typeName = tokOffset;
1595  arrayStart = tokOffset->tokAt(2);
1596  arrayEnd = arrayStart->link();
1597  if (!arrayEnd)
1598  syntaxError(arrayStart);
1599 
1600  tok = arrayEnd->next();
1601  }
1602 
1603  // pointer to class member
1604  else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
1605  tokOffset = tokOffset->tokAt(2);
1606  namespaceStart = tokOffset->previous();
1607  namespaceEnd = tokOffset;
1608  ptrMember = true;
1609  tokOffset = tokOffset->tokAt(2);
1610  typeName = tokOffset;
1611  tok = tokOffset->tokAt(2);
1612  }
1613 
1614  // unhandled typedef, skip it and continue
1615  else {
1616  unsupportedTypedef(typeDef);
1617  tok = deleteInvalidTypedef(typeDef);
1618  if (tok == list.front())
1619  //now the next token to process is 'tok', not 'tok->next()';
1620  goback = true;
1621  continue;
1622  }
1623 
1624  bool done = false;
1625  bool ok = true;
1626 
1627  TypedefInfo typedefInfo;
1628  typedefInfo.name = typeName->str();
1629  typedefInfo.filename = list.file(typeName);
1630  typedefInfo.lineNumber = typeName->linenr();
1631  typedefInfo.column = typeName->column();
1632  typedefInfo.used = false;
1633  mTypedefInfo.push_back(std::move(typedefInfo));
1634 
1635  while (!done) {
1636  std::string pattern = typeName->str();
1637  int scope = 0;
1638  bool simplifyType = false;
1639  bool inMemberFunc = false;
1640  int memberScope = 0;
1641  bool globalScope = false;
1642  int classLevel = spaceInfo.size();
1643  bool inTypeDef = false;
1644  bool inEnum = false;
1645  std::string removed;
1646  std::string classPath;
1647  for (size_t i = 1; i < spaceInfo.size(); ++i) {
1648  if (!classPath.empty())
1649  classPath += " :: ";
1650  classPath += spaceInfo[i].className;
1651  }
1652 
1653  for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1654  if (Settings::terminated())
1655  return;
1656 
1657  removed.clear();
1658 
1659  if (Token::simpleMatch(tok2, "typedef"))
1660  inTypeDef = true;
1661 
1662  if (inTypeDef && Token::simpleMatch(tok2, ";"))
1663  inTypeDef = false;
1664 
1665  // Check for variable declared with the same name
1666  if (!inTypeDef && spaceInfo.size() == 1 && Token::Match(tok2->previous(), "%name%") &&
1667  !tok2->previous()->isKeyword()) {
1668  Token* varDecl = tok2;
1669  while (Token::Match(varDecl, "*|&|&&|const"))
1670  varDecl = varDecl->next();
1671  if (Token::Match(varDecl, "%name% ;|,|)|=") && varDecl->str() == typeName->str()) {
1672  // Skip to the next closing brace
1673  if (Token::Match(varDecl, "%name% ) {")) { // is argument variable
1674  tok2 = varDecl->linkAt(2)->next();
1675  } else {
1676  tok2 = varDecl;
1677  while (tok2 && !Token::simpleMatch(tok2, "}")) {
1678  if (Token::Match(tok2, "(|{|["))
1679  tok2 = tok2->link();
1680  tok2 = tok2->next();
1681  }
1682  }
1683  if (!tok2)
1684  break;
1685  continue;
1686  }
1687  }
1688 
1689  if (tok2->link()) { // Pre-check for performance
1690  // check for end of scope
1691  if (tok2->str() == "}") {
1692  // check for end of member function
1693  if (inMemberFunc) {
1694  --memberScope;
1695  if (memberScope == 0)
1696  inMemberFunc = false;
1697  }
1698  inEnum = false;
1699 
1700  if (classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd2) {
1701  --classLevel;
1702  pattern.clear();
1703 
1704  for (int i = classLevel; i < spaceInfo.size(); ++i)
1705  pattern += (spaceInfo[i].className + " :: ");
1706 
1707  pattern += typeName->str();
1708  } else {
1709  if (scope == 0 && !(classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd))
1710  break;
1711  scope = std::max(scope - 1, 0);
1712  }
1713  }
1714 
1715  // check for member functions
1716  else if (tok2->isCpp() && tok2->str() == "(" && isFunctionHead(tok2, "{:")) {
1717  const Token *func = tok2->previous();
1718 
1719  /** @todo add support for multi-token operators */
1720  if (func->previous()->str() == "operator")
1721  func = func->previous();
1722 
1723  if (!func->previous())
1724  syntaxError(func);
1725 
1726  // check for qualifier
1727  if (Token::Match(func->tokAt(-2), "%name% ::")) {
1728  int offset = -2;
1729  while (Token::Match(func->tokAt(offset - 2), "%name% ::"))
1730  offset -= 2;
1731  // check for available and matching class name
1732  if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1733  func->strAt(offset) == spaceInfo[classLevel].className) {
1734  memberScope = 0;
1735  inMemberFunc = true;
1736  }
1737  }
1738  }
1739 
1740  // check for entering a new scope
1741  else if (tok2->str() == "{") {
1742  // check for entering a new namespace
1743  if (tok2->isCpp()) {
1744  if (tok2->strAt(-2) == "namespace") {
1745  if (classLevel < spaceInfo.size() &&
1746  spaceInfo[classLevel].isNamespace &&
1747  spaceInfo[classLevel].className == tok2->previous()->str()) {
1748  spaceInfo[classLevel].bodyEnd2 = tok2->link();
1749  ++classLevel;
1750  pattern.clear();
1751  for (int i = classLevel; i < spaceInfo.size(); ++i)
1752  pattern += spaceInfo[i].className + " :: ";
1753 
1754  pattern += typeName->str();
1755  }
1756  ++scope;
1757  }
1758  if (isEnumScope(tok2))
1759  inEnum = true;
1760  }
1761 
1762  // keep track of scopes within member function
1763  if (inMemberFunc)
1764  ++memberScope;
1765 
1766  ++scope;
1767  }
1768  }
1769 
1770  // check for operator typedef
1771  /** @todo add support for multi-token operators */
1772  else if (tok2->isCpp() &&
1773  tok2->str() == "operator" &&
1774  tok2->next() &&
1775  tok2->next()->str() == typeName->str() &&
1776  tok2->linkAt(2) &&
1777  tok2->strAt(2) == "(" &&
1778  Token::Match(tok2->linkAt(2), ") const| {")) {
1779  // check for qualifier
1780  if (tok2->previous()->str() == "::") {
1781  // check for available and matching class name
1782  if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1783  tok2->strAt(-2) == spaceInfo[classLevel].className) {
1784  tok2 = tok2->next();
1785  simplifyType = true;
1786  }
1787  }
1788  }
1789 
1790  else if (Token::Match(tok2->previous(), "class|struct %name% [:{]")) {
1791  // don't replace names in struct/class definition
1792  }
1793 
1794  // check for typedef that can be substituted
1795  else if ((tok2->isNameOnly() || (tok2->isName() && (tok2->isExpandedMacro() || tok2->isInline()))) &&
1796  (Token::simpleMatch(tok2, pattern.c_str(), pattern.size()) ||
1797  (inMemberFunc && tok2->str() == typeName->str()))) {
1798  // member function class variables don't need qualification
1799  if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
1800  Token *start = tok2;
1801  int count = 0;
1802  int back = classLevel - 1;
1803  bool good = true;
1804  // check for extra qualification
1805  while (back >= 1) {
1806  Token *qualificationTok = start->tokAt(-2);
1807  if (!Token::Match(qualificationTok, "%type% ::"))
1808  break;
1809  if (qualificationTok->str() == spaceInfo[back].className) {
1810  start = qualificationTok;
1811  back--;
1812  count++;
1813  } else {
1814  good = false;
1815  break;
1816  }
1817  }
1818  // check global namespace
1819  if (good && back == 1 && start->strAt(-1) == "::")
1820  good = false;
1821 
1822  if (good) {
1823  // remove any extra qualification if present
1824  while (count) {
1825  if (!removed.empty())
1826  removed.insert(0, " ");
1827  removed.insert(0, tok2->strAt(-2) + " " + tok2->strAt(-1));
1828  tok2->tokAt(-3)->deleteNext(2);
1829  --count;
1830  }
1831 
1832  // remove global namespace if present
1833  if (tok2->strAt(-1) == "::") {
1834  removed.insert(0, ":: ");
1835  tok2->tokAt(-2)->deleteNext();
1836  globalScope = true;
1837  }
1838 
1839  // remove qualification if present
1840  for (int i = classLevel; i < spaceInfo.size(); ++i) {
1841  if (!removed.empty())
1842  removed += " ";
1843  removed += (tok2->str() + " " + tok2->strAt(1));
1844  tok2->deleteThis();
1845  tok2->deleteThis();
1846  }
1847  simplifyType = true;
1848  }
1849  } else {
1850  if (tok2->strAt(-1) == "::") {
1851  int relativeSpaceInfoSize = spaceInfo.size();
1852  Token * tokBeforeType = tok2->previous();
1853  while (relativeSpaceInfoSize > 1 &&
1854  tokBeforeType && tokBeforeType->str() == "::" &&
1855  tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
1856  tokBeforeType = tokBeforeType->tokAt(-2);
1857  --relativeSpaceInfoSize;
1858  }
1859  if (tokBeforeType && tokBeforeType->str() != "::") {
1860  Token::eraseTokens(tokBeforeType, tok2);
1861  simplifyType = true;
1862  }
1863  } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
1864  tok2 = tok2->next();
1865  } else if (duplicateTypedef(tok2, typeName, typeDef)) {
1866  // skip to end of scope if not already there
1867  if (tok2->str() != "}") {
1868  while (tok2->next()) {
1869  if (tok2->next()->str() == "{")
1870  tok2 = tok2->linkAt(1)->previous();
1871  else if (tok2->next()->str() == "}")
1872  break;
1873 
1874  tok2 = tok2->next();
1875  }
1876  }
1877  } else if (Token::Match(tok2->tokAt(-2), "%type% *|&")) {
1878  // Ticket #5868: Don't substitute variable names
1879  } else if (tok2->previous()->str() != ".") {
1880  simplifyType = (TypedefSimplifier::canReplaceStatic(tok2) != 0);
1881  }
1882  }
1883  }
1884 
1885  simplifyType = simplifyType && (!inEnum || !Token::simpleMatch(tok2->next(), "="));
1886  simplifyType = simplifyType && !(Token::simpleMatch(tok2->next(), "<") && Token::simpleMatch(typeEnd, ">"));
1887 
1888  if (simplifyType) {
1889  mTypedefInfo.back().used = true;
1890 
1891  // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
1892  if (functionPtr && (tok2->previous()->str() == "operator" ||
1893  (tok2->next() && tok2->next()->str() == "operator"))) {
1894  simplifyType = false;
1895  tok2 = tok2->next();
1896  continue;
1897  }
1898 
1899  // There are 2 categories of typedef substitutions:
1900  // 1. variable declarations that preserve the variable name like
1901  // global, local, and function parameters
1902  // 2. not variable declarations that have no name like derived
1903  // classes, casts, operators, and template parameters
1904 
1905  // try to determine which category this substitution is
1906  bool inCast = false;
1907  bool inTemplate = false;
1908  bool inOperator = false;
1909  bool inSizeof = false;
1910 
1911  const bool sameStartEnd = (typeStart == typeEnd);
1912 
1913  // check for derived class: class A : some_typedef {
1914  const bool isDerived = Token::Match(tok2->previous(), "public|protected|private|: %type% {|,");
1915 
1916  // check for cast: (some_typedef) A or static_cast<some_typedef>(A)
1917  // todo: check for more complicated casts like: (const some_typedef *)A
1918  if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
1919  (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")) ||
1920  Token::Match(tok2->tokAt(-2), "( const %name% )"))
1921  inCast = true;
1922 
1923  // check for template parameters: t<some_typedef> t1
1924  else if (Token::Match(tok2->previous(), "<|,") &&
1925  Token::Match(tok2->next(), "&|*| &|*| >|,"))
1926  inTemplate = true;
1927 
1928  else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
1929  inSizeof = true;
1930 
1931  // check for operator
1932  if (tok2->strAt(-1) == "operator" ||
1933  Token::simpleMatch(tok2->tokAt(-2), "operator const"))
1934  inOperator = true;
1935 
1936  if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
1937  // Remove one typename if it is already contained in the goal
1938  typeStart = typeStart->next();
1939  }
1940 
1941  // skip over class or struct in derived class declaration
1942  bool structRemoved = false;
1943  if ((isDerived || inTemplate) && Token::Match(typeStart, "class|struct")) {
1944  if (typeStart->str() == "struct")
1945  structRemoved = true;
1946  typeStart = typeStart->next();
1947  }
1948  if (Token::Match(typeStart, "struct|class|union") && Token::Match(tok2, "%name% ::"))
1949  typeStart = typeStart->next();
1950 
1951  if (sameStartEnd)
1952  typeEnd = typeStart;
1953 
1954  // Is this a "T()" expression where T is a pointer type?
1955  const bool isPointerTypeCall = !inOperator && Token::Match(tok2, "%name% ( )") && !pointers.empty();
1956 
1957  // start substituting at the typedef name by replacing it with the type
1958  Token* replStart = tok2; // track first replaced token
1959  for (Token* tok3 = typeStart; tok3 && (tok3->str() != ";"); tok3 = tok3->next())
1960  tok3->isSimplifiedTypedef(true);
1961  if (isPointerTypeCall) {
1962  tok2->deleteThis();
1963  tok2->insertToken("0");
1964  tok2 = tok2->next();
1965  tok2->next()->insertToken("0");
1966  }
1967  if (Token::Match(tok2->tokAt(-1), "class|struct|union") && tok2->strAt(-1) == typeStart->str())
1968  tok2->deletePrevious();
1969  tok2->str(typeStart->str());
1970 
1971  // restore qualification if it was removed
1972  if (Token::Match(typeStart, "class|struct|union") || structRemoved) {
1973  if (structRemoved)
1974  tok2 = tok2->previous();
1975 
1976  if (globalScope) {
1977  replStart = tok2->insertToken("::");
1978  tok2 = tok2->next();
1979  }
1980 
1981  for (int i = classLevel; i < spaceInfo.size(); ++i) {
1982  tok2->insertToken(spaceInfo[i].className);
1983  tok2 = tok2->next();
1984  tok2->insertToken("::");
1985  tok2 = tok2->next();
1986  }
1987  }
1988 
1989  // add some qualification back if needed
1990  Token *start = tok2;
1991  std::string removed1 = removed;
1992  std::string::size_type idx = removed1.rfind(" ::");
1993 
1994  if (idx != std::string::npos)
1995  removed1.resize(idx);
1996  if (removed1 == classPath && !removed1.empty()) {
1997  for (std::vector<Space>::const_reverse_iterator it = spaceInfo.crbegin(); it != spaceInfo.crend(); ++it) {
1998  if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
1999  std::string::size_type spaceIdx = 0;
2000  std::string::size_type startIdx = 0;
2001  while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
2002  tok2->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
2003  startIdx = spaceIdx + 1;
2004  }
2005  tok2->previous()->insertToken(removed1.substr(startIdx));
2006  replStart = tok2->previous()->insertToken("::");
2007  break;
2008  }
2009  idx = removed1.rfind(" ::");
2010  if (idx == std::string::npos)
2011  break;
2012 
2013  removed1.resize(idx);
2014  }
2015  }
2016  replStart->isSimplifiedTypedef(true);
2017  Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
2018  // add remainder of type
2019  tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
2020 
2021  if (!pointers.empty()) {
2022  for (const std::string &p : pointers) {
2023  tok2->insertToken(p);
2024  tok2->isSimplifiedTypedef(true);
2025  tok2 = tok2->next();
2026  }
2027  if (constTok) {
2028  constTok->deleteThis();
2029  tok2->insertToken("const");
2030  tok2->isSimplifiedTypedef(true);
2031  tok2 = tok2->next();
2032  }
2033  }
2034 
2035  if (funcStart && funcEnd) {
2036  tok2->insertToken("(");
2037  tok2 = tok2->next();
2038  Token *paren = tok2;
2039  tok2 = TokenList::copyTokens(tok2, funcStart, funcEnd);
2040 
2041  if (!inCast)
2042  tok2 = processFunc(tok2, inOperator);
2043 
2044  if (!tok2)
2045  break;
2046 
2047  while (Token::Match(tok2, "%name%|] ["))
2048  tok2 = tok2->linkAt(1);
2049 
2050  tok2->insertToken(")");
2051  tok2 = tok2->next();
2052  Token::createMutualLinks(tok2, paren);
2053 
2054  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2055 
2056  if (specStart) {
2057  Token *spec = specStart;
2058  tok2->insertToken(spec->str());
2059  tok2 = tok2->next();
2060  while (spec != specEnd) {
2061  spec = spec->next();
2062  tok2->insertToken(spec->str());
2063  tok2 = tok2->next();
2064  }
2065  }
2066  }
2067 
2068  else if (functionPtr || function) {
2069  // don't add parentheses around function names because it
2070  // confuses other simplifications
2071  bool needParen = true;
2072  if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
2073  needParen = false;
2074  if (needParen) {
2075  tok2->insertToken("(");
2076  tok2 = tok2->next();
2077  }
2078  Token *tok3 = tok2;
2079  if (namespaceStart) {
2080  const Token *tok4 = namespaceStart;
2081 
2082  while (tok4 != namespaceEnd) {
2083  tok2->insertToken(tok4->str());
2084  tok2 = tok2->next();
2085  tok4 = tok4->next();
2086  }
2087  tok2->insertToken(namespaceEnd->str());
2088  tok2 = tok2->next();
2089  }
2090  if (functionPtr) {
2091  tok2->insertToken("*");
2092  tok2 = tok2->next();
2093  }
2094 
2095  if (!inCast)
2096  tok2 = processFunc(tok2, inOperator);
2097 
2098  if (needParen) {
2099  if (!tok2)
2100  syntaxError(nullptr);
2101 
2102  tok2->insertToken(")");
2103  tok2 = tok2->next();
2104  Token::createMutualLinks(tok2, tok3);
2105  }
2106  if (!tok2)
2107  syntaxError(nullptr);
2108 
2109  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2110  if (inTemplate) {
2111  if (!tok2)
2112  syntaxError(nullptr);
2113 
2114  tok2 = tok2->next();
2115  }
2116 
2117  if (specStart) {
2118  Token *spec = specStart;
2119  tok2->insertToken(spec->str());
2120  tok2 = tok2->next();
2121  while (spec != specEnd) {
2122  spec = spec->next();
2123  tok2->insertToken(spec->str());
2124  tok2 = tok2->next();
2125  }
2126  }
2127  } else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
2128  tok2->insertToken("(");
2129  tok2 = tok2->next();
2130  Token *tok3 = tok2;
2131  tok2->insertToken("*");
2132  tok2 = tok2->next();
2133 
2134  Token * tok4 = nullptr;
2135  if (functionPtrRetFuncPtr) {
2136  tok2->insertToken("(");
2137  tok2 = tok2->next();
2138  tok4 = tok2;
2139  tok2->insertToken("*");
2140  tok2 = tok2->next();
2141  }
2142 
2143  // skip over variable name if there
2144  if (!inCast) {
2145  if (!tok2 || !tok2->next())
2146  syntaxError(nullptr);
2147 
2148  if (tok2->next()->str() != ")")
2149  tok2 = tok2->next();
2150  }
2151 
2152  if (tok4 && functionPtrRetFuncPtr) {
2153  tok2->insertToken(")");
2154  tok2 = tok2->next();
2155  Token::createMutualLinks(tok2, tok4);
2156  }
2157 
2158  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2159 
2160  tok2->insertToken(")");
2161  tok2 = tok2->next();
2162  Token::createMutualLinks(tok2, tok3);
2163 
2164  tok2 = TokenList::copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
2165  } else if (ptrToArray || refToArray) {
2166  tok2->insertToken("(");
2167  tok2 = tok2->next();
2168  Token *tok3 = tok2;
2169 
2170  if (ptrToArray)
2171  tok2->insertToken("*");
2172  else
2173  tok2->insertToken("&");
2174  tok2 = tok2->next();
2175 
2176  bool hasName = false;
2177  // skip over name
2178  if (tok2->next() && tok2->next()->str() != ")" && tok2->next()->str() != "," &&
2179  tok2->next()->str() != ">") {
2180  hasName = true;
2181  if (tok2->next()->str() != "(")
2182  tok2 = tok2->next();
2183 
2184  // check for function and skip over args
2185  if (tok2 && tok2->next() && tok2->next()->str() == "(")
2186  tok2 = tok2->next()->link();
2187 
2188  // check for array
2189  if (tok2 && tok2->next() && tok2->next()->str() == "[")
2190  tok2 = tok2->next()->link();
2191  }
2192 
2193  tok2->insertToken(")");
2194  Token::createMutualLinks(tok2->next(), tok3);
2195 
2196  if (!hasName)
2197  tok2 = tok2->next();
2198  } else if (ptrMember) {
2199  if (Token::simpleMatch(tok2, "* (")) {
2200  tok2->insertToken("*");
2201  tok2 = tok2->next();
2202  } else {
2203  // This is the case of casting operator.
2204  // Name is not available, and () should not be
2205  // inserted
2206  const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
2207  Token *openParenthesis = nullptr;
2208 
2209  if (!castOperator) {
2210  tok2->insertToken("(");
2211  tok2 = tok2->next();
2212 
2213  openParenthesis = tok2;
2214  }
2215 
2216  const Token *tok4 = namespaceStart;
2217 
2218  while (tok4 != namespaceEnd) {
2219  tok2->insertToken(tok4->str());
2220  tok2 = tok2->next();
2221  tok4 = tok4->next();
2222  }
2223  tok2->insertToken(namespaceEnd->str());
2224  tok2 = tok2->next();
2225 
2226  tok2->insertToken("*");
2227  tok2 = tok2->next();
2228 
2229  if (openParenthesis) {
2230  // Skip over name, if any
2231  if (Token::Match(tok2->next(), "%name%"))
2232  tok2 = tok2->next();
2233 
2234  tok2->insertToken(")");
2235  tok2 = tok2->next();
2236 
2237  Token::createMutualLinks(tok2, openParenthesis);
2238  }
2239  }
2240  } else if (typeOf) {
2241  tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2242  } else if (Token::Match(tok2, "%name% [")) {
2243  while (Token::Match(tok2, "%name%|] [")) {
2244  tok2 = tok2->linkAt(1);
2245  }
2246  tok2 = tok2->previous();
2247  }
2248 
2249  if (arrayStart && arrayEnd) {
2250  do {
2251  if (!tok2->next())
2252  syntaxError(tok2); // can't recover so quit
2253 
2254  if (!inCast && !inSizeof && !inTemplate)
2255  tok2 = tok2->next();
2256 
2257  if (tok2->str() == "const")
2258  tok2 = tok2->next();
2259 
2260  // reference or pointer to array?
2261  if (Token::Match(tok2, "&|*|&&")) {
2262  tok2 = tok2->previous();
2263  tok2->insertToken("(");
2264  Token *tok3 = tok2->next();
2265 
2266  // handle missing variable name
2267  if (Token::Match(tok3, "( *|&|&& *|&|&& %name%"))
2268  tok2 = tok3->tokAt(3);
2269  else if (Token::Match(tok2->tokAt(3), "[(),;]"))
2270  tok2 = tok2->tokAt(2);
2271  else if (Token::simpleMatch(tok2->tokAt(3), ">"))
2272  tok2 = tok2->tokAt(2);
2273  else
2274  tok2 = tok2->tokAt(3);
2275  if (!tok2)
2276  syntaxError(nullptr);
2277 
2278  while (tok2->strAt(1) == "::")
2279  tok2 = tok2->tokAt(2);
2280 
2281  // skip over function parameters
2282  if (tok2->str() == "(")
2283  tok2 = tok2->link();
2284 
2285  if (tok2->strAt(1) == "(")
2286  tok2 = tok2->linkAt(1);
2287 
2288  // skip over const/noexcept
2289  while (Token::Match(tok2->next(), "const|noexcept")) {
2290  tok2 = tok2->next();
2291  if (Token::Match(tok2->next(), "( true|false )"))
2292  tok2 = tok2->tokAt(3);
2293  }
2294 
2295  tok2->insertToken(")");
2296  tok2 = tok2->next();
2297  Token::createMutualLinks(tok2, tok3);
2298  }
2299 
2300  if (!tok2->next())
2301  syntaxError(tok2); // can't recover so quit
2302 
2303  // skip over array dimensions
2304  while (tok2->next()->str() == "[")
2305  tok2 = tok2->linkAt(1);
2306 
2307  tok2 = TokenList::copyTokens(tok2, arrayStart, arrayEnd);
2308  if (!tok2->next())
2309  syntaxError(tok2);
2310 
2311  if (tok2->str() == "=") {
2312  if (tok2->next()->str() == "{")
2313  tok2 = tok2->next()->link()->next();
2314  else if (tok2->next()->str().at(0) == '\"')
2315  tok2 = tok2->tokAt(2);
2316  }
2317  } while (Token::Match(tok2, ", %name% ;|=|,"));
2318  }
2319 
2320  simplifyType = false;
2321  }
2322  if (!tok2)
2323  break;
2324  }
2325 
2326  if (!tok)
2327  syntaxError(nullptr);
2328 
2329  if (tok->str() == ";")
2330  done = true;
2331  else if (tok->str() == ",") {
2332  arrayStart = nullptr;
2333  arrayEnd = nullptr;
2334  tokOffset = tok->next();
2335  pointers.clear();
2336 
2337  while (Token::Match(tokOffset, "*|&")) {
2338  pointers.push_back(tokOffset->str());
2339  tokOffset = tokOffset->next();
2340  }
2341 
2342  if (Token::Match(tokOffset, "%type%")) {
2343  typeName = tokOffset;
2344  tokOffset = tokOffset->next();
2345 
2346  if (tokOffset && tokOffset->str() == "[") {
2347  arrayStart = tokOffset;
2348 
2349  for (;;) {
2350  while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
2351  tokOffset = tokOffset->next();
2352 
2353  if (!tokOffset->next())
2354  return; // invalid input
2355  if (tokOffset->next()->str() == ";")
2356  break;
2357  if (tokOffset->str() == "]")
2358  break;
2359  tokOffset = tokOffset->next();
2360  }
2361 
2362  arrayEnd = tokOffset;
2363  tokOffset = tokOffset->next();
2364  }
2365 
2366  if (Token::Match(tokOffset, ";|,"))
2367  tok = tokOffset;
2368  else {
2369  // we encountered a typedef we don't support yet so just continue
2370  done = true;
2371  ok = false;
2372  }
2373  } else {
2374  // we encountered a typedef we don't support yet so just continue
2375  done = true;
2376  ok = false;
2377  }
2378  } else {
2379  // something is really wrong (internal error)
2380  done = true;
2381  ok = false;
2382  }
2383  }
2384 
2385  if (ok) {
2386  // remove typedef
2387  Token::eraseTokens(typeDef, tok);
2388 
2389  if (typeDef != list.front()) {
2390  tok = typeDef->previous();
2391  tok->deleteNext();
2392  //no need to remove last token in the list
2393  if (tok->tokAt(2))
2394  tok->deleteNext();
2395  } else {
2396  list.front()->deleteThis();
2397  //no need to remove last token in the list
2398  if (list.front()->next())
2399  list.front()->deleteThis();
2400  tok = list.front();
2401  //now the next token to process is 'tok', not 'tok->next()';
2402  goback = true;
2403  }
2404  }
2405  }
2406 }
2407 
2408 namespace {
2409  struct ScopeInfo3 {
2410  enum Type { Global, Namespace, Record, MemberFunction, Other };
2411  ScopeInfo3() : parent(nullptr), type(Global), bodyStart(nullptr), bodyEnd(nullptr) {}
2412  ScopeInfo3(ScopeInfo3 *parent_, Type type_, std::string name_, const Token *bodyStart_, const Token *bodyEnd_)
2413  : parent(parent_), type(type_), name(std::move(name_)), bodyStart(bodyStart_), bodyEnd(bodyEnd_) {
2414  if (name.empty())
2415  return;
2416  fullName = name;
2417  ScopeInfo3 *scope = parent;
2418  while (scope && scope->parent) {
2419  if (scope->name.empty())
2420  break;
2421  fullName = scope->name + " :: " + fullName;
2422  scope = scope->parent;
2423  }
2424  }
2425  ScopeInfo3 *parent;
2426  std::list<ScopeInfo3> children;
2427  Type type;
2428  std::string fullName;
2429  std::string name;
2430  const Token * bodyStart;
2431  const Token * bodyEnd;
2432  std::set<std::string> usingNamespaces;
2433  std::set<std::string> recordTypes;
2434  std::set<std::string> baseTypes;
2435 
2436  ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) {
2437  children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken);
2438  return &children.back();
2439  }
2440 
2441  bool hasChild(const std::string &childName) const {
2442  return std::any_of(children.cbegin(), children.cend(), [&](const ScopeInfo3& child) {
2443  return child.name == childName;
2444  });
2445  }
2446 
2447  const ScopeInfo3 * findInChildren(const std::string & scope) const {
2448  for (const auto & child : children) {
2449  if (child.type == Record && (child.name == scope || child.fullName == scope))
2450  return &child;
2451 
2452  const ScopeInfo3 * temp = child.findInChildren(scope);
2453  if (temp)
2454  return temp;
2455  }
2456  return nullptr;
2457  }
2458 
2459  const ScopeInfo3 * findScope(const std::string & scope) const {
2460  const ScopeInfo3 * tempScope = this;
2461  while (tempScope) {
2462  // check children
2463  auto it = std::find_if(tempScope->children.cbegin(), tempScope->children.cend(), [&](const ScopeInfo3& child) {
2464  return &child != this && child.type == Record && (child.name == scope || child.fullName == scope);
2465  });
2466  if (it != tempScope->children.end())
2467  return &*it;
2468  // check siblings for same name
2469  if (tempScope->parent) {
2470  for (const auto &sibling : tempScope->parent->children) {
2471  if (sibling.name == tempScope->name && &sibling != this) {
2472  const ScopeInfo3 * temp = sibling.findInChildren(scope);
2473  if (temp)
2474  return temp;
2475  }
2476  }
2477  }
2478  tempScope = tempScope->parent;
2479  }
2480  return nullptr;
2481  }
2482 
2483  bool findTypeInBase(const std::string &scope) const {
2484  if (scope.empty())
2485  return false;
2486  // check in base types first
2487  if (baseTypes.find(scope) != baseTypes.end())
2488  return true;
2489  // check in base types base types
2490  for (const std::string & base : baseTypes) {
2491  const ScopeInfo3 * baseScope = findScope(base);
2492  // bail on uninstantiated recursive template
2493  if (baseScope == this)
2494  return false;
2495  if (baseScope && baseScope->fullName == scope)
2496  return true;
2497  if (baseScope && baseScope->findTypeInBase(scope))
2498  return true;
2499  }
2500  return false;
2501  }
2502 
2503  ScopeInfo3 * findScope(const ScopeInfo3 * scope) {
2504  if (scope->bodyStart == bodyStart)
2505  return this;
2506  for (auto & child : children) {
2507  ScopeInfo3 * temp = child.findScope(scope);
2508  if (temp)
2509  return temp;
2510  }
2511  return nullptr;
2512  }
2513  };
2514 
2515  void setScopeInfo(Token *tok, ScopeInfo3 *&scopeInfo, bool debug=false)
2516  {
2517  if (!tok)
2518  return;
2519  if (tok->str() == "{" && scopeInfo->parent && tok == scopeInfo->bodyStart)
2520  return;
2521  if (tok->str() == "}") {
2522  if (scopeInfo->parent && tok == scopeInfo->bodyEnd)
2523  scopeInfo = scopeInfo->parent;
2524  else {
2525  // Try to find parent scope
2526  ScopeInfo3 *parent = scopeInfo->parent;
2527  while (parent && parent->bodyEnd != tok)
2528  parent = parent->parent;
2529  if (parent) {
2530  scopeInfo = parent;
2531  if (debug)
2532  throw std::runtime_error("Internal error: unmatched }");
2533  }
2534  }
2535  return;
2536  }
2537  if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::|<")) {
2538  // check for using namespace
2539  if (Token::Match(tok, "using namespace %name% ;|::")) {
2540  const Token * tok1 = tok->tokAt(2);
2541  std::string nameSpace;
2542  while (tok1 && tok1->str() != ";") {
2543  if (!nameSpace.empty())
2544  nameSpace += " ";
2545  nameSpace += tok1->str();
2546  tok1 = tok1->next();
2547  }
2548  scopeInfo->usingNamespaces.insert(std::move(nameSpace));
2549  }
2550  // check for member function
2551  else if (tok->str() == "{") {
2552  bool added = false;
2553  Token *tok1 = tok;
2554  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2555  tok1 = tok1->previous();
2556  if (tok1->previous() && (tok1->strAt(-1) == ")" || tok->strAt(-1) == "}")) {
2557  tok1 = tok1->linkAt(-1);
2558  if (Token::Match(tok1->previous(), "throw|noexcept (")) {
2559  tok1 = tok1->previous();
2560  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2561  tok1 = tok1->previous();
2562  if (tok1->strAt(-1) != ")")
2563  return;
2564  tok1 = tok1->linkAt(-1);
2565  } else {
2566  while (Token::Match(tok1->tokAt(-2), ":|, %name%")) {
2567  tok1 = tok1->tokAt(-2);
2568  if (tok1->strAt(-1) != ")" && tok1->strAt(-1) != "}")
2569  return;
2570  tok1 = tok1->linkAt(-1);
2571  }
2572  }
2573  if (tok1->strAt(-1) == ">")
2574  tok1 = tok1->previous()->findOpeningBracket();
2575  if (tok1 && (Token::Match(tok1->tokAt(-3), "%name% :: %name%") ||
2576  Token::Match(tok1->tokAt(-4), "%name% :: ~ %name%"))) {
2577  tok1 = tok1->tokAt(-2);
2578  if (tok1->str() == "~")
2579  tok1 = tok1->previous();
2580  std::string scope = tok1->strAt(-1);
2581  while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
2582  scope = tok1->strAt(-3) + " :: " + scope;
2583  tok1 = tok1->tokAt(-2);
2584  }
2585  scopeInfo = scopeInfo->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link());
2586  added = true;
2587  }
2588  }
2589 
2590  if (!added)
2591  scopeInfo = scopeInfo->addChild(ScopeInfo3::Other, emptyString, tok, tok->link());
2592  }
2593  return;
2594  }
2595 
2596  const bool record = Token::Match(tok, "class|struct|union %name%");
2597  tok = tok->next();
2598  std::string classname = tok->str();
2599  while (Token::Match(tok, "%name% :: %name%")) {
2600  tok = tok->tokAt(2);
2601  classname += " :: " + tok->str();
2602  }
2603 
2604  // add record type to scope info
2605  if (record)
2606  scopeInfo->recordTypes.insert(classname);
2607  tok = tok->next();
2608 
2609  // skip template parameters
2610  if (tok && tok->str() == "<") {
2611  tok = tok->findClosingBracket();
2612  if (tok)
2613  tok = tok->next();
2614  }
2615 
2616  // get base class types
2617  std::set<std::string> baseTypes;
2618  if (tok && tok->str() == ":") {
2619  do {
2620  tok = tok->next();
2621  while (Token::Match(tok, "public|protected|private|virtual"))
2622  tok = tok->next();
2623  std::string base;
2624  while (tok && !Token::Match(tok, ";|,|{")) {
2625  if (!base.empty())
2626  base += ' ';
2627  base += tok->str();
2628  tok = tok->next();
2629  // add template parameters
2630  if (tok && tok->str() == "<") {
2631  const Token* endTok = tok->findClosingBracket();
2632  if (endTok) {
2633  endTok = endTok->next();
2634  while (tok != endTok) {
2635  base += tok->str();
2636  tok = tok->next();
2637  }
2638  }
2639  }
2640  }
2641  baseTypes.insert(std::move(base));
2642  } while (tok && !Token::Match(tok, ";|{"));
2643  }
2644 
2645  if (tok && tok->str() == "{") {
2646  scopeInfo = scopeInfo->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link());
2647  scopeInfo->baseTypes = std::move(baseTypes);
2648  }
2649  }
2650 
2651  Token *findSemicolon(Token *tok)
2652  {
2653  int level = 0;
2654 
2655  for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
2656  if (tok->str() == "{")
2657  ++level;
2658  else if (level > 0 && tok->str() == "}")
2659  --level;
2660  }
2661 
2662  return tok;
2663  }
2664 
2665  bool usingMatch(
2666  const Token *nameToken,
2667  const std::string &scope,
2668  Token *&tok,
2669  const std::string &scope1,
2670  const ScopeInfo3 *currentScope,
2671  const ScopeInfo3 *memberClassScope)
2672  {
2673  Token *tok1 = tok;
2674 
2675  if (tok1 && tok1->str() != nameToken->str())
2676  return false;
2677 
2678  // skip this using
2679  if (tok1 == nameToken) {
2680  tok = findSemicolon(tok1);
2681  return false;
2682  }
2683 
2684  // skip other using with this name
2685  if (tok1->strAt(-1) == "using") {
2686  // fixme: this is wrong
2687  // skip to end of scope
2688  if (currentScope->bodyEnd)
2689  tok = const_cast<Token*>(currentScope->bodyEnd->previous());
2690  return false;
2691  }
2692 
2693  if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) {
2694  // fixme
2695  return false;
2696  }
2697 
2698  // get qualification
2699  std::string qualification;
2700  const Token* tok2 = tok1;
2701  std::string::size_type index = scope.size();
2702  std::string::size_type new_index = std::string::npos;
2703  bool match = true;
2704  while (Token::Match(tok2->tokAt(-2), "%name% ::") && !tok2->tokAt(-2)->isKeyword()) {
2705  std::string last;
2706  if (match && !scope1.empty()) {
2707  new_index = scope1.rfind(' ', index - 1);
2708  if (new_index != std::string::npos)
2709  last = scope1.substr(new_index, index - new_index);
2710  else if (!qualification.empty())
2711  last.clear();
2712  else
2713  last = scope1;
2714  } else
2715  match = false;
2716  if (match && tok2->strAt(-2) == last)
2717  index = new_index;
2718  else {
2719  if (!qualification.empty())
2720  qualification = " :: " + qualification;
2721  qualification = tok2->strAt(-2) + qualification;
2722  }
2723  tok2 = tok2->tokAt(-2);
2724  }
2725 
2726  std::string fullScope1 = scope1;
2727  if (!scope1.empty() && !qualification.empty())
2728  fullScope1 += " :: ";
2729  fullScope1 += qualification;
2730 
2731  if (scope == fullScope1)
2732  return true;
2733 
2734  const ScopeInfo3 *scopeInfo = memberClassScope ? memberClassScope : currentScope;
2735 
2736  // check in base types
2737  if (qualification.empty() && scopeInfo->findTypeInBase(scope))
2738  return true;
2739 
2740  // check using namespace
2741  const ScopeInfo3 * tempScope = scopeInfo;
2742  while (tempScope) {
2743  //if (!tempScope->parent->usingNamespaces.empty()) {
2744  const std::set<std::string>& usingNS = tempScope->usingNamespaces;
2745  if (!usingNS.empty()) {
2746  if (qualification.empty()) {
2747  if (usingNS.find(scope) != usingNS.end())
2748  return true;
2749  } else {
2750  const std::string suffix = " :: " + qualification;
2751  if (std::any_of(usingNS.cbegin(), usingNS.cend(), [&](const std::string& ns) {
2752  return scope == ns + suffix;
2753  }))
2754  return true;
2755  }
2756  }
2757  tempScope = tempScope->parent;
2758  }
2759 
2760  std::string newScope1 = scope1;
2761 
2762  // scopes didn't match so try higher scopes
2763  index = newScope1.size();
2764  while (!newScope1.empty()) {
2765  const std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
2766  if (separator != std::string::npos)
2767  newScope1.resize(separator);
2768  else
2769  newScope1.clear();
2770 
2771  std::string newFullScope1 = newScope1;
2772  if (!newScope1.empty() && !qualification.empty())
2773  newFullScope1 += " :: ";
2774  newFullScope1 += qualification;
2775 
2776  if (scope == newFullScope1)
2777  return true;
2778  }
2779 
2780  return false;
2781  }
2782 
2783  std::string memberFunctionScope(const Token *tok)
2784  {
2785  std::string qualification;
2786  const Token *qualTok = tok->strAt(-2) == "~" ? tok->tokAt(-4) : tok->tokAt(-3);
2787  while (Token::Match(qualTok, "%type% ::")) {
2788  if (!qualification.empty())
2789  qualification = " :: " + qualification;
2790  qualification = qualTok->str() + qualification;
2791  qualTok = qualTok->tokAt(-2);
2792  }
2793  return qualification;
2794  }
2795 
2796  const Token * memberFunctionEnd(const Token *tok)
2797  {
2798  if (tok->str() != "(")
2799  return nullptr;
2800  const Token *end = tok->link()->next();
2801  while (end) {
2802  if (end->str() == "{" && !Token::Match(end->tokAt(-2), ":|, %name%"))
2803  return end;
2804  if (end->str() == ";")
2805  break;
2806  end = end->next();
2807  }
2808  return nullptr;
2809  }
2810 } // namespace
2811 
2812 bool Tokenizer::isMemberFunction(const Token *openParen)
2813 {
2814  return (Token::Match(openParen->tokAt(-2), ":: %name% (") ||
2815  Token::Match(openParen->tokAt(-3), ":: ~ %name% (")) &&
2816  isFunctionHead(openParen, "{|:");
2817 }
2818 
2819 static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
2820 {
2821  if (scope1.empty() || scope2.empty())
2822  return false;
2823 
2824  // check if scopes match
2825  if (scope1 == scope2)
2826  return true;
2827 
2828  // check if scopes only differ by global qualification
2829  if (scope1 == (":: " + scope2)) {
2830  std::string::size_type end = scope2.find_first_of(' ');
2831  if (end == std::string::npos)
2832  end = scope2.size();
2833  if (globalScope->hasChild(scope2.substr(0, end)))
2834  return true;
2835  } else if (scope2 == (":: " + scope1)) {
2836  std::string::size_type end = scope1.find_first_of(' ');
2837  if (end == std::string::npos)
2838  end = scope1.size();
2839  if (globalScope->hasChild(scope1.substr(0, end)))
2840  return true;
2841  }
2842 
2843  return false;
2844 }
2845 
2846 static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
2847  unsigned int dist = 0;
2848  const Token* tok = tok1;
2849  while (tok != tok2) {
2850  ++dist;
2851  tok = tok->next();
2852  }
2853  return dist;
2854 }
2855 
2857 {
2859  return false;
2860 
2861  // simplify using N::x; to using x = N::x;
2862  for (Token* tok = list.front(); tok; tok = tok->next()) {
2863  if (!Token::Match(tok, "using ::| %name% ::"))
2864  continue;
2865  const Token* ns = tok->tokAt(tok->strAt(1) == "::" ? 2 : 1);
2866  if (ns->isKeyword())
2867  continue;
2868  Token* end = tok->tokAt(3);
2869  while (end && !Token::Match(end, "[;,]")) {
2870  if (end->str() == "<") // skip template args
2871  end = end->findClosingBracket();
2872  else
2873  end = end->next();
2874  }
2875  if (!end)
2876  continue;
2877  if (!end->tokAt(-1)->isNameOnly() || end->tokAt(-2)->isLiteral()) // e.g. operator=, operator""sv
2878  continue;
2879  tok->insertToken(end->strAt(-1))->insertToken("=")->isSimplifiedTypedef(true);
2880  if (end->str() == ",") { // comma-separated list
2881  end->str(";");
2882  end->insertToken("using");
2883  }
2884  tok = end;
2885  }
2886 
2887  const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace
2888 
2889  bool substitute = false;
2890  ScopeInfo3 scopeInfo;
2891  ScopeInfo3 *currentScope = &scopeInfo;
2892  struct Using {
2893  Using(Token *start, Token *end) : startTok(start), endTok(end) {}
2894  Token *startTok;
2895  Token *endTok;
2896  };
2897  std::list<Using> usingList;
2898 
2899  for (Token *tok = list.front(); tok; tok = tok->next()) {
2900  if (!list.getFiles().empty())
2901  mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue());
2902 
2903  if (Settings::terminated())
2904  return substitute;
2905 
2906  if (Token::Match(tok, "enum class|struct")) {
2907  Token *bodyStart = tok;
2908  while (Token::Match(bodyStart, "%name%|:|::|<")) {
2909  if (bodyStart->str() == "<")
2910  bodyStart = bodyStart->findClosingBracket();
2911  bodyStart = bodyStart ? bodyStart->next() : nullptr;
2912  }
2913  if (Token::simpleMatch(bodyStart, "{"))
2914  tok = bodyStart->link();
2915  continue;
2916  }
2917 
2918  if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
2919  Token::Match(tok, "using namespace %name% ;|::")) {
2920  try {
2921  setScopeInfo(tok, currentScope, mSettings.debugwarnings);
2922  } catch (const std::runtime_error &) {
2923  reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2924  "simplifyUsing: unmatched body end");
2925  }
2926  continue;
2927  }
2928 
2929  // skip template declarations
2930  if (Token::Match(tok, "template < !!>")) {
2931  // add template record type to scope info
2932  const Token *end = tok->next()->findClosingBracket();
2933  if (end && Token::Match(end->next(), "class|struct|union %name%"))
2934  currentScope->recordTypes.insert(end->strAt(2));
2935 
2937  if (declEndToken)
2938  tok = declEndToken;
2939  continue;
2940  }
2941 
2942  // look for non-template type aliases
2943  if (!(tok->strAt(-1) != ">" &&
2944  (Token::Match(tok, "using %name% = ::| %name%") ||
2945  (Token::Match(tok, "using %name% [ [") &&
2946  Token::Match(tok->linkAt(2), "] ] = ::| %name%")))))
2947  continue;
2948 
2949  const std::string& name = tok->strAt(1);
2950  const Token *nameToken = tok->next();
2951  std::string scope = currentScope->fullName;
2952  Token *usingStart = tok;
2953  Token *start;
2954  if (tok->strAt(2) == "=") {
2955  if (currentScope->type == ScopeInfo3::Record && tok->tokAt(2)->isSimplifiedTypedef()) // don't simplify within class definition
2956  continue;
2957  start = tok->tokAt(3);
2958  }
2959  else
2960  start = tok->linkAt(2)->tokAt(3);
2961  Token *usingEnd = findSemicolon(start);
2962  if (!usingEnd)
2963  continue;
2964 
2965  // Move struct defined in using out of using.
2966  // using T = struct t { }; => struct t { }; using T = struct t;
2967  // fixme: this doesn't handle attributes
2968  if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
2969  Token *structEnd = start->tokAt(1);
2970  const bool hasName = Token::Match(structEnd, "%name%");
2971 
2972  // skip over name if present
2973  if (hasName)
2974  structEnd = structEnd->next();
2975 
2976  // skip over base class information
2977  if (structEnd->str() == ":") {
2978  structEnd = structEnd->next(); // skip over ":"
2979  while (structEnd && structEnd->str() != "{")
2980  structEnd = structEnd->next();
2981  if (!structEnd)
2982  continue;
2983  }
2984 
2985  // use link to go to end
2986  structEnd = structEnd->link();
2987 
2988  // add ';' after end of struct
2989  structEnd->insertToken(";", emptyString);
2990 
2991  // add name for anonymous struct
2992  if (!hasName) {
2993  std::string newName;
2994  if (structEnd->strAt(2) == ";")
2995  newName = name;
2996  else
2997  newName = "Unnamed" + std::to_string(mUnnamedCount++);
2998  TokenList::copyTokens(structEnd->next(), tok, start);
2999  structEnd->tokAt(5)->insertToken(newName, emptyString);
3000  start->insertToken(newName, emptyString);
3001  } else
3002  TokenList::copyTokens(structEnd->next(), tok, start->next());
3003 
3004  // add using after end of struct
3005  usingStart = structEnd->tokAt(2);
3006  nameToken = usingStart->next();
3007  if (usingStart->strAt(2) == "=")
3008  start = usingStart->tokAt(3);
3009  else
3010  start = usingStart->linkAt(2)->tokAt(3);
3011  usingEnd = findSemicolon(start);
3012 
3013  // delete original using before struct
3014  tok->deleteThis();
3015  tok->deleteThis();
3016  tok->deleteThis();
3017  tok = usingStart;
3018  }
3019 
3020  // remove 'typename' and 'template'
3021  else if (start->str() == "typename") {
3022  start->deleteThis();
3023  Token *temp = start;
3024  while (Token::Match(temp, "%name% ::"))
3025  temp = temp->tokAt(2);
3026  if (Token::Match(temp, "template %name%"))
3027  temp->deleteThis();
3028  }
3029 
3030  if (usingEnd)
3031  tok = usingEnd;
3032 
3033  // Unfortunately we have to start searching from the beginning
3034  // of the token stream because templates are instantiated at
3035  // the end of the token stream and it may be used before then.
3036  ScopeInfo3 scopeInfo1;
3037  ScopeInfo3 *currentScope1 = &scopeInfo1;
3038  Token *startToken = list.front();
3039  Token *endToken = nullptr;
3040  bool inMemberFunc = false;
3041  const ScopeInfo3 * memberFuncScope = nullptr;
3042  const Token * memberFuncEnd = nullptr;
3043 
3044  // We can limit the search to the current function when the type alias
3045  // is defined in that function.
3046  if (currentScope->type == ScopeInfo3::Other ||
3047  currentScope->type == ScopeInfo3::MemberFunction) {
3048  scopeInfo1 = scopeInfo;
3049  currentScope1 = scopeInfo1.findScope(currentScope);
3050  if (!currentScope1)
3051  return substitute; // something bad happened
3052  startToken = usingEnd->next();
3053  endToken = const_cast<Token*>(currentScope->bodyEnd->next());
3054  if (currentScope->type == ScopeInfo3::MemberFunction) {
3055  const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName);
3056  if (temp) {
3057  inMemberFunc = true;
3058  memberFuncScope = temp;
3059  memberFuncEnd = endToken;
3060  }
3061  }
3062  }
3063 
3064  std::string scope1 = currentScope1->fullName;
3065  bool skip = false; // don't erase type aliases we can't parse
3066  Token *enumOpenBrace = nullptr;
3067  for (Token* tok1 = startToken; !skip && tok1 && tok1 != endToken; tok1 = tok1->next()) {
3068  // skip enum body
3069  if (tok1 && tok1 == enumOpenBrace) {
3070  tok1 = tok1->link();
3071  enumOpenBrace = nullptr;
3072  continue;
3073  }
3074 
3075  if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
3076  Token::Match(tok1, "using namespace %name% ;|::")) {
3077  try {
3078  setScopeInfo(tok1, currentScope1, mSettings.debugwarnings);
3079  } catch (const std::runtime_error &) {
3080  reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
3081  "simplifyUsing: unmatched body end");
3082  }
3083  scope1 = currentScope1->fullName;
3084  if (inMemberFunc && memberFuncEnd && tok1 == memberFuncEnd) {
3085  inMemberFunc = false;
3086  memberFuncScope = nullptr;
3087  memberFuncEnd = nullptr;
3088  }
3089  continue;
3090  }
3091 
3092  // skip template definitions
3093  if (Token::Match(tok1, "template < !!>")) {
3095  if (declEndToken)
3096  tok1 = declEndToken;
3097  continue;
3098  }
3099 
3100  // check for enum with body
3101  if (tok1->str() == "enum") {
3102  if (Token::Match(tok1, "enum class|struct"))
3103  tok1 = tok1->next();
3104  Token *defStart = tok1;
3105  while (Token::Match(defStart, "%name%|::|:"))
3106  defStart = defStart->next();
3107  if (Token::simpleMatch(defStart, "{"))
3108  enumOpenBrace = defStart;
3109  continue;
3110  }
3111 
3112  // check for member function and adjust scope
3113  if (isMemberFunction(tok1)) {
3114  if (!scope1.empty())
3115  scope1 += " :: ";
3116  scope1 += memberFunctionScope(tok1);
3117  const ScopeInfo3 * temp = currentScope1->findScope(scope1);
3118  if (temp) {
3119  const Token *end = memberFunctionEnd(tok1);
3120  if (end) {
3121  inMemberFunc = true;
3122  memberFuncScope = temp;
3123  memberFuncEnd = end;
3124  }
3125  }
3126  continue;
3127  }
3128  if (inMemberFunc && memberFuncScope) {
3129  if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, memberFuncScope))
3130  continue;
3131  } else if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, nullptr))
3132  continue;
3133 
3134  const auto nReplace = tokDistance(start, usingEnd);
3135  if (nReplace > maxReplacementTokens) {
3136  simplifyUsingError(usingStart, usingEnd);
3137  continue;
3138  }
3139 
3140  // remove the qualification
3141  std::string fullScope = scope;
3142  std::string removed;
3143  while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
3144  removed = (tok1->strAt(-2) + " :: ") + removed;
3145  if (fullScope == tok1->strAt(-2)) {
3146  tok1->deletePrevious();
3147  tok1->deletePrevious();
3148  break;
3149  }
3150  const std::string::size_type idx = fullScope.rfind("::");
3151 
3152  if (idx == std::string::npos)
3153  break;
3154 
3155  if (tok1->strAt(-2) == fullScope.substr(idx + 3)) {
3156  tok1->deletePrevious();
3157  tok1->deletePrevious();
3158  fullScope.resize(idx - 1);
3159  } else
3160  break;
3161  }
3162 
3163  // remove global namespace if present
3164  if (tok1->strAt(-1) == "::") {
3165  removed.insert(0, ":: ");
3166  tok1->deletePrevious();
3167  }
3168 
3169  Token * arrayStart = nullptr;
3170 
3171  // parse the type
3172  Token *type = start;
3173  if (type->str() == "::") {
3174  type = type->next();
3175  while (Token::Match(type, "%type% ::"))
3176  type = type->tokAt(2);
3177  if (Token::Match(type, "%type%"))
3178  type = type->next();
3179  } else if (Token::Match(type, "%type% ::")) {
3180  do {
3181  type = type->tokAt(2);
3182  } while (Token::Match(type, "%type% ::"));
3183  if (Token::Match(type, "%type%"))
3184  type = type->next();
3185  } else if (Token::Match(type, "%type%")) {
3186  while (Token::Match(type, "const|class|struct|union|enum %type%") ||
3187  (type->next() && type->next()->isStandardType()))
3188  type = type->next();
3189 
3190  type = type->next();
3191 
3192  while (Token::Match(type, "%type%") &&
3193  (type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
3194  type = type->next();
3195  }
3196 
3197  bool atEnd = false;
3198  while (!atEnd) {
3199  if (type && type->str() == "::") {
3200  type = type->next();
3201  }
3202 
3203  if (Token::Match(type, "%type%") &&
3204  type->next() && !Token::Match(type->next(), "[|,|(")) {
3205  type = type->next();
3206  } else if (Token::simpleMatch(type, "const (")) {
3207  type = type->next();
3208  atEnd = true;
3209  } else
3210  atEnd = true;
3211  }
3212  } else
3213  syntaxError(type);
3214 
3215  // check for invalid input
3216  if (!type)
3217  syntaxError(tok1);
3218 
3219  // check for template
3220  if (type->str() == "<") {
3221  type = type->findClosingBracket();
3222 
3223  while (type && Token::Match(type->next(), ":: %type%"))
3224  type = type->tokAt(2);
3225 
3226  if (!type) {
3227  syntaxError(tok1);
3228  }
3229 
3230  while (Token::Match(type->next(), "const|volatile"))
3231  type = type->next();
3232 
3233  type = type->next();
3234  }
3235 
3236  // check for pointers and references
3237  std::list<std::string> pointers;
3238  while (Token::Match(type, "*|&|&&|const")) {
3239  pointers.push_back(type->str());
3240  type = type->next();
3241  }
3242 
3243  // check for array
3244  if (type && type->str() == "[") {
3245  do {
3246  if (!arrayStart)
3247  arrayStart = type;
3248 
3249  bool atEnd = false;
3250  while (!atEnd) {
3251  while (type->next() && !Token::Match(type->next(), ";|,")) {
3252  type = type->next();
3253  }
3254 
3255  if (!type->next())
3256  syntaxError(type); // invalid input
3257  else if (type->next()->str() == ";")
3258  atEnd = true;
3259  else if (type->str() == "]")
3260  atEnd = true;
3261  else
3262  type = type->next();
3263  }
3264 
3265  type = type->next();
3266  } while (type && type->str() == "[");
3267  }
3268 
3269  // make sure we are in a good state
3270  if (!tok1 || !tok1->next())
3271  break; // bail
3272 
3273  Token* after = tok1->next();
3274  // check if type was parsed
3275  if (type && type == usingEnd) {
3276  // check for array syntax and add type around variable
3277  if (arrayStart) {
3278  if (Token::Match(tok1->next(), "%name%")) {
3279  TokenList::copyTokens(tok1->next(), arrayStart, usingEnd->previous());
3280  TokenList::copyTokens(tok1, start, arrayStart->previous());
3281  tok1->deleteThis();
3282  substitute = true;
3283  }
3284  } else {
3285  // add some qualification back if needed
3286  std::string removed1 = std::move(removed);
3287  std::string::size_type idx = removed1.rfind(" ::");
3288  if (idx != std::string::npos)
3289  removed1.resize(idx);
3290  if (scopesMatch(removed1, scope, &scopeInfo1)) {
3291  ScopeInfo3 * tempScope = currentScope;
3292  while (tempScope->parent) {
3293  if (tempScope->recordTypes.find(start->str()) != tempScope->recordTypes.end()) {
3294  std::string::size_type spaceIdx = 0;
3295  std::string::size_type startIdx = 0;
3296  while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
3297  tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
3298  startIdx = spaceIdx + 1;
3299  }
3300  tok1->previous()->insertToken(removed1.substr(startIdx));
3301  tok1->previous()->insertToken("::");
3302  break;
3303  }
3304  idx = removed1.rfind(" ::");
3305  if (idx == std::string::npos)
3306  break;
3307 
3308  removed1.resize(idx);
3309  tempScope = tempScope->parent;
3310  }
3311  }
3312 
3313  // Is this a "T()" expression where T is a pointer type?
3314  if (Token::Match(tok1, "%name% ( )") && !pointers.empty()) {
3315  Token* tok2 = tok1->linkAt(1);
3316  tok1->deleteThis();
3317  TokenList::copyTokens(tok1, start, usingEnd->previous());
3318  tok2->insertToken("0");
3319  after = tok2->next();
3320  }
3321  else { // just replace simple type aliases
3322  TokenList::copyTokens(tok1, start, usingEnd->previous());
3323  tok1->deleteThis();
3324  }
3325  substitute = true;
3326  }
3327  } else {
3328  skip = true;
3329  simplifyUsingError(usingStart, usingEnd);
3330  }
3331  tok1 = after->previous();
3332  }
3333 
3334  if (!skip)
3335  usingList.emplace_back(usingStart, usingEnd);
3336  }
3337 
3338  // delete all used type alias definitions
3339  for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
3340  Token *usingStart = it->startTok;
3341  Token *usingEnd = it->endTok;
3342  if (usingStart->previous()) {
3343  if (usingEnd->next())
3344  Token::eraseTokens(usingStart->previous(), usingEnd->next());
3345  else {
3346  Token::eraseTokens(usingStart->previous(), usingEnd);
3347  usingEnd->deleteThis();
3348  }
3349  } else {
3350  if (usingEnd->next()) {
3351  Token::eraseTokens(usingStart, usingEnd->next());
3352  usingStart->deleteThis();
3353  } else {
3354  // this is the only code being checked so leave ';'
3355  Token::eraseTokens(usingStart, usingEnd);
3356  usingStart->deleteThis();
3357  }
3358  }
3359  }
3360 
3361  return substitute;
3362 }
3363 
3364 void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
3365 {
3366  if (mSettings.debugwarnings) {
3367  std::string str;
3368  for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
3369  if (!str.empty())
3370  str += ' ';
3371  str += tok->str();
3372  }
3373  str += " ;";
3374  std::list<const Token *> callstack(1, usingStart);
3375  mErrorLogger.reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
3376  "Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
3377  }
3378 }
3379 
3380 bool Tokenizer::simplifyTokens1(const std::string &configuration)
3381 {
3382  // Fill the map mTypeSize..
3383  fillTypeSizes();
3384 
3385  mConfiguration = configuration;
3386 
3387  if (mTimerResults) {
3388  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings.showtime, mTimerResults);
3389  if (!simplifyTokenList1(list.getFiles().front().c_str()))
3390  return false;
3391  } else {
3392  if (!simplifyTokenList1(list.getFiles().front().c_str()))
3393  return false;
3394  }
3395 
3396  if (mTimerResults) {
3397  Timer t("Tokenizer::simplifyTokens1::createAst", mSettings.showtime, mTimerResults);
3398  list.createAst();
3400  } else {
3401  list.createAst();
3403  }
3404 
3405  if (mTimerResults) {
3406  Timer t("Tokenizer::simplifyTokens1::createSymbolDatabase", mSettings.showtime, mTimerResults);
3408  } else {
3410  }
3411 
3412  if (mTimerResults) {
3413  Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings.showtime, mTimerResults);
3416  } else {
3419  }
3420 
3421  if (!mSettings.buildDir.empty())
3422  Summaries::create(*this, configuration);
3423 
3424  // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only
3425  const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW");
3426  const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0);
3427 
3428  if (doValueFlow) {
3429  if (mTimerResults) {
3430  Timer t("Tokenizer::simplifyTokens1::ValueFlow", mSettings.showtime, mTimerResults);
3432  } else {
3434  }
3435 
3437  }
3438 
3439  // Warn about unhandled character literals
3441  for (const Token *tok = tokens(); tok; tok = tok->next()) {
3442  if (tok->tokType() == Token::eChar && tok->values().empty()) {
3443  try {
3444  simplecpp::characterLiteralToLL(tok->str());
3445  } catch (const std::exception &e) {
3446  unhandledCharLiteral(tok, e.what());
3447  }
3448  }
3449  }
3450  }
3451 
3452  if (doValueFlow) {
3454  }
3455 
3456  printDebugOutput(1);
3457 
3458  return true;
3459 }
3460 
3461 //---------------------------------------------------------------------------
3462 
3464 {
3465  validate();
3467 }
3468 
3470 {
3471  for (const Token *tok = list.front(); tok; tok = tok->next()) {
3472  if (Token::Match(tok, "enum %name% {")) {
3473  tok = tok->tokAt(2);
3474  const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
3475  if (tok2)
3476  syntaxError(tok2);
3477  tok = tok->link();
3478  }
3479  }
3480 }
3481 
3483 {
3484  mTypeSize.clear();
3485  mTypeSize["char"] = 1;
3498 }
3499 
3501 {
3502  const bool cpp = isCPP();
3503 
3504  // Combine tokens..
3505  for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
3506  const char c1 = tok->str()[0];
3507 
3508  if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
3509  const char c2 = tok->next()->str()[0];
3510 
3511  // combine +-*/ and =
3512  if (c2 == '=' && (std::strchr("+-*/%|^=!<>", c1)) && !Token::Match(tok->previous(), "%type% *")) {
3513  // skip templates
3514  if (cpp && (tok->str() == ">" || Token::simpleMatch(tok->previous(), "> *"))) {
3515  const Token* opening =
3516  tok->str() == ">" ? tok->findOpeningBracket() : tok->previous()->findOpeningBracket();
3517  if (opening && Token::Match(opening->previous(), "%name%"))
3518  continue;
3519  }
3520  tok->str(tok->str() + c2);
3521  tok->deleteNext();
3522  continue;
3523  }
3524  } else if (tok->next()->str() == "=") {
3525  if (tok->str() == ">>") {
3526  tok->str(">>=");
3527  tok->deleteNext();
3528  } else if (tok->str() == "<<") {
3529  tok->str("<<=");
3530  tok->deleteNext();
3531  }
3532  } else if (cpp && (c1 == 'p' || c1 == '_') &&
3533  Token::Match(tok, "private|protected|public|__published : !!:")) {
3534  bool simplify = false;
3535  int par = 0;
3536  for (const Token *prev = tok->previous(); prev; prev = prev->previous()) {
3537  if (prev->str() == ")") {
3538  ++par;
3539  } else if (prev->str() == "(") {
3540  if (par == 0U)
3541  break;
3542  --par;
3543  }
3544  if (par != 0U || prev->str() == "(")
3545  continue;
3546  if (Token::Match(prev, "[;{}]")) {
3547  simplify = true;
3548  break;
3549  }
3550  if (prev->isName() && prev->isUpperCaseName())
3551  continue;
3552  if (prev->isName() && endsWith(prev->str(), ':'))
3553  simplify = true;
3554  break;
3555  }
3556  if (simplify) {
3557  tok->str(tok->str() + ":");
3558  tok->deleteNext();
3559  }
3560  } else if (tok->str() == "->") {
3561  // If the preceding sequence is "( & %name% )", replace it by "%name%"
3562  Token *t = tok->tokAt(-4);
3563  if (Token::Match(t, "( & %name% )") && !Token::simpleMatch(t->previous(), ">")) {
3564  t->deleteThis();
3565  t->deleteThis();
3566  t->deleteNext();
3567  tok->str(".");
3568  } else {
3569  tok->str(".");
3570  tok->originalName("->");
3571  }
3572  }
3573  }
3574 }
3575 
3577 {
3578  // Combine strings
3579  for (Token *tok = list.front(); tok; tok = tok->next()) {
3580  if (!isStringLiteral(tok->str()))
3581  continue;
3582 
3583  tok->str(simplifyString(tok->str()));
3584 
3585  while (Token::Match(tok->next(), "%str%") || Token::Match(tok->next(), "_T|_TEXT|TEXT ( %str% )")) {
3586  if (tok->next()->isName()) {
3587  if (!mSettings.platform.isWindows())
3588  break;
3589  tok->deleteNext(2);
3590  tok->next()->deleteNext();
3591  }
3592  // Two strings after each other, combine them
3593  tok->concatStr(simplifyString(tok->next()->str()));
3594  tok->deleteNext();
3595  }
3596  }
3597 }
3598 
3600 {
3601  for (Token *tok = list.front(); tok; tok = tok->next()) {
3602  if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->tokType() == Token::eIncDecOp)
3603  continue;
3604 
3605  while (tok->str() != ">" && tok->next() && tok->next()->str() == "+" && (!Token::Match(tok->tokAt(2), "%name% (|;") || Token::Match(tok, "%op%")))
3606  tok->deleteNext();
3607 
3608  if (Token::Match(tok->next(), "- %num%")) {
3609  tok->deleteNext();
3610  tok->next()->str("-" + tok->next()->str());
3611  }
3612  }
3613 }
3614 
3616 {
3617  if (isC())
3618  return;
3619 
3620  // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens.
3621  for (Token *tok = list.front(); tok; tok = tok->next()) {
3622  if (Token::Match(tok, "extern \"C\"|\"C++\"")) {
3623  Token *tok2 = tok->next();
3624  const bool isExtC = tok->next()->str().size() == 3;
3625  if (tok->strAt(2) == "{") {
3626  tok2 = tok2->next(); // skip {
3627  while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2))
3628  tok2->isExternC(isExtC);
3629  tok->linkAt(2)->deleteThis(); // }
3630  tok->deleteNext(2); // "C" {
3631  } else {
3632  while ((tok2 = tok2->next()) && !Token::Match(tok2, "[;{]"))
3633  tok2->isExternC(isExtC);
3634  tok->deleteNext(); // "C"
3635  }
3636  tok->deleteThis(); // extern
3637  }
3638  }
3639 }
3640 
3642 {
3643  for (Token *tok = list.front(); tok; tok = tok->next()) {
3644  while (Token::Match(tok, "[;{}:] ( {") &&
3645  Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
3646  if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
3647  break;
3648  Token *end = tok->linkAt(2)->tokAt(-3);
3649  if (Token::Match(end, "[;{}] %num%|%str% ;"))
3650  end->deleteNext(2);
3651  tok->linkAt(2)->previous()->deleteNext(3);
3652  tok->deleteNext(2);
3653  }
3654  if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
3655  tok->deleteNext();
3656  tok->deleteThis();
3657  tok->deleteNext(3);
3658  }
3659  }
3660 }
3661 
3663 {
3664  for (Token *tok = list.front(); tok; tok = tok->next()) {
3665  if (!Token::simpleMatch(tok, "__CPPCHECK_EMBEDDED_SQL_EXEC__ SQL"))
3666  continue;
3667 
3668  const Token *end = findSQLBlockEnd(tok);
3669  if (end == nullptr)
3670  syntaxError(nullptr);
3671 
3672  const std::string instruction = tok->stringifyList(end);
3673  // delete all tokens until the embedded SQL block end
3674  Token::eraseTokens(tok, end);
3675 
3676  // insert "asm ( "instruction" ) ;"
3677  tok->str("asm");
3678  // it can happen that 'end' is NULL when wrong code is inserted
3679  if (!tok->next())
3680  tok->insertToken(";");
3681  tok->insertToken(")");
3682  tok->insertToken("\"" + instruction + "\"");
3683  tok->insertToken("(");
3684  // jump to ';' and continue
3685  tok = tok->tokAt(3);
3686  }
3687 }
3688 
3690 {
3691  // 0[a] -> a[0]
3692  for (Token *tok = list.front(); tok; tok = tok->next()) {
3693  if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
3694  const std::string number(tok->str());
3695  Token* indexTok = tok->tokAt(2);
3696  tok->str(indexTok->str());
3697  tok->varId(indexTok->varId());
3698  indexTok->str(number);
3699  }
3700  }
3701 }
3702 
3704 {
3705  for (Token* tok = list.front(); tok; tok = tok->next()) {
3706  if (Token::Match(tok, "%name% ( void )") && !Token::Match(tok, "sizeof|decltype|typeof|return")) {
3707  tok->next()->deleteNext();
3708  tok->next()->setRemovedVoidParameter(true);
3709  }
3710  }
3711 }
3712 
3714 {
3715  // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
3716  for (Token *tok = list.front(); tok;) {
3717  if (Token::simpleMatch(tok, "= {")) {
3718  tok = tok->linkAt(1);
3719  } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
3720  //remove internal parentheses
3721  tok->next()->link()->deleteThis();
3722  tok->deleteNext();
3723  } else
3724  tok = tok->next();
3725  }
3726 }
3727 
3729 {
3730  // Convert - - into + and + - into -
3731  for (Token *tok = list.front(); tok; tok = tok->next()) {
3732  while (tok->next()) {
3733  if (tok->str() == "+") {
3734  if (tok->next()->str()[0] == '-') {
3735  tok = tok->next();
3736  if (tok->str().size() == 1) {
3737  tok = tok->previous();
3738  tok->str("-");
3739  tok->deleteNext();
3740  } else if (tok->isNumber()) {
3741  tok->str(tok->str().substr(1));
3742  tok = tok->previous();
3743  tok->str("-");
3744  }
3745  continue;
3746  }
3747  } else if (tok->str() == "-") {
3748  if (tok->next()->str()[0] == '-') {
3749  tok = tok->next();
3750  if (tok->str().size() == 1) {
3751  tok = tok->previous();
3752  tok->str("+");
3753  tok->deleteNext();
3754  } else if (tok->isNumber()) {
3755  tok->str(tok->str().substr(1));
3756  tok = tok->previous();
3757  tok->str("+");
3758  }
3759  continue;
3760  }
3761  }
3762 
3763  break;
3764  }
3765  }
3766 }
3767 
3768 /** Specify array size if it hasn't been given */
3769 
3771 {
3772  auto getStrTok = [](Token* tok, bool addLength, Token*& endStmt) -> Token* {
3773  if (addLength) {
3774  endStmt = tok->tokAt(5);
3775  return tok->tokAt(4);
3776  }
3777  if (Token::Match(tok, "%var% [ ] =")) {
3778  tok = tok->tokAt(4);
3779  int parCount = 0;
3780  while (Token::simpleMatch(tok, "(")) {
3781  ++parCount;
3782  tok = tok->next();
3783  }
3784  if (Token::Match(tok, "%str%")) {
3785  endStmt = tok->tokAt(parCount + 1);
3786  return tok;
3787  }
3788  }
3789  return nullptr;
3790  };
3791 
3792  for (Token *tok = list.front(); tok; tok = tok->next()) {
3793  if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
3794  continue;
3795  bool addlength = false;
3796  if (Token::Match(tok->previous(), "!!* %var% [ ] = { %str% } ;")) {
3797  Token *t = tok->tokAt(3);
3798  t->deleteNext();
3799  t->next()->deleteNext();
3800  addlength = true;
3801  }
3802 
3803  Token* endStmt{};
3804  if (const Token* strTok = getStrTok(tok, addlength, endStmt)) {
3805  const int sz = Token::getStrArraySize(strTok);
3806  tok->next()->insertToken(std::to_string(sz));
3807  tok = endStmt;
3808  }
3809 
3810  else if (Token::Match(tok, "%var% [ ] = {")) {
3811  MathLib::biguint sz = 1;
3812  tok = tok->next();
3813  Token *end = tok->linkAt(3);
3814  for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
3815  if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
3816  if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
3817  if (Token::Match(tok2, "[ %num% ]"))
3818  sz = std::max(sz, MathLib::toBigUNumber(tok2->strAt(1)) + 1U);
3819  else {
3820  sz = 0;
3821  break;
3822  }
3823  }
3824  tok2 = tok2->link();
3825  } else if (tok2->str() == ",") {
3826  if (!Token::Match(tok2->next(), "[},]"))
3827  ++sz;
3828  else {
3829  tok2 = tok2->previous();
3830  tok2->deleteNext();
3831  }
3832  }
3833  }
3834 
3835  if (sz != 0)
3836  tok->insertToken(std::to_string(sz));
3837 
3838  tok = end->next() ? end->next() : end;
3839  }
3840  }
3841 }
3842 
3844 {
3845  // After ValueFlow, adjust array sizes.
3846  for (const Variable* var: mSymbolDatabase->variableList()) {
3847  if (!var || !var->isArray())
3848  continue;
3849  if (!Token::Match(var->nameToken(), "%name% [ ] = { ["))
3850  continue;
3851  MathLib::bigint maxIndex = -1;
3852  const Token* const startToken = var->nameToken()->tokAt(4);
3853  const Token* const endToken = startToken->link();
3854  for (const Token* tok = startToken; tok != endToken; tok = tok->next()) {
3855  if (!Token::Match(tok, "[{,] [") || !Token::simpleMatch(tok->linkAt(1), "] ="))
3856  continue;
3857  const Token* expr = tok->next()->astOperand1();
3858  if (expr && expr->hasKnownIntValue())
3859  maxIndex = std::max(maxIndex, expr->getKnownIntValue());
3860  }
3861  if (maxIndex >= 0) {
3862  // insert array size
3863  Token* tok = const_cast<Token*>(var->nameToken()->next());
3864  tok->insertToken(std::to_string(maxIndex + 1));
3865  // ast
3866  tok->astOperand2(tok->next());
3867  // Token::scope
3868  tok->next()->scope(tok->scope());
3869  // Value flow
3870  ValueFlow::Value value(maxIndex + 1);
3871  value.setKnown();
3872  tok->next()->addValue(value);
3873  // Set array dimensions
3874  Dimension d;
3875  d.num = maxIndex + 1;
3876  std::vector<Dimension> dimensions{d};
3877  const_cast<Variable*>(var)->setDimensions(dimensions);
3878  }
3879  }
3880 }
3881 
3883 {
3884  int colonLevel = 1;
3885  while (nullptr != (tok = tok->next())) {
3886  if (tok->str() == "?") {
3887  ++colonLevel;
3888  } else if (tok->str() == ":") {
3889  --colonLevel;
3890  if (colonLevel == 0) {
3891  tok = tok->next();
3892  break;
3893  }
3894  }
3895  if (tok->link() && Token::Match(tok, "[(<]"))
3896  tok = tok->link();
3897  else if (Token::Match(tok->next(), "[{};)]"))
3898  break;
3899  }
3900  if (colonLevel > 0) // Ticket #5214: Make sure the ':' matches the proper '?'
3901  return nullptr;
3902  return tok;
3903 }
3904 
3905 // Skips until the colon at the end of the case label, the argument must point to the "case" token.
3906 // In case of success returns the colon token.
3907 // In case of failure returns the token that caused the error.
3909 {
3910  assert(tok->str() == "case");
3911  while (nullptr != (tok = tok->next())) {
3912  if (Token::Match(tok, "(|["))
3913  tok = tok->link();
3914  else if (tok->str() == "?") {
3915  Token * tok1 = skipTernaryOp(tok);
3916  if (!tok1)
3917  return tok;
3918  tok = tok1;
3919  }
3920  if (Token::Match(tok, "[:{};]"))
3921  return tok;
3922  }
3923  return nullptr;
3924 }
3925 
3927 {
3928  if (tok->str() != ")")
3929  return nullptr;
3930 
3931  tok = Tokenizer::isFunctionHead(tok, ":{");
3932 
3933  if (Token::Match(tok, ": %name% [({]")) {
3934  while (Token::Match(tok, "[:,] %name% [({]"))
3935  tok = tok->linkAt(2)->next();
3936  }
3937 
3938  return (tok && tok->str() == "{") ? tok : nullptr;
3939 }
3940 
3941 
3942 /** simplify labels and case|default in the code: add a ";" if not already in.*/
3943 
3945 {
3946  const bool cpp = isCPP();
3947  bool executablescope = false;
3948  int indentLevel = 0;
3949  for (Token *tok = list.front(); tok; tok = tok->next()) {
3950  // Simplify labels in the executable scope..
3951  auto *start = const_cast<Token *>(startOfExecutableScope(tok));
3952  if (start) {
3953  tok = start;
3954  executablescope = true;
3955  }
3956 
3957  if (!executablescope)
3958  continue;
3959 
3960  if (tok->str() == "{") {
3961  if (tok->previous()->str() == "=")
3962  tok = tok->link();
3963  else
3964  ++indentLevel;
3965  } else if (tok->str() == "}") {
3966  --indentLevel;
3967  if (indentLevel == 0) {
3968  executablescope = false;
3969  continue;
3970  }
3971  } else if (Token::Match(tok, "(|["))
3972  tok = tok->link();
3973 
3974  if (Token::Match(tok, "[;{}:] case")) {
3975  tok = skipCaseLabel(tok->next());
3976  if (!tok)
3977  break;
3978  if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next())
3979  syntaxError(tok);
3980  if (tok->next()->str() != ";" && tok->next()->str() != "case")
3981  tok->insertToken(";");
3982  else
3983  tok = tok->previous();
3984  } else if (Token::Match(tok, "[;{}] %name% : !!;")) {
3985  if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) {
3986  tok = tok->tokAt(2);
3987  tok->insertToken(";");
3988  }
3989  }
3990  }
3991 }
3992 
3993 
3995 {
3996  for (Token* tok = list.front(); tok; tok = tok->next()) {
3997  if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
3998  const MathLib::bigint start = MathLib::toBigNumber(tok->strAt(1));
4000  end = std::min(start + 50, end); // Simplify it 50 times at maximum
4001  if (start < end) {
4002  tok = tok->tokAt(2);
4003  tok->str(":");
4004  tok->insertToken("case");
4005  for (MathLib::bigint i = end-1; i > start; i--) {
4006  tok->insertToken(":");
4007  tok->insertToken(std::to_string(i));
4008  tok->insertToken("case");
4009  }
4010  }
4011  }
4012  }
4013 }
4014 
4016 {
4017  for (auto *tok = list.front(); tok; tok = tok->next())
4018  tok->scopeInfo(nullptr);
4019 
4020  std::string nextScopeNameAddition;
4021  std::shared_ptr<ScopeInfo2> primaryScope = std::make_shared<ScopeInfo2>("", nullptr);
4022  list.front()->scopeInfo(std::move(primaryScope));
4023 
4024  for (Token* tok = list.front(); tok; tok = tok->next()) {
4025  if (tok == list.front() || !tok->scopeInfo()) {
4026  if (tok != list.front())
4027  tok->scopeInfo(tok->previous()->scopeInfo());
4028 
4029  if (Token::Match(tok, "using namespace %name% ::|<|;")) {
4030  std::string usingNamespaceName;
4031  for (const Token* namespaceNameToken = tok->tokAt(2);
4032  namespaceNameToken && namespaceNameToken->str() != ";";
4033  namespaceNameToken = namespaceNameToken->next()) {
4034  usingNamespaceName += namespaceNameToken->str();
4035  usingNamespaceName += " ";
4036  }
4037  if (!usingNamespaceName.empty())
4038  usingNamespaceName.pop_back();
4039  tok->scopeInfo()->usingNamespaces.insert(std::move(usingNamespaceName));
4040  } else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
4041  for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
4042  if (Token::Match(nameTok, ";|<")) {
4043  nextScopeNameAddition = "";
4044  break;
4045  }
4046  nextScopeNameAddition.append(nameTok->str());
4047  nextScopeNameAddition.append(" ");
4048  }
4049  if (!nextScopeNameAddition.empty())
4050  nextScopeNameAddition.pop_back();
4051  }
4052 
4053  if (Token::simpleMatch(tok, "{")) {
4054  // This might be the opening of a member function
4055  Token *tok1 = tok;
4056  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4057  tok1 = tok1->previous();
4058  if (tok1->previous() && tok1->strAt(-1) == ")") {
4059  bool member = true;
4060  tok1 = tok1->linkAt(-1);
4061  if (Token::Match(tok1->previous(), "throw|noexcept")) {
4062  tok1 = tok1->previous();
4063  while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4064  tok1 = tok1->previous();
4065  if (tok1->strAt(-1) != ")")
4066  member = false;
4067  } else if (Token::Match(tok->tokAt(-2), ":|, %name%")) {
4068  tok1 = tok1->tokAt(-2);
4069  if (tok1->strAt(-1) != ")")
4070  member = false;
4071  }
4072  if (member) {
4073  if (tok1->strAt(-1) == ">")
4074  tok1 = tok1->previous()->findOpeningBracket();
4075  if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
4076  tok1 = tok1->tokAt(-2);
4077  std::string scope = tok1->strAt(-1);
4078  while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
4079  scope = tok1->strAt(-3) + " :: " + scope;
4080  tok1 = tok1->tokAt(-2);
4081  }
4082 
4083  if (!nextScopeNameAddition.empty() && !scope.empty())
4084  nextScopeNameAddition += " :: ";
4085  nextScopeNameAddition += scope;
4086  }
4087  }
4088  }
4089 
4090  // New scope is opening, record it here
4091  std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(tok->scopeInfo()->name, tok->link(), tok->scopeInfo()->usingNamespaces);
4092 
4093  if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty())
4094  newScopeInfo->name.append(" :: ");
4095  newScopeInfo->name.append(nextScopeNameAddition);
4096  nextScopeNameAddition = "";
4097 
4098  if (tok->link())
4099  tok->link()->scopeInfo(tok->scopeInfo());
4100  tok->scopeInfo(std::move(newScopeInfo));
4101  }
4102  }
4103  }
4104 }
4105 
4107 {
4108  if (isC())
4109  return;
4110 
4111  const std::time_t maxTime = mSettings.templateMaxTime > 0 ? std::time(nullptr) + mSettings.templateMaxTime : 0;
4113  maxTime);
4114 }
4115 //---------------------------------------------------------------------------
4116 
4117 
4118 namespace {
4119  /** Class used in Tokenizer::setVarIdPass1 */
4120  class VariableMap {
4121  private:
4122  std::unordered_map<std::string, nonneg int> mVariableId;
4123  std::unordered_map<std::string, nonneg int> mVariableId_global;
4124  std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
4125  mutable nonneg int mVarId{};
4126  public:
4127  VariableMap() = default;
4128  void enterScope();
4129  bool leaveScope();
4130  void addVariable(const std::string& varname, bool globalNamespace);
4131  bool hasVariable(const std::string& varname) const {
4132  return mVariableId.find(varname) != mVariableId.end();
4133  }
4134 
4135  const std::unordered_map<std::string, nonneg int>& map(bool global) const {
4136  return global ? mVariableId_global : mVariableId;
4137  }
4138  nonneg int& getVarId() {
4139  return mVarId;
4140  }
4141  };
4142 }
4143 
4144 
4145 void VariableMap::enterScope()
4146 {
4147  mScopeInfo.emplace(/*std::vector<std::pair<std::string, nonneg int>>()*/);
4148 }
4149 
4150 bool VariableMap::leaveScope()
4151 {
4152  if (mScopeInfo.empty())
4153  return false;
4154 
4155  for (const std::pair<std::string, nonneg int>& outerVariable : mScopeInfo.top()) {
4156  if (outerVariable.second != 0)
4157  mVariableId[outerVariable.first] = outerVariable.second;
4158  else
4159  mVariableId.erase(outerVariable.first);
4160  }
4161  mScopeInfo.pop();
4162  return true;
4163 }
4164 
4165 void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
4166 {
4167  if (mScopeInfo.empty()) {
4168  mVariableId[varname] = ++mVarId;
4169  if (globalNamespace)
4170  mVariableId_global[varname] = mVariableId[varname];
4171  return;
4172  }
4173  std::unordered_map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
4174  if (it == mVariableId.end()) {
4175  mScopeInfo.top().emplace_back(varname, 0);
4176  mVariableId[varname] = ++mVarId;
4177  if (globalNamespace)
4178  mVariableId_global[varname] = mVariableId[varname];
4179  return;
4180  }
4181  mScopeInfo.top().emplace_back(varname, it->second);
4182  it->second = ++mVarId;
4183 }
4184 
4185 static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope)
4186 {
4187  const Token* const tok1 = tok;
4188  Token* tok2 = tok;
4189  if (!tok2->isName())
4190  return false;
4191 
4192  nonneg int typeCount = 0;
4193  nonneg int singleNameCount = 0;
4194  bool hasstruct = false; // Is there a "struct" or "class"?
4195  bool bracket = false;
4196  bool ref = false;
4197  while (tok2) {
4198  if (tok2->isName()) {
4199  if (Token::simpleMatch(tok2, "alignas (")) {
4200  tok2 = tok2->linkAt(1)->next();
4201  continue;
4202  }
4203  if (tok2->isCpp() && Token::Match(tok2, "namespace|public|private|protected"))
4204  return false;
4205  if (tok2->isCpp() && Token::simpleMatch(tok2, "decltype (")) {
4206  typeCount = 1;
4207  tok2 = tok2->linkAt(1)->next();
4208  continue;
4209  }
4210  if (Token::Match(tok2, "struct|union|enum") || (tok2->isCpp() && Token::Match(tok2, "class|typename"))) {
4211  hasstruct = true;
4212  typeCount = 0;
4213  singleNameCount = 0;
4214  } else if (Token::Match(tok2, "const|extern")) {
4215  // just skip "const", "extern"
4216  } else if (!hasstruct && variableMap.map(false).count(tok2->str()) && tok2->previous()->str() != "::") {
4217  ++typeCount;
4218  tok2 = tok2->next();
4219  if (!tok2 || tok2->str() != "::")
4220  break;
4221  } else {
4222  if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
4223  ++typeCount;
4224  ++singleNameCount;
4225  }
4226  } else if (tok2->isCpp() && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
4227  Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
4228  const Token *start = tok;
4229  if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/"))
4230  return false;
4231  Token* const closingBracket = tok2->findClosingBracket();
4232  if (closingBracket == nullptr) { /* Ticket #8151 */
4233  throw tok2;
4234  }
4235  tok2 = closingBracket;
4236  if (tok2->str() != ">")
4237  break;
4238  singleNameCount = 1;
4239  if (Token::Match(tok2, "> %name% %or%|%oror%|&&|&|^|+|-|*|/") && !Token::Match(tok2, "> const [*&]"))
4240  return false;
4241  if (Token::Match(tok2, "> %name% )")) {
4242  if (Token::Match(tok2->linkAt(2)->previous(), "if|for|while ("))
4243  return false;
4244  if (!Token::Match(tok2->linkAt(2)->previous(), "%name%|] ("))
4245  return false;
4246  }
4247  } else if (Token::Match(tok2, "&|&&")) {
4248  ref = !bracket;
4249  } else if (singleNameCount >= 1 && Token::Match(tok2, "( [*&]") && Token::Match(tok2->link(), ") (|[")) {
4250  for (const Token* tok3 = tok2->tokAt(2); Token::Match(tok3, "!!)"); tok3 = tok3->next()) {
4251  if (Token::Match(tok3, "(|["))
4252  tok3 = tok3->link();
4253  if (tok3->str() == ",")
4254  return false;
4255  }
4256  bracket = true; // Skip: Seems to be valid pointer to array or function pointer
4257  } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]")) {
4258  bracket = true;
4259  } else if (singleNameCount >= 1 && tok2->previous() && tok2->previous()->isStandardType() && Token::Match(tok2, "( *|&| %name% ) ;")) {
4260  bracket = true;
4261  } else if (tok2->str() == "::") {
4262  singleNameCount = 0;
4263  } else if (tok2->str() != "*" && tok2->str() != "...") {
4264  break;
4265  }
4266  tok2 = tok2->next();
4267  }
4268 
4269  if (tok2) {
4270  bool isLambdaArg = false;
4271  {
4272  const Token *tok3 = tok->previous();
4273  if (tok3 && tok3->str() == ",") {
4274  while (tok3 && !Token::Match(tok3,";|(|[|{")) {
4275  if (Token::Match(tok3, ")|]"))
4276  tok3 = tok3->link();
4277  tok3 = tok3->previous();
4278  }
4279 
4280  if (tok3 && executableScope && Token::Match(tok3->previous(), "%name% (")) {
4281  const Token *fdecl = tok3->previous();
4282  int count = 0;
4283  while (Token::Match(fdecl, "%name%|*")) {
4284  fdecl = fdecl->previous();
4285  count++;
4286  }
4287  if (!Token::Match(fdecl, "[;{}] %name%") || count <= 1)
4288  return false;
4289  }
4290  }
4291 
4292  if (tok3 && tok3->isCpp() && Token::simpleMatch(tok3->previous(), "] (") &&
4293  (Token::simpleMatch(tok3->link(), ") {") || Token::Match(tok3->link(), ") . %name%")))
4294  isLambdaArg = true;
4295  }
4296 
4297 
4298  tok = tok2;
4299 
4300  // In executable scopes, references must be assigned
4301  // Catching by reference is an exception
4302  if (executableScope && ref && !isLambdaArg) {
4303  if (Token::Match(tok2, "(|=|{|:"))
4304  ; // reference is assigned => ok
4305  else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
4306  return false; // not catching by reference => not declaration
4307  }
4308  }
4309 
4310  // Check if array declaration is valid (#2638)
4311  // invalid declaration: AAA a[4] = 0;
4312  if (typeCount >= 2 && executableScope && Token::Match(tok2, ")| [")) {
4313  const Token *tok3 = tok2->str() == ")" ? tok2->next() : tok2;
4314  while (tok3 && tok3->str() == "[") {
4315  tok3 = tok3->link()->next();
4316  }
4317  if (Token::Match(tok3, "= %num%"))
4318  return false;
4319  if (bracket && Token::Match(tok1->previous(), "[(,]") && Token::Match(tok3, "[,)]"))
4320  return false;
4321  }
4322 
4323  return (typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
4324 }
4325 
4326 
4327 static void setVarIdStructMembers(Token *&tok1,
4328  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4329  nonneg int &varId)
4330 {
4331  Token *tok = tok1;
4332 
4333  if (Token::Match(tok, "%name% = { . %name% =|{")) {
4334  const nonneg int struct_varid = tok->varId();
4335  if (struct_varid == 0)
4336  return;
4337 
4338  std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4339 
4340  tok = tok->tokAt(3);
4341  while (tok->str() != "}") {
4342  if (Token::Match(tok, "{|[|("))
4343  tok = tok->link();
4344  if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
4345  tok = tok->next();
4346  const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4347  if (it == members.end()) {
4348  members[tok->str()] = ++varId;
4349  tok->varId(varId);
4350  } else {
4351  tok->varId(it->second);
4352  }
4353  }
4354  tok = tok->next();
4355  }
4356 
4357  return;
4358  }
4359 
4360  while (Token::Match(tok->next(), ")| . %name% !!(")) {
4361  // Don't set varid for trailing return type
4362  if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-1), "%name%|]") &&
4363  Tokenizer::isFunctionHead(tok->linkAt(1), "{|;")) {
4364  tok = tok->tokAt(3);
4365  continue;
4366  }
4367  const nonneg int struct_varid = tok->varId();
4368  tok = tok->tokAt(2);
4369  if (struct_varid == 0)
4370  continue;
4371 
4372  if (tok->str() == ".")
4373  tok = tok->next();
4374 
4375  // Don't set varid for template function
4377  break;
4378 
4379  std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4380  const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4381  if (it == members.end()) {
4382  members[tok->str()] = ++varId;
4383  tok->varId(varId);
4384  } else {
4385  tok->varId(it->second);
4386  }
4387  }
4388  // tok can't be null
4389  tok1 = tok;
4390 }
4391 
4392 static bool setVarIdClassDeclaration(Token* const startToken,
4393  VariableMap& variableMap,
4394  const nonneg int scopeStartVarId,
4395  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers)
4396 {
4397  // end of scope
4398  const Token* const endToken = startToken->link();
4399 
4400  // determine class name
4401  std::string className;
4402  for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
4403  if (!tok->isName() && tok->str() != ":")
4404  break;
4405  if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
4406  className = tok->next()->str();
4407  break;
4408  }
4409  }
4410 
4411  // replace varids..
4412  int indentlevel = 0;
4413  bool initList = false;
4414  bool inEnum = false;
4415  const Token *initListArgLastToken = nullptr;
4416  for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
4417  if (!tok)
4418  return false;
4419  if (initList) {
4420  if (tok == initListArgLastToken)
4421  initListArgLastToken = nullptr;
4422  else if (!initListArgLastToken &&
4423  Token::Match(tok->previous(), "%name%|>|>> {|(") &&
4424  Token::Match(tok->link(), "}|) ,|{"))
4425  initListArgLastToken = tok->link();
4426  }
4427  if (tok->str() == "{") {
4428  inEnum = isEnumStart(tok);
4429  if (initList && !initListArgLastToken)
4430  initList = false;
4431  ++indentlevel;
4432  } else if (tok->str() == "}") {
4433  --indentlevel;
4434  inEnum = false;
4435  } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
4436  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4437  if (it != variableMap.map(false).end()) {
4438  tok->varId(it->second);
4439  }
4440  } else if (tok->isName() && tok->varId() <= scopeStartVarId) {
4441  if (indentlevel > 0 || initList) {
4442  if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
4443  continue;
4444  if (!tok->next())
4445  return false;
4446  if (tok->next()->str() == "::") {
4447  if (tok->str() == className)
4448  tok = tok->tokAt(2);
4449  else
4450  continue;
4451  }
4452 
4453  if (!inEnum) {
4454  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4455  if (it != variableMap.map(false).end()) {
4456  tok->varId(it->second);
4457  setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4458  }
4459  }
4460  }
4461  } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
4462  initList = true;
4463  }
4464  return true;
4465 }
4466 
4467 
4468 
4469 // Update the variable ids..
4470 // Parse each function..
4471 void Tokenizer::setVarIdClassFunction(const std::string &classname,
4472  Token * const startToken,
4473  const Token * const endToken,
4474  const std::map<std::string, nonneg int> &varlist,
4475  std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4476  nonneg int &varId_)
4477 {
4478  const auto pos = classname.rfind(' '); // TODO handle multiple scopes
4479  const std::string lastScope = classname.substr(pos == std::string::npos ? 0 : pos + 1);
4480  for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
4481  if (tok2->varId() != 0 || !tok2->isName())
4482  continue;
4483  if (Token::Match(tok2->tokAt(-2), ("!!" + lastScope + " ::").c_str()))
4484  continue;
4485  if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
4486  continue;
4487  if (Token::Match(tok2->tokAt(-2), "!!this .") && !Token::simpleMatch(tok2->tokAt(-5), "( * this ) ."))
4488  continue;
4489  if (Token::Match(tok2, "%name% ::"))
4490  continue;
4491 
4492  const std::map<std::string, nonneg int>::const_iterator it = varlist.find(tok2->str());
4493  if (it != varlist.end()) {
4494  tok2->varId(it->second);
4495  setVarIdStructMembers(tok2, structMembers, varId_);
4496  }
4497  }
4498 }
4499 
4500 
4501 
4503 {
4504  // Clear all variable ids
4505  for (Token *tok = list.front(); tok; tok = tok->next()) {
4506  if (tok->isName())
4507  tok->varId(0);
4508  }
4509 
4510  setVarIdPass1();
4511 
4512  setPodTypes();
4513 
4514  setVarIdPass2();
4515 }
4516 
4517 
4518 // Variable declarations can't start with "return" etc.
4519 #define NOTSTART_C "NOT", "case", "default", "goto", "not", "return", "sizeof", "typedef"
4520 static const std::unordered_set<std::string> notstart_c = { NOTSTART_C };
4521 static const std::unordered_set<std::string> notstart_cpp = { NOTSTART_C,
4522  "delete", "friend", "new", "throw", "using", "virtual", "explicit", "const_cast", "dynamic_cast", "reinterpret_cast", "static_cast", "template"
4523 };
4524 
4526 {
4527  // Variable declarations can't start with "return" etc.
4528  const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
4529 
4530  VariableMap variableMap;
4531  std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
4532 
4533  std::stack<VarIdScopeInfo> scopeStack;
4534 
4535  scopeStack.emplace(/*VarIdScopeInfo()*/);
4536  std::stack<const Token *> functionDeclEndStack;
4537  const Token *functionDeclEndToken = nullptr;
4538  bool initlist = false;
4539  bool inlineFunction = false;
4540  for (Token *tok = list.front(); tok; tok = tok->next()) {
4541  if (tok->isOp())
4542  continue;
4543  if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
4544  Token* closingBracket = tok->next()->findClosingBracket();
4545  if (closingBracket)
4546  tok = closingBracket;
4547  continue;
4548  }
4549 
4550  if (tok == functionDeclEndToken) {
4551  functionDeclEndStack.pop();
4552  functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
4553  if (tok->str() == ":")
4554  initlist = true;
4555  else if (tok->str() == ";") {
4556  if (!variableMap.leaveScope())
4557  cppcheckError(tok);
4558  } else if (tok->str() == "{") {
4559  scopeStack.emplace(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/ false, variableMap.getVarId());
4560 
4561  // check if this '{' is a start of an "if" body
4562  const Token * ifToken = tok->previous();
4563  if (ifToken && ifToken->str() == ")")
4564  ifToken = ifToken->link();
4565  else
4566  ifToken = nullptr;
4567  if (ifToken)
4568  ifToken = ifToken->previous();
4569  if (ifToken && ifToken->str() == "if") {
4570  // open another scope to differentiate between variables declared in the "if" condition and in the "if" body
4571  variableMap.enterScope();
4572  }
4573  }
4574  } else if (!initlist && tok->str()=="(") {
4575  const Token * newFunctionDeclEnd = nullptr;
4576  if (!scopeStack.top().isExecutable)
4577  newFunctionDeclEnd = isFunctionHead(tok, "{:;");
4578  else {
4579  const Token* tokenLinkNext = tok->link()->next();
4580  if (Token::simpleMatch(tokenLinkNext, ".")) { // skip trailing return type
4581  tokenLinkNext = tokenLinkNext->next();
4582  while (Token::Match(tokenLinkNext, "%name%|::")) {
4583  tokenLinkNext = tokenLinkNext->next();
4584  if (Token::simpleMatch(tokenLinkNext, "<") && tokenLinkNext->link())
4585  tokenLinkNext = tokenLinkNext->link()->next();
4586  }
4587  }
4588  if (tokenLinkNext && tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
4589  newFunctionDeclEnd = tokenLinkNext;
4590  }
4591  if (newFunctionDeclEnd && newFunctionDeclEnd != functionDeclEndToken) {
4592  functionDeclEndStack.push(newFunctionDeclEnd);
4593  functionDeclEndToken = newFunctionDeclEnd;
4594  variableMap.enterScope();
4595  }
4596  } else if (Token::Match(tok, "{|}")) {
4597  inlineFunction = false;
4598 
4599  const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
4600 
4601  // parse anonymous namespaces as part of the current scope
4602  if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
4603  !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(") && Token::Match(startToken->link(), "} ,|{|)"))) {
4604 
4605  if (tok->str() == "{") {
4606  bool isExecutable;
4607  const Token *prev = tok->previous();
4608  while (Token::Match(prev, "%name%|."))
4609  prev = prev->previous();
4610  const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] (");
4611  if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) ||
4612  (initlist && tok->strAt(-1) == "}")) {
4613  isExecutable = true;
4614  } else {
4615  isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
4617  if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
4618  variableMap.enterScope();
4619  }
4620  initlist = false;
4621  scopeStack.emplace(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), variableMap.getVarId());
4622  } else { /* if (tok->str() == "}") */
4623  bool isNamespace = false;
4624  for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) {
4625  if (tok1->str() == "namespace") {
4626  isNamespace = true;
4627  break;
4628  }
4629  }
4630  // Set variable ids in class declaration..
4631  if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
4632  if (!setVarIdClassDeclaration(tok->link(),
4633  variableMap,
4634  scopeStack.top().startVarid,
4635  structMembers)) {
4636  syntaxError(nullptr);
4637  }
4638  }
4639 
4640  if (!scopeStack.top().isStructInit) {
4641  variableMap.leaveScope();
4642 
4643  // check if this '}' is an end of an "else" body or an "if" body without an "else" part
4644  const Token * ifToken = startToken->previous();
4645  if (ifToken && ifToken->str() == ")")
4646  ifToken = ifToken->link()->previous();
4647  else
4648  ifToken = nullptr;
4649  if (startToken->strAt(-1) == "else" || (ifToken && ifToken->str() == "if" && tok->strAt(1) != "else")) {
4650  // leave the extra scope used to differentiate between variables declared in the "if" condition and in the "if" body
4651  variableMap.leaveScope();
4652  }
4653  }
4654 
4655  scopeStack.pop();
4656  if (scopeStack.empty()) { // should be impossible
4657  scopeStack.emplace(/*VarIdScopeInfo()*/);
4658  }
4659  }
4660  }
4661  }
4662 
4663  if ((!scopeStack.top().isStructInit &&
4664  (tok == list.front() ||
4665  Token::Match(tok, "[;{}]") ||
4666  (tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
4667  (tok->str() == "," && (!scopeStack.top().isExecutable || inlineFunction || !tok->previous()->varId())) ||
4668  (tok->isName() && endsWith(tok->str(), ':')))) ||
4669  (tok->str() == "(" && isFunctionHead(tok, "{"))) {
4670 
4671  // No variable declarations in sizeof
4672  if (Token::simpleMatch(tok->previous(), "sizeof (")) {
4673  continue;
4674  }
4675 
4676  if (Settings::terminated())
4677  return;
4678 
4679  // locate the variable name..
4680  Token* tok2 = (tok->isName()) ? tok : tok->next();
4681 
4682  // private: protected: public: etc
4683  while (tok2 && endsWith(tok2->str(), ':')) {
4684  tok2 = tok2->next();
4685  }
4686  if (!tok2)
4687  break;
4688 
4689  // Variable declaration can't start with "return", etc
4690  if (notstart.find(tok2->str()) != notstart.end())
4691  continue;
4692 
4693  if (!isC() && Token::simpleMatch(tok2, "const new"))
4694  continue;
4695 
4696  bool decl;
4697  if (isCPP() && mSettings.standards.cpp >= Standards::CPP17 && Token::Match(tok, "[(;{}] const| auto &|&&| [")) {
4698  // Structured bindings
4699  tok2 = Token::findsimplematch(tok, "[");
4700  if ((Token::simpleMatch(tok->previous(), "for (") && Token::simpleMatch(tok2->link(), "] :")) ||
4701  Token::simpleMatch(tok2->link(), "] =")) {
4702  while (tok2 && tok2->str() != "]") {
4703  if (Token::Match(tok2, "%name% [,]]"))
4704  variableMap.addVariable(tok2->str(), false);
4705  tok2 = tok2->next();
4706  }
4707  continue;
4708  }
4709  }
4710 
4711  try { /* Ticket #8151 */
4712  decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable);
4713  } catch (const Token * errTok) {
4714  syntaxError(errTok);
4715  }
4716 
4717  if (tok->str() == "(" && isFunctionHead(tok, "{") && scopeStack.top().isExecutable)
4718  inlineFunction = true;
4719 
4720  if (decl) {
4721  if (isCPP()) {
4722  if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
4723  for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
4724  if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
4725  declTok->varId(variableMap.map(false).find(declTok->str())->second);
4726  }
4727  }
4728  }
4729 
4730  const Token* prev2 = tok2->previous();
4731  if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
4732  ;
4733  else if (Token::Match(prev2, "%type% :") && tok->strAt(-1) == "for")
4734  ;
4735  else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
4736  // In C++ , a variable can't be called operator+ or something like that.
4737  if (prev2->isCpp() &&
4738  prev2->isOperatorKeyword())
4739  continue;
4740 
4741  const Token *tok3 = tok2->next();
4742  if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
4743  if (!scopeStack.top().isExecutable) {
4744  // 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.
4745  decl = false;
4746  bool rhs = false;
4747  for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
4748  if (tok3->str() == "=") {
4749  rhs = true;
4750  continue;
4751  }
4752 
4753  if (tok3->str() == ",") {
4754  rhs = false;
4755  continue;
4756  }
4757 
4758  if (rhs)
4759  continue;
4760 
4761  if (tok3->isLiteral() ||
4762  (tok3->isName() && (variableMap.hasVariable(tok3->str()) ||
4763  (tok3->strAt(-1) == "(" && Token::simpleMatch(tok3->next(), "(") && !Token::simpleMatch(tok3->linkAt(1)->next(), "(")))) ||
4764  tok3->isOp() ||
4765  tok3->str() == "(" ||
4766  notstart.find(tok3->str()) != notstart.end()) {
4767  decl = true;
4768  break;
4769  }
4770  }
4771  }
4772  } else
4773  decl = false;
4774  } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
4775  if (tok2->link() != tok2->next() && // add value-initialized variable T x{};
4776  (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:")))
4777  continue;
4778  } else
4779  decl = false;
4780 
4781  if (decl) {
4782  if (isC() && Token::Match(prev2->previous(), "&|&&"))
4783  syntaxErrorC(prev2, prev2->strAt(-2) + prev2->strAt(-1) + " " + prev2->str());
4784  variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
4785 
4786  if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
4787  for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
4788  if (Token::Match(tok3, "[([]"))
4789  tok3 = tok3->link();
4790  if (Token::Match(tok3, ", %name% [,=;]"))
4791  variableMap.addVariable(tok3->next()->str(), false);
4792  }
4793  }
4794 
4795  // set varid for template parameters..
4796  tok = tok->next();
4797  while (Token::Match(tok, "%name%|::"))
4798  tok = tok->next();
4799  if (tok && tok->str() == "<") {
4800  const Token *end = tok->findClosingBracket();
4801  while (tok != end) {
4802  if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
4803  Token::Match(tok->tokAt(-1), ":: %name%"))) {
4804  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4805  if (it != variableMap.map(false).end())
4806  tok->varId(it->second);
4807  }
4808  tok = tok->next();
4809  }
4810  }
4811 
4812  tok = tok2->previous();
4813  }
4814  }
4815  }
4816 
4817  if (tok->isName() && !tok->isKeyword() && !tok->isStandardType()) {
4818  // don't set variable id after a struct|enum|union
4819  if (Token::Match(tok->previous(), "struct|enum|union") || (tok->isCpp() && tok->strAt(-1) == "class"))
4820  continue;
4821 
4822  bool globalNamespace = false;
4823  if (!isC()) {
4824  if (tok->previous() && tok->previous()->str() == "::") {
4825  if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
4826  continue;
4827  globalNamespace = true;
4828  }
4829  if (tok->next() && tok->next()->str() == "::")
4830  continue;
4831  if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
4832  continue;
4833  }
4834 
4835  // function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
4836  if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) {
4837  bool par = false;
4838  const Token* start;
4839  Token* end;
4840 
4841  // search begin of function declaration
4842  for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
4843  if (start->str() == "(") {
4844  if (par)
4845  break;
4846  par = true;
4847  }
4848  if (Token::Match(start, "[(,]")) {
4849  if (!Token::Match(start, "[(,] %type% %name%|*|&"))
4850  break;
4851  }
4852  if (start->varId() > 0)
4853  break;
4854  }
4855 
4856  // search end of function declaration
4857  for (end = tok->next(); Token::Match(end, "%name%|*|&|,|[|]|%num%"); end = end->next()) {}
4858 
4859  // there are tokens which can't appear at the begin of a function declaration such as "return"
4860  const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();
4861 
4862  // now check if it is a function declaration
4863  if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword) {
4864  // function declaration => don't set varid
4865  tok = end;
4866  continue;
4867  }
4868  }
4869 
4870  if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
4871  !Token::simpleMatch(tok->next(), ": ;")) {
4872  const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
4873  if (it != variableMap.map(globalNamespace).end()) {
4874  tok->varId(it->second);
4875  setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4876  }
4877  }
4878  } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) {
4879  // Don't set varid after a :: or . token
4880  tok = tok->next();
4881  } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
4882  do {
4883  tok = tok->next();
4884  } while (tok && (tok->isName() || tok->str() == ","));
4885  if (!tok)
4886  break;
4887  tok = tok->previous();
4888  }
4889  }
4890 
4891  mVarId = variableMap.getVarId();
4892 }
4893 
4894 namespace {
4895  struct Member {
4896  Member(std::list<std::string> s, std::list<const Token *> ns, Token *t) : usingnamespaces(std::move(ns)), scope(std::move(s)), tok(t) {}
4897  std::list<const Token *> usingnamespaces;
4898  std::list<std::string> scope;
4899  Token *tok;
4900  };
4901 }
4902 
4903 static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
4904 {
4905  std::string ret;
4906  for (const ScopeInfo2 &si : scopeInfo)
4907  ret += (ret.empty() ? "" : " :: ") + (si.name);
4908  return ret;
4909 }
4910 
4911 static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
4912 {
4913  std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.cbegin();
4914 
4915  // Current scope..
4916  for (std::list<std::string>::const_iterator it = scope.cbegin(); it != scope.cend(); ++it) {
4917  if (scopeIt == scopeInfo.cend() || scopeIt->name != *it)
4918  return nullptr;
4919  ++scopeIt;
4920  }
4921 
4922  // using namespace..
4923  if (nsToken) {
4924  while (Token::Match(nsToken, "%name% ::")) {
4925  if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
4926  nsToken = nsToken->tokAt(2);
4927  ++scopeIt;
4928  } else {
4929  return nullptr;
4930  }
4931  }
4932  if (!Token::Match(nsToken, "%name% ;"))
4933  return nullptr;
4934  if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
4935  return nullptr;
4936  ++scopeIt;
4937  }
4938 
4939  // Parse member tokens..
4940  while (scopeIt != scopeInfo.end()) {
4941  if (!Token::Match(memberToken, "%name% ::|<"))
4942  return nullptr;
4943  if (memberToken->str() != scopeIt->name)
4944  return nullptr;
4945  if (memberToken->next()->str() == "<") {
4946  memberToken = memberToken->next()->findClosingBracket();
4947  if (!Token::simpleMatch(memberToken, "> ::"))
4948  return nullptr;
4949  }
4950  memberToken = memberToken->tokAt(2);
4951  ++scopeIt;
4952  }
4953 
4954  return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
4955 }
4956 
4957 static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
4958 {
4959  if (scopeInfo.empty())
4960  return nullptr;
4961 
4962  // Does this member match without "using namespace"..
4963  Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
4964  if (ret)
4965  return ret;
4966 
4967  // Try to match member using the "using namespace ..." namespaces..
4968  for (const Token *ns : member.usingnamespaces) {
4969  ret = matchMemberName(member.scope, ns, member.tok, scopeInfo);
4970  if (ret)
4971  return ret;
4972  }
4973 
4974  return nullptr;
4975 }
4976 
4977 static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
4978 {
4979  Token *tok = matchMemberName(var, scopeInfo);
4980  if (Token::Match(tok, "%name%")) {
4981  if (!tok->next() || tok->strAt(1) != "(" || (tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
4982  return tok;
4983  }
4984  return nullptr;
4985 }
4986 
4987 static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
4988 {
4989  Token *tok = matchMemberName(func, scopeInfo);
4990  return Token::Match(tok, "~| %name% (") ? tok : nullptr;
4991 }
4992 
4993 template<typename T>
4994 static T* skipInitializerList(T* tok)
4995 {
4996  T* const start = tok;
4997  while (Token::Match(tok, "[:,] ::| %name%")) {
4998  tok = tok->tokAt(tok->strAt(1) == "::" ? 1 : 2);
4999  while (Token::Match(tok, ":: %name%"))
5000  tok = tok->tokAt(2);
5001  if (!Token::Match(tok, "[({<]") || !tok->link())
5002  return start;
5003  const bool isTemplate = tok->str() == "<";
5004  tok = tok->link()->next();
5005  if (isTemplate && tok && tok->link())
5006  tok = tok->link()->next();
5007  }
5008  return tok;
5009 }
5010 
5012 {
5013  std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
5014 
5015  // Member functions and variables in this source
5016  std::list<Member> allMemberFunctions;
5017  std::list<Member> allMemberVars;
5018  if (!isC()) {
5019  std::map<const Token *, std::string> endOfScope;
5020  std::list<std::string> scope;
5021  std::list<const Token *> usingnamespaces;
5022  for (Token *tok = list.front(); tok; tok = tok->next()) {
5023  if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
5024  if (Token::Match(tok, "using namespace %name% ::|;")) {
5025  Token *endtok = tok->tokAt(2);
5026  while (Token::Match(endtok, "%name% ::"))
5027  endtok = endtok->tokAt(2);
5028  if (Token::Match(endtok, "%name% ;"))
5029  usingnamespaces.push_back(tok->tokAt(2));
5030  tok = endtok;
5031  continue;
5032  }
5033  if (Token::Match(tok, "namespace %name% {")) {
5034  scope.push_back(tok->strAt(1));
5035  endOfScope[tok->linkAt(2)] = tok->strAt(1);
5036  }
5037  }
5038 
5039  if (tok->str() == "}") {
5040  const std::map<const Token *, std::string>::iterator it = endOfScope.find(tok);
5041  if (it != endOfScope.end())
5042  scope.remove(it->second);
5043  }
5044 
5045  Token* const tok1 = tok;
5046  if (Token::Match(tok, "%name% :: ~| %name%"))
5047  tok = tok->next();
5048  else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5049  tok = tok->next()->findClosingBracket()->next();
5050  else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean ||
5051  Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") ||
5052  (!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
5053  continue;
5054 
5055  if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
5056  continue;
5057 
5058  while (Token::Match(tok, ":: ~| %name%")) {
5059  tok = tok->next();
5060  if (tok->str() == "~")
5061  tok = tok->next();
5062  else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5063  tok = tok->next()->findClosingBracket()->next();
5064  else if (Token::Match(tok, "%name% ::"))
5065  tok = tok->next();
5066  else
5067  break;
5068  }
5069  if (!tok->next())
5070  syntaxError(tok);
5071  if (Token::Match(tok, "%name% (") && !(tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
5072  allMemberFunctions.emplace_back(scope, usingnamespaces, tok1);
5073  else
5074  allMemberVars.emplace_back(scope, usingnamespaces, tok1);
5075  }
5076  }
5077 
5078  std::list<ScopeInfo2> scopeInfo;
5079 
5080  // class members..
5081  std::map<std::string, std::map<std::string, nonneg int>> varsByClass;
5082  for (Token *tok = list.front(); tok; tok = tok->next()) {
5083  while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
5084  scopeInfo.pop_back();
5085 
5086  if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<"))
5087  continue;
5088 
5089  const std::string &scopeName(getScopeName(scopeInfo));
5090  const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
5091 
5092  std::list<const Token*> classnameTokens{ tok->next() };
5093  Token* tokStart = tok->tokAt(2);
5094  while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") {
5095  if (tokStart->str() == "<") {
5096  // skip the template part
5097  Token* closeTok = tokStart->findClosingBracket();
5098  if (!closeTok)
5099  syntaxError(tok);
5100  tokStart = closeTok->next();
5101  } else {
5102  classnameTokens.push_back(tokStart->next());
5103  tokStart = tokStart->tokAt(2);
5104  }
5105  }
5106 
5107  std::string classname;
5108  for (const Token *it : classnameTokens)
5109  classname += (classname.empty() ? "" : " :: ") + it->str();
5110 
5111  std::map<std::string, nonneg int> &thisClassVars = varsByClass[scopeName2 + classname];
5112  while (Token::Match(tokStart, ":|::|,|%name%")) {
5113  if (Token::Match(tokStart, "%name% <")) { // TODO: why skip templates?
5114  tokStart = tokStart->next()->findClosingBracket();
5115  if (tokStart)
5116  tokStart = tokStart->next();
5117  continue;
5118  }
5119  if (Token::Match(tokStart, "%name% ,|{")) {
5120  std::string baseClassName = tokStart->str();
5121  const Token* baseStart = tokStart;
5122  while (Token::Match(baseStart->tokAt(-2), "%name% ::")) { // build base class name
5123  baseClassName.insert(0, baseStart->strAt(-2) + " :: ");
5124  baseStart = baseStart->tokAt(-2);
5125  }
5126  std::string scopeName3(scopeName2);
5127  while (!scopeName3.empty()) {
5128  const std::string name = scopeName3 + baseClassName;
5129  if (varsByClass.find(name) != varsByClass.end()) {
5130  baseClassName = name;
5131  break;
5132  }
5133  // Remove last scope name
5134  if (scopeName3.size() <= 8)
5135  break;
5136  scopeName3.erase(scopeName3.size() - 4);
5137  const std::string::size_type pos = scopeName3.rfind(" :: ");
5138  if (pos == std::string::npos)
5139  break;
5140  scopeName3.erase(pos + 4);
5141  }
5142  const std::map<std::string, nonneg int>& baseClassVars = varsByClass[baseClassName];
5143  thisClassVars.insert(baseClassVars.cbegin(), baseClassVars.cend());
5144  }
5145  tokStart = tokStart->next();
5146  }
5147  if (!Token::simpleMatch(tokStart, "{"))
5148  continue;
5149 
5150  // What member variables are there in this class?
5151  std::transform(classnameTokens.cbegin(), classnameTokens.cend(), std::back_inserter(scopeInfo), [&](const Token* tok) {
5152  return ScopeInfo2(tok->str(), tokStart->link());
5153  });
5154 
5155  for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
5156  // skip parentheses..
5157  if (tok2->link()) {
5158  if (tok2->str() == "(") {
5159  Token *funcstart = const_cast<Token*>(isFunctionHead(tok2, "{"));
5160  if (funcstart) {
5161  setVarIdClassFunction(scopeName2 + classname, funcstart, funcstart->link(), thisClassVars, structMembers, mVarId);
5162  tok2 = funcstart->link();
5163  continue;
5164  }
5165  }
5166  if (tok2->str() == "{" && !Token::simpleMatch(tok2->previous(), "union")) {
5167  if (tok2->strAt(-1) == ")")
5168  setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, mVarId);
5169  tok2 = tok2->link();
5170  } else if (Token::Match(tok2, "( %name%|)")) {
5171  tok2 = tok2->link();
5172 
5173  // Skip initialization list
5174  if (Token::simpleMatch(tok2, ") :")) {
5175  tok2 = skipInitializerList(tok2->next());
5176  if (Token::simpleMatch(tok2, "{"))
5177  tok2 = tok2->link();
5178  }
5179  }
5180  }
5181 
5182  // Found a member variable..
5183  else if (tok2->varId() > 0)
5184  thisClassVars[tok2->str()] = tok2->varId();
5185  }
5186 
5187  // Are there any member variables in this class?
5188  if (thisClassVars.empty())
5189  continue;
5190 
5191  // Member variables
5192  for (const Member &var : allMemberVars) {
5193  Token *tok2 = matchMemberVarName(var, scopeInfo);
5194  if (!tok2)
5195  continue;
5196  if (tok2->varId() == 0)
5197  tok2->varId(thisClassVars[tok2->str()]);
5198  }
5199 
5200  if (isC() || tok->str() == "namespace")
5201  continue;
5202 
5203  // Set variable ids in member functions for this class..
5204  for (const Member &func : allMemberFunctions) {
5205  Token *tok2 = matchMemberFunctionName(func, scopeInfo);
5206  if (!tok2)
5207  continue;
5208 
5209  if (tok2->str() == "~")
5210  tok2 = tok2->linkAt(2);
5211  else
5212  tok2 = tok2->linkAt(1);
5213 
5214  // If this is a function implementation.. add it to funclist
5215  Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
5216  if (start) {
5217  setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, mVarId);
5218  }
5219 
5220  if (Token::Match(tok2, ") %name% ("))
5221  tok2 = tok2->linkAt(2);
5222 
5223  // constructor with initializer list
5224  if (!Token::Match(tok2, ") : ::| %name%"))
5225  continue;
5226 
5227  Token *tok3 = tok2;
5228  while (Token::Match(tok3, "[)}] [,:]")) {
5229  tok3 = tok3->tokAt(2);
5230  if (Token::Match(tok3, ":: %name%"))
5231  tok3 = tok3->next();
5232  while (Token::Match(tok3, "%name% :: %name%"))
5233  tok3 = tok3->tokAt(2);
5234  if (!Token::Match(tok3, "%name% (|{|<"))
5235  break;
5236 
5237  // set varid
5238  const std::map<std::string, nonneg int>::const_iterator varpos = thisClassVars.find(tok3->str());
5239  if (varpos != thisClassVars.end())
5240  tok3->varId(varpos->second);
5241 
5242  // goto end of var
5243  if (tok3->strAt(1) == "<") {
5244  tok3 = tok3->next()->findClosingBracket();
5245  if (tok3 && tok3->next() && tok3->next()->link())
5246  tok3 = tok3->next()->link();
5247  } else
5248  tok3 = tok3->linkAt(1);
5249  }
5250  if (Token::Match(tok3, ")|} {")) {
5251  setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, structMembers, mVarId);
5252  }
5253  }
5254  }
5255 }
5256 
5257 static void linkBrackets(const Tokenizer & tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token * const token, const char open, const char close)
5258 {
5259  if (token->str()[0] == open) {
5260  links.push(token);
5261  type.push(token);
5262  } else if (token->str()[0] == close) {
5263  if (links.empty()) {
5264  // Error, { and } don't match.
5265  tokenizer.unmatchedToken(token);
5266  }
5267  if (type.top()->str()[0] != open) {
5268  tokenizer.unmatchedToken(type.top());
5269  }
5270  type.pop();
5271 
5272  Token::createMutualLinks(links.top(), token);
5273  links.pop();
5274  }
5275 }
5276 
5278 {
5279  std::stack<const Token*> type;
5280  std::stack<Token*> links1;
5281  std::stack<Token*> links2;
5282  std::stack<Token*> links3;
5283  for (Token *token = list.front(); token; token = token->next()) {
5284  if (token->link()) {
5285  token->link(nullptr);
5286  }
5287 
5288  linkBrackets(*this, type, links1, token, '{', '}');
5289 
5290  linkBrackets(*this, type, links2, token, '(', ')');
5291 
5292  linkBrackets(*this, type, links3, token, '[', ']');
5293  }
5294 
5295  if (!links1.empty()) {
5296  // Error, { and } don't match.
5297  unmatchedToken(links1.top());
5298  }
5299 
5300  if (!links2.empty()) {
5301  // Error, ( and ) don't match.
5302  unmatchedToken(links2.top());
5303  }
5304 
5305  if (!links3.empty()) {
5306  // Error, [ and ] don't match.
5307  unmatchedToken(links3.top());
5308  }
5309 }
5310 
5312 {
5313  if (isC())
5314  return;
5315 
5316  bool isStruct = false;
5317 
5318  std::stack<Token*> type;
5319  std::stack<Token*> templateTokens;
5320  for (Token *token = list.front(); token; token = token->next()) {
5321  if (Token::Match(token, "%name%|> %name% [:<]"))
5322  isStruct = true;
5323  else if (Token::Match(token, "[;{}]"))
5324  isStruct = false;
5325 
5326  if (token->link()) {
5327  if (Token::Match(token, "{|[|("))
5328  type.push(token);
5329  else if (!type.empty() && Token::Match(token, "}|]|)")) {
5330  while (type.top()->str() == "<") {
5331  if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
5332  templateTokens.pop();
5333  type.pop();
5334  }
5335  type.pop();
5336  }
5337  } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
5338  if (Token::Match(token, "&& [,>]"))
5339  continue;
5340  // If there is some such code: A<B||C>..
5341  // Then this is probably a template instantiation if either "B" or "C" has comparisons
5342  if (token->tokType() == Token::eLogicalOp && !type.empty() && type.top()->str() == "<") {
5343  const Token *prev = token->previous();
5344  bool foundComparison = false;
5345  while (Token::Match(prev, "%name%|%num%|%str%|%cop%|)|]") && prev != type.top()) {
5346  if (prev->str() == ")" || prev->str() == "]")
5347  prev = prev->link();
5348  else if (prev->tokType() == Token::eLogicalOp)
5349  break;
5350  else if (prev->isComparisonOp())
5351  foundComparison = true;
5352  prev = prev->previous();
5353  }
5354  if (prev == type.top() && foundComparison)
5355  continue;
5356  const Token *next = token->next();
5357  foundComparison = false;
5358  while (Token::Match(next, "%name%|%num%|%str%|%cop%|(|[") && next->str() != ">") {
5359  if (next->str() == "(" || next->str() == "[")
5360  next = next->link();
5361  else if (next->tokType() == Token::eLogicalOp)
5362  break;
5363  else if (next->isComparisonOp())
5364  foundComparison = true;
5365  next = next->next();
5366  }
5367  if (next && next->str() == ">" && foundComparison)
5368  continue;
5369  }
5370 
5371  while (!type.empty() && type.top()->str() == "<") {
5372  const Token* end = type.top()->findClosingBracket();
5373  if (Token::Match(end, "> %comp%|;|.|=|{|(|::"))
5374  break;
5375  // Variable declaration
5376  if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
5377  break;
5378  type.pop();
5379  }
5380  } else if (token->str() == "<" &&
5381  ((token->previous() && (token->previous()->isTemplate() ||
5382  (token->previous()->isName() && !token->previous()->varId()) ||
5383  (token->strAt(-1) == "]" && (!Token::Match(token->linkAt(-1)->previous(), "%name%|)") || token->linkAt(-1)->previous()->isKeyword())) ||
5384  (token->strAt(-1) == ")" && token->linkAt(-1)->strAt(-1) == "operator"))) ||
5385  Token::Match(token->next(), ">|>>"))) {
5386  type.push(token);
5387  if (token->previous()->str() == "template")
5388  templateTokens.push(token);
5389  } else if (token->str() == ">" || token->str() == ">>") {
5390  if (type.empty() || type.top()->str() != "<") // < and > don't match.
5391  continue;
5392  Token * const top1 = type.top();
5393  type.pop();
5394  Token * const top2 = type.empty() ? nullptr : type.top();
5395  type.push(top1);
5396  if (!top2 || top2->str() != "<") {
5397  if (token->str() == ">>")
5398  continue;
5399  if (!Token::Match(token->next(), "%name%|%cop%|%assign%|::|,|(|)|{|}|;|[|]|:|.|=|?|...") &&
5400  !Token::Match(token->next(), "&& %name% ="))
5401  continue;
5402  }
5403 
5404  if (token->str() == ">>" && top1 && top2) {
5405  type.pop();
5406  type.pop();
5407  // Split the angle brackets
5408  token->str(">");
5409  Token::createMutualLinks(top1, token->insertTokenBefore(">"));
5410  Token::createMutualLinks(top2, token);
5411  if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
5412  templateTokens.pop();
5413  templateTokens.pop();
5414  }
5415  } else {
5416  type.pop();
5417  if (Token::Match(token, "> %name%") && !token->next()->isKeyword() &&
5418  Token::Match(top1->tokAt(-2), "%op% %name% <") && top1->strAt(-2) != "<" &&
5419  (templateTokens.empty() || top1 != templateTokens.top()))
5420  continue;
5421  Token::createMutualLinks(top1, token);
5422  if (!templateTokens.empty() && top1 == templateTokens.top())
5423  templateTokens.pop();
5424  }
5425  }
5426  }
5427 }
5428 
5430 {
5431  if (isC())
5432  return;
5433  for (Token* tok = list.front(); tok; tok = tok->next()) {
5434  if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast")) {
5435  if (!Token::simpleMatch(tok->next(), "<") || !Token::simpleMatch(tok->linkAt(1), "> ("))
5436  syntaxError(tok);
5437  tok = tok->linkAt(1)->next();
5438  tok->isCast(true);
5439  }
5440  }
5441 
5442 }
5443 
5445 {
5446  for (Token *tok = list.front(); tok; tok = tok->next()) {
5447  if (!Token::Match(tok, "sizeof !!("))
5448  continue;
5449  if (tok->next()->isLiteral() || Token::Match(tok->next(), "%name%|*|~|!|&")) {
5450  Token *endToken = tok->next();
5451  while (Token::simpleMatch(endToken, "* *"))
5452  endToken = endToken->next();
5453  while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
5454  if (Token::Match(endToken->next(), "(|["))
5455  endToken = endToken->linkAt(1);
5456  else
5457  endToken = endToken->next();
5458  }
5459 
5460  // Add ( after sizeof and ) behind endToken
5461  tok->insertToken("(");
5462  endToken->insertToken(")");
5463  Token::createMutualLinks(tok->next(), endToken->next());
5464  }
5465  }
5466 }
5467 
5468 bool Tokenizer::simplifyTokenList1(const char FileName[])
5469 {
5470  if (Settings::terminated())
5471  return false;
5472 
5473  // if MACRO
5474  for (Token *tok = list.front(); tok; tok = tok->next()) {
5475  if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
5476  if (Token::simpleMatch(tok, "for each")) {
5477  // 'for each ( )' -> 'asm ( )'
5478  tok->str("asm");
5479  tok->deleteNext();
5480  } else if (tok->strAt(1) == "constexpr") {
5481  tok->deleteNext();
5482  tok->isConstexpr(true);
5483  } else {
5484  syntaxError(tok);
5485  }
5486  }
5487  }
5488 
5489  // Is there C++ code in C file?
5490  validateC();
5491 
5492  // Combine strings and character literals, e.g. L"string", L'c', "string1" "string2"
5494 
5495  // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
5496  simplifySQL();
5497 
5498  createLinks();
5499 
5500  // Simplify debug intrinsics
5501  simplifyDebug();
5502 
5503  removePragma();
5504 
5505  // Simplify the C alternative tokens (and, or, etc.)
5507 
5509 
5511 
5512  // Remove __asm..
5513  simplifyAsm();
5514 
5515  // foo < bar < >> => foo < bar < > >
5516  if (isCPP() || mSettings.daca)
5518 
5519  // Remove extra "template" tokens that are not used by cppcheck
5521 
5523 
5524  // @..
5525  simplifyAt();
5526 
5527  // Remove __declspec()
5528  simplifyDeclspec();
5529 
5530  // Remove "inline", "register", and "restrict"
5531  simplifyKeyword();
5532 
5533  // Remove [[attribute]]
5535 
5536  // remove __attribute__((?))
5538 
5539  validate();
5540 
5541  // Bail out if code is garbage
5542  if (mTimerResults) {
5543  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mSettings.showtime, mTimerResults);
5544  findGarbageCode();
5545  } else {
5546  findGarbageCode();
5547  }
5548 
5550 
5551  // if (x) MACRO() ..
5552  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5553  if (Token::simpleMatch(tok, "if (")) {
5554  tok = tok->next()->link();
5555  if (Token::Match(tok, ") %name% (") &&
5556  tok->next()->isUpperCaseName() &&
5557  Token::Match(tok->linkAt(2), ") {|else")) {
5558  syntaxError(tok->next());
5559  }
5560  }
5561  }
5562 
5563  if (Settings::terminated())
5564  return false;
5565 
5566  // convert C++17 style nested namespaces to old style namespaces
5568 
5569  // convert c++20 coroutines
5571 
5572  // simplify namespace aliases
5574 
5575  // simplify cppcheck attributes __cppcheck_?__(?)
5577 
5578  // Combine tokens..
5579  combineOperators();
5580 
5581  // combine "- %num%"
5583 
5584  // remove extern "C" and extern "C" {}
5585  if (isCPP())
5586  simplifyExternC();
5587 
5588  // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
5590 
5591  // check for simple syntax errors..
5592  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5593  if (Token::simpleMatch(tok, "> struct {") &&
5594  Token::simpleMatch(tok->linkAt(2), "} ;")) {
5595  syntaxError(tok);
5596  }
5597  }
5598 
5599  if (!simplifyAddBraces())
5600  return false;
5601 
5603 
5604  // Simplify: 0[foo] -> *(foo)
5605  for (Token* tok = list.front(); tok; tok = tok->next()) {
5606  if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
5607  tok->str("*");
5608  tok->next()->str("(");
5609  tok->linkAt(1)->str(")");
5610  }
5611  }
5612 
5613  if (Settings::terminated())
5614  return false;
5615 
5616  validate();
5617 
5618  // simplify simple calculations inside <..>
5619  if (isCPP()) {
5620  Token *lt = nullptr;
5621  for (Token *tok = list.front(); tok; tok = tok->next()) {
5622  if (Token::Match(tok, "[;{}]"))
5623  lt = nullptr;
5624  else if (Token::Match(tok, "%type% <"))
5625  lt = tok->next();
5626  else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
5627  const Token * const end = tok;
5628  for (tok = lt; tok != end; tok = tok->next()) {
5629  if (tok->isNumber())
5631  }
5632  lt = tok->next();
5633  }
5634  }
5635  }
5636 
5637  // Convert K&R function declarations to modern C
5638  simplifyVarDecl(true);
5640 
5641  // simplify case ranges (gcc extension)
5643 
5644  // simplify labels and 'case|default'-like syntaxes
5646 
5647  if (!isC() && !mSettings.library.markupFile(FileName)) {
5649  }
5650 
5651  if (Settings::terminated())
5652  return false;
5653 
5654  // remove calling conventions __cdecl, __stdcall..
5656 
5658 
5659  // remove some unhandled macros in global scope
5661 
5662  // remove undefined macro in class definition:
5663  // class DLLEXPORT Fred { };
5664  // class Fred FINAL : Base { };
5666 
5667  // That call here fixes #7190
5668  validate();
5669 
5670  // remove unnecessary member qualification..
5672 
5673  // convert Microsoft memory functions
5675 
5676  // convert Microsoft string functions
5678 
5679  if (Settings::terminated())
5680  return false;
5681 
5682  // remove Borland stuff..
5683  simplifyBorland();
5684 
5685  // syntax error: enum with typedef in it
5687 
5688  // Add parentheses to ternary operator where necessary
5690 
5691  // Change initialisation of variable to assignment
5692  simplifyInitVar();
5693 
5694  // Split up variable declarations.
5695  simplifyVarDecl(false);
5696 
5698 
5700 
5701  // typedef..
5702  if (mTimerResults) {
5703  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mSettings.showtime, mTimerResults);
5704  simplifyTypedef();
5705  } else {
5706  simplifyTypedef();
5707  }
5708 
5709  // using A = B;
5710  while (simplifyUsing())
5711  ;
5712 
5713  // Add parentheses to ternary operator where necessary
5714  // TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
5715  // If typedef handling is refactored and moved to symboldatabase someday we can remove this
5717 
5718  // class x y {
5720  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5721  if (Token::Match(tok, "class %type% %type% [:{]")) {
5723  }
5724  }
5725  }
5726 
5727  // catch bad typedef canonicalization
5728  //
5729  // to reproduce bad typedef, download upx-ucl from:
5730  // http://packages.debian.org/sid/upx-ucl
5731  // analyse the file src/stub/src/i386-linux.elf.interp-main.c
5732  validate();
5733 
5734  // The simplify enum have inner loops
5735  if (Settings::terminated())
5736  return false;
5737 
5738  // Put ^{} statements in asm()
5739  simplifyAsm2();
5740 
5741  // When the assembly code has been cleaned up, no @ is allowed
5742  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5743  if (tok->str() == "(") {
5744  const Token *tok1 = tok;
5745  tok = tok->link();
5746  if (!tok)
5747  syntaxError(tok1);
5748  } else if (tok->str() == "@") {
5749  syntaxError(tok);
5750  }
5751  }
5752 
5753  // Order keywords "static" and "const"
5755 
5756  // convert platform dependent types to standard types
5757  // 32 bits: size_t -> unsigned long
5758  // 64 bits: size_t -> unsigned long long
5760 
5761  // collapse compound standard types into a single token
5762  // unsigned long long int => long (with _isUnsigned=true,_isLong=true)
5764 
5765  if (Settings::terminated())
5766  return false;
5767 
5768  // simplify bit fields..
5770 
5771  if (Settings::terminated())
5772  return false;
5773 
5774  // struct simplification "struct S {} s; => struct S { } ; S s ;
5776 
5777  if (Settings::terminated())
5778  return false;
5779 
5780  // x = ({ 123; }); => { x = 123; }
5782 
5783  if (Settings::terminated())
5784  return false;
5785 
5787 
5788  // Collapse operator name tokens into single token
5789  // operator = => operator=
5791 
5792  // Remove redundant parentheses
5794 
5795  if (isCPP()) {
5797 
5798  // Handle templates..
5799  if (mTimerResults) {
5800  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mSettings.showtime, mTimerResults);
5802  } else {
5804  }
5805 
5806  // The simplifyTemplates have inner loops
5807  if (Settings::terminated())
5808  return false;
5809 
5810  validate(); // #6847 - invalid code
5811  }
5812 
5813  // Simplify pointer to standard types (C only)
5815 
5816  // simplify function pointers
5818 
5819  // Change initialisation of variable to assignment
5820  simplifyInitVar();
5821 
5822  // Split up variable declarations.
5823  simplifyVarDecl(false);
5824 
5825  elseif();
5826 
5827  validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
5828 
5829  if (mTimerResults) {
5830  Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mSettings.showtime, mTimerResults);
5831  setVarId();
5832  } else {
5833  setVarId();
5834  }
5835 
5836  // Link < with >
5837  createLinks2();
5838 
5839  // Mark C++ casts
5840  markCppCasts();
5841 
5842  // specify array size
5843  arraySize();
5844 
5845  // The simplify enum might have inner loops
5846  if (Settings::terminated())
5847  return false;
5848 
5849  // Add std:: in front of std classes, when using namespace std; was given
5851 
5852  // Change initialisation of variable to assignment
5853  simplifyInitVar();
5854 
5856 
5858 
5860 
5862 
5864 
5866 
5868 
5870 
5872 
5873  validate();
5874 
5875  list.front()->assignIndexes();
5876 
5877  return true;
5878 }
5879 //---------------------------------------------------------------------------
5880 
5881 void Tokenizer::printDebugOutput(int simplification) const
5882 {
5883  const bool debug = (simplification != 1U && mSettings.debugSimplified) ||
5884  (simplification != 2U && mSettings.debugnormal);
5885 
5886  if (debug && list.front()) {
5887  list.front()->printOut(nullptr, list.getFiles());
5888 
5889  if (mSettings.xml)
5890  std::cout << "<debug>" << std::endl;
5891 
5892  if (mSymbolDatabase) {
5893  if (mSettings.xml)
5894  mSymbolDatabase->printXml(std::cout);
5895  else if (mSettings.verbose) {
5896  mSymbolDatabase->printOut("Symbol database");
5897  }
5898  }
5899 
5900  if (mSettings.verbose)
5902 
5903  list.front()->printValueFlow(mSettings.xml, std::cout);
5904 
5905  if (mSettings.xml)
5906  std::cout << "</debug>" << std::endl;
5907  }
5908 
5909  if (mSymbolDatabase && simplification == 2U && mSettings.debugwarnings) {
5911 
5912  // the typeStartToken() should come before typeEndToken()
5913  for (const Variable *var : mSymbolDatabase->variableList()) {
5914  if (!var)
5915  continue;
5916 
5917  const Token * typetok = var->typeStartToken();
5918  while (typetok && typetok != var->typeEndToken())
5919  typetok = typetok->next();
5920 
5921  if (typetok != var->typeEndToken()) {
5922  reportError(var->typeStartToken(),
5924  "debug",
5925  "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()));
5926  }
5927  }
5928  }
5929 }
5930 
5931 void Tokenizer::dump(std::ostream &out) const
5932 {
5933  // Create a xml data dump.
5934  // The idea is not that this will be readable for humans. It's a
5935  // data dump that 3rd party tools could load and get useful info from.
5936 
5937  std::string outs;
5938 
5939  std::set<const Library::Container*> containers;
5940 
5941  outs += " <directivelist>";
5942  outs += '\n';
5943  for (const Directive &dir : mDirectives) {
5944  outs += " <directive ";
5945  outs += "file=\"";
5947  outs += "\" ";
5948  outs += "linenr=\"";
5949  outs += std::to_string(dir.linenr);
5950  outs += "\" ";
5951  // str might contain characters such as '"', '<' or '>' which
5952  // could result in invalid XML, so run it through toxml().
5953  outs += "str=\"";
5954  outs += ErrorLogger::toxml(dir.str);
5955  outs +="\"/>";
5956  outs += '\n';
5957  }
5958  outs += " </directivelist>";
5959  outs += '\n';
5960 
5961  // tokens..
5962  outs += " <tokenlist>";
5963  outs += '\n';
5964  for (const Token *tok = list.front(); tok; tok = tok->next()) {
5965  outs += " <token id=\"";
5966  outs += id_string(tok);
5967  outs += "\" file=\"";
5968  outs += ErrorLogger::toxml(list.file(tok));
5969  outs += "\" linenr=\"";
5970  outs += std::to_string(tok->linenr());
5971  outs += "\" column=\"";
5972  outs += std::to_string(tok->column());
5973  outs += "\"";
5974 
5975  outs += " str=\"";
5976  outs += ErrorLogger::toxml(tok->str());
5977  outs += '\"';
5978 
5979  outs += " scope=\"";
5980  outs += id_string(tok->scope());
5981  outs += '\"';
5982  if (tok->isName()) {
5983  outs += " type=\"name\"";
5984  if (tok->isUnsigned())
5985  outs += " isUnsigned=\"true\"";
5986  else if (tok->isSigned())
5987  outs += " isSigned=\"true\"";
5988  } else if (tok->isNumber()) {
5989  outs += " type=\"number\"";
5990  if (MathLib::isInt(tok->str()))
5991  outs += " isInt=\"true\"";
5992  if (MathLib::isFloat(tok->str()))
5993  outs += " isFloat=\"true\"";
5994  } else if (tok->tokType() == Token::eString) {
5995  outs += " type=\"string\" strlen=\"";
5996  outs += std::to_string(Token::getStrLength(tok));
5997  outs += '\"';
5998  }
5999  else if (tok->tokType() == Token::eChar)
6000  outs += " type=\"char\"";
6001  else if (tok->isBoolean())
6002  outs += " type=\"boolean\"";
6003  else if (tok->isOp()) {
6004  outs += " type=\"op\"";
6005  if (tok->isArithmeticalOp())
6006  outs += " isArithmeticalOp=\"true\"";
6007  else if (tok->isAssignmentOp())
6008  outs += " isAssignmentOp=\"true\"";
6009  else if (tok->isComparisonOp())
6010  outs += " isComparisonOp=\"true\"";
6011  else if (tok->tokType() == Token::eLogicalOp)
6012  outs += " isLogicalOp=\"true\"";
6013  }
6014  if (tok->isCast())
6015  outs += " isCast=\"true\"";
6016  if (tok->isExternC())
6017  outs += " externLang=\"C\"";
6018  if (tok->isExpandedMacro())
6019  outs += " macroName=\"" + tok->getMacroName() + "\"";
6020  if (tok->isTemplateArg())
6021  outs += " isTemplateArg=\"true\"";
6022  if (tok->isRemovedVoidParameter())
6023  outs += " isRemovedVoidParameter=\"true\"";
6024  if (tok->isSplittedVarDeclComma())
6025  outs += " isSplittedVarDeclComma=\"true\"";
6026  if (tok->isSplittedVarDeclEq())
6027  outs += " isSplittedVarDeclEq=\"true\"";
6028  if (tok->isImplicitInt())
6029  outs += " isImplicitInt=\"true\"";
6030  if (tok->isComplex())
6031  outs += " isComplex=\"true\"";
6032  if (tok->isRestrict())
6033  outs += " isRestrict=\"true\"";
6034  if (tok->isAtomic())
6035  outs += " isAtomic=\"true\"";
6036  if (tok->isAttributeExport())
6037  outs += " isAttributeExport=\"true\"";
6038  if (tok->isAttributeMaybeUnused())
6039  outs += " isAttributeMaybeUnused=\"true\"";
6040  if (tok->isAttributeUnused())
6041  outs += " isAttributeUnused=\"true\"";
6042  if (tok->link()) {
6043  outs += " link=\"";
6044  outs += id_string(tok->link());
6045  outs += '\"';
6046  }
6047  if (tok->varId() > 0) {
6048  outs += " varId=\"";
6049  outs += std::to_string(tok->varId());
6050  outs += '\"';
6051  }
6052  if (tok->exprId() > 0) {
6053  outs += " exprId=\"";
6054  outs += std::to_string(tok->exprId());
6055  outs += '\"';
6056  }
6057  if (tok->variable()) {
6058  outs += " variable=\"";
6059  outs += id_string(tok->variable());
6060  outs += '\"';
6061  }
6062  if (tok->function()) {
6063  outs += " function=\"";
6064  outs += id_string(tok->function());
6065  outs += '\"';
6066  }
6067  if (!tok->values().empty()) {
6068  outs += " values=\"";
6069  outs += id_string(&tok->values());
6070  outs += '\"';
6071  }
6072  if (tok->type()) {
6073  outs += " type-scope=\"";
6074  outs += id_string(tok->type()->classScope);
6075  outs += '\"';
6076  }
6077  if (tok->astParent()) {
6078  outs += " astParent=\"";
6079  outs += id_string(tok->astParent());
6080  outs += '\"';
6081  }
6082  if (tok->astOperand1()) {
6083  outs += " astOperand1=\"";
6084  outs += id_string(tok->astOperand1());
6085  outs += '\"';
6086  }
6087  if (tok->astOperand2()) {
6088  outs += " astOperand2=\"";
6089  outs += id_string(tok->astOperand2());
6090  outs += '\"';
6091  }
6092  if (!tok->originalName().empty()) {
6093  outs += " originalName=\"";
6094  outs += tok->originalName();
6095  outs += '\"';
6096  }
6097  if (tok->valueType()) {
6098  const std::string vt = tok->valueType()->dump();
6099  if (!vt.empty()) {
6100  outs += ' ';
6101  outs += vt;
6102  }
6103  containers.insert(tok->valueType()->container);
6104  }
6105  if (!tok->varId() && tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) {
6106  if (mSettings.library.isnoreturn(tok))
6107  outs += " noreturn=\"true\"";
6108  }
6109 
6110  outs += "/>";
6111  outs += '\n';
6112  }
6113  outs += " </tokenlist>";
6114  outs += '\n';
6115 
6116  out << outs;
6117  outs.clear();
6118 
6119  if (mSymbolDatabase)
6120  mSymbolDatabase->printXml(out);
6121 
6122  containers.erase(nullptr);
6123  if (!containers.empty()) {
6124  outs += " <containers>";
6125  outs += '\n';
6126  for (const Library::Container* c: containers) {
6127  outs += " <container id=\"";
6128  outs += id_string(c);
6129  outs += "\" array-like-index-op=\"";
6130  outs += bool_to_string(c->arrayLike_indexOp);
6131  outs += "\" ";
6132  outs += "std-string-like=\"";
6133  outs += bool_to_string(c->stdStringLike);
6134  outs += "\"/>";
6135  outs += '\n';
6136  }
6137  outs += " </containers>";
6138  outs += '\n';
6139  }
6140 
6141  if (list.front())
6142  list.front()->printValueFlow(true, out);
6143 
6144  if (!mTypedefInfo.empty()) {
6145  outs += " <typedef-info>";
6146  outs += '\n';
6147  for (const TypedefInfo &typedefInfo: mTypedefInfo) {
6148  outs += " <info";
6149 
6150  outs += " name=\"";
6151  outs += typedefInfo.name;
6152  outs += "\"";
6153 
6154  outs += " file=\"";
6155  outs += ErrorLogger::toxml(typedefInfo.filename);
6156  outs += "\"";
6157 
6158  outs += " line=\"";
6159  outs += std::to_string(typedefInfo.lineNumber);
6160  outs += "\"";
6161 
6162  outs += " column=\"";
6163  outs += std::to_string(typedefInfo.column);
6164  outs += "\"";
6165 
6166  outs += " used=\"";
6167  outs += std::to_string(typedefInfo.used?1:0);
6168  outs += "\"";
6169 
6170  outs += "/>";
6171  outs += '\n';
6172  }
6173  outs += " </typedef-info>";
6174  outs += '\n';
6175  }
6176  outs += mTemplateSimplifier->dump();
6177 
6178  out << outs;
6179 }
6180 
6182 {
6184  // Full analysis. All information in the headers are kept.
6185  return;
6186 
6187  const bool checkHeaders = mSettings.checkHeaders;
6188  const bool removeUnusedIncludedFunctions = !mSettings.checkHeaders;
6189  const bool removeUnusedIncludedClasses = !mSettings.checkHeaders;
6190  const bool removeUnusedIncludedTemplates = !mSettings.checkUnusedTemplates || !mSettings.checkHeaders;
6191  const bool removeUnusedTemplates = !mSettings.checkUnusedTemplates;
6192 
6193  // checkHeaders:
6194  //
6195  // If it is true then keep all code in the headers. It's possible
6196  // to remove unused types/variables if false positives / false
6197  // negatives can be avoided.
6198  //
6199  // If it is false, then we want to remove selected stuff from the
6200  // headers but not *everything*. The intention here is to not damage
6201  // the analysis of the source file. You should get all warnings in
6202  // the source file. You should not get false positives.
6203 
6204  // functions and types to keep
6205  std::set<std::string> keep;
6206  for (const Token *tok = list.front(); tok; tok = tok->next()) {
6207  if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
6208  const Token *closingBracket = tok->next()->findClosingBracket();
6209  if (Token::Match(closingBracket, "> class|struct %name% {"))
6210  tok = closingBracket->linkAt(3);
6211  }
6212 
6213  if (!tok->isName() || tok->isKeyword())
6214  continue;
6215 
6216  if (!checkHeaders && tok->fileIndex() != 0)
6217  continue;
6218 
6219  if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
6220  keep.insert(tok->str());
6221  continue;
6222  }
6223 
6224  if (Token::Match(tok, "%name% %name%|::|*|&|<")) {
6225  keep.insert(tok->str());
6226  }
6227  }
6228 
6229  const std::set<std::string> functionStart{"static", "const", "unsigned", "signed", "void", "bool", "char", "short", "int", "long", "float", "*"};
6230 
6231  for (Token *tok = list.front(); tok; tok = tok->next()) {
6232  const bool isIncluded = (tok->fileIndex() != 0);
6233 
6234  // Remove executable code
6235  if (isIncluded && !mSettings.checkHeaders && tok->str() == "{") {
6236  // TODO: We probably need to keep the executable code if this function is called from the source file.
6237  const Token *prev = tok->previous();
6238  while (prev && prev->isName())
6239  prev = prev->previous();
6240  if (Token::simpleMatch(prev, ")")) {
6241  // Replace all tokens from { to } with a ";".
6242  Token::eraseTokens(tok,tok->link()->next());
6243  tok->str(";");
6244  tok->link(nullptr);
6245  }
6246  }
6247 
6248  if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
6249  // Remove unused function declarations
6250  if (isIncluded && removeUnusedIncludedFunctions) {
6251  while (true) {
6252  Token *start = tok;
6253  while (start && functionStart.find(start->str()) != functionStart.end())
6254  start = start->next();
6255  if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
6256  Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
6257  tok->deleteThis();
6258  } else
6259  break;
6260  }
6261  }
6262 
6263  if (isIncluded && removeUnusedIncludedClasses) {
6264  if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
6265  // Remove this class/struct
6266  const Token *endToken = tok->tokAt(2);
6267  if (endToken->str() == ":") {
6268  endToken = endToken->next();
6269  while (Token::Match(endToken, "%name%|,"))
6270  endToken = endToken->next();
6271  }
6272  if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
6273  Token::eraseTokens(tok, endToken->link()->next());
6274  tok->deleteThis();
6275  }
6276  }
6277  }
6278 
6279  if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
6280  if (Token::Match(tok, "template < %name%")) {
6281  const Token *closingBracket = tok->next()->findClosingBracket();
6282  if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6283  const Token *endToken = closingBracket->tokAt(3);
6284  if (endToken->str() == ":") {
6285  endToken = endToken->next();
6286  while (Token::Match(endToken, "%name%|,"))
6287  endToken = endToken->next();
6288  }
6289  if (endToken && endToken->str() == "{")
6290  endToken = endToken->link()->next();
6291  if (endToken && endToken->str() == ";") {
6292  Token::eraseTokens(tok, endToken);
6293  tok->deleteThis();
6294  }
6295  } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6296  const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
6297  Token::eraseTokens(tok, endToken);
6298  tok->deleteThis();
6299  }
6300  }
6301  }
6302  }
6303  }
6304 }
6305 
6307 {
6308  if (isCPP()) {
6309  for (Token *tok = list.front(); tok; tok = tok->next()) {
6310  if (Token::Match(tok, "%name%|>|) .|:: template %name%")) {
6311  tok->next()->deleteNext();
6312  Token* templateName = tok->tokAt(2);
6313  while (Token::Match(templateName, "%name%|::")) {
6314  templateName->isTemplate(true);
6315  templateName = templateName->next();
6316  }
6317  if (!templateName)
6318  syntaxError(tok);
6319  if (Token::Match(templateName->previous(), "operator %op%|(")) {
6320  templateName->isTemplate(true);
6321  if (templateName->str() == "(" && templateName->link())
6322  templateName->link()->isTemplate(true);
6323  }
6324  }
6325  }
6326  }
6327 }
6328 
6329 static std::string getExpression(const Token *tok)
6330 {
6331  std::string line;
6332  for (const Token *prev = tok->previous(); prev && !Token::Match(prev, "[;{}]"); prev = prev->previous())
6333  line = prev->str() + " " + line;
6334  line += "!!!" + tok->str() + "!!!";
6335  for (const Token *next = tok->next(); next && !Token::Match(next, "[;{}]"); next = next->next())
6336  line += " " + next->str();
6337  return line;
6338 }
6339 
6341 {
6342  std::vector<std::pair<std::string, int>> vars;
6343 
6344  int scopeLevel = 0;
6345  for (Token *tok = list.front(); tok; tok = tok->next()) {
6346  if (tok->str() == "{")
6347  ++scopeLevel;
6348  else if (tok->str() == "}") {
6349  vars.erase(std::remove_if(vars.begin(), vars.end(), [scopeLevel](const std::pair<std::string, int>& v) {
6350  return v.second == scopeLevel;
6351  }), vars.end());
6352  --scopeLevel;
6353  }
6354  if (Token::Match(tok, "[;{}] %type% %type% [;,=]") && tok->next()->isStandardType())
6355  vars.emplace_back(tok->strAt(2), scopeLevel);
6356 
6357  // Ticket #6181: normalize C++11 template parameter list closing syntax
6358  if (tok->previous() && tok->str() == "<" && TemplateSimplifier::templateParameters(tok) && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6359  return v.first == tok->previous()->str();
6360  })) {
6361  Token *endTok = tok->findClosingBracket();
6362  if (check) {
6363  if (Token::Match(endTok, ">>|>>="))
6364  reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6365  continue;
6366  }
6367  if (endTok && endTok->str() == ">>") {
6368  endTok->str(">");
6369  endTok->insertToken(">");
6370  } else if (endTok && endTok->str() == ">>=") {
6371  endTok->str(">");
6372  endTok->insertToken("=");
6373  endTok->insertToken(">");
6374  }
6375  } 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) {
6376  return v.first == tok->next()->str();
6377  })) {
6378  Token *endTok = tok->tokAt(2)->findClosingBracket();
6379  if (check) {
6380  if (Token::simpleMatch(endTok, ">>"))
6381  reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6382  continue;
6383  }
6384  if (Token::Match(endTok, ">> ;|{|%type%")) {
6385  endTok->str(">");
6386  endTok->insertToken(">");
6387  }
6388  }
6389  }
6390 }
6391 
6393 {
6394  for (Token *tok = list.front(); tok; tok = tok->next()) {
6395  if (tok->str() == "(") {
6396  tok = tok->link();
6397  if (Token::Match(tok, ") %type% {") &&
6398  !tok->next()->isStandardType() &&
6399  !tok->next()->isKeyword() &&
6400  !Token::Match(tok->next(), "override|final") &&
6401  tok->next()->isUpperCaseName())
6402  tok->deleteNext();
6403  }
6404 
6405  if (Token::Match(tok, "%type%") && tok->isUpperCaseName() &&
6406  (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) {
6407  const Token *tok2 = tok->next();
6408  if (tok2 && tok2->str() == "(")
6409  tok2 = tok2->link()->next();
6410 
6411  // Several unknown macros...
6412  while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName())
6413  tok2 = tok2->linkAt(1)->next();
6414 
6415  if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") &&
6416  !Token::Match(tok2, "requires|namespace|class|struct|union|private:|protected:|public:"))
6417  unknownMacroError(tok);
6418 
6419  if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{"))
6420  unknownMacroError(tok);
6421 
6422  // remove unknown macros before namespace|class|struct|union
6423  if (Token::Match(tok2, "namespace|class|struct|union")) {
6424  // is there a "{" for?
6425  const Token *tok3 = tok2;
6426  while (tok3 && !Token::Match(tok3,"[;{}()]"))
6427  tok3 = tok3->next();
6428  if (tok3 && tok3->str() == "{") {
6429  Token::eraseTokens(tok, tok2);
6430  tok->deleteThis();
6431  }
6432  continue;
6433  }
6434 
6435  // replace unknown macros before foo(
6436  /*
6437  if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) {
6438  std::string typeName;
6439  for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next())
6440  typeName += tok3->str();
6441  Token::eraseTokens(tok, tok2);
6442  tok->str(typeName);
6443  }
6444  */
6445  // remove unknown macros before foo::foo(
6446  if (Token::Match(tok2, "%type% :: %type%")) {
6447  const Token *tok3 = tok2;
6448  while (Token::Match(tok3, "%type% :: %type% ::"))
6449  tok3 = tok3->tokAt(2);
6450  if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) {
6451  Token::eraseTokens(tok, tok2);
6452  tok->deleteThis();
6453  }
6454  continue;
6455  }
6456  }
6457 
6458  // Skip executable scopes
6459  if (tok->str() == "{") {
6460  const Token *prev = tok->previous();
6461  while (prev && prev->isName())
6462  prev = prev->previous();
6463  if (prev && prev->str() == ")")
6464  tok = tok->link();
6465  }
6466  }
6467 }
6468 
6469 //---------------------------------------------------------------------------
6470 
6472 {
6473  if (isC() && mSettings.standards.c == Standards::C89)
6474  return;
6476  return;
6477  for (Token *tok = list.front(); tok; tok = tok->next()) {
6478  while (Token::simpleMatch(tok, "_Pragma (")) {
6479  Token::eraseTokens(tok, tok->linkAt(1)->next());
6480  tok->deleteThis();
6481  }
6482  }
6483 }
6484 
6485 //---------------------------------------------------------------------------
6486 
6488 {
6489  for (Token *tok = list.front(); tok; tok = tok->next()) {
6490  if (!Token::Match(tok, "class|struct %name% %name% final| {|:"))
6491  continue;
6492 
6493  const bool nextIsUppercase = tok->next()->isUpperCaseName();
6494  const bool afterNextIsUppercase = tok->tokAt(2)->isUpperCaseName();
6495  if (nextIsUppercase && !afterNextIsUppercase)
6496  tok->deleteNext();
6497  else if (!nextIsUppercase && afterNextIsUppercase)
6498  tok->next()->deleteNext();
6499  }
6500 }
6501 
6502 //---------------------------------------------------------------------------
6503 
6505 {
6506  if (!isCPP())
6507  return;
6508  for (Token *tok = list.front(); tok; tok = tok->next()) {
6509  if (tok->str() != ")")
6510  continue;
6511  const Token *macro = tok->link() ? tok->link()->previous() : nullptr;
6512  if (!macro || !macro->isName())
6513  continue;
6514  if (Token::simpleMatch(tok, ") try") && !Token::Match(macro, "if|for|while"))
6515  tok->insertToken(";");
6516  else if (Token::simpleMatch(tok, ") using"))
6517  tok->insertToken(";");
6518  }
6519 }
6520 //---------------------------------------------------------------------------
6521 
6523 {
6524  if (isC())
6525  return;
6526 
6527  bool goback = false;
6528  for (Token *tok = list.front(); tok; tok = tok ? tok->next() : nullptr) {
6529  if (goback) {
6530  tok = tok->previous();
6531  goback = false;
6532  }
6533  if (Token::Match(tok, "(|[|{")) {
6534  tok = tok->link();
6535  continue;
6536  }
6537  if (!Token::Match(tok, "namespace %name%| {"))
6538  continue;
6539  const bool isAnonymousNS = tok->strAt(1) == "{";
6540  if (tok->strAt(3 - isAnonymousNS) == "}") {
6541  tok->deleteNext(3 - isAnonymousNS); // remove '%name%| { }'
6542  if (!tok->previous()) {
6543  // remove 'namespace' or replace it with ';' if isolated
6544  tok->deleteThis();
6545  goback = true;
6546  } else { // '%any% namespace %any%'
6547  tok = tok->previous(); // goto previous token
6548  tok->deleteNext(); // remove next token: 'namespace'
6549  if (tok->str() == "{") {
6550  // Go back in case we were within a namespace that's empty now
6551  tok = tok->tokAt(-2) ? tok->tokAt(-2) : tok->previous();
6552  goback = true;
6553  }
6554  }
6555  } else {
6556  tok = tok->tokAt(2 - isAnonymousNS);
6557  }
6558  }
6559 }
6560 
6562 {
6563  for (Token *tok = list.front(); tok; tok = tok->next()) {
6564  if (tok->link() && tok->str() == "(") {
6565  tok = tok->link();
6566  continue;
6567  }
6568  for (;;) {
6569  if (Token::simpleMatch(tok, "; ;")) {
6570  tok->deleteNext();
6571  } else if (Token::simpleMatch(tok, "; { ; }")) {
6572  tok->deleteNext(3);
6573  } else {
6574  break;
6575  }
6576  }
6577  }
6578 }
6579 
6580 
6582 {
6583  for (Token *tok = list.front(); tok; tok = tok->next()) {
6584  Token const * tokRet=simplifyAddBracesToCommand(tok);
6585  if (!tokRet)
6586  return false;
6587  }
6588  return true;
6589 }
6590 
6592 {
6593  Token * tokEnd=tok;
6594  if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6595  tokEnd=simplifyAddBracesPair(tok,true);
6596  } else if (tok->str()=="while") {
6597  Token *tokPossibleDo=tok->previous();
6598  if (Token::simpleMatch(tok->previous(), "{"))
6599  tokPossibleDo = nullptr;
6600  else if (Token::simpleMatch(tokPossibleDo,"}"))
6601  tokPossibleDo = tokPossibleDo->link();
6602  if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6603  tokEnd=simplifyAddBracesPair(tok,true);
6604  } else if (tok->str()=="do") {
6605  tokEnd=simplifyAddBracesPair(tok,false);
6606  if (tokEnd!=tok) {
6607  // walk on to next token, i.e. "while"
6608  // such that simplifyAddBracesPair does not close other braces
6609  // before the "while"
6610  if (tokEnd) {
6611  tokEnd=tokEnd->next();
6612  if (!tokEnd || tokEnd->str()!="while") // no while
6613  syntaxError(tok);
6614  }
6615  }
6616  } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6617  tokEnd=simplifyAddBracesPair(tok,true);
6618  if (!tokEnd)
6619  return nullptr;
6620  if (tokEnd->strAt(1) == "else") {
6621  Token * tokEndNextNext= tokEnd->tokAt(2);
6622  if (!tokEndNextNext || tokEndNextNext->str() == "}")
6623  syntaxError(tokEndNextNext);
6624  if (tokEndNextNext->str() == "if")
6625  // do not change "else if ..." to "else { if ... }"
6626  tokEnd=simplifyAddBracesToCommand(tokEndNextNext);
6627  else
6628  tokEnd=simplifyAddBracesPair(tokEnd->next(),false);
6629  }
6630  }
6631 
6632  return tokEnd;
6633 }
6634 
6635 Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition)
6636 {
6637  Token * tokCondition=tok->next();
6638  if (!tokCondition) // Missing condition
6639  return tok;
6640 
6641  Token *tokAfterCondition=tokCondition;
6642  if (commandWithCondition) {
6643  if (tokCondition->str()=="(")
6644  tokAfterCondition=tokCondition->link();
6645  else
6646  syntaxError(tok); // Bad condition
6647 
6648  if (!tokAfterCondition || tokAfterCondition->strAt(1) == "]")
6649  syntaxError(tok); // Bad condition
6650 
6651  tokAfterCondition=tokAfterCondition->next();
6652  if (!tokAfterCondition || Token::Match(tokAfterCondition, ")|}|,")) {
6653  // No tokens left where to add braces around
6654  return tok;
6655  }
6656  }
6657  // Skip labels
6658  Token * tokStatement = tokAfterCondition;
6659  while (true) {
6660  if (Token::Match(tokStatement, "%name% :"))
6661  tokStatement = tokStatement->tokAt(2);
6662  else if (tokStatement->str() == "case") {
6663  tokStatement = skipCaseLabel(tokStatement);
6664  if (!tokStatement)
6665  return tok;
6666  if (tokStatement->str() != ":")
6667  syntaxError(tokStatement);
6668  tokStatement = tokStatement->next();
6669  } else
6670  break;
6671  if (!tokStatement)
6672  return tok;
6673  }
6674  Token * tokBracesEnd=nullptr;
6675  if (tokStatement->str() == "{") {
6676  // already surrounded by braces
6677  if (tokStatement != tokAfterCondition) {
6678  // Move the opening brace before labels
6679  Token::move(tokStatement, tokStatement, tokAfterCondition->previous());
6680  }
6681  tokBracesEnd = tokStatement->link();
6682  } else if (Token::simpleMatch(tokStatement, "try {") &&
6683  Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) {
6684  tokAfterCondition->previous()->insertToken("{");
6685  Token * tokOpenBrace = tokAfterCondition->previous();
6686  Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1);
6687  if (!tokEnd) {
6688  syntaxError(tokStatement);
6689  }
6690  tokEnd->insertToken("}");
6691  Token * tokCloseBrace = tokEnd->next();
6692 
6693  Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
6694  tokBracesEnd = tokCloseBrace;
6695  } else {
6696  Token * tokEnd = simplifyAddBracesToCommand(tokStatement);
6697  if (!tokEnd) // Ticket #4887
6698  return tok;
6699  if (tokEnd->str()!="}") {
6700  // Token does not end with brace
6701  // Look for ; to add own closing brace after it
6702  while (tokEnd && !Token::Match(tokEnd, ";|)|}")) {
6703  if (tokEnd->tokType()==Token::eBracket || tokEnd->str() == "(") {
6704  tokEnd = tokEnd->link();
6705  if (!tokEnd) {
6706  // Inner bracket does not close
6707  return tok;
6708  }
6709  }
6710  tokEnd=tokEnd->next();
6711  }
6712  if (!tokEnd || tokEnd->str() != ";") {
6713  // No trailing ;
6714  if (tokStatement->isUpperCaseName())
6715  unknownMacroError(tokStatement);
6716  else
6717  syntaxError(tokStatement);
6718  }
6719  }
6720 
6721  tokAfterCondition->previous()->insertToken("{");
6722  Token * tokOpenBrace=tokAfterCondition->previous();
6723 
6724  tokEnd->insertToken("}");
6725  Token * tokCloseBrace=tokEnd->next();
6726 
6727  Token::createMutualLinks(tokOpenBrace,tokCloseBrace);
6728  tokBracesEnd=tokCloseBrace;
6729  }
6730 
6731  return tokBracesEnd;
6732 }
6733 
6735 {
6736  for (Token *tok = list.front(); tok; tok = tok->next()) {
6737  if (tok->link() && Token::Match(tok, "{|[|(")) {
6738  tok = tok->link();
6739  }
6740 
6741  // Find the function e.g. foo( x ) or foo( x, y )
6742  else if (Token::Match(tok, "%name% ( %name% [,)]") &&
6743  !(tok->strAt(-1) == ":" || tok->strAt(-1) == "," || tok->strAt(-1) == "::")) {
6744  // We have found old style function, now we need to change it
6745 
6746  // First step: Get list of argument names in parentheses
6747  std::map<std::string, Token *> argumentNames;
6748  bool bailOut = false;
6749  Token * tokparam = nullptr;
6750 
6751  //take count of the function name..
6752  const std::string& funcName(tok->str());
6753 
6754  //floating token used to check for parameters
6755  Token *tok1 = tok;
6756 
6757  while (nullptr != (tok1 = tok1->tokAt(2))) {
6758  if (!Token::Match(tok1, "%name% [,)]")) {
6759  bailOut = true;
6760  break;
6761  }
6762 
6763  //same parameters: take note of the parameter
6764  if (argumentNames.find(tok1->str()) != argumentNames.end())
6765  tokparam = tok1;
6766  else if (tok1->str() != funcName)
6767  argumentNames[tok1->str()] = tok1;
6768  else {
6769  if (tok1->next()->str() == ")") {
6770  if (tok1->previous()->str() == ",") {
6771  tok1 = tok1->tokAt(-2);
6772  tok1->deleteNext(2);
6773  } else {
6774  tok1 = tok1->previous();
6775  tok1->deleteNext();
6776  bailOut = true;
6777  break;
6778  }
6779  } else {
6780  tok1 = tok1->tokAt(-2);
6781  tok1->next()->deleteNext(2);
6782  }
6783  }
6784 
6785  if (tok1->next()->str() == ")") {
6786  tok1 = tok1->tokAt(2);
6787  //expect at least a type name after round brace..
6788  if (!tok1 || !tok1->isName())
6789  bailOut = true;
6790  break;
6791  }
6792  }
6793 
6794  //goto '('
6795  tok = tok->next();
6796 
6797  if (bailOut) {
6798  tok = tok->link();
6799  continue;
6800  }
6801 
6802  tok1 = tok->link()->next();
6803 
6804  // there should be the sequence '; {' after the round parentheses
6805  for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) {
6806  if (Token::simpleMatch(tok2, "; {"))
6807  break;
6808  if (tok2->str() == "{") {
6809  bailOut = true;
6810  break;
6811  }
6812  }
6813 
6814  if (bailOut) {
6815  tok = tok->link();
6816  continue;
6817  }
6818 
6819  // Last step: check out if the declarations between ')' and '{' match the parameters list
6820  std::map<std::string, Token *> argumentNames2;
6821 
6822  while (tok1 && tok1->str() != "{") {
6823  if (Token::Match(tok1, "(|)")) {
6824  bailOut = true;
6825  break;
6826  }
6827  if (tok1->str() == ";") {
6828  if (tokparam) {
6829  syntaxError(tokparam);
6830  }
6831  Token *tok2 = tok1->previous();
6832  while (tok2->str() == "]")
6833  tok2 = tok2->link()->previous();
6834 
6835  //it should be a name..
6836  if (!tok2->isName()) {
6837  bailOut = true;
6838  break;
6839  }
6840 
6841  if (argumentNames2.find(tok2->str()) != argumentNames2.end()) {
6842  //same parameter names...
6843  syntaxError(tok1);
6844  } else
6845  argumentNames2[tok2->str()] = tok2;
6846 
6847  if (argumentNames.find(tok2->str()) == argumentNames.end()) {
6848  //non-matching parameter... bailout
6849  bailOut = true;
6850  break;
6851  }
6852  }
6853  tok1 = tok1->next();
6854  }
6855 
6856  if (bailOut || !tok1) {
6857  tok = tok->link();
6858  continue;
6859  }
6860 
6861  //the two containers may not hold the same size...
6862  //in that case, the missing parameters are defined as 'int'
6863  if (argumentNames.size() != argumentNames2.size()) {
6864  //move back 'tok1' to the last ';'
6865  tok1 = tok1->previous();
6866  for (const std::pair<const std::string, Token *>& argumentName : argumentNames) {
6867  if (argumentNames2.find(argumentName.first) == argumentNames2.end()) {
6868  //add the missing parameter argument declaration
6869  tok1->insertToken(";");
6870  tok1->insertToken(argumentName.first);
6871  //register the change inside argumentNames2
6872  argumentNames2[argumentName.first] = tok1->next();
6873  tok1->insertToken("int");
6874  }
6875  }
6876  }
6877 
6878  while (tok->str() != ")") {
6879  //initialize start and end tokens to be moved
6880  Token *declStart = argumentNames2[tok->next()->str()];
6881  Token *declEnd = declStart;
6882  while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")")
6883  declStart = declStart->previous();
6884  while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{")
6885  declEnd = declEnd->next();
6886 
6887  //remove ';' after declaration
6888  declEnd->deleteNext();
6889 
6890  //replace the parameter name in the parentheses with all the declaration
6891  Token::replace(tok->next(), declStart, declEnd);
6892 
6893  //since there are changes to tokens, put tok where tok1 is
6894  tok = declEnd->next();
6895 
6896  //fix up line number
6897  if (tok->str() == ",")
6898  tok->linenr(tok->previous()->linenr());
6899  }
6900  //goto forward and continue
6901  tok = tok->next()->link();
6902  }
6903  }
6904 }
6905 
6907 {
6908  if (!isC())
6909  return;
6910 
6911  for (Token *tok = list.front(); tok; tok = tok->next()) {
6912  if (!Token::Match(tok, "& %name% [ 0 ] !!["))
6913  continue;
6914 
6915  if (!Token::Match(tok->previous(), "[,(=]"))
6916  continue;
6917 
6918  // Remove '[ 0 ]' suffix
6919  Token::eraseTokens(tok->next(), tok->tokAt(5));
6920  // Remove '&' prefix
6921  tok = tok->previous();
6922  if (!tok)
6923  break;
6924  tok->deleteNext();
6925  }
6926 }
6927 
6929 {
6930  for (Token *tok = list.front(); tok; tok = tok->next()) {
6931  // #2873 - do not simplify function pointer usage here:
6932  // (void)(xy(*p)(0));
6933  if (Token::simpleMatch(tok, ") (")) {
6934  tok = tok->next()->link();
6935  continue;
6936  }
6937 
6938  // check for function pointer cast
6939  if (Token::Match(tok, "( %type% %type%| *| *| ( * ) (") ||
6940  Token::Match(tok, "static_cast < %type% %type%| *| *| ( * ) (")) {
6941  Token *tok1 = tok;
6942 
6943  if (tok1->isCpp() && tok1->str() == "static_cast")
6944  tok1 = tok1->next();
6945 
6946  tok1 = tok1->next();
6947 
6948  if (Token::Match(tok1->next(), "%type%"))
6949  tok1 = tok1->next();
6950 
6951  while (tok1->next()->str() == "*")
6952  tok1 = tok1->next();
6953 
6954  // check that the cast ends
6955  if (!Token::Match(tok1->linkAt(4), ") )|>"))
6956  continue;
6957 
6958  // ok simplify this function pointer cast to an ordinary pointer cast
6959  tok1->deleteNext();
6960  tok1->next()->deleteNext();
6961  Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next());
6962  continue;
6963  }
6964 
6965  // check for start of statement
6966  if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
6967  continue;
6968 
6969  if (Token::Match(tok, "delete|else|return|throw|typedef"))
6970  continue;
6971 
6972  while (Token::Match(tok, "%type%|:: %type%|::"))
6973  tok = tok->next();
6974 
6975  Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
6976  while (Token::Match(tok2, "*|&"))
6977  tok2 = tok2->next();
6978  if (!tok2 || tok2->str() != "(")
6979  continue;
6980  while (Token::Match(tok2, "(|:: %type%"))
6981  tok2 = tok2->tokAt(2);
6982  if (!Token::Match(tok2, "(|:: * *| %name%"))
6983  continue;
6984  tok2 = tok2->tokAt(2);
6985  if (tok2->str() == "*")
6986  tok2 = tok2->next();
6987  while (Token::Match(tok2, "%type%|:: %type%|::"))
6988  tok2 = tok2->next();
6989 
6990  if (!Token::Match(tok2, "%name% ) (") &&
6991  !Token::Match(tok2, "%name% [ ] ) (") &&
6992  !(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
6993  continue;
6994 
6995  while (tok && tok->str() != "(")
6996  tok = tok->next();
6997 
6998  // check that the declaration ends
6999  if (!tok || !tok->link() || !tok->link()->next()) {
7000  syntaxError(nullptr);
7001  }
7002  Token *endTok = tok->link()->next()->link();
7003  if (Token::simpleMatch(endTok, ") throw ("))
7004  endTok = endTok->linkAt(2);
7005  if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
7006  continue;
7007 
7008  while (Token::Match(endTok->next(), "const|volatile"))
7009  endTok->deleteNext();
7010 
7011  // ok simplify this function pointer to an ordinary pointer
7012  if (Token::simpleMatch(tok->link()->previous(), ") )")) {
7013  // Function returning function pointer
7014  // void (*dostuff(void))(void) {}
7015  Token::eraseTokens(tok->link(), endTok->next());
7016  tok->link()->deleteThis();
7017  tok->deleteThis();
7018  } else {
7019  Token::eraseTokens(tok->link()->linkAt(1), endTok->next());
7020 
7021  // remove variable names
7022  int indent = 0;
7023  for (Token* tok3 = tok->link()->tokAt(2); Token::Match(tok3, "%name%|*|&|[|(|)|::|,|<"); tok3 = tok3->next()) {
7024  if (tok3->str() == ")" && --indent < 0)
7025  break;
7026  if (tok3->str() == "<" && tok3->link())
7027  tok3 = tok3->link();
7028  else if (Token::Match(tok3, "["))
7029  tok3 = tok3->link();
7030  else if (tok3->str() == "(") {
7031  tok3 = tok3->link();
7032  if (Token::simpleMatch(tok3, ") (")) {
7033  tok3 = tok3->next();
7034  ++indent;
7035  } else
7036  break;
7037  }
7038  if (Token::Match(tok3, "%type%|*|&|> %name% [,)[]"))
7039  tok3->deleteNext();
7040  }
7041 
7042  // TODO Keep this info
7043  while (Token::Match(tok, "( %type% ::"))
7044  tok->deleteNext(2);
7045  }
7046  }
7047 }
7048 
7049 void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
7050 {
7051  simplifyVarDecl(list.front(), nullptr, only_k_r_fpar);
7052 }
7053 
7054 void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
7055 {
7056  const bool isCPP11 = isCPP() && (mSettings.standards.cpp >= Standards::CPP11);
7057 
7058  // Split up variable declarations..
7059  // "int a=4;" => "int a; a=4;"
7060  bool finishedwithkr = true;
7061  bool scopeDecl = false;
7062  for (Token *tok = tokBegin; tok != tokEnd; tok = tok->next()) {
7063  if (Token::Match(tok, "{|;"))
7064  scopeDecl = false;
7065  if (isCPP()) {
7066  if (Token::Match(tok, "class|struct|namespace|union"))
7067  scopeDecl = true;
7068  if (Token::Match(tok, "decltype|noexcept (")) {
7069  tok = tok->next()->link();
7070  // skip decltype(...){...}
7071  if (tok && Token::simpleMatch(tok->previous(), ") {"))
7072  tok = tok->link();
7073  } else if (Token::simpleMatch(tok, "= {") ||
7074  (!scopeDecl && Token::Match(tok, "%name%|> {") &&
7075  !Token::Match(tok, "else|try|do|const|constexpr|override|volatile|noexcept"))) {
7076  if (!tok->next()->link())
7077  syntaxError(tokBegin);
7078  // Check for lambdas before skipping
7079  if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type
7080  // TODO: support lambda without parameter clause?
7081  Token* lambdaStart = tok->linkAt(-2)->previous();
7082  if (Token::simpleMatch(lambdaStart, "]"))
7083  lambdaStart = lambdaStart->link();
7084  Token* lambdaEnd = findLambdaEndScope(lambdaStart);
7085  if (lambdaEnd)
7086  simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7087  } else {
7088  for (Token* tok2 = tok->next(); tok2 != tok->next()->link(); tok2 = tok2->next()) {
7089  Token* lambdaEnd = findLambdaEndScope(tok2);
7090  if (!lambdaEnd)
7091  continue;
7092  simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7093  }
7094  }
7095  tok = tok->next()->link();
7096  }
7097 
7098  } else if (Token::simpleMatch(tok, "= {")) {
7099  tok = tok->next()->link();
7100  }
7101  if (!tok) {
7102  syntaxError(tokBegin);
7103  }
7104  if (only_k_r_fpar && finishedwithkr) {
7105  if (Token::Match(tok, "(|[|{")) {
7106  tok = tok->link();
7107  if (tok->next() && Token::Match(tok, ") !!{"))
7108  tok = tok->next();
7109  else
7110  continue;
7111  } else
7112  continue;
7113  } else if (tok->str() == "(") {
7114  if (isCPP()) {
7115  for (Token * tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
7116  if (Token::Match(tok2, "[(,] [")) {
7117  // lambda function at tok2->next()
7118  // find start of lambda body
7119  Token * lambdaBody = tok2;
7120  while (lambdaBody && lambdaBody != tok2->link() && lambdaBody->str() != "{")
7121  lambdaBody = lambdaBody->next();
7122  if (lambdaBody && lambdaBody != tok2->link() && lambdaBody->link())
7123  simplifyVarDecl(lambdaBody, lambdaBody->link()->next(), only_k_r_fpar);
7124  }
7125  }
7126  }
7127  tok = tok->link();
7128  }
7129 
7130  if (!tok)
7131  syntaxError(nullptr); // #7043 invalid code
7132  if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:"))
7133  continue;
7134  if (Token::simpleMatch(tok, "template <"))
7135  continue;
7136 
7137  Token *type0 = tok;
7138  if (!Token::Match(type0, "::|extern| %type%"))
7139  continue;
7140  if (Token::Match(type0, "else|return|public:|protected:|private:"))
7141  continue;
7142  if (isCPP11 && type0->str() == "using")
7143  continue;
7144  if (type0->isCpp() && Token::Match(type0, "namespace|delete"))
7145  continue;
7146 
7147  bool isconst = false;
7148  bool isstatic = false;
7149  Token *tok2 = type0;
7150  int typelen = 1;
7151 
7152  if (Token::Match(tok2, "::|extern")) {
7153  tok2 = tok2->next();
7154  typelen++;
7155  }
7156 
7157  //check if variable is declared 'const' or 'static' or both
7158  while (tok2) {
7159  if (!Token::Match(tok2, "const|static|constexpr") && Token::Match(tok2, "%type% const|static")) {
7160  tok2 = tok2->next();
7161  ++typelen;
7162  }
7163 
7164  if (Token::Match(tok2, "const|constexpr"))
7165  isconst = true;
7166 
7167  else if (Token::Match(tok2, "static|constexpr"))
7168  isstatic = true;
7169 
7170  else if (Token::Match(tok2, "%type% :: %type%")) {
7171  tok2 = tok2->next();
7172  ++typelen;
7173  }
7174 
7175  else
7176  break;
7177 
7178  if (tok2->strAt(1) == "*")
7179  break;
7180 
7181  if (Token::Match(tok2->next(), "& %name% ,"))
7182  break;
7183 
7184  tok2 = tok2->next();
7185  ++typelen;
7186  }
7187 
7188  // strange looking variable declaration => don't split up.
7189  if (Token::Match(tok2, "%type% *|&| %name% , %type% *|&| %name%"))
7190  continue;
7191 
7192  if (Token::Match(tok2, "struct|union|class %type%")) {
7193  tok2 = tok2->next();
7194  ++typelen;
7195  }
7196 
7197  // check for qualification..
7198  if (Token::Match(tok2, ":: %type%")) {
7199  ++typelen;
7200  tok2 = tok2->next();
7201  }
7202 
7203  //skip combinations of templates and namespaces
7204  while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
7205  if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
7206  tok2 = nullptr;
7207  break;
7208  }
7209  typelen += 2;
7210  tok2 = tok2->tokAt(2);
7211  if (tok2 && tok2->previous()->str() == "::")
7212  continue;
7213  int indentlevel = 0;
7214  int parens = 0;
7215 
7216  for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
7217  ++typelen;
7218 
7219  if (!parens && tok3->str() == "<") {
7220  ++indentlevel;
7221  } else if (!parens && tok3->str() == ">") {
7222  if (indentlevel == 0) {
7223  tok2 = tok3->next();
7224  break;
7225  }
7226  --indentlevel;
7227  } else if (!parens && tok3->str() == ">>") {
7228  if (indentlevel <= 1) {
7229  tok2 = tok3->next();
7230  break;
7231  }
7232  indentlevel -= 2;
7233  } else if (tok3->str() == "(") {
7234  ++parens;
7235  } else if (tok3->str() == ")") {
7236  if (!parens) {
7237  tok2 = nullptr;
7238  break;
7239  }
7240  --parens;
7241  } else if (tok3->str() == ";") {
7242  break;
7243  }
7244  }
7245 
7246  if (Token::Match(tok2, ":: %type%")) {
7247  ++typelen;
7248  tok2 = tok2->next();
7249  }
7250 
7251  // east const
7252  if (Token::simpleMatch(tok2, "const"))
7253  isconst = true;
7254  }
7255 
7256  //pattern: "%type% *| ... *| const| %name% ,|="
7257  if (Token::Match(tok2, "%type%") ||
7258  (tok2 && tok2->previous() && tok2->previous()->str() == ">")) {
7259  Token *varName = tok2;
7260  if (!tok2->previous() || tok2->previous()->str() != ">")
7261  varName = varName->next();
7262  else
7263  --typelen;
7264  if (isCPP() && Token::Match(varName, "public:|private:|protected:|using"))
7265  continue;
7266  //skip all the pointer part
7267  bool isPointerOrRef = false;
7268  while (Token::simpleMatch(varName, "*") || Token::Match(varName, "& %name% ,")) {
7269  isPointerOrRef = true;
7270  varName = varName->next();
7271  }
7272 
7273  while (Token::Match(varName, "%type% %type%")) {
7274  if (varName->str() != "const" && varName->str() != "volatile") {
7275  ++typelen;
7276  }
7277  varName = varName->next();
7278  }
7279  // Function pointer
7280  if (Token::simpleMatch(varName, "( *") &&
7281  Token::Match(varName->link()->previous(), "%name% ) (") &&
7282  Token::simpleMatch(varName->link()->linkAt(1), ") =")) {
7283  Token *endDecl = varName->link()->linkAt(1);
7284  varName = varName->link()->previous();
7285  endDecl->insertToken(";");
7286  endDecl = endDecl->next();
7287  endDecl->next()->isSplittedVarDeclEq(true);
7288  endDecl->insertToken(varName->str());
7289  endDecl->next()->setMacroName(varName->getMacroName());
7290  continue;
7291  }
7292  //non-VLA case
7293  if (Token::Match(varName, "%name% ,|=")) {
7294  if (varName->str() != "operator") {
7295  tok2 = varName->next(); // The ',' or '=' token
7296 
7297  if (tok2->str() == "=" && (isstatic || (isconst && !isPointerOrRef))) {
7298  //do not split const non-pointer variables..
7299  while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7300  if (Token::Match(tok2, "{|(|["))
7301  tok2 = tok2->link();
7302  const Token *tok3 = tok2;
7303  if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
7304  tok2 = tok2->findClosingBracket();
7305  }
7306  if (!tok2)
7307  syntaxError(tok3); // #6881 invalid code
7308  tok2 = tok2->next();
7309  }
7310  if (tok2 && tok2->str() == ";")
7311  tok2 = nullptr;
7312  }
7313  } else
7314  tok2 = nullptr;
7315  }
7316 
7317  //VLA case
7318  else if (Token::Match(varName, "%name% [")) {
7319  tok2 = varName->next();
7320 
7321  while (Token::Match(tok2->link(), "] ,|=|["))
7322  tok2 = tok2->link()->next();
7323  if (!Token::Match(tok2, "=|,"))
7324  tok2 = nullptr;
7325  if (tok2 && tok2->str() == "=") {
7326  while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7327  if (Token::Match(tok2, "{|(|["))
7328  tok2 = tok2->link();
7329  tok2 = tok2->next();
7330  }
7331  if (tok2 && tok2->str() == ";")
7332  tok2 = nullptr;
7333  }
7334  }
7335 
7336  // brace initialization
7337  else if (Token::Match(varName, "%name% {")) {
7338  tok2 = varName->next();
7339  tok2 = tok2->link();
7340  if (tok2)
7341  tok2 = tok2->next();
7342  if (tok2 && tok2->str() != ",")
7343  tok2 = nullptr;
7344  }
7345 
7346  // function declaration
7347  else if (Token::Match(varName, "%name% (")) {
7348  Token* commaTok = varName->linkAt(1)->next();
7349  while (Token::Match(commaTok, "const|noexcept|override|final")) {
7350  commaTok = commaTok->next();
7351  if (Token::Match(commaTok, "( true|false )"))
7352  commaTok = commaTok->link()->next();
7353  }
7354  tok2 = Token::simpleMatch(commaTok, ",") ? commaTok : nullptr;
7355  }
7356 
7357  else
7358  tok2 = nullptr;
7359  } else {
7360  tok2 = nullptr;
7361  }
7362 
7363  if (!tok2) {
7364  if (only_k_r_fpar)
7365  finishedwithkr = false;
7366  continue;
7367  }
7368 
7369  if (tok2->str() == ",") {
7370  tok2->str(";");
7371  tok2->isSplittedVarDeclComma(true);
7372  //TODO: should we have to add also template '<>' links?
7373  TokenList::insertTokens(tok2, type0, typelen);
7374  }
7375 
7376  else {
7377  Token *eq = tok2;
7378 
7379  while (tok2) {
7380  if (Token::Match(tok2, "{|(|["))
7381  tok2 = tok2->link();
7382 
7383  else if (!isC() && tok2->str() == "<" && ((tok2->previous()->isName() && !tok2->previous()->varId()) || tok2->strAt(-1) == "]"))
7384  tok2 = tok2->findClosingBracket();
7385 
7386  else if (std::strchr(";,", tok2->str()[0])) {
7387  // "type var =" => "type var; var ="
7388  const Token *varTok = type0->tokAt(typelen);
7389  while (Token::Match(varTok, "%name%|*|& %name%|*|&"))
7390  varTok = varTok->next();
7391  if (!varTok)
7392  syntaxError(tok2); // invalid code
7393  TokenList::insertTokens(eq, varTok, 2);
7394  eq->str(";");
7395  eq->isSplittedVarDeclEq(true);
7396 
7397  // "= x, " => "= x; type "
7398  if (tok2->str() == ",") {
7399  tok2->str(";");
7400  tok2->isSplittedVarDeclComma(true);
7401  TokenList::insertTokens(tok2, type0, typelen);
7402  }
7403  break;
7404  }
7405  if (tok2)
7406  tok2 = tok2->next();
7407  }
7408  }
7409  finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{");
7410  }
7411 }
7412 
7414 {
7415  // This function will simplify the token list so that the qualifiers "extern", "static"
7416  // and "const" appear in the same order as in the array below.
7417  const std::string qualifiers[] = {"extern", "static", "const"};
7418 
7419  // Move 'const' before all other qualifiers and types and then
7420  // move 'static' before all other qualifiers and types, ...
7421  for (Token *tok = list.front(); tok; tok = tok->next()) {
7422  bool continue2 = false;
7423  for (int i = 0; i < sizeof(qualifiers)/sizeof(qualifiers[0]); i++) {
7424 
7425  // Keep searching for a qualifier
7426  if (!tok->next() || tok->next()->str() != qualifiers[i])
7427  continue;
7428 
7429  // Look backwards to find the beginning of the declaration
7430  Token* leftTok = tok;
7431  bool behindOther = false;
7432  for (; leftTok; leftTok = leftTok->previous()) {
7433  for (int j = 0; j <= i; j++) {
7434  if (leftTok->str() == qualifiers[j]) {
7435  behindOther = true;
7436  break;
7437  }
7438  }
7439  if (behindOther)
7440  break;
7441  if (isCPP() && Token::simpleMatch(leftTok, ">")) {
7442  Token* opening = leftTok->findOpeningBracket();
7443  if (opening) {
7444  leftTok = opening;
7445  continue;
7446  }
7447  }
7448  if (!Token::Match(leftTok, "%type%|struct|::") ||
7449  (isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator|template"))) {
7450  break;
7451  }
7452  }
7453 
7454  // The token preceding the declaration should indicate the start of a declaration
7455  if (leftTok == tok)
7456  continue;
7457 
7458  if (leftTok && !behindOther && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:")) {
7459  continue2 = true;
7460  break;
7461  }
7462 
7463  // Move the qualifier to the left-most position in the declaration
7464  tok->deleteNext();
7465  if (!leftTok) {
7466  list.front()->insertToken(qualifiers[i]);
7467  list.front()->swapWithNext();
7468  tok = list.front();
7469  } else if (leftTok->next()) {
7470  leftTok->next()->insertTokenBefore(qualifiers[i]);
7471  tok = leftTok->next();
7472  } else {
7473  leftTok->insertToken(qualifiers[i]);
7474  tok = leftTok;
7475  }
7476  }
7477  if (continue2)
7478  continue;
7479  }
7480 }
7481 
7483 {
7484  for (Token *tok = list.front(); tok; tok = tok->next()) {
7485  if (Token::Match(tok, "%name% = %name% = %num%|%name% ;")) {
7486  // skip intermediate assignments
7487  Token *tok2 = tok->previous();
7488  while (tok2 &&
7489  tok2->str() == "=" &&
7490  Token::Match(tok2->previous(), "%name%")) {
7491  tok2 = tok2->tokAt(-2);
7492  }
7493 
7494  if (!tok2 || tok2->str() != ";") {
7495  continue;
7496  }
7497 
7498  Token *stopAt = tok->tokAt(2);
7499  const Token *valueTok = stopAt->tokAt(2);
7500  const std::string& value(valueTok->str());
7501  tok2 = tok2->next();
7502 
7503  while (tok2 != stopAt) {
7504  tok2->next()->insertToken(";");
7505  tok2->next()->insertToken(value);
7506  tok2 = tok2->tokAt(4);
7507  }
7508  }
7509  }
7510 }
7511 
7512 // Binary operators simplification map
7513 static const std::unordered_map<std::string, std::string> cAlternativeTokens = {
7514  std::make_pair("and", "&&")
7515  , std::make_pair("and_eq", "&=")
7516  , std::make_pair("bitand", "&")
7517  , std::make_pair("bitor", "|")
7518  , std::make_pair("not_eq", "!=")
7519  , std::make_pair("or", "||")
7520  , std::make_pair("or_eq", "|=")
7521  , std::make_pair("xor", "^")
7522  , std::make_pair("xor_eq", "^=")
7523 };
7524 
7525 // Simplify the C alternative tokens:
7526 // and => &&
7527 // and_eq => &=
7528 // bitand => &
7529 // bitor => |
7530 // compl => ~
7531 // not => !
7532 // not_eq => !=
7533 // or => ||
7534 // or_eq => |=
7535 // xor => ^
7536 // xor_eq => ^=
7538 {
7539  /* executable scope level */
7540  int executableScopeLevel = 0;
7541 
7542  std::vector<Token *> alt;
7543  bool replaceAll = false; // replace all or none
7544 
7545  for (Token *tok = list.front(); tok; tok = tok->next()) {
7546  if (tok->str() == ")") {
7547  if (const Token *end = isFunctionHead(tok, "{")) {
7548  ++executableScopeLevel;
7549  tok = const_cast<Token *>(end);
7550  continue;
7551  }
7552  }
7553 
7554  if (tok->str() == "{") {
7555  if (executableScopeLevel > 0)
7556  ++executableScopeLevel;
7557  continue;
7558  }
7559 
7560  if (tok->str() == "}") {
7561  if (executableScopeLevel > 0)
7562  --executableScopeLevel;
7563  continue;
7564  }
7565 
7566  if (!tok->isName())
7567  continue;
7568 
7569  const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7570  if (cOpIt != cAlternativeTokens.end()) {
7571  alt.push_back(tok);
7572 
7573  // Is this a variable declaration..
7574  if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]"))
7575  return false;
7576 
7577  if (!Token::Match(tok->previous(), "%name%|%num%|%char%|)|]|> %name% %name%|%num%|%char%|%op%|("))
7578  continue;
7579  if (Token::Match(tok->next(), "%assign%|%or%|%oror%|&&|*|/|%|^") && !Token::Match(tok->previous(), "%num%|%char%|) %name% *"))
7580  continue;
7581  if (executableScopeLevel == 0 && Token::Match(tok, "%name% (")) {
7582  const Token *start = tok;
7583  while (Token::Match(start, "%name%|*"))
7584  start = start->previous();
7585  if (!start || Token::Match(start, "[;}]"))
7586  continue;
7587  }
7588  replaceAll = true;
7589  } else if (Token::Match(tok, "not|compl")) {
7590  alt.push_back(tok);
7591 
7592  if ((Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) && !Token::Match(tok->next(), ".|->")) {
7593  replaceAll = true;
7594  continue;
7595  }
7596 
7597  // Don't simplify 'not p;' (in case 'not' is a type)
7598  if (!Token::Match(tok->next(), "%name%|(") ||
7599  Token::Match(tok->previous(), "[;{}]") ||
7600  (executableScopeLevel == 0U && tok->strAt(-1) == "("))
7601  continue;
7602 
7603  replaceAll = true;
7604  }
7605  }
7606 
7607  if (!replaceAll)
7608  return false;
7609 
7610  for (Token *tok: alt) {
7611  const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7612  if (cOpIt != cAlternativeTokens.end())
7613  tok->str(cOpIt->second);
7614  else if (tok->str() == "not")
7615  tok->str("!");
7616  else
7617  tok->str("~");
7618  }
7619 
7620  return !alt.empty();
7621 }
7622 
7623 // int i(0); => int i; i = 0;
7624 // int i(0), j; => int i; i = 0; int j;
7626 {
7627  if (isC())
7628  return;
7629 
7630  for (Token *tok = list.front(); tok; tok = tok->next()) {
7631  if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]")))
7632  continue;
7633 
7634  if (tok->str() == "return")
7635  continue;
7636 
7637  if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ;")) {
7638  tok = initVar(tok);
7639  } else if (Token::Match(tok, "%type% *| %name% ( %type% (")) {
7640  const Token* tok2 = tok->tokAt(2);
7641  if (!tok2->link())
7642  tok2 = tok2->next();
7643  if (!tok2->link() || (tok2->link()->strAt(1) == ";" && !Token::simpleMatch(tok2->linkAt(2), ") (")))
7644  tok = initVar(tok);
7645  } else if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ,") && tok->str() != "new") {
7646  Token *tok1 = tok->tokAt(5);
7647  while (tok1->str() != ",")
7648  tok1 = tok1->next();
7649  tok1->str(";");
7650 
7651  const int numTokens = (Token::Match(tok, "class|struct|union")) ? 2U : 1U;
7652  TokenList::insertTokens(tok1, tok, numTokens);
7653  tok = initVar(tok);
7654  }
7655  }
7656 }
7657 
7659 {
7660  // call constructor of class => no simplification
7661  if (Token::Match(tok, "class|struct|union")) {
7662  if (tok->strAt(2) != "*")
7663  return tok;
7664 
7665  tok = tok->next();
7666  } else if (!tok->isStandardType() && tok->str() != "auto" && tok->next()->str() != "*")
7667  return tok;
7668 
7669  // goto variable name..
7670  tok = tok->next();
7671  if (tok->str() == "*")
7672  tok = tok->next();
7673 
7674  // sizeof is not a variable name..
7675  if (tok->str() == "sizeof")
7676  return tok;
7677 
7678  // check initializer..
7679  if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void")
7680  return tok;
7681  if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0)
7682  return tok;
7683 
7684  // insert '; var ='
7685  tok->insertToken(";");
7686  tok->next()->insertToken(tok->str());
7687  tok->tokAt(2)->varId(tok->varId());
7688  tok = tok->tokAt(2);
7689  tok->insertToken("=");
7690 
7691  // goto '('..
7692  tok = tok->tokAt(2);
7693 
7694  // delete ')'
7695  tok->link()->deleteThis();
7696 
7697  // delete this
7698  tok->deleteThis();
7699 
7700  return tok;
7701 }
7702 
7704 {
7705  for (Token *tok = list.front(); tok; tok = tok->next()) {
7706  if (tok->str() != "else")
7707  continue;
7708 
7709  if (!Token::Match(tok->previous(), ";|}"))
7710  syntaxError(tok->previous());
7711 
7712  if (!Token::Match(tok->next(), "%name%"))
7713  continue;
7714 
7715  if (tok->strAt(1) != "if")
7716  unknownMacroError(tok->next());
7717 
7718  for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
7719  if (Token::Match(tok2, "(|{|["))
7720  tok2 = tok2->link();
7721 
7722  if (Token::Match(tok2, "}|;")) {
7723  if (tok2->next() && tok2->next()->str() != "else") {
7724  tok->insertToken("{");
7725  tok2->insertToken("}");
7726  Token::createMutualLinks(tok->next(), tok2->next());
7727  break;
7728  }
7729  }
7730  }
7731  }
7732 }
7733 
7734 
7736 {
7738  return;
7739 
7740  const bool forInit = (mSettings.standards.cpp >= Standards::CPP20);
7741 
7742  for (Token *tok = list.front(); tok; tok = tok->next()) {
7743  if (!Token::Match(tok, "if|switch|for ("))
7744  continue;
7745 
7746  Token *semicolon = tok->tokAt(2);
7747  while (!Token::Match(semicolon, "[;)]")) {
7748  if (Token::Match(semicolon, "(|{|[") && semicolon->link())
7749  semicolon = semicolon->link();
7750  semicolon = semicolon->next();
7751  }
7752  if (semicolon->str() != ";")
7753  continue;
7754 
7755  if (tok->str() == "for") {
7756  if (!forInit)
7757  continue;
7758 
7759  // Is it a for range..
7760  const Token *tok2 = semicolon->next();
7761  bool rangeFor = false;
7762  while (!Token::Match(tok2, "[;)]")) {
7763  if (tok2->str() == "(")
7764  tok2 = tok2->link();
7765  else if (!rangeFor && tok2->str() == "?")
7766  break;
7767  else if (tok2->str() == ":")
7768  rangeFor = true;
7769  tok2 = tok2->next();
7770  }
7771  if (!rangeFor || tok2->str() != ")")
7772  continue;
7773  }
7774 
7775  Token *endpar = tok->linkAt(1);
7776  if (!Token::simpleMatch(endpar, ") {"))
7777  continue;
7778 
7779  Token *endscope = endpar->linkAt(1);
7780  if (Token::simpleMatch(endscope, "} else {"))
7781  endscope = endscope->linkAt(2);
7782 
7783  // Simplify, the initialization expression is broken out..
7784  semicolon->insertToken(tok->str());
7785  semicolon->next()->insertToken("(");
7786  Token::createMutualLinks(semicolon->next()->next(), endpar);
7787  tok->deleteNext();
7788  tok->str("{");
7789  endscope->insertToken("}");
7790  Token::createMutualLinks(tok, endscope->next());
7791  tok->isSimplifiedScope(true);
7792  }
7793 }
7794 
7795 
7797 {
7798  bool ret = false;
7799  for (Token *tok = list.front(); tok; tok = tok->next()) {
7800  if (tok->str() != "(")
7801  continue;
7802 
7803  if (tok->isCpp() && Token::simpleMatch(tok->previous(), "} (")) {
7804  const Token* plp = tok->previous()->link()->previous();
7805  if (Token::Match(plp, "%name%|>|] {") || (Token::simpleMatch(plp, ")") && Token::simpleMatch(plp->link()->previous(), "]")))
7806  continue;
7807  }
7808 
7809  if (Token::simpleMatch(tok, "( {"))
7810  continue;
7811 
7812  if (Token::Match(tok->link(), ") %num%")) {
7813  tok = tok->link();
7814  continue;
7815  }
7816 
7817  // Do not simplify if there is comma inside parentheses..
7818  if (Token::Match(tok->previous(), "%op% (") || Token::Match(tok->link(), ") %op%")) {
7819  bool innerComma = false;
7820  for (const Token *inner = tok->link()->previous(); inner != tok; inner = inner->previous()) {
7821  if (inner->str() == ")")
7822  inner = inner->link();
7823  if (inner->str() == ",") {
7824  innerComma = true;
7825  break;
7826  }
7827  }
7828  if (innerComma)
7829  continue;
7830  }
7831 
7832  // !!operator = ( x ) ;
7833  if (tok->strAt(-2) != "operator" &&
7834  tok->previous() && tok->previous()->str() == "=" &&
7835  tok->next() && tok->next()->str() != "{" &&
7836  Token::simpleMatch(tok->link(), ") ;")) {
7837  tok->link()->deleteThis();
7838  tok->deleteThis();
7839  continue;
7840  }
7841 
7842  while (Token::simpleMatch(tok, "( (") &&
7843  tok->link() && tok->link()->previous() == tok->next()->link()) {
7844  // We have "(( *something* ))", remove the inner
7845  // parentheses
7846  tok->deleteNext();
7847  tok->link()->tokAt(-2)->deleteNext();
7848  ret = true;
7849  }
7850 
7851  if (isCPP() && Token::Match(tok->tokAt(-2), "[;{}=(] new (") && Token::Match(tok->link(), ") [;,{}[]")) {
7852  // Remove the parentheses in "new (type)" constructs
7853  tok->link()->deleteThis();
7854  tok->deleteThis();
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% ) .")) {
7866  // Remove the parentheses
7867  tok->deleteThis();
7868  tok->deleteNext();
7869  ret = true;
7870  }
7871 
7872  if (Token::Match(tok->previous(), "[(,;{}] ( %name% (") && !tok->next()->isKeyword() &&
7873  tok->link()->previous() == tok->linkAt(2)) {
7874  // We have "( func ( *something* ))", remove the outer
7875  // parentheses
7876  tok->link()->deleteThis();
7877  tok->deleteThis();
7878  ret = true;
7879  }
7880 
7881  if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %name% ) ;")) {
7882  // We have "( delete [| ]| var )", remove the outer
7883  // parentheses
7884  tok->link()->deleteThis();
7885  tok->deleteThis();
7886  ret = true;
7887  }
7888 
7889  if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
7890  Token::Match(tok->previous(), "delete|; (") &&
7891  (tok->previous()->str() != "delete" || tok->next()->varId() > 0) &&
7892  Token::Match(tok->link(), ") ;|,")) {
7893  tok->link()->deleteThis();
7894  tok->deleteThis();
7895  ret = true;
7896  }
7897 
7898  if (Token::Match(tok->previous(), "[(!*;{}] ( %name% )") &&
7899  (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]")) && !tok->next()->isStandardType()) {
7900  // We have "( var )", remove the parentheses
7901  tok->deleteThis();
7902  tok->deleteNext();
7903  ret = true;
7904  }
7905 
7906  while (Token::Match(tok->previous(), "[;{}[(,!*] ( %name% .")) {
7907  Token *tok2 = tok->tokAt(2);
7908  while (Token::Match(tok2, ". %name%")) {
7909  tok2 = tok2->tokAt(2);
7910  }
7911  if (tok2 != tok->link())
7912  break;
7913  // We have "( var . var . ... . var )", remove the parentheses
7914  tok = tok->previous();
7915  tok->deleteNext();
7916  tok2->deleteThis();
7917  ret = true;
7918  }
7919 
7920  while (Token::Match(tok->previous(), "[{([,] ( !!{") &&
7921  Token::Match(tok->link(), ") [;,])]") &&
7922  !Token::simpleMatch(tok->tokAt(-2), "operator ,") && // Ticket #5709
7923  !Token::findsimplematch(tok, ",", tok->link())) {
7924  // We have "( ... )", remove the parentheses
7925  tok->link()->deleteThis();
7926  tok->deleteThis();
7927  ret = true;
7928  }
7929 
7930  if (Token::simpleMatch(tok->previous(), ", (") &&
7931  Token::simpleMatch(tok->link(), ") =")) {
7932  tok->link()->deleteThis();
7933  tok->deleteThis();
7934  ret = true;
7935  }
7936 
7937  // Simplify "!!operator !!%name%|)|]|>|>> ( %num%|%bool% ) %op%|;|,|)"
7938  if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") &&
7939  tok->strAt(-2) != "operator" &&
7940  tok->previous() &&
7941  !Token::Match(tok->previous(), "%name%|)|]") &&
7942  (!(isCPP() && Token::Match(tok->previous(),">|>>")))) {
7943  tok->link()->deleteThis();
7944  tok->deleteThis();
7945  ret = true;
7946  }
7947 
7948  if (Token::Match(tok->previous(), "*|& ( %name% )")) {
7949  // We may have a variable declaration looking like "type_name *(var_name)"
7950  Token *tok2 = tok->tokAt(-2);
7951  while (Token::Match(tok2, "%type%|static|const|extern") && tok2->str() != "operator") {
7952  tok2 = tok2->previous();
7953  }
7954  if (tok2 && !Token::Match(tok2, "[;,{]")) {
7955  // Not a variable declaration
7956  } else {
7957  tok->deleteThis();
7958  tok->deleteNext();
7959  }
7960  }
7961  }
7962  return ret;
7963 }
7964 
7966 {
7967  static const std::unordered_map<std::string, std::string> intrinsics = {
7968  { "__has_nothrow_assign", "has_nothrow_assign" },
7969  { "__has_nothrow_constructor", "has_nothrow_constructor" },
7970  { "__has_nothrow_copy", "has_nothrow_copy" },
7971  { "__has_trivial_assign", "has_trivial_assign" },
7972  { "__has_trivial_constructor", "has_trivial_constructor" },
7973  { "__has_trivial_copy", "has_trivial_copy" },
7974  { "__has_trivial_destructor", "has_trivial_destructor" },
7975  { "__has_virtual_destructor", "has_virtual_destructor" },
7976  { "__is_abstract", "is_abstract" },
7977  { "__is_aggregate", "is_aggregate" },
7978  { "__is_assignable", "is_assignable" },
7979  { "__is_base_of", "is_base_of" },
7980  { "__is_class", "is_class" },
7981  { "__is_constructible", "is_constructible" },
7982  { "__is_convertible_to", "is_convertible_to" },
7983  { "__is_destructible", "is_destructible" },
7984  { "__is_empty", "is_empty" },
7985  { "__is_enum", "is_enum" },
7986  { "__is_final", "is_final" },
7987  { "__is_nothrow_assignable", "is_nothrow_assignable" },
7988  { "__is_nothrow_constructible", "is_nothrow_constructible" },
7989  { "__is_nothrow_destructible", "is_nothrow_destructible" },
7990  { "__is_pod", "is_pod" },
7991  { "__is_polymorphic", "is_polymorphic" },
7992  { "__is_trivially_assignable", "is_trivially_assignable" },
7993  { "__is_trivially_constructible", "is_trivially_constructible" },
7994  { "__is_union", "is_union" },
7995  };
7996  for (Token *tok = list.front(); tok; tok = tok->next()) {
7997  if (!Token::Match(tok, "%name% ("))
7998  continue;
7999  auto p = intrinsics.find(tok->str());
8000  if (p == intrinsics.end())
8001  continue;
8002  Token * end = tok->next()->link();
8003  Token * prev = tok->previous();
8004  tok->str(p->second);
8005  prev->insertToken("::");
8006  prev->insertToken("std");
8007  tok->next()->str("<");
8008  end->str(">");
8009  end->insertToken("}");
8010  end->insertToken("{");
8011  Token::createMutualLinks(end->tokAt(1), end->tokAt(2));
8012  }
8013 }
8014 
8015 //---------------------------------------------------------------------------
8016 // Helper functions for handling the tokens list
8017 //---------------------------------------------------------------------------
8018 
8019 //---------------------------------------------------------------------------
8020 
8021 bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
8022 {
8023  std::string unknownFunc;
8024  const bool ret = mSettings.library.isScopeNoReturn(endScopeToken,&unknownFunc);
8025  if (!unknownFunc.empty() && mSettings.summaryReturn.find(unknownFunc) != mSettings.summaryReturn.end()) {
8026  return false;
8027  }
8028  if (unknown)
8029  *unknown = !unknownFunc.empty();
8030  if (!unknownFunc.empty() && mSettings.checkLibrary) {
8031  bool warn = true;
8032  if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
8033  const Token * const ftok = endScopeToken->linkAt(-2)->previous();
8034  if (ftok && (ftok->type() || ftok->function() || ftok->variable())) // constructor call
8035  warn = false;
8036  }
8037 
8038  if (warn) {
8039  reportError(endScopeToken->previous(),
8041  "checkLibraryNoReturn",
8042  "--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
8043  }
8044  }
8045  return ret;
8046 }
8047 
8048 //---------------------------------------------------------------------------
8049 
8050 void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
8051 {
8052  printDebugOutput(0);
8053  throw InternalError(tok, code.empty() ? "syntax error" : "syntax error: " + code, InternalError::SYNTAX);
8054 }
8055 
8056 void Tokenizer::unmatchedToken(const Token *tok) const
8057 {
8058  printDebugOutput(0);
8059  throw InternalError(tok,
8060  "Unmatched '" + tok->str() + "'. Configuration: '" + mConfiguration + "'.",
8062 }
8063 
8064 void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
8065 {
8066  printDebugOutput(0);
8067  throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
8068 }
8069 
8070 void Tokenizer::unknownMacroError(const Token *tok1) const
8071 {
8072  printDebugOutput(0);
8073  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);
8074 }
8075 
8077 {
8078  reportError(tok,
8080  "class_X_Y",
8081  "The code '" +
8082  tok->str() + " " +
8083  tok->strAt(1) + " " +
8084  tok->strAt(2) + " " +
8085  tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
8086 }
8087 
8088 void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string &macroName) const
8089 {
8090  reportError(tok,
8092  "macroWithSemicolon",
8093  "Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
8094 }
8095 
8096 void Tokenizer::cppcheckError(const Token *tok) const
8097 {
8098  printDebugOutput(0);
8099  throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL);
8100 }
8101 
8102 void Tokenizer::unhandledCharLiteral(const Token *tok, const std::string& msg) const
8103 {
8104  std::string s = tok ? (" " + tok->str()) : "";
8105  for (int i = 0; i < s.size(); ++i) {
8106  if ((unsigned char)s[i] >= 0x80)
8107  s.clear();
8108  }
8109 
8110  reportError(tok,
8112  "nonStandardCharLiteral",
8113  "Non-standard character literal" + s + ". " + msg);
8114 }
8115 
8116 /**
8117  * Helper function to check whether number is equal to integer constant X
8118  * or floating point pattern X.0
8119  * @param s the string to check
8120  * @param intConstant the integer constant to check against
8121  * @param floatConstant the string with stringified float constant to check against
8122  * @return true in case s is equal to X or X.0 and false otherwise.
8123  */
8124 static bool isNumberOneOf(const std::string &s, MathLib::bigint intConstant, const char* floatConstant)
8125 {
8126  if (MathLib::isInt(s)) {
8127  if (MathLib::toBigNumber(s) == intConstant)
8128  return true;
8129  } else if (MathLib::isFloat(s)) {
8130  if (MathLib::toString(MathLib::toDoubleNumber(s)) == floatConstant)
8131  return true;
8132  }
8133  return false;
8134 }
8135 
8136 // ------------------------------------------------------------------------
8137 // Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
8138 // @param s the string to check
8139 // @return true in case s is one and false otherwise.
8140 // ------------------------------------------------------------------------
8141 bool Tokenizer::isOneNumber(const std::string &s)
8142 {
8143  if (!MathLib::isPositive(s))
8144  return false;
8145  return isNumberOneOf(s, 1L, "1.0");
8146 }
8147 // ------------------------------------------------------------------------
8149 {
8151  return;
8152  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8153  if (!Token::Match(tok, "%name% ("))
8154  continue;
8155  if (tok->isControlFlowKeyword())
8156  continue;
8157  for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
8158  if (tok2->str() == ";") {
8159  macroWithSemicolonError(tok, tok->str());
8160  break;
8161  }
8162  if (Token::Match(tok2, "(|{"))
8163  tok2 = tok2->link();
8164  }
8165  }
8166 }
8167 
8169 {
8170  if (isCPP())
8171  return;
8172  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8173  // That might trigger false positives, but it's much faster to have this truncated pattern
8174  if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
8175  syntaxErrorC(tok, "C++ cast <...");
8176  // Template function..
8177  if (Token::Match(tok, "%name% < %name% > (")) {
8178  const Token *tok2 = tok->tokAt(5);
8179  while (tok2 && !Token::Match(tok2, "[()]"))
8180  tok2 = tok2->next();
8181  if (Token::simpleMatch(tok2, ") {"))
8182  syntaxErrorC(tok, tok->str() + '<' + tok->strAt(2) + ">() {}");
8183  }
8184  if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
8185  continue;
8186  if (Token::Match(tok, "using namespace %name% ;"))
8187  syntaxErrorC(tok, "using namespace " + tok->strAt(2));
8188  if (Token::Match(tok, "template < class|typename %name% [,>]"))
8189  syntaxErrorC(tok, "template<...");
8190  if (Token::Match(tok, "%name% :: %name%"))
8191  syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8192  if (Token::Match(tok, "class|namespace %name% [:{]"))
8193  syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8194  }
8195 }
8196 
8198 {
8199  std::stack<const Token *> linkTokens;
8200  const Token *lastTok = nullptr;
8201  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8202  lastTok = tok;
8203  if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) {
8204  if (tok->link() == nullptr)
8205  cppcheckError(tok);
8206 
8207  linkTokens.push(tok);
8208  }
8209 
8210  else if (Token::Match(tok, "[})]]") || (Token::Match(tok, ">|>>") && tok->link())) {
8211  if (tok->link() == nullptr)
8212  cppcheckError(tok);
8213 
8214  if (linkTokens.empty())
8215  cppcheckError(tok);
8216 
8217  if (tok->link() != linkTokens.top())
8218  cppcheckError(tok);
8219 
8220  if (tok != tok->link()->link())
8221  cppcheckError(tok);
8222 
8223  linkTokens.pop();
8224  }
8225 
8226  else if (tok->link() != nullptr)
8227  cppcheckError(tok);
8228  }
8229 
8230  if (!linkTokens.empty())
8231  cppcheckError(linkTokens.top());
8232 
8233  // Validate that the Tokenizer::list.back() is updated correctly during simplifications
8234  if (lastTok != list.back())
8235  cppcheckError(lastTok);
8236 }
8237 
8238 static const Token *findUnmatchedTernaryOp(const Token * const begin, const Token * const end, int depth = 0)
8239 {
8240  std::stack<const Token *> ternaryOp;
8241  for (const Token *tok = begin; tok != end && tok->str() != ";"; tok = tok->next()) {
8242  if (tok->str() == "?")
8243  ternaryOp.push(tok);
8244  else if (!ternaryOp.empty() && tok->str() == ":")
8245  ternaryOp.pop();
8246  else if (depth < 100 && Token::Match(tok,"(|[")) {
8247  const Token *inner = findUnmatchedTernaryOp(tok->next(), tok->link(), depth+1);
8248  if (inner)
8249  return inner;
8250  tok = tok->link();
8251  }
8252  }
8253  return ternaryOp.empty() ? nullptr : ternaryOp.top();
8254 }
8255 
8256 static bool isCPPAttribute(const Token * tok)
8257 {
8258  return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
8259 }
8260 
8261 static bool isAlignAttribute(const Token * tok)
8262 {
8263  return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
8264 }
8265 
8266 template<typename T>
8267 static T* skipCPPOrAlignAttribute(T * tok)
8268 {
8269  if (isCPPAttribute(tok))
8270  return tok->link();
8271  if (isAlignAttribute(tok)) {
8272  return tok->next()->link();
8273  }
8274  return tok;
8275 }
8276 
8277 static bool isNonMacro(const Token* tok)
8278 {
8279  if (tok->isKeyword() || tok->isStandardType())
8280  return true;
8281  if (cAlternativeTokens.count(tok->str()) > 0)
8282  return true;
8283  if (startsWith(tok->str(), "__")) // attribute/annotation
8284  return true;
8285  if (Token::simpleMatch(tok, "alignas ("))
8286  return true;
8287  return false;
8288 }
8289 
8291 {
8292  // Report unknown macros used in expressions "%name% %num%"
8293  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8294  if (Token::Match(tok, "%name% %num%")) {
8295  // A keyword is not an unknown macro
8296  if (tok->isKeyword())
8297  continue;
8298 
8299  if (Token::Match(tok->previous(), "%op%|("))
8300  unknownMacroError(tok);
8301  }
8302  }
8303 
8304  // Report unknown macros before } "{ .. if (x) MACRO }"
8305  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8306  if (Token::Match(tok, ")|; %name% } !!)")) {
8307  if (tok->link() && !Token::simpleMatch(tok->link()->tokAt(-1), "if"))
8308  continue;
8309  const Token* prev = tok->linkAt(2);
8310  while (Token::simpleMatch(prev, "{"))
8311  prev = prev->previous();
8312  if (Token::Match(prev, ";|)"))
8313  unknownMacroError(tok->next());
8314  }
8315  }
8316 
8317  // Report unknown macros that contain several statements "MACRO(a;b;c)"
8318  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8319  if (!Token::Match(tok, "%name% ("))
8320  continue;
8321  if (!tok->isUpperCaseName())
8322  continue;
8323  const Token *endTok = tok->linkAt(1);
8324  for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8325  if (Token::Match(inner, "[[({]"))
8326  inner = inner->link();
8327  else if (inner->str() == ";")
8328  unknownMacroError(tok);
8329  }
8330  }
8331 
8332  // Report unknown macros that contain struct initialization "MACRO(a, .b=3)"
8333  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8334  if (!Token::Match(tok, "%name% ("))
8335  continue;
8336  const Token *endTok = tok->linkAt(1);
8337  for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8338  if (Token::Match(inner, "[[({]"))
8339  inner = inner->link();
8340  else if (Token::Match(inner->previous(), "[,(] . %name% =|{"))
8341  unknownMacroError(tok);
8342  }
8343  }
8344 
8345  // Report unknown macros in non-executable scopes..
8346  std::set<std::string> possible;
8347  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8348  // Skip executable scopes..
8349  if (tok->str() == "{") {
8350  const Token *prev = tok->previous();
8351  while (prev && prev->isName())
8352  prev = prev->previous();
8353  if (prev && prev->str() == ")")
8354  tok = tok->link();
8355  else
8356  possible.clear();
8357  } else if (tok->str() == "}")
8358  possible.clear();
8359 
8360  if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
8361  // A keyword is not an unknown macro
8362  if (tok->isKeyword())
8363  continue;
8364 
8365  const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
8366  const Token *bodyEnd = tok->link();
8367  for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) {
8368  if (Token::Match(tok2, "if|switch|for|while|return"))
8369  unknownMacroError(tok);
8370  }
8371  } else if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::Match(tok->linkAt(1), ") %name% (") && Token::Match(tok->linkAt(1)->linkAt(2), ") [;{]")) {
8372  if (!(tok->linkAt(1)->next() && tok->linkAt(1)->next()->isKeyword())) { // e.g. noexcept(true)
8373  if (possible.count(tok->str()) == 0)
8374  possible.insert(tok->str());
8375  else
8376  unknownMacroError(tok);
8377  }
8378  } else if (isCPP() && Token::Match(tok, "public|private|protected %name% :")) {
8379  unknownMacroError(tok->next());
8380  }
8381  }
8382 
8383  // String concatenation with unknown macros
8384  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8385  if ((Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) ||
8386  (Token::Match(tok, "%str% %name% %str%") && !(startsWith(tok->strAt(1), "PRI") || startsWith(tok->strAt(1), "SCN")))) { // TODO: implement macros in std.cfg
8387  if (tok->next()->isKeyword())
8388  continue;
8389  unknownMacroError(tok->next());
8390  }
8391  if (Token::Match(tok, "[(,] %name% (") && Token::Match(tok->linkAt(2), ") %name% %name%|,|)")) {
8392  if (tok->next()->isKeyword() || tok->linkAt(2)->next()->isKeyword())
8393  continue;
8394  if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
8395  continue;
8396  if (startsWith(tok->next()->str(), "__")) // attribute/annotation
8397  continue;
8398  unknownMacroError(tok->next());
8399  }
8400  }
8401 
8402  // Report unknown macros without commas or operators inbetween statements: MACRO1() MACRO2()
8403  for (const Token* tok = tokens(); tok; tok = tok->next()) {
8404  if (!Token::Match(tok, "%name% ("))
8405  continue;
8406  if (isNonMacro(tok) && !tok->isStandardType())
8407  continue;
8408 
8409  const Token* endTok = tok->linkAt(1);
8410  if (!Token::Match(endTok, ") %name% (|."))
8411  continue;
8412 
8413  const Token* tok2 = endTok->next();
8414  if (isNonMacro(tok2))
8415  continue;
8416 
8417  if (tok2->next()->str() == "(") {
8418  if (Token::Match(tok->previous(), "%name%|::|>"))
8419  continue;
8420  }
8421 
8422  unknownMacroError(tok->isStandardType() ? tok2 : tok);
8423  }
8424 }
8425 
8426 void Tokenizer::findGarbageCode() const
8427 {
8428  const bool isCPP11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
8429 
8430  static const std::unordered_set<std::string> nonConsecutiveKeywords{ "break",
8431  "continue",
8432  "for",
8433  "goto",
8434  "if",
8435  "return",
8436  "switch",
8437  "throw",
8438  "typedef",
8439  "while" };
8440 
8441  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8442  // initialization: = {
8443  if (Token::simpleMatch(tok, "= {") && Token::simpleMatch(tok->linkAt(1), "} ("))
8444  syntaxError(tok->linkAt(1));
8445 
8446  // Inside [] there can't be ; or various keywords
8447  else if (tok->str() == "[") {
8448  for (const Token* inner = tok->next(); inner != tok->link(); inner = inner->next()) {
8449  if (Token::Match(inner, "(|[|{"))
8450  inner = inner->link();
8451  else if (Token::Match(inner, ";|goto|return|typedef"))
8452  syntaxError(inner);
8453  }
8454  }
8455 
8456  // array assignment
8457  else if (Token::Match(tok, "%assign% [") && Token::simpleMatch(tok->linkAt(1), "] ;"))
8458  syntaxError(tok, tok->str() + "[...];");
8459 
8460  else if (Token::Match(tok, "[({<] %assign%"))
8461  syntaxError(tok);
8462 
8463  else if (Token::Match(tok, "[`\\@]"))
8464  syntaxError(tok);
8465 
8466  // UNKNOWN_MACRO(return)
8467  if (tok->isKeyword() && Token::Match(tok, "throw|return )") && Token::Match(tok->linkAt(1)->previous(), "%name% ("))
8468  unknownMacroError(tok->linkAt(1)->previous());
8469 
8470  // UNKNOWN_MACRO(return)
8471  else if (Token::Match(tok, "%name% throw|return") && std::isupper(tok->str()[0]))
8472  unknownMacroError(tok);
8473 
8474  // Assign/increment/decrement literal
8475  else if (Token::Match(tok, "!!) %num%|%str%|%char% %assign%|++|--")) {
8476  if (!isCPP() || mSettings.standards.cpp < Standards::CPP20 || !Token::Match(tok->previous(), "%name% : %num% ="))
8477  syntaxError(tok, tok->next()->str() + " " + tok->strAt(2));
8478  }
8479  else if (Token::simpleMatch(tok, ") return") && !Token::Match(tok->link()->previous(), "if|while|for (")) {
8480  if (tok->link()->previous() && tok->link()->previous()->isUpperCaseName())
8481  unknownMacroError(tok->link()->previous());
8482  else
8483  syntaxError(tok);
8484  }
8485 
8486  if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for|switch")) { // if|while|for|switch (EXPR) { ... }
8487  if (tok->previous() && !Token::Match(tok->previous(), "%name%|:|;|{|}|)")) {
8488  if (Token::Match(tok->previous(), "[,(]")) {
8489  const Token *prev = tok->previous();
8490  while (prev && prev->str() != "(") {
8491  if (prev->str() == ")")
8492  prev = prev->link();
8493  prev = prev->previous();
8494  }
8495  if (prev && Token::Match(prev->previous(), "%name% ("))
8496  unknownMacroError(prev->previous());
8497  }
8498  if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if"))
8499  syntaxError(tok);
8500  }
8501  if (!Token::Match(tok->next(), "( !!)"))
8502  syntaxError(tok);
8503  if (tok->str() != "for") {
8504  if (isGarbageExpr(tok->next(), tok->linkAt(1), isCPP() && (mSettings.standards.cpp>=Standards::cppstd_t::CPP17)))
8505  syntaxError(tok);
8506  }
8507  }
8508 
8509  // keyword keyword
8510  if (tok->isKeyword() && nonConsecutiveKeywords.count(tok->str()) != 0) {
8511  if (Token::Match(tok, "%name% %name%") && nonConsecutiveKeywords.count(tok->next()->str()) == 1)
8512  syntaxError(tok);
8513  const Token* prev = tok;
8514  while (prev && prev->isName())
8515  prev = prev->previous();
8516  if (Token::Match(prev, "%op%|%num%|%str%|%char%")) {
8517  if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if") &&
8518  !Token::simpleMatch(tok->tokAt(-2), "extern \"C\"") &&
8519  !Token::simpleMatch(prev, "> typedef"))
8520  syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str()));
8521  }
8522  }
8523  }
8524 
8525  // invalid struct declaration
8526  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8527  if (Token::Match(tok, "struct|class|enum %name%| {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
8528  const Token *tok2 = tok->linkAt(tok->next()->isName() ? 2 : 1);
8529  if (Token::Match(tok2, "} %op%")) {
8530  tok2 = tok2->next();
8531  if (!Token::Match(tok2, "*|&|&&"))
8532  syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
8533  while (Token::Match(tok2, "*|&|&&"))
8534  tok2 = tok2->next();
8535  if (!Token::Match(tok2, "%name%"))
8536  syntaxError(tok2, "Unexpected token '" + (tok2 ? tok2->str() : "") + "'");
8537  }
8538  }
8539  if (Token::Match(tok, "enum : %num%| {"))
8540  syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'");
8541  }
8542 
8543  // Keywords in global scope
8544  static const std::unordered_set<std::string> nonGlobalKeywords{"break",
8545  "continue",
8546  "for",
8547  "goto",
8548  "if",
8549  "return",
8550  "switch",
8551  "while",
8552  "try",
8553  "catch"};
8554  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8555  if (tok->str() == "{")
8556  tok = tok->link();
8557  else if (tok->isKeyword() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
8558  syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
8559  }
8560 
8561  // case keyword must be inside switch
8562  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8563  if (Token::simpleMatch(tok, "switch (")) {
8564  if (Token::simpleMatch(tok->linkAt(1), ") {")) {
8565  tok = tok->linkAt(1)->linkAt(1);
8566  continue;
8567  }
8568  const Token *switchToken = tok;
8569  tok = tok->linkAt(1);
8570  if (!tok)
8571  syntaxError(switchToken);
8572  // Look for the end of the switch statement, i.e. the first semi-colon or '}'
8573  for (; tok; tok = tok->next()) {
8574  if (tok->str() == "{") {
8575  tok = tok->link();
8576  }
8577  if (Token::Match(tok, ";|}")) {
8578  // We're at the end of the switch block
8579  if (tok->str() == "}" && tok->strAt(-1) == ":") // Invalid case
8580  syntaxError(switchToken);
8581  break;
8582  }
8583  }
8584  if (!tok)
8585  break;
8586  } else if (tok->str() == "(") {
8587  tok = tok->link();
8588  } else if (tok->str() == "case") {
8589  syntaxError(tok);
8590  }
8591  }
8592 
8593  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8594  if (!Token::simpleMatch(tok, "for (")) // find for loops
8595  continue;
8596  // count number of semicolons
8597  int semicolons = 0, colons = 0;
8598  const Token* const startTok = tok;
8599  tok = tok->next()->link()->previous(); // find ")" of the for-loop
8600  // walk backwards until we find the beginning (startTok) of the for() again
8601  for (; tok != startTok; tok = tok->previous()) {
8602  if (tok->str() == ";") { // do the counting
8603  semicolons++;
8604  } else if (tok->str() == ":") {
8605  colons++;
8606  } else if (tok->str() == ")") { // skip pairs of ( )
8607  tok = tok->link();
8608  }
8609  }
8610  // if we have an invalid number of semicolons inside for( ), assume syntax error
8611  if (semicolons > 2)
8612  syntaxError(tok);
8613  if (semicolons == 1 && !(isCPP() && mSettings.standards.cpp >= Standards::CPP20))
8614  syntaxError(tok);
8615  if (semicolons == 0 && colons == 0)
8616  syntaxError(tok);
8617  }
8618 
8619  // Operators without operands..
8620  const Token *templateEndToken = nullptr;
8621  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8622  if (!templateEndToken) {
8623  if (tok->str() == "<" && isCPP())
8624  templateEndToken = tok->findClosingBracket();
8625  } else {
8626  if (templateEndToken == tok)
8627  templateEndToken = nullptr;
8628  if (Token::Match(tok, "> %cop%"))
8629  continue;
8630  }
8631  // skip C++ attributes [[...]]
8632  if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok))) {
8633  tok = skipCPPOrAlignAttribute(tok);
8634  continue;
8635  }
8636  {
8637  bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
8638  bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
8639  if (isCPP()) {
8640  match1 = match1 || Token::Match(tok, "throw|decltype|typeof");
8641  match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
8642  }
8643  if (match1 && !tok->isIncDecOp()) {
8644  match2 = match2 || Token::Match(tok->next(), "%assign%");
8645  }
8646  if (match1 && match2)
8647  syntaxError(tok);
8648  }
8649  if (Token::Match(tok, "%or%|%oror%|~|^|!|%comp%|+|-|/|%")) {
8650  std::string code;
8651  if (Token::Match(tok->next(), ")|]|}"))
8652  code = tok->str() + tok->next()->str();
8653  if (Token::simpleMatch(tok->next(), "( )"))
8654  code = tok->str() + "()";
8655  if (!code.empty()) {
8656  if (isC() || (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")))
8657  syntaxError(tok, code);
8658  }
8659  }
8660  if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
8661  syntaxError(tok);
8662  if (Token::Match(tok, "%assign% typename|class %assign%"))
8663  syntaxError(tok);
8664  if (Token::Match(tok, "%assign% [;)}]") && (!isCPP() || !Token::simpleMatch(tok->previous(), "operator")))
8665  syntaxError(tok);
8666  if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%"))
8667  syntaxError(tok);
8668  if (Token::Match(tok, "[;([{] %comp%|%oror%|%or%|%|/"))
8669  syntaxError(tok);
8670  if (Token::Match(tok, "%cop%|= ]") && !(isCPP() && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]")))
8671  syntaxError(tok);
8672  if (Token::Match(tok, "[+-] [;,)]}]") && !(isCPP() && Token::simpleMatch(tok->previous(), "operator")))
8673  syntaxError(tok);
8674  if (Token::simpleMatch(tok, ",") &&
8675  !Token::Match(tok->tokAt(-2), "[ = , &|%name%")) {
8676  if (Token::Match(tok->previous(), "(|[|{|<|%assign%|%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|::|sizeof"))
8677  syntaxError(tok);
8678  if (isCPP() && Token::Match(tok->previous(), "throw|decltype|typeof"))
8679  syntaxError(tok);
8680  if (Token::Match(tok->next(), ")|]|>|%assign%|%or%|%oror%|==|!=|/|>=|<=|&&"))
8681  syntaxError(tok);
8682  }
8683  if (Token::simpleMatch(tok, ".") &&
8684  !Token::simpleMatch(tok->previous(), ".") &&
8685  !Token::simpleMatch(tok->next(), ".") &&
8686  !Token::Match(tok->previous(), "{|, . %name% =|.|[|{") &&
8687  !Token::Match(tok->previous(), ", . %name%")) {
8688  if (!Token::Match(tok->previous(), "%name%|)|]|>|}"))
8689  syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8690  if (!Token::Match(tok->next(), "%name%|*|~"))
8691  syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8692  }
8693  if (Token::Match(tok, "[!|+-/%^~] )|]"))
8694  syntaxError(tok);
8695  if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
8696  syntaxError(tok, tok->str() + " " + tok->strAt(1));
8697  if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") ||
8698  (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator"))))
8699  syntaxError(tok);
8700  if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">")
8701  syntaxError(tok);
8702  if (Token::Match(tok, "^ %op%") && !Token::Match(tok->next(), "[>*+-!~]"))
8703  syntaxError(tok);
8704  if (Token::Match(tok, ": [)]=]"))
8705  syntaxError(tok);
8706  if (Token::Match(tok, "typedef [,;]"))
8707  syntaxError(tok);
8708  if (Token::Match(tok, "! %comp%"))
8709  syntaxError(tok);
8710  if (Token::Match(tok, "] %name%") && (!isCPP() || !(tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), "delete [")))) {
8711  if (tok->next()->isUpperCaseName())
8712  unknownMacroError(tok->next());
8713  else
8714  syntaxError(tok);
8715  }
8716 
8717  if (tok->link() && Token::Match(tok, "[([]") && (!tok->tokAt(-1) || !tok->tokAt(-1)->isControlFlowKeyword())) {
8718  const Token* const end = tok->link();
8719  for (const Token* inner = tok->next(); inner != end; inner = inner->next()) {
8720  if (inner->str() == "{")
8721  inner = inner->link();
8722  else if (inner->str() == ";" || (Token::simpleMatch(inner, ", ,") && (!isCPP() || !Token::simpleMatch(inner->previous(), "operator")))) {
8723  if (tok->tokAt(-1) && tok->tokAt(-1)->isUpperCaseName())
8724  unknownMacroError(tok->tokAt(-1));
8725  else
8726  syntaxError(inner);
8727  }
8728  }
8729  }
8730 
8731  if ((!isCPP() || !Token::simpleMatch(tok->previous(), "operator")) && Token::Match(tok, "[,;] ,"))
8732  syntaxError(tok);
8733  if (tok->str() == "typedef") {
8734  for (const Token* tok2 = tok->next(); tok2 && tok2->str() != ";"; tok2 = tok2->next()) {
8735  if (tok2->str() == "{") {
8736  tok2 = tok2->link();
8737  continue;
8738  }
8739  if (isUnevaluated(tok2)) {
8740  tok2 = tok2->linkAt(1);
8741  continue;
8742  }
8743  if (!tok2->next() || tok2->isControlFlowKeyword() || Token::Match(tok2, "typedef|static|."))
8744  syntaxError(tok);
8745  }
8746  }
8747  }
8748 
8749  // ternary operator without :
8750  if (const Token *ternaryOp = findUnmatchedTernaryOp(tokens(), nullptr))
8751  syntaxError(ternaryOp);
8752 
8753  // Code must not start with an arithmetical operand
8754  if (Token::Match(list.front(), "%cop%"))
8755  syntaxError(list.front());
8756 
8757  // Code must end with } ; ) NAME
8758  if (!Token::Match(list.back(), "%name%|;|}|)"))
8759  syntaxError(list.back());
8760  if (list.back()->str() == ")" && !Token::Match(list.back()->link()->previous(), "%name%|> ("))
8761  syntaxError(list.back());
8762  for (const Token *end = list.back(); end && end->isName(); end = end->previous()) {
8763  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"))
8764  syntaxError(list.back());
8765  }
8766  if ((list.back()->str()==")" || list.back()->str()=="}") && list.back()->previous() && list.back()->previous()->isControlFlowKeyword())
8767  syntaxError(list.back()->previous());
8768 
8769  // Garbage templates..
8770  if (isCPP()) {
8771  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8772  if (Token::simpleMatch(tok, "< >") && !(Token::Match(tok->tokAt(-1), "%name%") || (tok->tokAt(-1) && Token::Match(tok->tokAt(-2), "operator %op%"))))
8773  syntaxError(tok);
8774  if (!Token::simpleMatch(tok, "template <"))
8775  continue;
8776  if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) {
8777  if (tok->previous()->isUpperCaseName())
8778  unknownMacroError(tok->previous());
8779  else
8780  syntaxError(tok);
8781  }
8782  const Token * const tok1 = tok;
8783  tok = tok->next()->findClosingBracket();
8784  if (!tok)
8785  syntaxError(tok1);
8786  if (!Token::Match(tok, ">|>> ::|...| %name%") &&
8787  !Token::Match(tok, ">|>> [ [ %name%") &&
8788  !Token::Match(tok, "> >|*"))
8789  syntaxError(tok->next() ? tok->next() : tok1);
8790  }
8791  }
8792 
8793  // Objective C/C++
8794  for (const Token *tok = tokens(); tok; tok = tok->next()) {
8795  if (Token::Match(tok, "[;{}] [ %name% %name% ] ;"))
8796  syntaxError(tok->next());
8797  }
8798 }
8799 
8800 
8801 bool Tokenizer::isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
8802 {
8803  for (const Token *tok = start; tok != end; tok = tok->next()) {
8804  if (tok->isControlFlowKeyword())
8805  return true;
8806  if (!allowSemicolon && tok->str() == ";")
8807  return true;
8808  if (tok->str() == "{")
8809  tok = tok->link();
8810  }
8811  return false;
8812 }
8813 
8814 std::string Tokenizer::simplifyString(const std::string &source)
8815 {
8816  std::string str = source;
8817 
8818  for (std::string::size_type i = 0; i + 1U < str.size(); ++i) {
8819  if (str[i] != '\\')
8820  continue;
8821 
8822  int c = 'a'; // char
8823  int sz = 0; // size of stringdata
8824  if (str[i+1] == 'x') {
8825  sz = 2;
8826  while (sz < 4 && std::isxdigit((unsigned char)str[i+sz]))
8827  sz++;
8828  if (sz > 2) {
8829  std::istringstream istr(str.substr(i+2, sz-2));
8830  istr >> std::hex >> c;
8831  }
8832  } else if (MathLib::isOctalDigit(str[i+1])) {
8833  sz = 2;
8834  while (sz < 4 && MathLib::isOctalDigit(str[i+sz]))
8835  sz++;
8836  std::istringstream istr(str.substr(i+1, sz-1));
8837  istr >> std::oct >> c;
8838  str = str.replace(i, sz, std::string(1U, (char)c));
8839  continue;
8840  }
8841 
8842  if (sz <= 2)
8843  i++;
8844  else if (i+sz < str.size())
8845  str.replace(i, sz, std::string(1U, (char)c));
8846  else
8847  str.replace(i, str.size() - i - 1U, "a");
8848  }
8849 
8850  return str;
8851 }
8852 
8854 {
8855  if (!isCPP())
8856  return;
8857 
8858  for (Token * tok = list.front(); tok; tok = tok->next()) {
8859  if (!Token::Match(tok, "try {|:"))
8860  continue;
8861  if (!isFunctionHead(tok->previous(), "try"))
8862  continue;
8863 
8864  Token* tryStartToken = skipInitializerList(tok->next());
8865 
8866  if (!Token::simpleMatch(tryStartToken, "{"))
8867  syntaxError(tryStartToken, "Invalid function-try-catch block code. Did not find '{' for try body.");
8868 
8869  // find the end of the last catch block
8870  Token * const tryEndToken = tryStartToken->link();
8871  Token * endToken = tryEndToken;
8872  while (Token::simpleMatch(endToken, "} catch (")) {
8873  endToken = endToken->linkAt(2)->next();
8874  if (!endToken)
8875  break;
8876  if (endToken->str() != "{") {
8877  endToken = nullptr;
8878  break;
8879  }
8880  endToken = endToken->link();
8881  }
8882  if (!endToken || endToken == tryEndToken)
8883  continue;
8884 
8885  tok->previous()->insertToken("{");
8886  endToken->insertToken("}");
8887  Token::createMutualLinks(tok->previous(), endToken->next());
8888  }
8889 }
8890 
8891 static bool isAnonymousEnum(const Token* tok)
8892 {
8893  if (!Token::Match(tok, "enum {|:"))
8894  return false;
8895  if (tok->index() > 2 && Token::Match(tok->tokAt(-3), "using %name% ="))
8896  return false;
8897  const Token* end = tok->next();
8898  if (end->str() == ":") {
8899  end = end->next();
8900  while (Token::Match(end, "%name%|::"))
8901  end = end->next();
8902  }
8903  return end && Token::Match(end->link(), "} (| %type%| )| [,;[({=]");
8904 }
8905 
8907 {
8908  const bool cpp = isCPP();
8909 
8910  // A counter that is used when giving unique names for anonymous structs.
8911  int count = 0;
8912 
8913  // Add names for anonymous structs
8914  for (Token *tok = list.front(); tok; tok = tok->next()) {
8915  if (!tok->isName())
8916  continue;
8917  // check for anonymous struct/union
8918  if (Token::Match(tok, "struct|union {")) {
8919  if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) {
8920  tok->insertToken("Anonymous" + std::to_string(count++));
8921  }
8922  }
8923  // check for derived anonymous class/struct
8924  else if (cpp && Token::Match(tok, "class|struct :")) {
8925  const Token *tok1 = Token::findsimplematch(tok, "{");
8926  if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) {
8927  tok->insertToken("Anonymous" + std::to_string(count++));
8928  }
8929  }
8930  // check for anonymous enum
8931  else if (isAnonymousEnum(tok)) {
8932  Token *start = tok->strAt(1) == ":" ? tok->linkAt(3) : tok->linkAt(1);
8933  if (start && Token::Match(start->next(), "( %type% )")) {
8934  start->next()->link()->deleteThis();
8935  start->next()->deleteThis();
8936  }
8937  tok->insertToken("Anonymous" + std::to_string(count++));
8938  }
8939  }
8940 
8941  // "{" token for current scope
8942  std::stack<const Token*> scopeStart;
8943  const Token* functionEnd = nullptr;
8944 
8945  for (Token *tok = list.front(); tok; tok = tok->next()) {
8946 
8947  // check for start of scope and determine if it is in a function
8948  if (tok->str() == "{") {
8949  scopeStart.push(tok);
8950  if (!functionEnd && Token::Match(tok->previous(), "const|)"))
8951  functionEnd = tok->link();
8952  }
8953 
8954  // end of scope
8955  else if (tok->str() == "}") {
8956  if (!scopeStart.empty())
8957  scopeStart.pop();
8958  if (tok == functionEnd)
8959  functionEnd = nullptr;
8960  }
8961 
8962  // check for named struct/union
8963  else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
8964  Token *start = tok;
8965  while (Token::Match(start->previous(), "%type%"))
8966  start = start->previous();
8967  const Token * const type = tok->next();
8968  Token *next = tok->tokAt(2);
8969 
8970  while (next && !Token::Match(next, "[{;]"))
8971  next = next->next();
8972  if (!next || next->str() == ";")
8973  continue;
8974  Token* after = next->link();
8975  if (!after)
8976  break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8977 
8978  // check for named type
8979  if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
8980  after->insertToken(";");
8981  after = after->next();
8982  while (!Token::Match(start, "struct|class|union|enum")) {
8983  after->insertToken(start->str());
8984  after = after->next();
8985  start->deleteThis();
8986  }
8987  tok = start;
8988  if (!after)
8989  break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8990  after->insertToken(type->str());
8991  if (start->str() != "class") {
8992  after->insertToken(start->str());
8993  after = after->next();
8994  }
8995 
8996  after = after->tokAt(2);
8997 
8998  if (Token::Match(after, "( %type% )")) {
8999  after->link()->deleteThis();
9000  after->deleteThis();
9001  }
9002 
9003  // check for initialization
9004  if (Token::Match(after, "%any% (|{")) {
9005  after->insertToken("=");
9006  after = after->next();
9007  const bool isEnum = start->str() == "enum";
9008  if (!isEnum && cpp) {
9009  after->insertToken(type->str());
9010  after = after->next();
9011  }
9012 
9013  if (isEnum) {
9014  if (Token::Match(after->next(), "{ !!}")) {
9015  after->next()->str("(");
9016  after->linkAt(1)->str(")");
9017  }
9018  }
9019  }
9020  }
9021  }
9022 
9023  // check for anonymous struct/union
9024  else {
9025  // unnamed anonymous struct/union so possibly remove it
9026  bool done = false;
9027  while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
9028  done = true;
9029 
9030  // is this a class/struct/union scope?
9031  bool isClassStructUnionScope = false;
9032  if (!scopeStart.empty()) {
9033  for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
9034  if (Token::Match(tok2, "class|struct|union")) {
9035  isClassStructUnionScope = true;
9036  break;
9037  }
9038  }
9039  }
9040 
9041  // remove unnamed anonymous struct/union
9042  // * not in class/struct/union scopes
9043  if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
9044  tok->linkAt(1)->previous()->deleteNext(2);
9045  tok->deleteNext();
9046  tok->deleteThis();
9047  done = false;
9048  }
9049  }
9050  }
9051  }
9052 }
9053 
9055 {
9056  const bool windows = mSettings.platform.isWindows();
9057 
9058  for (Token *tok = list.front(); tok; tok = tok->next()) {
9059  while (Token::Match(tok, "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near") || (windows && Token::Match(tok, "WINAPI|APIENTRY|CALLBACK"))) {
9060  tok->deleteThis();
9061  }
9062  }
9063 }
9064 
9065 static bool isAttribute(const Token* tok, bool gcc) {
9066  return gcc ? Token::Match(tok, "__attribute__|__attribute (") : Token::Match(tok, "__declspec|_declspec (");
9067 }
9068 
9069 static Token* getTokenAfterAttributes(Token* tok, bool gccattr) {
9070  Token* after = tok;
9071  while (isAttribute(after, gccattr))
9072  after = after->linkAt(1)->next();
9073  return after;
9074 }
9075 
9076 Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
9077  if (!Token::Match(tok, "%name% ("))
9078  return nullptr;
9079  Token* const after = getTokenAfterAttributes(tok, gccattr);
9080  if (!after)
9081  syntaxError(tok);
9082 
9083  if (Token::Match(after, "%name%|*|&|(")) {
9084  Token *ftok = after;
9085  while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
9086  if (ftok->str() == "<") {
9087  ftok = ftok->findClosingBracket();
9088  if (!ftok)
9089  break;
9090  }
9091  ftok = ftok->next();
9092  }
9093  if (Token::simpleMatch(ftok, "( *"))
9094  ftok = ftok->tokAt(2);
9095  if (Token::Match(ftok, "%name% (|)"))
9096  return ftok;
9097  } else if (Token::Match(after, "[;{=:]")) {
9098  Token *prev = tok->previous();
9099  while (Token::Match(prev, "%name%"))
9100  prev = prev->previous();
9101  if (Token::simpleMatch(prev, ")")) {
9102  if (Token::Match(prev->link()->previous(), "%name% ("))
9103  return prev->link()->previous();
9104  if (Token::Match(prev->link()->tokAt(-2), "%name% ) ("))
9105  return prev->link()->tokAt(-2);
9106  }
9107  if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
9108  return prev->link()->tokAt(-2);
9109  if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
9110  return tok->previous();
9111  }
9112  return nullptr;
9113 }
9114 
9116 {
9117  for (Token *tok = list.front(); tok; tok = tok->next()) {
9118  while (isAttribute(tok, false)) {
9119  if (Token::Match(tok->tokAt(2), "noreturn|nothrow|dllexport")) {
9120  Token *functok = getAttributeFuncTok(tok, false);
9121  if (functok) {
9122  if (tok->strAt(2) == "noreturn")
9123  functok->isAttributeNoreturn(true);
9124  else if (tok->strAt(2) == "nothrow")
9125  functok->isAttributeNothrow(true);
9126  else
9127  functok->isAttributeExport(true);
9128  }
9129  } else if (tok->strAt(2) == "property")
9130  tok->next()->link()->insertToken("__property");
9131 
9132  Token::eraseTokens(tok, tok->next()->link()->next());
9133  tok->deleteThis();
9134  }
9135  }
9136 }
9137 
9139 {
9140  for (Token *tok = list.front(); tok; tok = tok->next()) {
9141  if (!tok->isKeyword() && Token::Match(tok, "%type% (") && !mSettings.library.isNotLibraryFunction(tok)) {
9142  if (mSettings.library.isFunctionConst(tok->str(), true))
9143  tok->isAttributePure(true);
9144  if (mSettings.library.isFunctionConst(tok->str(), false))
9145  tok->isAttributeConst(true);
9146  }
9147  while (isAttribute(tok, true)) {
9148  Token *functok = getAttributeFuncTok(tok, true);
9149 
9150  for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
9151  if (Token::Match(attr, "%name% ("))
9152  attr = attr->linkAt(1);
9153 
9154  if (Token::Match(attr, "[(,] constructor|__constructor__ [,()]")) {
9155  if (!functok)
9156  syntaxError(tok);
9157  functok->isAttributeConstructor(true);
9158  }
9159 
9160  else if (Token::Match(attr, "[(,] destructor|__destructor__ [,()]")) {
9161  if (!functok)
9162  syntaxError(tok);
9163  functok->isAttributeDestructor(true);
9164  }
9165 
9166  else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
9167  Token *vartok = nullptr;
9168  Token *after = getTokenAfterAttributes(tok, true);
9169 
9170  // check if after variable name
9171  if (Token::Match(after, ";|=")) {
9172  Token *prev = tok->previous();
9173  while (Token::simpleMatch(prev, "]"))
9174  prev = prev->link()->previous();
9175  if (Token::Match(prev, "%type%"))
9176  vartok = prev;
9177  }
9178 
9179  // check if before variable name
9180  else if (Token::Match(after, "%type%"))
9181  vartok = after;
9182 
9183  if (vartok) {
9184  const std::string &attribute(attr->next()->str());
9185  if (attribute.find("unused") != std::string::npos)
9186  vartok->isAttributeUnused(true);
9187  else
9188  vartok->isAttributeUsed(true);
9189  }
9190  }
9191 
9192  else if (Token::Match(attr, "[(,] pure|__pure__|const|__const__|noreturn|__noreturn__|nothrow|__nothrow__|warn_unused_result [,)]")) {
9193  if (!functok)
9194  syntaxError(tok);
9195 
9196  const std::string &attribute(attr->next()->str());
9197  if (attribute.find("pure") != std::string::npos)
9198  functok->isAttributePure(true);
9199  else if (attribute.find("const") != std::string::npos)
9200  functok->isAttributeConst(true);
9201  else if (attribute.find("noreturn") != std::string::npos)
9202  functok->isAttributeNoreturn(true);
9203  else if (attribute.find("nothrow") != std::string::npos)
9204  functok->isAttributeNothrow(true);
9205  else if (attribute.find("warn_unused_result") != std::string::npos)
9206  functok->isAttributeNodiscard(true);
9207  }
9208 
9209  else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
9210  tok->previous()->isAttributePacked(true);
9211 
9212  else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )"))
9213  functok->isAttributeExport(true);
9214  }
9215 
9216  Token::eraseTokens(tok, tok->linkAt(1)->next());
9217  tok->deleteThis();
9218  }
9219  }
9220 }
9221 
9223 {
9224  for (Token *tok = list.front(); tok; tok = tok->next()) {
9225  if (tok->str() != "(")
9226  continue;
9227  if (!tok->previous())
9228  continue;
9229  const std::string &attr = tok->previous()->str();
9230  if (!startsWith(attr, "__cppcheck_"))
9231  continue;
9232  if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
9233  continue;
9234 
9235  Token *vartok = tok->link();
9236  while (Token::Match(vartok->next(), "%name%|*|&|::")) {
9237  vartok = vartok->next();
9238  if (Token::Match(vartok, "%name% (") && startsWith(vartok->str(),"__cppcheck_"))
9239  vartok = vartok->linkAt(1);
9240  }
9241 
9242  if (vartok->isName()) {
9243  if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
9244  vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9245  MathLib::toBigNumber(tok->next()->str()));
9246  else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
9247  vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9248  MathLib::toBigNumber(tok->next()->str()));
9249  }
9250 
9251  // Delete cppcheck attribute..
9252  if (tok->tokAt(-2)) {
9253  tok = tok->tokAt(-2);
9254  Token::eraseTokens(tok, tok->linkAt(2)->next());
9255  } else {
9256  tok = tok->previous();
9257  Token::eraseTokens(tok, tok->linkAt(1)->next());
9258  tok->str(";");
9259  }
9260  }
9261 }
9262 
9264 {
9266  return;
9267 
9268  for (Token *tok = list.front(); tok;) {
9269  if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
9270  tok = tok->next();
9271  continue;
9272  }
9273  if (isCPPAttribute(tok)) {
9274  if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
9275  Token * head = skipCPPOrAlignAttribute(tok)->next();
9276  while (isCPPAttribute(head) || isAlignAttribute(head))
9277  head = skipCPPOrAlignAttribute(head)->next();
9278  while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
9279  head = head->next();
9280  if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9281  head->previous()->isAttributeNoreturn(true);
9282  }
9283  } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
9284  Token * head = skipCPPOrAlignAttribute(tok)->next();
9285  while (isCPPAttribute(head) || isAlignAttribute(head))
9286  head = skipCPPOrAlignAttribute(head)->next();
9287  while (Token::Match(head, "%name%|::|*|&|<|>|,"))
9288  head = head->next();
9289  if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9290  head->previous()->isAttributeNodiscard(true);
9291  }
9292  } else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
9293  Token* head = skipCPPOrAlignAttribute(tok)->next();
9294  while (isCPPAttribute(head) || isAlignAttribute(head))
9295  head = skipCPPOrAlignAttribute(head)->next();
9296  head->isAttributeMaybeUnused(true);
9297  } else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
9298  const Token *vartok = tok->tokAt(4);
9299  if (vartok->str() == ":")
9300  vartok = vartok->next();
9301  Token *argtok = tok->tokAt(-2);
9302  while (argtok && argtok->str() != "(") {
9303  if (argtok->str() == vartok->str())
9304  break;
9305  if (argtok->str() == ")")
9306  argtok = argtok->link();
9307  argtok = argtok->previous();
9308  }
9309  if (argtok && argtok->str() == vartok->str()) {
9310  if (vartok->next()->str() == ">=")
9311  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9312  MathLib::toBigNumber(vartok->strAt(2)));
9313  else if (vartok->next()->str() == ">")
9314  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9315  MathLib::toBigNumber(vartok->strAt(2)) + 1);
9316  else if (vartok->next()->str() == "<=")
9317  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9318  MathLib::toBigNumber(vartok->strAt(2)));
9319  else if (vartok->next()->str() == "<")
9320  argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9321  MathLib::toBigNumber(vartok->strAt(2)) - 1);
9322  }
9323  }
9324  } else {
9325  if (Token::simpleMatch(tok, "alignas (")) {
9326  // alignment requirements could be checked here
9327  }
9328  }
9329  Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
9330  tok->deleteThis();
9331  }
9332 }
9333 
9335 {
9337  for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
9338  if (Token::simpleMatch(tok, "<= >")) {
9339  tok->str("<=>");
9340  tok->deleteNext();
9341  }
9342  }
9343  }
9344 }
9345 
9346 static const std::unordered_set<std::string> keywords = {
9347  "inline"
9348  , "_inline"
9349  , "__inline"
9350  , "__forceinline"
9351  , "register"
9352  , "__restrict"
9353  , "__restrict__"
9354  , "__thread"
9355 };
9356 // Remove "inline", "register", "restrict", "override", "static" and "constexpr"
9357 // "restrict" keyword
9358 // - New to 1999 ANSI/ISO C standard
9359 // - Not in C++ standard yet
9361 {
9362  // FIXME: There is a risk that "keywords" are removed by mistake. This
9363  // code should be fixed so it doesn't remove variables etc. Nonstandard
9364  // keywords should be defined with a library instead. For instance the
9365  // linux kernel code at least uses "_inline" as struct member name at some
9366  // places.
9367 
9368  const bool c99 = isC() && mSettings.standards.c >= Standards::C99;
9369  const bool cpp11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
9370  const bool cpp20 = isCPP() && mSettings.standards.cpp >= Standards::CPP20;
9371 
9372  for (Token *tok = list.front(); tok; tok = tok->next()) {
9373  if (keywords.find(tok->str()) != keywords.end()) {
9374  // Don't remove struct members
9375  if (!Token::simpleMatch(tok->previous(), ".")) {
9376  const bool isinline = (tok->str().find("inline") != std::string::npos);
9377  const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
9378  if (isinline || isrestrict) {
9379  for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9380  if (isinline)
9381  temp->isInline(true);
9382  if (isrestrict)
9383  temp->isRestrict(true);
9384  }
9385  }
9386  tok->deleteThis(); // Simplify..
9387  }
9388  }
9389 
9390  if (isC() || mSettings.standards.cpp == Standards::CPP03) {
9391  if (tok->str() == "auto")
9392  tok->deleteThis();
9393  }
9394 
9395  // simplify static keyword:
9396  // void foo( int [ static 5 ] ); ==> void foo( int [ 5 ] );
9397  if (Token::Match(tok, "[ static %num%"))
9398  tok->deleteNext();
9399 
9400  if (c99) {
9401  auto getTypeTokens = [tok]() {
9402  std::vector<Token*> ret;
9403  for (Token *temp = tok; Token::Match(temp, "%name%"); temp = temp->previous()) {
9404  if (!temp->isKeyword())
9405  ret.emplace_back(temp);
9406  }
9407  for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9408  if (!temp->isKeyword())
9409  ret.emplace_back(temp);
9410  }
9411  return ret;
9412  };
9413 
9414  if (tok->str() == "restrict") {
9415  for (Token* temp: getTypeTokens())
9416  temp->isRestrict(true);
9417  tok->deleteThis();
9418  }
9419 
9421  while (tok->str() == "_Atomic") {
9422  for (Token* temp: getTypeTokens())
9423  temp->isAtomic(true);
9424  tok->deleteThis();
9425  }
9426  }
9427  }
9428 
9429  else if (cpp11) {
9430  if (cpp20 && tok->str() == "consteval") {
9431  tok->originalName(tok->str());
9432  tok->str("constexpr");
9433  } else if (cpp20 && tok->str() == "constinit") {
9434  tok->deleteThis();
9435  }
9436 
9437  // final:
9438  // 1) struct name final { }; <- struct is final
9439  if (Token::Match(tok->previous(), "struct|class|union %type%")) {
9440  Token* finalTok = tok->next();
9441  if (tok->isUpperCaseName() && Token::Match(finalTok, "%type%") && finalTok->str() != "final") {
9442  tok = finalTok;
9443  finalTok = finalTok->next();
9444  }
9445  if (Token::simpleMatch(finalTok, "<")) { // specialization
9446  finalTok = finalTok->findClosingBracket();
9447  if (finalTok)
9448  finalTok = finalTok->next();
9449  }
9450  if (Token::Match(finalTok, "final [:{]")) {
9451  finalTok->deleteThis();
9452  tok->previous()->isFinalType(true);
9453  }
9454  }
9455 
9456  // noexcept -> noexcept(true)
9457  // 2) void f() noexcept; -> void f() noexcept(true);
9458  else if (Token::Match(tok, ") const|override|final| noexcept :|{|;|,|const|override|final")) {
9459  // Insertion is done in inverse order
9460  // The brackets are linked together accordingly afterwards
9461  Token* tokNoExcept = tok->next();
9462  while (tokNoExcept->str() != "noexcept")
9463  tokNoExcept = tokNoExcept->next();
9464  tokNoExcept->insertToken(")");
9465  Token * braceEnd = tokNoExcept->next();
9466  tokNoExcept->insertToken("true");
9467  tokNoExcept->insertToken("(");
9468  Token * braceStart = tokNoExcept->next();
9469  tok = tok->tokAt(3);
9470  Token::createMutualLinks(braceStart, braceEnd);
9471  }
9472 
9473  // 3) thread_local -> static
9474  // on single thread thread_local has the effect of static
9475  else if (tok->str() == "thread_local") {
9476  tok->originalName(tok->str());
9477  tok->str("static");
9478  }
9479  }
9480  }
9481 }
9482 
9483 static Token* setTokenDebug(Token* start, TokenDebug td)
9484 {
9485  if (!start->link())
9486  return nullptr;
9487  Token* end = start->link();
9488  start->deleteThis();
9489  for (Token* tok = start; tok != end; tok = tok->next()) {
9490  tok->setTokenDebug(td);
9491  }
9492  end->deleteThis();
9493  return end;
9494 }
9495 
9497 {
9499  return;
9500  static const std::unordered_map<std::string, TokenDebug> m = {{"debug_valueflow", TokenDebug::ValueFlow},
9501  {"debug_valuetype", TokenDebug::ValueType}};
9502  for (Token* tok = list.front(); tok; tok = tok->next()) {
9503  if (!Token::Match(tok, "%name% ("))
9504  continue;
9505  auto it = m.find(tok->str());
9506  if (it != m.end()) {
9507  tok->deleteThis();
9508  tok = setTokenDebug(tok, it->second);
9509  }
9510  }
9511 }
9512 
9514 {
9515  for (Token *tok = list.front(); tok; tok = tok->next()) {
9516  if (Token::Match(tok, "[;{}] %name% = ( {")) {
9517  const std::string &varname = tok->next()->str();
9518 
9519  // goto the "} )"
9520  int indentlevel = 0;
9521  Token *tok2 = tok;
9522  while (nullptr != (tok2 = tok2->next())) {
9523  if (Token::Match(tok2, "(|{"))
9524  ++indentlevel;
9525  else if (Token::Match(tok2, ")|}")) {
9526  if (indentlevel <= 2)
9527  break;
9528  --indentlevel;
9529  } else if (indentlevel == 2 && tok2->str() == varname && Token::Match(tok2->previous(), "%type%|*"))
9530  // declaring variable in inner scope with same name as lhs variable
9531  break;
9532  }
9533  if (indentlevel == 2 && Token::simpleMatch(tok2, "} )")) {
9534  tok2 = tok2->tokAt(-3);
9535  if (Token::Match(tok2, "[;{}] %num%|%name% ;")) {
9536  tok2->insertToken("=");
9537  tok2->insertToken(tok->next()->str());
9538  tok2->next()->varId(tok->next()->varId());
9539  tok->deleteNext(3);
9540  tok2->tokAt(5)->deleteNext();
9541  }
9542  }
9543  }
9544  }
9545 }
9546 
9547 // Remove __asm..
9549 {
9550  std::string instruction;
9551  for (Token *tok = list.front(); tok; tok = tok->next()) {
9552  if (Token::Match(tok, "__asm|_asm|asm {") &&
9553  tok->next()->link()->next()) {
9554  instruction = tok->tokAt(2)->stringifyList(tok->next()->link());
9555  Token::eraseTokens(tok, tok->next()->link()->next());
9556  }
9557 
9558  else if (Token::Match(tok, "asm|__asm|__asm__ volatile|__volatile|__volatile__| (")) {
9559  // Goto "("
9560  Token *partok = tok->next();
9561  if (partok->str() != "(")
9562  partok = partok->next();
9563  instruction = partok->next()->stringifyList(partok->link());
9564  Token::eraseTokens(tok, partok->link()->next());
9565  }
9566 
9567  else if (Token::Match(tok, "_asm|__asm")) {
9568  Token *endasm = tok->next();
9569  const Token *firstSemiColon = nullptr;
9570  int comment = 0;
9571  while (Token::Match(endasm, "%num%|%name%|,|:|;") || (endasm && endasm->linenr() == comment)) {
9572  if (Token::Match(endasm, "_asm|__asm|__endasm"))
9573  break;
9574  if (endasm->str() == ";") {
9575  comment = endasm->linenr();
9576  if (!firstSemiColon)
9577  firstSemiColon = endasm;
9578  }
9579  endasm = endasm->next();
9580  }
9581  if (Token::simpleMatch(endasm, "__endasm")) {
9582  instruction = tok->next()->stringifyList(endasm);
9583  Token::eraseTokens(tok, endasm->next());
9584  if (!Token::simpleMatch(tok->next(), ";"))
9585  tok->insertToken(";");
9586  } else if (firstSemiColon) {
9587  instruction = tok->next()->stringifyList(firstSemiColon);
9588  Token::eraseTokens(tok, firstSemiColon);
9589  } else if (!endasm) {
9590  instruction = tok->next()->stringifyList(endasm);
9591  Token::eraseTokens(tok, endasm);
9592  tok->insertToken(";");
9593  } else
9594  continue;
9595  }
9596 
9597  else
9598  continue;
9599 
9600  if (Token::Match(tok->previous(), ") %name% %name% (")) {
9601  tok->deleteThis();
9602  continue;
9603  }
9604 
9605  // insert "asm ( "instruction" )"
9606  tok->str("asm");
9607  if (tok->strAt(1) != ";" && tok->strAt(1) != "{")
9608  tok->insertToken(";");
9609  tok->insertToken(")");
9610  tok->insertToken("\"" + instruction + "\"");
9611  tok->insertToken("(");
9612 
9613  tok = tok->next();
9614  Token::createMutualLinks(tok, tok->tokAt(2));
9615 
9616  //move the new tokens in the same line as ";" if available
9617  tok = tok->tokAt(2);
9618  if (tok->next() && tok->next()->str() == ";" &&
9619  tok->next()->linenr() != tok->linenr()) {
9620  const int endposition = tok->next()->linenr();
9621  tok = tok->tokAt(-3);
9622  for (int i = 0; i < 4; ++i) {
9623  tok = tok->next();
9624  tok->linenr(endposition);
9625  }
9626  }
9627  }
9628 }
9629 
9631 {
9632  // Block declarations: ^{}
9633  // A C extension used to create lambda like closures.
9634 
9635  // Put ^{} statements in asm()
9636  for (Token *tok = list.front(); tok; tok = tok->next()) {
9637  if (tok->str() != "^")
9638  continue;
9639 
9640  if (Token::simpleMatch(tok, "^ {") || (Token::simpleMatch(tok->linkAt(1), ") {") && tok->strAt(-1) != "operator")) {
9641  Token * start = tok;
9642  while (start && !Token::Match(start, "[,(;{}=]")) {
9643  if (start->link() && Token::Match(start, ")|]|>"))
9644  start = start->link();
9645  start = start->previous();
9646  }
9647 
9648  const Token *last = tok->next()->link();
9649  if (Token::simpleMatch(last, ") {"))
9650  last = last->linkAt(1);
9651  last = last->next();
9652  while (last && !Token::Match(last, "%cop%|,|;|{|}|)")) {
9653  if (Token::Match(last, "(|["))
9654  last = last->link();
9655  last = last->next();
9656  }
9657 
9658  if (start && last) {
9659  std::string asmcode;
9660  while (start->next() != last) {
9661  asmcode += start->next()->str();
9662  start->deleteNext();
9663  }
9664  if (last->str() == "}")
9665  start->insertToken(";");
9666  start->insertToken(")");
9667  start->insertToken("\"" + asmcode + "\"");
9668  start->insertToken("(");
9669  start->insertToken("asm");
9670  start->tokAt(2)->link(start->tokAt(4));
9671  start->tokAt(4)->link(start->tokAt(2));
9672  tok = start->tokAt(4);
9673  }
9674  }
9675  }
9676 }
9677 
9678 void Tokenizer::simplifyAt()
9679 {
9680  std::set<std::string> var;
9681 
9682  for (Token *tok = list.front(); tok; tok = tok->next()) {
9683  if (Token::Match(tok, "%name%|] @ %num%|%name%|%str%|(")) {
9684  const Token *end = tok->tokAt(2);
9685  if (end->isLiteral())
9686  end = end->next();
9687  else if (end->str() == "(") {
9688  int par = 0;
9689  while ((end = end->next()) != nullptr) {
9690  if (end->str() == "(")
9691  par++;
9692  else if (end->str() == ")") {
9693  if (--par < 0)
9694  break;
9695  }
9696  }
9697  end = end ? end->next() : nullptr;
9698  } else if (var.find(end->str()) != var.end())
9699  end = end->next();
9700  else
9701  continue;
9702 
9703  if (Token::Match(end, ": %num% ;"))
9704  end = end->tokAt(2);
9705 
9706  if (Token::Match(end, "[;=]")) {
9707  if (tok->isName())
9708  var.insert(tok->str());
9709  tok->isAtAddress(true);
9710  Token::eraseTokens(tok, end);
9711  }
9712  }
9713 
9714  // keywords in compiler from cosmic software for STM8
9715  // TODO: Should use platform configuration.
9716  if (Token::Match(tok, "@ builtin|eeprom|far|inline|interrupt|near|noprd|nostack|nosvf|packed|stack|svlreg|tiny|vector")) {
9717  tok->str(tok->next()->str() + "@");
9718  tok->deleteNext();
9719  }
9720  }
9721 }
9722 
9723 // Simplify bitfields
9725 {
9726  bool goback = false;
9727  for (Token *tok = list.front(); tok; tok = tok->next()) {
9728  if (goback) {
9729  goback = false;
9730  tok = tok->previous();
9731  }
9732  Token *last = nullptr;
9733 
9734  if (Token::simpleMatch(tok, "for ("))
9735  tok = tok->linkAt(1);
9736 
9737  if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
9738  continue;
9739 
9740  bool isEnum = false;
9741  if (tok->str() == "}") {
9742  const Token *type = tok->link()->previous();
9743  while (type && type->isName()) {
9744  if (type->str() == "enum") {
9745  isEnum = true;
9746  break;
9747  }
9748  type = type->previous();
9749  }
9750  }
9751 
9752  if (Token::Match(tok->next(), "const| %type% %name% :") &&
9753  !Token::Match(tok->next(), "case|public|protected|private|class|struct") &&
9754  !Token::simpleMatch(tok->tokAt(2), "default :")) {
9755  Token *tok1 = (tok->next()->str() == "const") ? tok->tokAt(3) : tok->tokAt(2);
9756  if (Token::Match(tok1, "%name% : %num% [;=]"))
9757  tok1->setBits(MathLib::toBigNumber(tok1->strAt(2)));
9758  if (tok1 && tok1->tokAt(2) &&
9759  (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
9760  !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
9761  while (tok1->next() && !Token::Match(tok1->next(), "[;,)]{}=]")) {
9762  if (Token::Match(tok1->next(), "[([]"))
9763  Token::eraseTokens(tok1, tok1->next()->link());
9764  tok1->deleteNext();
9765  }
9766 
9767  last = tok1->next();
9768  }
9769  } else if (isEnum && Token::Match(tok, "} %name%| : %num% ;")) {
9770  if (tok->next()->str() == ":") {
9771  tok->deleteNext(2);
9772  tok->insertToken("Anonymous");
9773  } else {
9774  tok->next()->deleteNext(2);
9775  }
9776  } else if (Token::Match(tok->next(), "const| %type% : %num%|%bool% ;") &&
9777  tok->next()->str() != "default") {
9778  const int offset = (tok->next()->str() == "const") ? 1 : 0;
9779  if (!Token::Match(tok->tokAt(3 + offset), "[{};()]")) {
9780  tok->deleteNext(4 + offset);
9781  goback = true;
9782  }
9783  }
9784 
9785  if (last && last->str() == ",") {
9786  Token * tok1 = last;
9787  tok1->str(";");
9788 
9789  const Token *const tok2 = tok->next();
9790  tok1->insertToken(tok2->str());
9791  tok1 = tok1->next();
9792  tok1->isSigned(tok2->isSigned());
9793  tok1->isUnsigned(tok2->isUnsigned());
9794  tok1->isLong(tok2->isLong());
9795  }
9796  }
9797 }
9798 
9799 static bool isStdContainerOrIterator(const Token* tok, const Settings& settings)
9800 {
9801  const Library::Container* ctr = settings.library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true);
9802  return ctr && startsWith(ctr->startPattern, "std ::");
9803 }
9804 
9805 static bool isStdSmartPointer(const Token* tok, const Settings& settings)
9806 {
9807  const Library::SmartPointer* ptr = settings.library.detectSmartPointer(tok, /*withoutStd*/ true);
9808  return ptr && startsWith(ptr->name, "std::");
9809 }
9810 
9811 // Add std:: in front of std classes, when using namespace std; was given
9813 {
9814  if (!isCPP())
9815  return;
9816 
9817  std::set<std::string> userFunctions;
9818 
9819  for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
9820  bool insert = false;
9821  if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
9822  skipEnumBody(tok);
9823  }
9824  if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId())
9825  continue;
9826  if (Token::Match(tok->previous(), ".|::|namespace"))
9827  continue;
9828  if (Token::simpleMatch(tok->next(), "(")) {
9829  if (isFunctionHead(tok->next(), "{"))
9830  userFunctions.insert(tok->str());
9831  else if (isFunctionHead(tok->next(), ";")) {
9832  const Token *start = tok;
9833  while (Token::Match(start->previous(), "%type%|*|&"))
9834  start = start->previous();
9835  if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
9836  userFunctions.insert(tok->str());
9837  }
9838  if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str()))
9839  insert = true;
9840  } else if (Token::simpleMatch(tok->next(), "<") &&
9841  (isStdContainerOrIterator(tok, mSettings) || isStdSmartPointer(tok, mSettings)))
9842  insert = true;
9843  else if (mSettings.library.hasAnyTypeCheck("std::" + tok->str()) ||
9844  mSettings.library.podtype("std::" + tok->str()) ||
9845  isStdContainerOrIterator(tok, mSettings))
9846  insert = true;
9847 
9848  if (insert) {
9849  tok->previous()->insertToken("std");
9850  tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
9851  tok->previous()->fileIndex(tok->fileIndex());
9852  tok->previous()->insertToken("::");
9853  }
9854  }
9855 
9856  for (Token* tok = list.front(); tok; tok = tok->next()) {
9857  if (Token::simpleMatch(tok, "using namespace std ;")) {
9858  Token::eraseTokens(tok, tok->tokAt(4));
9859  tok->deleteThis();
9860  }
9861  }
9862 }
9863 
9864 
9866 {
9867  // skip if not Windows
9868  if (!mSettings.platform.isWindows())
9869  return;
9870 
9871  for (Token *tok = list.front(); tok; tok = tok->next()) {
9872  if (tok->strAt(1) != "(")
9873  continue;
9874 
9875  if (Token::Match(tok, "CopyMemory|RtlCopyMemory|RtlCopyBytes")) {
9876  tok->str("memcpy");
9877  } else if (Token::Match(tok, "MoveMemory|RtlMoveMemory")) {
9878  tok->str("memmove");
9879  } else if (Token::Match(tok, "FillMemory|RtlFillMemory|RtlFillBytes")) {
9880  // FillMemory(dst, len, val) -> memset(dst, val, len)
9881  tok->str("memset");
9882 
9883  Token *tok1 = tok->tokAt(2);
9884  if (tok1)
9885  tok1 = tok1->nextArgument(); // Second argument
9886  if (tok1) {
9887  Token *tok2 = tok1->nextArgument(); // Third argument
9888 
9889  if (tok2)
9890  Token::move(tok1->previous(), tok2->tokAt(-2), tok->next()->link()->previous()); // Swap third with second argument
9891  }
9892  } else if (Token::Match(tok, "ZeroMemory|RtlZeroMemory|RtlZeroBytes|RtlSecureZeroMemory")) {
9893  // ZeroMemory(dst, len) -> memset(dst, 0, len)
9894  tok->str("memset");
9895 
9896  Token *tok1 = tok->tokAt(2);
9897  if (tok1)
9898  tok1 = tok1->nextArgument(); // Second argument
9899 
9900  if (tok1) {
9901  tok1 = tok1->previous();
9902  tok1->insertToken("0");
9903  tok1 = tok1->next();
9904  tok1->insertToken(",");
9905  }
9906  } else if (Token::simpleMatch(tok, "RtlCompareMemory")) {
9907  // RtlCompareMemory(src1, src2, len) -> memcmp(src1, src2, len)
9908  tok->str("memcmp");
9909  // For the record, when memcmp returns 0, both strings are equal.
9910  // When RtlCompareMemory returns len, both strings are equal.
9911  // It might be needed to improve this replacement by something
9912  // like ((len - memcmp(src1, src2, len)) % (len + 1)) to
9913  // respect execution path (if required)
9914  }
9915  }
9916 }
9917 
9918 namespace {
9919  struct triplet {
9920  triplet(const char* m, const char* u) : mbcs(m), unicode(u) {}
9921  std::string mbcs, unicode;
9922  };
9923 
9924  const std::map<std::string, triplet> apis = {
9925  std::make_pair("_topen", triplet("open", "_wopen")),
9926  std::make_pair("_tsopen_s", triplet("_sopen_s", "_wsopen_s")),
9927  std::make_pair("_tfopen", triplet("fopen", "_wfopen")),
9928  std::make_pair("_tfopen_s", triplet("fopen_s", "_wfopen_s")),
9929  std::make_pair("_tfreopen", triplet("freopen", "_wfreopen")),
9930  std::make_pair("_tfreopen_s", triplet("freopen_s", "_wfreopen_s")),
9931  std::make_pair("_tcscat", triplet("strcat", "wcscat")),
9932  std::make_pair("_tcschr", triplet("strchr", "wcschr")),
9933  std::make_pair("_tcscmp", triplet("strcmp", "wcscmp")),
9934  std::make_pair("_tcsdup", triplet("strdup", "wcsdup")),
9935  std::make_pair("_tcscpy", triplet("strcpy", "wcscpy")),
9936  std::make_pair("_tcslen", triplet("strlen", "wcslen")),
9937  std::make_pair("_tcsncat", triplet("strncat", "wcsncat")),
9938  std::make_pair("_tcsncpy", triplet("strncpy", "wcsncpy")),
9939  std::make_pair("_tcsnlen", triplet("strnlen", "wcsnlen")),
9940  std::make_pair("_tcsrchr", triplet("strrchr", "wcsrchr")),
9941  std::make_pair("_tcsstr", triplet("strstr", "wcsstr")),
9942  std::make_pair("_tcstok", triplet("strtok", "wcstok")),
9943  std::make_pair("_ftprintf", triplet("fprintf", "fwprintf")),
9944  std::make_pair("_tprintf", triplet("printf", "wprintf")),
9945  std::make_pair("_stprintf", triplet("sprintf", "swprintf")),
9946  std::make_pair("_sntprintf", triplet("_snprintf", "_snwprintf")),
9947  std::make_pair("_ftscanf", triplet("fscanf", "fwscanf")),
9948  std::make_pair("_tscanf", triplet("scanf", "wscanf")),
9949  std::make_pair("_stscanf", triplet("sscanf", "swscanf")),
9950  std::make_pair("_ftprintf_s", triplet("fprintf_s", "fwprintf_s")),
9951  std::make_pair("_tprintf_s", triplet("printf_s", "wprintf_s")),
9952  std::make_pair("_stprintf_s", triplet("sprintf_s", "swprintf_s")),
9953  std::make_pair("_sntprintf_s", triplet("_snprintf_s", "_snwprintf_s")),
9954  std::make_pair("_ftscanf_s", triplet("fscanf_s", "fwscanf_s")),
9955  std::make_pair("_tscanf_s", triplet("scanf_s", "wscanf_s")),
9956  std::make_pair("_stscanf_s", triplet("sscanf_s", "swscanf_s"))
9957  };
9958 }
9959 
9961 {
9962  // skip if not Windows
9963  if (!mSettings.platform.isWindows())
9964  return;
9965 
9966  const bool ansi = mSettings.platform.type == Platform::Type::Win32A;
9967  for (Token *tok = list.front(); tok; tok = tok->next()) {
9968  if (tok->strAt(1) != "(")
9969  continue;
9970 
9971  const std::map<std::string, triplet>::const_iterator match = apis.find(tok->str());
9972  if (match!=apis.end()) {
9973  tok->str(ansi ? match->second.mbcs : match->second.unicode);
9974  tok->originalName(match->first);
9975  } else if (Token::Match(tok, "_T|_TEXT|TEXT ( %char%|%str% )")) {
9976  tok->deleteNext();
9977  tok->deleteThis();
9978  tok->deleteNext();
9979  if (!ansi) {
9980  tok->isLong(true);
9981  if (tok->str()[0] != 'L')
9982  tok->str("L" + tok->str());
9983  }
9984  while (Token::Match(tok->next(), "_T|_TEXT|TEXT ( %char%|%str% )")) {
9985  tok->next()->deleteNext();
9986  tok->next()->deleteThis();
9987  tok->next()->deleteNext();
9988  tok->concatStr(tok->next()->str());
9989  tok->deleteNext();
9990  }
9991  }
9992  }
9993 }
9994 
9995 // Remove Borland code
9997 {
9998  // skip if not Windows
9999  if (!mSettings.platform.isWindows())
10000  return;
10001  if (isC())
10002  return;
10003  for (Token *tok = list.front(); tok; tok = tok->next()) {
10004  if (Token::Match(tok, "( __closure * %name% )")) {
10005  tok->deleteNext();
10006  }
10007  }
10008 
10009  // I think that these classes are always declared at the outer scope
10010  // I save some time by ignoring inner classes.
10011  for (Token *tok = list.front(); tok; tok = tok->next()) {
10012  if (tok->str() == "{" && !Token::Match(tok->tokAt(-2), "namespace %type%")) {
10013  tok = tok->link();
10014  if (!tok)
10015  break;
10016  } else if (Token::Match(tok, "class %name% :|{")) {
10017  while (tok && tok->str() != "{" && tok->str() != ";")
10018  tok = tok->next();
10019  if (!tok)
10020  break;
10021  if (tok->str() == ";")
10022  continue;
10023 
10024  const Token* end = tok->link()->next();
10025  for (Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
10026  if (tok2->str() == "__property" &&
10027  Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) {
10028  while (tok2->next() && !Token::Match(tok2->next(), "{|;"))
10029  tok2->deleteNext();
10030  tok2->deleteThis();
10031  if (tok2->str() == "{") {
10032  Token::eraseTokens(tok2, tok2->link());
10033  tok2->deleteNext();
10034  tok2->deleteThis();
10035 
10036  // insert "; __property ;"
10037  tok2->previous()->insertToken(";");
10038  tok2->previous()->insertToken("__property");
10039  tok2->previous()->insertToken(";");
10040  }
10041  }
10042  }
10043  }
10044  }
10045 }
10046 
10048 {
10049  if (!mSymbolDatabase)
10052 }
10053 
10054 bool Tokenizer::operatorEnd(const Token * tok)
10055 {
10056  if (tok && tok->str() == ")") {
10057  if (isFunctionHead(tok, "{|;|?|:|["))
10058  return true;
10059 
10060  tok = tok->next();
10061  while (tok && !Token::Match(tok, "[=;{),]")) {
10062  if (Token::Match(tok, "const|volatile|override")) {
10063  tok = tok->next();
10064  } else if (tok->str() == "noexcept") {
10065  tok = tok->next();
10066  if (tok && tok->str() == "(") {
10067  tok = tok->link()->next();
10068  }
10069  } else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
10070  tok = tok->next()->link()->next();
10071  }
10072  // unknown macros ") MACRO {" and ") MACRO(...) {"
10073  else if (tok->isUpperCaseName()) {
10074  tok = tok->next();
10075  if (tok && tok->str() == "(") {
10076  tok = tok->link()->next();
10077  }
10078  } else if (Token::Match(tok, "%op% !!(") ||
10079  (Token::Match(tok, "%op% (") && !isFunctionHead(tok->next(), "{")))
10080  break;
10081  else
10082  return false;
10083  }
10084 
10085  return true;
10086  }
10087 
10088  return false;
10089 }
10090 
10092 {
10093  if (isC())
10094  return;
10095 
10096  for (Token *tok = list.front(); tok; tok = tok->next()) {
10097  if (Token::Match(tok, "using|:: operator %op%|%name% ;")) {
10098  tok->next()->str("operator" + tok->strAt(2));
10099  tok->next()->deleteNext();
10100  continue;
10101  }
10102 
10103  if (tok->str() != "operator")
10104  continue;
10105  // operator op
10106  if (Token::Match(tok, "operator %op% (") && !operatorEnd(tok->linkAt(2))) {
10107  tok->str(tok->str() + tok->next()->str());
10108  tok->deleteNext();
10109  continue;
10110  }
10111  std::string op;
10112  Token *par = tok->next();
10113  bool done = false;
10114  while (!done && par) {
10115  done = true;
10116  if (par->isName()) {
10117  op += par->str();
10118  par = par->next();
10119  // merge namespaces eg. 'operator std :: string () const {'
10120  if (Token::Match(par, ":: %name%|%op%|.")) {
10121  op += par->str();
10122  par = par->next();
10123  }
10124  done = false;
10125  } else if (Token::Match(par, ".|%op%|,")) {
10126  // check for operator in template
10127  if (par->str() == "," && !op.empty())
10128  break;
10129  if (!(Token::Match(par, "<|>") && !op.empty())) {
10130  op += par->str() == "." ? par->originalName() : par->str();
10131  par = par->next();
10132  done = false;
10133  }
10134  } else if (Token::simpleMatch(par, "[ ]")) {
10135  op += "[]";
10136  par = par->tokAt(2);
10137  done = false;
10138  } else if (Token::Match(par, "( *| )")) {
10139  // break out and simplify..
10140  if (operatorEnd(par->next()))
10141  break;
10142 
10143  while (par->str() != ")") {
10144  op += par->str();
10145  par = par->next();
10146  }
10147  op += ")";
10148  par = par->next();
10149  if (Token::simpleMatch(par, "...")) {
10150  op.clear();
10151  par = nullptr;
10152  break;
10153  }
10154  done = false;
10155  } else if (Token::Match(par, "\"\" %name% )| (|;|<")) {
10156  op += "\"\"";
10157  op += par->strAt(1);
10158  par = par->tokAt(2);
10159  if (par->str() == ")") {
10160  par->link()->deleteThis();
10161  par = par->next();
10162  par->deletePrevious();
10163  tok = par->tokAt(-3);
10164  }
10165  done = true;
10166  } else if (par->str() == "::") {
10167  op += par->str();
10168  par = par->next();
10169  done = false;
10170  } else if (par->str() == ";" || par->str() == ")") {
10171  done = true;
10172  } else if (par->str() != "(") {
10173  syntaxError(par, "operator");
10174  }
10175  }
10176 
10177  const bool returnsRef = Token::simpleMatch(par, "( & (") && tok->next()->isName();
10178  if (par && !op.empty()) {
10179  if (returnsRef) {
10180  par->next()->insertToken("operator" + op)->isOperatorKeyword(true);
10181  tok->deleteThis();
10182  }
10183  else {
10184  tok->str("operator" + op);
10185  Token::eraseTokens(tok, par);
10186  }
10187  }
10188 
10189  if (!op.empty() && !returnsRef)
10190  tok->isOperatorKeyword(true);
10191  }
10192 
10193  for (Token *tok = list.front(); tok; tok = tok->next()) {
10194  if (Token::Match(tok, "%op% %str% %name%")) {
10195  const std::string name = tok->strAt(2);
10196  Token * const str = tok->next();
10197  str->deleteNext();
10198  tok->insertToken("operator\"\"" + name);
10199  tok = tok->next();
10200  tok->isOperatorKeyword(true);
10201  tok->insertToken("(");
10202  str->insertToken(")");
10203  Token::createMutualLinks(tok->next(), str->next());
10204  str->insertToken(std::to_string(Token::getStrLength(str)));
10205  str->insertToken(",");
10206  }
10207  }
10208 
10209  if (mSettings.debugwarnings) {
10210  const Token *tok = list.front();
10211 
10212  while ((tok = Token::findsimplematch(tok, "operator")) != nullptr) {
10213  reportError(tok, Severity::debug, "debug",
10214  "simplifyOperatorName: found unsimplified operator name");
10215  tok = tok->next();
10216  }
10217  }
10218 }
10219 
10221 {
10222  if (isC())
10223  return;
10224  std::set<std::string> classNames;
10225  std::set<nonneg int> classVars;
10226  for (Token *tok = list.front(); tok; tok = tok->next()) {
10227  if (!tok->isName())
10228  continue;
10229 
10230  if (Token::simpleMatch(tok, "this ) (") && Token::simpleMatch(tok->tokAt(-2), "( *")) {
10231  tok = tok->next();
10232  tok->insertToken("operator()");
10233  tok->insertToken(".");
10234  continue;
10235  }
10236 
10237  // Get classes that have operator() member
10238  if (Token::Match(tok, "class|struct %name% [:{]")) {
10239  int indent = 0;
10240  for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
10241  if (tok2->str() == "}")
10242  break;
10243  if (indent == 0 && tok2->str() == ";")
10244  break;
10245  if (tok2->str() == "{") {
10246  if (indent == 0)
10247  ++indent;
10248  else
10249  tok2 = tok2->link();
10250  } else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
10251  classNames.insert(tok->strAt(1));
10252  break;
10253  }
10254  }
10255  }
10256 
10257  // Get variables that have operator() member
10258  if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
10259  tok = tok->next();
10260  while (!tok->isName())
10261  tok = tok->next();
10262  classVars.insert(tok->varId());
10263  }
10264 
10265  // Simplify operator() calls
10266  if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
10267  // constructor init list..
10268  if (Token::Match(tok->previous(), "[:,]")) {
10269  const Token *start = tok->previous();
10270  while (Token::simpleMatch(start, ",")) {
10271  if (Token::simpleMatch(start->previous(), ")"))
10272  start = start->linkAt(-1);
10273  else
10274  break;
10275  if (Token::Match(start->previous(), "%name%"))
10276  start = start->tokAt(-2);
10277  else
10278  break;
10279  }
10280  const Token *after = tok->linkAt(1);
10281  while (Token::Match(after, ")|} , %name% (|{"))
10282  after = after->linkAt(3);
10283 
10284  // Do not simplify initlist
10285  if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
10286  continue;
10287  }
10288 
10289  tok->insertToken("operator()");
10290  tok->insertToken(".");
10291  }
10292  }
10293 }
10294 
10295 // remove unnecessary member qualification..
10297 {
10298  if (isC())
10299  return;
10300 
10301  std::vector<Space> classInfo;
10302  for (Token *tok = list.front(); tok; tok = tok->next()) {
10303  if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
10304  (!tok->previous() || tok->previous()->str() != "enum")) {
10305  Space info;
10306  info.isNamespace = tok->str() == "namespace";
10307  tok = tok->next();
10308  info.className = tok->str();
10309  tok = tok->next();
10310  while (tok && tok->str() != "{")
10311  tok = tok->next();
10312  if (!tok)
10313  return;
10314  info.bodyEnd = tok->link();
10315  classInfo.push_back(std::move(info));
10316  } else if (!classInfo.empty()) {
10317  if (tok == classInfo.back().bodyEnd)
10318  classInfo.pop_back();
10319  else if (tok->str() == classInfo.back().className &&
10320  !classInfo.back().isNamespace && tok->previous()->str() != ":" &&
10321  (Token::Match(tok, "%type% :: ~| %type% (") ||
10322  Token::Match(tok, "%type% :: operator"))) {
10323  const Token *tok1 = tok->tokAt(3);
10324  if (tok->strAt(2) == "operator") {
10325  // check for operator ()
10326  if (tok1->str() == "(")
10327  tok1 = tok1->next();
10328 
10329  while (tok1 && tok1->str() != "(") {
10330  if (tok1->str() == ";")
10331  break;
10332  tok1 = tok1->next();
10333  }
10334  if (!tok1 || tok1->str() != "(")
10335  continue;
10336  } else if (tok->strAt(2) == "~")
10337  tok1 = tok1->next();
10338 
10339  if (!tok1 || !Token::Match(tok1->link(), ") const| {|;|:")) {
10340  continue;
10341  }
10342 
10343  const bool isConstructorOrDestructor =
10344  Token::Match(tok, "%type% :: ~| %type%") && (tok->strAt(2) == tok->str() || (tok->strAt(2) == "~" && tok->strAt(3) == tok->str()));
10345  if (!isConstructorOrDestructor) {
10346  bool isPrependedByType = Token::Match(tok->previous(), "%type%");
10347  if (!isPrependedByType) {
10348  const Token* tok2 = tok->tokAt(-2);
10349  isPrependedByType = Token::Match(tok2, "%type% *|&");
10350  }
10351  if (!isPrependedByType) {
10352  const Token* tok3 = tok->tokAt(-3);
10353  isPrependedByType = Token::Match(tok3, "%type% * *|&");
10354  }
10355  if (!isPrependedByType) {
10356  // It's not a constructor declaration and it's not a function declaration so
10357  // this is a function call which can have all the qualifiers just fine - skip.
10358  continue;
10359  }
10360  }
10361  }
10362  }
10363  }
10364 }
10365 
10366 void Tokenizer::printUnknownTypes() const
10367 {
10368  if (!mSymbolDatabase)
10369  return;
10370 
10371  std::vector<std::pair<std::string, const Token *>> unknowns;
10372 
10373  for (int i = 1; i <= mVarId; ++i) {
10375  if (!var)
10376  continue;
10377  // is unknown type?
10378  if (var->type() || var->typeStartToken()->isStandardType())
10379  continue;
10380 
10381  std::string name;
10382  const Token * nameTok;
10383 
10384  // single token type?
10385  if (var->typeStartToken() == var->typeEndToken()) {
10386  nameTok = var->typeStartToken();
10387  name = nameTok->str();
10388  }
10389 
10390  // complicated type
10391  else {
10392  const Token *tok = var->typeStartToken();
10393  int level = 0;
10394 
10395  nameTok = tok;
10396 
10397  while (tok) {
10398  // skip pointer and reference part of type
10399  if (level == 0 && Token::Match(tok, "*|&"))
10400  break;
10401 
10402  name += tok->str();
10403 
10404  if (Token::Match(tok, "struct|union|enum"))
10405  name += " ";
10406 
10407  // pointers and references are OK in template
10408  else if (tok->str() == "<")
10409  ++level;
10410  else if (tok->str() == ">")
10411  --level;
10412 
10413  if (tok == var->typeEndToken())
10414  break;
10415 
10416  tok = tok->next();
10417  }
10418  }
10419 
10420  unknowns.emplace_back(std::move(name), nameTok);
10421  }
10422 
10423  if (!unknowns.empty()) {
10424  std::string last;
10425  int count = 0;
10426 
10427  for (auto it = unknowns.cbegin(); it != unknowns.cend(); ++it) {
10428  // skip types is std namespace because they are not interesting
10429  if (it->first.find("std::") != 0) {
10430  if (it->first != last) {
10431  last = it->first;
10432  count = 1;
10433  reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10434  } else {
10435  if (count < 3) // limit same type to 3
10436  reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10437  count++;
10438  }
10439  }
10440  }
10441  }
10442 }
10443 
10445 {
10446  // http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
10447  // "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
10448  // The AST parser relies on this function to add such parentheses where necessary.
10449  for (Token* tok = list.front(); tok; tok = tok->next()) {
10450  if (tok->str() == "?") {
10451  bool parenthesesNeeded = false;
10452  int depth = 0;
10453  Token* tok2 = tok->next();
10454  for (; tok2; tok2 = tok2->next()) {
10455  if (tok2->link() && Token::Match(tok2, "[|(|<"))
10456  tok2 = tok2->link();
10457  else if (tok2->str() == ":") {
10458  if (depth == 0)
10459  break;
10460  depth--;
10461  } else if (tok2->str() == ";" || (tok2->link() && tok2->str() != "{" && tok2->str() != "}"))
10462  break;
10463  else if (tok2->str() == ",")
10464  parenthesesNeeded = true;
10465  else if (tok2->str() == "<")
10466  parenthesesNeeded = true;
10467  else if (tok2->str() == "?") {
10468  depth++;
10469  parenthesesNeeded = true;
10470  }
10471  }
10472  if (parenthesesNeeded && tok2 && tok2->str() == ":") {
10473  tok->insertToken("(");
10474  tok2->insertTokenBefore(")");
10475  Token::createMutualLinks(tok->next(), tok2->previous());
10476  }
10477  }
10478  }
10479 }
10480 
10481 void Tokenizer::reportError(const Token* tok, const Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10482 {
10483  const std::list<const Token*> callstack(1, tok);
10484  reportError(callstack, severity, id, msg, inconclusive);
10485 }
10486 
10487 void Tokenizer::reportError(const std::list<const Token*>& callstack, Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10488 {
10489  const ErrorMessage errmsg(callstack, &list, severity, id, msg, inconclusive ? Certainty::inconclusive : Certainty::normal);
10490  mErrorLogger.reportErr(errmsg);
10491 }
10492 
10494 {
10495  for (Token *tok = list.front(); tok; tok = tok->next()) {
10496  if (!tok->isName() || tok->varId())
10497  continue;
10498 
10499  // pod type
10500  const Library::PodType *podType = mSettings.library.podtype(tok->str());
10501  if (podType) {
10502  const Token *prev = tok->previous();
10503  while (prev && prev->isName())
10504  prev = prev->previous();
10505  if (prev && !Token::Match(prev, ";|{|}|,|("))
10506  continue;
10507  tok->isStandardType(true);
10508  }
10509  }
10510 }
10511 
10512 const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
10513 {
10514  const Token *tokLastEnd = nullptr;
10515  for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr; tok = tok->next()) {
10516  if (tokLastEnd == nullptr && tok->str() == ";")
10517  tokLastEnd = tok;
10518  else if (tok->str() == "__CPPCHECK_EMBEDDED_SQL_EXEC__") {
10519  if (Token::simpleMatch(tok->tokAt(-2), "END - __CPPCHECK_EMBEDDED_SQL_EXEC__ ;"))
10520  return tok->next();
10521  return tokLastEnd;
10522  } else if (Token::Match(tok, "{|}|==|&&|!|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|~"))
10523  break; // We are obviously outside the SQL block
10524  }
10525 
10526  return tokLastEnd;
10527 }
10528 
10530 {
10531  if (!isCPP())
10532  return;
10533 
10534  for (Token *tok = list.front(); tok; tok = tok->next()) {
10535  if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
10536  Token * tok2 = tok->tokAt(2);
10537 
10538  // validate syntax
10539  while (Token::Match(tok2, ":: %name%"))
10540  tok2 = tok2->tokAt(2);
10541 
10542  if (!tok2 || tok2->str() != "{")
10543  return; // syntax error
10544 
10545  std::stack<Token *> links;
10546  tok2 = tok->tokAt(2);
10547 
10548  while (tok2->str() == "::") {
10549  links.push(tok2);
10550  tok2->str("{");
10551  tok2->insertToken("namespace");
10552  tok2 = tok2->tokAt(3);
10553  }
10554 
10555  tok = tok2;
10556 
10557  if (!links.empty() && tok2->str() == "{") {
10558  tok2 = tok2->link();
10559  while (!links.empty()) {
10560  tok2->insertToken("}");
10561  tok2 = tok2->next();
10562  Token::createMutualLinks(links.top(), tok2);
10563  links.pop();
10564  }
10565  }
10566  }
10567  }
10568 }
10569 
10571 {
10573  return;
10574  for (Token *tok = list.front(); tok; tok = tok->next()) {
10575  if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await"))
10576  continue;
10577  Token *end = tok->next();
10578  while (end && end->str() != ";") {
10579  if (Token::Match(end, "[({[]"))
10580  end = end->link();
10581  else if (Token::Match(end, "[)]}]"))
10582  break;
10583  end = end->next();
10584  }
10585  if (Token::simpleMatch(end, ";")) {
10586  tok->insertToken("(");
10587  end->previous()->insertToken(")");
10588  Token::createMutualLinks(tok->next(), end->previous());
10589  }
10590  }
10591 }
10592 
10593 static bool sameTokens(const Token *first, const Token *last, const Token *other)
10594 {
10595  while (other && first->str() == other->str()) {
10596  if (first == last)
10597  return true;
10598  first = first->next();
10599  other = other->next();
10600  }
10601 
10602  return false;
10603 }
10604 
10605 static bool alreadyHasNamespace(const Token *first, const Token *last, const Token *end)
10606 {
10607  while (end && last->str() == end->str()) {
10608  if (first == last)
10609  return true;
10610  last = last->previous();
10611  end = end->previous();
10612  }
10613 
10614  return false;
10615 }
10616 
10617 static Token * deleteAlias(Token * tok)
10618 {
10620 
10621  // delete first token
10622  tok->deleteThis();
10623 
10624  // delete ';' if not last token
10625  tok->deleteThis();
10626 
10627  return tok;
10628 }
10629 
10631 {
10632  if (!isCPP())
10633  return;
10634 
10635  int scope = 0;
10636 
10637  for (Token *tok = list.front(); tok; tok = tok->next()) {
10638  bool isPrev{};
10639  if (tok->str() == "{")
10640  scope++;
10641  else if (tok->str() == "}")
10642  scope--;
10643  else if (Token::Match(tok, "namespace %name% =") || (isPrev = Token::Match(tok->previous(), "namespace %name% ="))) {
10644  if (isPrev)
10645  tok = tok->previous();
10646  if (tok->tokAt(-1) && !Token::Match(tok->tokAt(-1), "[;{}]"))
10647  syntaxError(tok->tokAt(-1));
10648  const std::string name(tok->next()->str());
10649  Token * tokNameStart = tok->tokAt(3);
10650  Token * tokNameEnd = tokNameStart;
10651 
10652  while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";") {
10653  if (tokNameEnd->str() == "(") {
10654  if (tokNameEnd->previous()->isName())
10655  unknownMacroError(tokNameEnd->previous());
10656  else
10657  syntaxError(tokNameEnd);
10658  }
10659  tokNameEnd = tokNameEnd->next();
10660  }
10661 
10662  if (!tokNameEnd)
10663  return; // syntax error
10664 
10665  int endScope = scope;
10666  Token * tokLast = tokNameEnd->next();
10667  if (!tokLast)
10668  return;
10669  Token * tokNext = tokLast->next();
10670  Token * tok2 = tokNext;
10671 
10672  while (tok2 && endScope >= scope) {
10673  if (Token::simpleMatch(tok2, "{"))
10674  endScope++;
10675  else if (Token::simpleMatch(tok2, "}"))
10676  endScope--;
10677  else if (tok2->str() == name) {
10678  if (Token::Match(tok2->previous(), "namespace %name% =")) {
10679  // check for possible duplicate aliases
10680  if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
10681  // delete duplicate
10682  tok2 = deleteAlias(tok2->previous());
10683  continue;
10684  }
10685  // conflicting declaration (syntax error)
10686  // cppcheck-suppress duplicateBranch - remove when TODO below is addressed
10687  if (endScope == scope) {
10688  // delete conflicting declaration
10689  tok2 = deleteAlias(tok2->previous());
10690  }
10691 
10692  // new declaration
10693  else {
10694  // TODO: use the new alias in this scope
10695  tok2 = deleteAlias(tok2->previous());
10696  }
10697  continue;
10698  }
10699 
10700  if (tok2->strAt(1) == "::" && !alreadyHasNamespace(tokNameStart, tokNameEnd, tok2)) {
10701  if (Token::simpleMatch(tok2->tokAt(-1), "::") && tokNameStart->str() == "::")
10702  tok2->deletePrevious();
10703  tok2->str(tokNameStart->str());
10704  Token * tok3 = tokNameStart;
10705  while (tok3 != tokNameEnd) {
10706  tok2->insertToken(tok3->next()->str());
10707  tok2 = tok2->next();
10708  tok3 = tok3->next();
10709  }
10710  }
10711  }
10712  tok2 = tok2->next();
10713  }
10714 
10715  if (tok->previous() && tokNext) {
10716  Token::eraseTokens(tok->previous(), tokNext);
10717  tok = tokNext->previous();
10718  } else if (tok->previous()) {
10719  Token::eraseTokens(tok->previous(), tokLast);
10720  tok = tokLast;
10721  } else if (tokNext) {
10722  Token::eraseTokens(tok, tokNext);
10723  tok->deleteThis();
10724  } else {
10725  Token::eraseTokens(tok, tokLast);
10726  tok->deleteThis();
10727  }
10728  }
10729  }
10730 }
10731 
10732 void Tokenizer::setDirectives(std::list<Directive> directives)
10733 {
10734  mDirectives = std::move(directives);
10735 }
10736 
10737 bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
10738 {
10739  const auto& directives = mDirectives;
10740  return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10741  return startsWith(d.str, "#if") &&
10742  d.linenr >= start->linenr() &&
10743  d.linenr <= end->linenr() &&
10744  start->fileIndex() < list.getFiles().size() &&
10745  d.file == list.getFiles()[start->fileIndex()];
10746  });
10747 }
10748 
10749 bool Tokenizer::isPacked(const Token * bodyStart) const
10750 {
10751  const auto& directives = mDirectives;
10752  // TODO: should this return true if the #pragma exists in any line before the start token?
10753  return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10754  return d.linenr < bodyStart->linenr() && d.str == "#pragma pack(1)" && d.file == list.getFiles().front();
10755  });
10756 }
static bool match(const Token *tok, const std::string &rhs)
Definition: astutils.cpp:342
bool isUnevaluated(const Token *tok)
Definition: astutils.cpp:3612
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:1718
bool hasAnyTypeCheck(const std::string &typeName) const
Definition: library.cpp:1757
bool isnoreturn(const Token *ftok) const
Definition: library.cpp:1558
bool isScopeNoReturn(const Token *end, std::string *unknownFunc) const
Definition: library.cpp:1141
const PodType * podtype(const std::string &name) const
Definition: library.h:450
bool markupFile(const std::string &path) const
Definition: library.cpp:1593
bool isNotLibraryFunction(const Token *ftok) const
Definition: library.cpp:1286
bool matchArguments(const Token *ftok, const std::string &functionName) const
Definition: library.cpp:1301
bool isFunctionConst(const std::string &functionName, bool pure) const
Definition: library.cpp:1534
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:688
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:329
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:1257
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:2228
bool isUnsigned() const
Definition: token.h:424
bool hasKnownIntValue() const
Definition: token.cpp:2519
static void replace(Token *replaceThis, Token *start, Token *end)
Replace token replaceThis with tokens between start and end, including start and end.
Definition: token.cpp:346
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:212
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:1337
bool isBoolean() const
Definition: token.h:404
bool isUpperCaseName() const
Definition: token.cpp:203
static void createMutualLinks(Token *begin, Token *end)
Links two elements against each other.
Definition: token.cpp:1248
bool isAttributeDestructor() const
Definition: token.h:470
bool isCpp() const
Definition: token.cpp:2718
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:777
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:423
bool isAttributeUnused() const
Definition: token.h:476
static void assignProgressValues(Token *tok)
Calculate progress values for all tokens.
Definition: token.cpp:2307
void astOperand1(Token *tok)
Definition: token.cpp:1456
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1093
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:834
bool isSigned() const
Definition: token.h:430
const Token * findClosingBracket() const
Returns the closing bracket of opening '<'.
Definition: token.cpp:917
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:2317
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:1764
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:807
bool isOp() const
Definition: token.h:380
void scopeInfo(std::shared_ptr< ScopeInfo2 > newScopeInfo)
Definition: token.cpp:2510
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
Definition: token.h:763
const Token * tokAt(int index) const
Definition: token.cpp:393
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:245
Token * insertToken(const std::string &tokenStr, const std::string &originalNameStr=emptyString, const std::string &macroNameStr=emptyString, bool prepend=false)
Insert new token after this token.
Definition: token.cpp:1105
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1468
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
bool isLong() const
Definition: token.h:443
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:413
@ 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:1681
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:2333
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:1238
nonneg int linenr() const
Definition: token.h:816
bool isStandardType() const
Definition: token.h:449
const Token * nextArgumentBeforeCreateLinks2() const
Definition: token.cpp:879
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:869
void swapWithNext()
Swap the contents of this token with the next token.
Definition: token.cpp:285
bool isAtomic() const
Definition: token.h:636
const Token * findOpeningBracket() const
Definition: token.cpp:982
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
nonneg int fileIndex() const
Definition: token.h:809
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:265
nonneg int column() const
Definition: token.h:823
bool isAttributePure() const
Definition: token.h:488
void astParent(Token *tok)
Definition: token.cpp:1437
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:8021
nonneg int sizeOfType(const Token *type) const
Calculates sizeof value for given type.
Definition: tokenize.cpp:192
void setVarIdPass1()
Definition: tokenize.cpp:4525
void simplifyLabelsCaseDefault()
Simplify labels and 'case|default' syntaxes.
Definition: tokenize.cpp:3944
void simplifyRoundCurlyParentheses()
Definition: tokenize.cpp:3641
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:7735
void simplifyBitfields()
Simplify bitfields - the field width is removed as we don't use it.
void fillTypeSizes()
Definition: tokenize.cpp:3482
NORETURN void unknownMacroError(const Token *tok1) const
Warn about unknown macro(s), configuration is recommended.
Definition: tokenize.cpp:8070
void splitTemplateRightAngleBrackets(bool check)
Split up template right angle brackets.
Definition: tokenize.cpp:6340
Token * deleteInvalidTypedef(Token *typeDef)
Definition: tokenize.cpp:369
void printDebugOutput(int simplification) const
print –debug output if debug flags match the simplification: 0=unknown/both simplifications 1=1st sim...
Definition: tokenize.cpp:5881
void elseif()
Simplify "if else".
Definition: tokenize.cpp:7703
void simplifyRedundantConsecutiveBraces()
Definition: tokenize.cpp:3713
void removeMacrosInGlobalScope()
Remove macros in global scope.
Definition: tokenize.cpp:6392
void simplifyHeadersAndUnusedTemplates()
If –check-headers=no has been given; then remove unneeded code in headers.
Definition: tokenize.cpp:6181
void calculateScopes()
Definition: tokenize.cpp:4015
void simplifyTemplates()
Simplify templates.
Definition: tokenize.cpp:4106
void simplifyUsingError(const Token *usingStart, const Token *usingEnd)
Definition: tokenize.cpp:3364
bool isPacked(const Token *bodyStart) const
void removePragma()
Definition: tokenize.cpp:6471
void setVarIdPass2()
Definition: tokenize.cpp:5011
const Token * tokens() const
Definition: tokenize.h:592
void simplifyAttribute()
Remove __attribute__ ((?))
void simplifyExternC()
Definition: tokenize.cpp:3615
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:7625
static bool isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
Detect garbage expression.
void simplifySQL()
Definition: tokenize.cpp:3662
void removeUnnecessaryQualification()
Remove unnecessary member qualification.
void simplifyVarDecl(const bool only_k_r_fpar)
Simplify variable declarations (split up)
Definition: tokenize.cpp:7049
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:8141
void simplifyTypedef()
typedef A mytype; mytype c;
Definition: tokenize.cpp:1054
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:3380
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:5468
void simplifyFunctionTryCatch()
Simplify function level try blocks: Convert "void f() try {} catch (int) {}" to "void f() { try {} ca...
void simplifyDoublePlusAndDoubleMinus()
Definition: tokenize.cpp:3728
void removeExtraTemplateKeywords()
Remove extra "template" keywords that are not used by Cppcheck.
Definition: tokenize.cpp:6306
void simplifyTypedefLHS()
Move typedef token to the left og the expression.
Definition: tokenize.cpp:569
std::list< Directive > mDirectives
Definition: tokenize.h:671
void simplifyCaseRange()
simplify case ranges (gcc extension)
Definition: tokenize.cpp:3994
ErrorLogger & mErrorLogger
errorlogger
Definition: tokenize.h:648
bool simplifyRedundantParentheses()
Remove redundant parentheses:
Definition: tokenize.cpp:7796
void simplifyTypedefCpp()
Definition: tokenize.cpp:1147
void addSemicolonAfterUnknownMacro()
Definition: tokenize.cpp:6504
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:161
void simplifyEmptyNamespaces()
Simplify useless C++ empty namespaces, like: 'namespace name% { }'.
Definition: tokenize.cpp:6522
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:6635
void simplifyMicrosoftMemoryFunctions()
Convert Microsoft memory functions CopyMemory(dst, src, len) -> memcpy(dst, src, len) FillMemory(dst,...
void setVarId()
Set variable id.
Definition: tokenize.cpp:4502
void setDirectives(std::list< Directive > directives)
void simplifyAssignmentBlock()
Simplify assignment where rhs is a block : "x=({123;});" => "{x=123;}".
void findComplicatedSyntaxErrorsInTemplates()
Definition: tokenize.cpp:3463
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:7658
Token * simplifyAddBracesToCommand(Token *tok)
Add braces to an if-block, for-block, etc.
Definition: tokenize.cpp:6591
nonneg int mVarId
variable count
Definition: tokenize.h:674
static bool isMemberFunction(const Token *openParen)
Definition: tokenize.cpp:2812
void simplifyKeyword()
Remove keywords "volatile", "inline", "register", and "restrict".
void macroWithSemicolonError(const Token *tok, const std::string &macroName) const
Definition: tokenize.cpp:8088
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:546
bool simplifyAddBraces()
Add braces to an if-block, for-block, etc.
Definition: tokenize.cpp:6581
void unhandled_macro_class_x_y(const Token *tok) const
Report that there is an unhandled "class x y {" code.
Definition: tokenize.cpp:8076
void reportUnknownMacros() const
Detect unknown macros and throw unknownMacro.
Definition: tokenize.cpp:8290
void arraySize()
Insert array size where it isn't given.
Definition: tokenize.cpp:3770
void createLinks2()
Setup links between < and >.
Definition: tokenize.cpp:5311
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:4471
const Settings & mSettings
settings
Definition: tokenize.h:645
void simplifyParameterVoid()
Definition: tokenize.cpp:3703
void sizeofAddParentheses()
Add parentheses for sizeof: sizeof x => sizeof(x)
Definition: tokenize.cpp:5444
void dump(std::ostream &out) const
Definition: tokenize.cpp:5931
void validateC() const
Is there C++ code in C file?
Definition: tokenize.cpp:8168
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:7413
void simplifyDeclspec()
Remove __declspec()
void createLinks()
Setup links for tokens so that one can call Token::link().
Definition: tokenize.cpp:5277
NORETURN void cppcheckError(const Token *tok) const
Send error message to error logger about internal bug.
Definition: tokenize.cpp:8096
void markCppCasts()
Set isCast() for C++ casts.
Definition: tokenize.cpp:5429
NORETURN void unmatchedToken(const Token *tok) const
Syntax error.
Definition: tokenize.cpp:8056
void simplifyPointerToStandardType()
Simplify pointer to standard type (C only)
Definition: tokenize.cpp:6906
void simplifySpaceshipOperator()
Simplify c++20 spaceship operator.
void combineStringAndCharLiterals()
Definition: tokenize.cpp:3576
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:6561
void simplifyCallingConvention()
Remove calling convention.
void arraySizeAfterValueFlow()
Definition: tokenize.cpp:3843
void simplifyFunctionPointers()
Simplify function pointers.
Definition: tokenize.cpp:6928
void setPodTypes()
Set pod types.
void unsupportedTypedef(const Token *tok) const
Definition: tokenize.cpp:338
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:3500
const Token * processFunc(const Token *tok2, bool inOperator) const
Definition: tokenize.cpp:481
void simplifyDebug()
static const Token * isFunctionHead(const Token *tok, const std::string &endsWith)
is token pointing at function head?
Definition: tokenize.cpp:97
bool simplifyCAlternativeTokens()
Simplify the 'C Alternative Tokens' Examples: "if(s and t)" => "if(s && t)" "while((r bitand s) and n...
Definition: tokenize.cpp:7537
void simplifyAt()
Simplify @… (compiler extension)
void concatenateNegativeNumberAndAnyPositive()
Definition: tokenize.cpp:3599
bool simplifyUsing()
Definition: tokenize.cpp:2856
void validate() const
assert that tokens are ok - used during debugging for example to catch problems in simplifyTokenList1...
Definition: tokenize.cpp:8197
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:8064
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:220
void simplifyTypeIntrinsics()
Definition: tokenize.cpp:7965
static const Token * startOfExecutableScope(const Token *tok)
Helper function to check for start of function execution scope.
Definition: tokenize.cpp:3926
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:6487
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:8050
void checkForEnumsWithTypedef()
Definition: tokenize.cpp:3469
TimerResults * mTimerResults
TimerResults.
Definition: tokenize.h:682
void simplifyNestedNamespace()
Convert C++17 style nested namespace to older style.
void simplifyArrayAccessSyntax()
Definition: tokenize.cpp:3689
void unhandledCharLiteral(const Token *tok, const std::string &msg) const
Definition: tokenize.cpp:8102
void simplifyCPPAttribute()
Remove [[attribute]] (C++11, C23) from TokenList.
void simplifyVariableMultipleAssign()
Simplify multiple assignments.
Definition: tokenize.cpp:7482
void checkConfiguration() const
Check configuration (unknown macros etc)
Definition: tokenize.cpp:8148
void simplifyFunctionParameters()
Simplify functions like "void f(x) int x; {" into "void f(int x) {".
Definition: tokenize.cpp:6734
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:2686
@ 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:446
std::string name
Definition: library.h:437
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:1708
TokenDebug
Definition: token.h:60
static std::string getExpression(const Token *tok)
Definition: tokenize.cpp:6329
static Token * splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
Definition: tokenize.cpp:407
static void setVarIdStructMembers(Token *&tok1, std::map< nonneg int, std::map< std::string, nonneg int >> &structMembers, nonneg int &varId)
Definition: tokenize.cpp:4327
static Token * skipTernaryOp(Token *tok)
Definition: tokenize.cpp:3882
static Token * matchMemberFunctionName(const Member &func, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4987
static const std::unordered_set< std::string > notstart_cpp
Definition: tokenize.cpp:4521
static bool isCPPAttribute(const Token *tok)
Definition: tokenize.cpp:8256
static const std::unordered_map< std::string, std::string > cAlternativeTokens
Definition: tokenize.cpp:7513
static bool isClassStructUnionEnumStart(const Token *tok)
is tok the start brace { of a class, struct, union, or enum
Definition: tokenize.cpp:149
static bool setVarIdParseDeclaration(Token *&tok, const VariableMap &variableMap, bool executableScope)
Definition: tokenize.cpp:4185
static unsigned int tokDistance(const Token *tok1, const Token *tok2)
Definition: tokenize.cpp:2846
static Token * matchMemberName(const std::list< std::string > &scope, const Token *nsToken, Token *memberToken, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4911
static T * skipCPPOrAlignAttribute(T *tok)
Definition: tokenize.cpp:8267
static const Token * findUnmatchedTernaryOp(const Token *const begin, const Token *const end, int depth=0)
Definition: tokenize.cpp:8238
static Token * matchMemberVarName(const Member &var, const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4977
static T * skipInitializerList(T *tok)
Definition: tokenize.cpp:4994
static bool isEnumStart(const Token *tok)
Return whether tok is the "{" that starts an enumerator list.
Definition: tokenize.cpp:80
static const std::unordered_set< std::string > notstart_c
Definition: tokenize.cpp:4520
static bool isEnumScope(const Token *tok)
Definition: tokenize.cpp:1135
#define NOTSTART_C
Definition: tokenize.cpp:4519
static std::string getScopeName(const std::list< ScopeInfo2 > &scopeInfo)
Definition: tokenize.cpp:4903
static bool isNonMacro(const Token *tok)
Definition: tokenize.cpp:8277
static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
Definition: tokenize.cpp:2819
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:5257
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:4392
static bool isAlignAttribute(const Token *tok)
Definition: tokenize.cpp:8261
static Token * skipCaseLabel(Token *tok)
Definition: tokenize.cpp:3908
static void skipEnumBody(T *&tok)
Definition: tokenize.cpp:88
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:8124
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