1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2021 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 "check.h"
23 #include "errorlogger.h"
24 #include "library.h"
25 #include "mathlib.h"
26 #include "platform.h"
27 #include "preprocessor.h"
28 #include "settings.h"
29 #include "standards.h"
30 #include "summaries.h"
31 #include "symboldatabase.h"
32 #include "templatesimplifier.h"
33 #include "timer.h"
34 #include "token.h"
35 #include "utils.h"
36 #include "valueflow.h"
37 
38 #include <algorithm>
39 #include <cassert>
40 #include <cctype>
41 #include <cstring>
42 #include <iostream>
43 #include <set>
44 #include <stack>
45 #include <unordered_map>
46 #include <utility>
47 #include <vector>
48 //---------------------------------------------------------------------------
49 
50 namespace {
51     // local struct used in setVarId
52     // in order to store information about the scope
53     struct VarIdScopeInfo {
VarIdScopeInfo__anon5685b77f0111::VarIdScopeInfo54         VarIdScopeInfo()
55             : isExecutable(false), isStructInit(false), isEnum(false), startVarid(0) {}
VarIdScopeInfo__anon5685b77f0111::VarIdScopeInfo56         VarIdScopeInfo(bool isExecutable, bool isStructInit, bool isEnum, nonneg int startVarid)
57             : isExecutable(isExecutable), isStructInit(isStructInit), isEnum(isEnum), startVarid(startVarid) {}
58 
59         const bool isExecutable;
60         const bool isStructInit;
61         const bool isEnum;
62         const nonneg int startVarid;
63     };
64 }
65 
66 /** Return whether tok is the "{" that starts an enumerator list */
isEnumStart(const Token * tok)67 static bool isEnumStart(const Token* tok)
68 {
69     if (!tok || tok->str() != "{")
70         return false;
71     return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum");
72 }
73 
74 template<typename T>
skipEnumBody(T ** tok)75 static void skipEnumBody(T **tok)
76 {
77     T *defStart = *tok;
78     while (Token::Match(defStart, "%name%|::|:"))
79         defStart = defStart->next();
80     if (defStart && defStart->str() == "{")
81         *tok = defStart->link()->next();
82 }
83 
isFunctionHead(const Token * tok,const std::string & endsWith) const84 const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith) const
85 {
86     return Tokenizer::isFunctionHead(tok, endsWith, isCPP());
87 }
88 
isFunctionHead(const Token * tok,const std::string & endsWith,bool cpp)89 const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith, bool cpp)
90 {
91     if (!tok)
92         return nullptr;
93     if (tok->str() == "(")
94         tok = tok->link();
95     if (Token::Match(tok, ") ;|{|[")) {
96         tok = tok->next();
97         while (tok && tok->str() == "[" && tok->link()) {
98             if (endsWith.find(tok->str()) != std::string::npos)
99                 return tok;
100             tok = tok->link()->next();
101         }
102         return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
103     }
104     if (cpp && tok->str() == ")") {
105         tok = tok->next();
106         while (Token::Match(tok, "const|noexcept|override|final|volatile|&|&& !!(") ||
107                (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
108             tok = tok->next();
109         if (tok && tok->str() == ")")
110             tok = tok->next();
111         while (tok && tok->str() == "[")
112             tok = tok->link()->next();
113         if (Token::Match(tok, "throw|noexcept ("))
114             tok = tok->linkAt(1)->next();
115         if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
116             tok = tok->linkAt(1)->next();
117         if (tok && tok->originalName() == "->") { // trailing return type
118             for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
119                 if (tok->link() && Token::Match(tok, "<|[|("))
120                     tok = tok->link();
121         }
122         while (Token::Match(tok, "override|final !!(") ||
123                (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
124             tok = tok->next();
125         if (Token::Match(tok, "= 0|default|delete ;"))
126             tok = tok->tokAt(2);
127 
128         return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
129     }
130     return nullptr;
131 }
132 
133 /**
134  * is tok the start brace { of a class, struct, union, or enum
135  */
isClassStructUnionEnumStart(const Token * tok)136 static bool isClassStructUnionEnumStart(const Token * tok)
137 {
138     if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
139         return false;
140     const Token * tok2 = tok->previous();
141     while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
142         tok2 = tok2->previous();
143     return Token::Match(tok2, "class|struct|union|enum");
144 }
145 
146 //---------------------------------------------------------------------------
147 
Tokenizer()148 Tokenizer::Tokenizer() :
149     list(nullptr),
150     mSettings(nullptr),
151     mErrorLogger(nullptr),
152     mSymbolDatabase(nullptr),
153     mTemplateSimplifier(nullptr),
154     mVarId(0),
155     mUnnamedCount(0),
156     mCodeWithTemplates(false), //is there any templates?
157     mTimerResults(nullptr)
158 #ifdef MAXTIME
159     , mMaxTime(std::time(0) + MAXTIME)
160 #endif
161     , mPreprocessor(nullptr)
162 {}
163 
Tokenizer(const Settings * settings,ErrorLogger * errorLogger)164 Tokenizer::Tokenizer(const Settings *settings, ErrorLogger *errorLogger) :
165     list(settings),
166     mSettings(settings),
167     mErrorLogger(errorLogger),
168     mSymbolDatabase(nullptr),
169     mTemplateSimplifier(nullptr),
170     mVarId(0),
171     mUnnamedCount(0),
172     mCodeWithTemplates(false), //is there any templates?
173     mTimerResults(nullptr)
174 #ifdef MAXTIME
175     ,mMaxTime(std::time(0) + MAXTIME)
176 #endif
177     , mPreprocessor(nullptr)
178 {
179     // make sure settings are specified
180     assert(mSettings);
181 
182     mTemplateSimplifier = new TemplateSimplifier(this);
183 }
184 
~Tokenizer()185 Tokenizer::~Tokenizer()
186 {
187     delete mSymbolDatabase;
188     delete mTemplateSimplifier;
189 }
190 
191 
192 //---------------------------------------------------------------------------
193 // SizeOfType - gives the size of a type
194 //---------------------------------------------------------------------------
195 
sizeOfType(const Token * type) const196 nonneg int Tokenizer::sizeOfType(const Token *type) const
197 {
198     if (!type || type->str().empty())
199         return 0;
200 
201     if (type->tokType() == Token::eString)
202         return Token::getStrLength(type) + 1U;
203 
204     const std::map<std::string, int>::const_iterator it = mTypeSize.find(type->str());
205     if (it == mTypeSize.end()) {
206         const Library::PodType* podtype = mSettings->library.podtype(type->str());
207         if (!podtype)
208             return 0;
209 
210         return podtype->size;
211     } else if (type->isLong()) {
212         if (type->str() == "double")
213             return mSettings->sizeof_long_double;
214         else if (type->str() == "long")
215             return mSettings->sizeof_long_long;
216     }
217 
218     return it->second;
219 }
220 //---------------------------------------------------------------------------
221 
222 // check if this statement is a duplicate definition
duplicateTypedef(Token ** tokPtr,const Token * name,const Token * typeDef) const223 bool Tokenizer::duplicateTypedef(Token **tokPtr, const Token *name, const Token *typeDef) const
224 {
225     // check for an end of definition
226     const Token * tok = *tokPtr;
227     if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) {
228         const Token * end = tok->next();
229 
230         if (end->str() == "[") {
231             if (!end->link())
232                 syntaxError(end); // invalid code
233             end = end->link()->next();
234         } else if (end->str() == ",") {
235             // check for derived class
236             if (Token::Match(tok->previous(), "public|private|protected"))
237                 return false;
238 
239             // find end of definition
240             while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
241                 if (end->next()->str() == "(")
242                     end = end->linkAt(1);
243 
244                 end = (end)?end->next():nullptr;
245             }
246             if (end)
247                 end = end->next();
248         } else if (end->str() == "(") {
249             if (tok->previous()->str().compare(0, 8, "operator")  == 0) {
250                 // conversion operator
251                 return false;
252             } else if (tok->previous()->str() == "typedef") {
253                 // typedef of function returning this type
254                 return false;
255             } else if (Token::Match(tok->previous(), "public:|private:|protected:")) {
256                 return false;
257             } else if (tok->previous()->str() == ">") {
258                 if (!Token::Match(tok->tokAt(-2), "%type%"))
259                     return false;
260 
261                 if (!Token::Match(tok->tokAt(-3), ",|<"))
262                     return false;
263 
264                 *tokPtr = end->link();
265                 return true;
266             }
267         }
268 
269         if (end) {
270             if (Token::simpleMatch(end, ") {")) { // function parameter ?
271                 // look backwards
272                 if (Token::Match(tok->previous(), "%type%") &&
273                     !Token::Match(tok->previous(), "return|new|const|struct")) {
274                     // duplicate definition so skip entire function
275                     *tokPtr = end->next()->link();
276                     return true;
277                 }
278             } else if (end->str() == ">") { // template parameter ?
279                 // look backwards
280                 if (Token::Match(tok->previous(), "%type%") &&
281                     !Token::Match(tok->previous(), "return|new|const|volatile")) {
282                     // duplicate definition so skip entire template
283                     while (end && end->str() != "{")
284                         end = end->next();
285                     if (end) {
286                         *tokPtr = end->link();
287                         return true;
288                     }
289                 }
290             } else {
291                 // look backwards
292                 if (Token::Match(tok->previous(), "typedef|}|>") ||
293                     (end->str() == ";" && tok->previous()->str() == ",") ||
294                     (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
295                     (Token::Match(tok->previous(), "%type%") &&
296                      (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
297                       !Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
298                     // scan backwards for the end of the previous statement
299                     while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
300                         if (tok->previous()->str() == "}") {
301                             tok = tok->previous()->link();
302                         } else if (tok->previous()->str() == "typedef") {
303                             return true;
304                         } else if (tok->previous()->str() == "enum") {
305                             return true;
306                         } else if (tok->previous()->str() == "struct") {
307                             if (tok->strAt(-2) == "typedef" &&
308                                 tok->next()->str() == "{" &&
309                                 typeDef->strAt(3) != "{") {
310                                 // declaration after forward declaration
311                                 return true;
312                             } else if (tok->next()->str() == "{") {
313                                 return true;
314                             } else if (Token::Match(tok->next(), ")|*")) {
315                                 return true;
316                             } else if (tok->next()->str() == name->str()) {
317                                 return true;
318                             } else if (tok->next()->str() != ";") {
319                                 return true;
320                             } else {
321                                 return false;
322                             }
323                         } else if (tok->previous()->str() == "union") {
324                             if (tok->next()->str() != ";") {
325                                 return true;
326                             } else {
327                                 return false;
328                             }
329                         } else if (isCPP() && tok->previous()->str() == "class") {
330                             if (tok->next()->str() != ";") {
331                                 return true;
332                             } else {
333                                 return false;
334                             }
335                         }
336                         if (tok)
337                             tok = tok->previous();
338                     }
339 
340                     if ((*tokPtr)->strAt(1) != "(" || !Token::Match((*tokPtr)->linkAt(1), ") .|(|["))
341                         return true;
342                 }
343             }
344         }
345     }
346 
347     return false;
348 }
349 
unsupportedTypedef(const Token * tok) const350 void Tokenizer::unsupportedTypedef(const Token *tok) const
351 {
352     if (!mSettings->debugwarnings)
353         return;
354 
355     std::ostringstream str;
356     const Token *tok1 = tok;
357     int level = 0;
358     while (tok) {
359         if (level == 0 && tok->str() == ";")
360             break;
361         else if (tok->str() == "{")
362             ++level;
363         else if (tok->str() == "}") {
364             if (level == 0)
365                 break;
366             --level;
367         }
368 
369         if (tok != tok1)
370             str << " ";
371         str << tok->str();
372         tok = tok->next();
373     }
374     if (tok)
375         str << " ;";
376 
377     reportError(tok1, Severity::debug, "simplifyTypedef",
378                 "Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
379 }
380 
deleteInvalidTypedef(Token * typeDef)381 Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
382 {
383     Token *tok = nullptr;
384 
385     // remove typedef but leave ;
386     while (typeDef->next()) {
387         if (typeDef->next()->str() == ";") {
388             typeDef->deleteNext();
389             break;
390         } else if (typeDef->next()->str() == "{")
391             Token::eraseTokens(typeDef, typeDef->linkAt(1));
392         else if (typeDef->next()->str() == "}")
393             break;
394         typeDef->deleteNext();
395     }
396 
397     if (typeDef != list.front()) {
398         tok = typeDef->previous();
399         tok->deleteNext();
400     } else {
401         list.front()->deleteThis();
402         tok = list.front();
403     }
404 
405     return tok;
406 }
407 
408 namespace {
409     struct Space {
Space__anon5685b77f0211::Space410         Space() : bodyEnd(nullptr), bodyEnd2(nullptr), isNamespace(false) {}
411         std::string className;
412         const Token * bodyEnd;  // for body contains typedef define
413         const Token * bodyEnd2; // for body contains typedef using
414         bool isNamespace;
415         std::set<std::string> recordTypes;
416     };
417 }
418 
splitDefinitionFromTypedef(Token * tok,nonneg int * unnamedCount)419 static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
420 {
421     std::string name;
422     bool isConst = false;
423     Token *tok1 = tok->next();
424 
425     // skip const if present
426     if (tok1->str() == "const") {
427         tok1->deleteThis();
428         isConst = true;
429     }
430 
431     // skip "class|struct|union|enum"
432     tok1 = tok1->next();
433 
434     const bool hasName = Token::Match(tok1, "%name%");
435 
436     // skip name
437     if (hasName) {
438         name = tok1->str();
439         tok1 = tok1->next();
440     }
441 
442     // skip base classes if present
443     if (tok1->str() == ":") {
444         tok1 = tok1->next();
445         while (tok1 && tok1->str() != "{")
446             tok1 = tok1->next();
447         if (!tok1)
448             return nullptr;
449     }
450 
451     // skip to end
452     tok1 = tok1->link();
453 
454     if (!hasName) { // unnamed
455         if (tok1->next()) {
456             // use typedef name if available
457             if (Token::Match(tok1->next(), "%type%"))
458                 name = tok1->next()->str();
459             else // create a unique name
460                 name = "Unnamed" + MathLib::toString((*unnamedCount)++);
461             tok->next()->insertToken(name);
462         } else
463             return nullptr;
464     }
465 
466     tok1->insertToken(";");
467     tok1 = tok1->next();
468 
469     if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
470         tok->deleteThis();
471         tok1->deleteThis();
472         return nullptr;
473     } else {
474         tok1->insertToken("typedef");
475         tok1 = tok1->next();
476         Token * tok3 = tok1;
477         if (isConst) {
478             tok1->insertToken("const");
479             tok1 = tok1->next();
480         }
481         tok1->insertToken(tok->next()->str()); // struct, union or enum
482         tok1 = tok1->next();
483         tok1->insertToken(name);
484         tok->deleteThis();
485         tok = tok3;
486     }
487 
488     return tok;
489 }
490 
491 /* This function is called when processing function related typedefs.
492  * If simplifyTypedef generates an "Internal Error" message and the
493  * code that generated it deals in some way with functions, then this
494  * function will probably need to be extended to handle a new function
495  * related pattern */
processFunc(Token * tok2,bool inOperator) const496 Token *Tokenizer::processFunc(Token *tok2, bool inOperator) const
497 {
498     if (tok2->next() && tok2->next()->str() != ")" &&
499         tok2->next()->str() != ",") {
500         // skip over tokens for some types of canonicalization
501         if (Token::Match(tok2->next(), "( * %type% ) ("))
502             tok2 = tok2->linkAt(5);
503         else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
504             tok2 = tok2->linkAt(6);
505         else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
506             tok2 = tok2->tokAt(5);
507         else if (Token::Match(tok2->next(), "* ( %type% [") &&
508                  Token::Match(tok2->linkAt(4), "] ) ;|="))
509             tok2 = tok2->linkAt(4)->next();
510         else if (Token::Match(tok2->next(), "* ( * %type% ("))
511             tok2 = tok2->linkAt(5)->next();
512         else if (Token::simpleMatch(tok2->next(), "* [") &&
513                  Token::simpleMatch(tok2->linkAt(2), "] ;"))
514             tok2 = tok2->next();
515         else {
516             if (tok2->next()->str() == "(")
517                 tok2 = tok2->next()->link();
518             else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
519                 tok2 = tok2->next();
520 
521                 while (Token::Match(tok2, "*|&") &&
522                        !Token::Match(tok2->next(), ")|>"))
523                     tok2 = tok2->next();
524 
525                 // skip over namespace
526                 while (Token::Match(tok2, "%name% ::"))
527                     tok2 = tok2->tokAt(2);
528 
529                 if (!tok2)
530                     return nullptr;
531 
532                 if (tok2->str() == "(" &&
533                     tok2->link()->next() &&
534                     tok2->link()->next()->str() == "(") {
535                     tok2 = tok2->link();
536 
537                     if (tok2->next()->str() == "(")
538                         tok2 = tok2->next()->link();
539                 }
540 
541                 // skip over typedef parameter
542                 if (tok2->next() && tok2->next()->str() == "(") {
543                     tok2 = tok2->next()->link();
544                     if (!tok2->next())
545                         syntaxError(tok2);
546 
547                     if (tok2->next()->str() == "(")
548                         tok2 = tok2->next()->link();
549                 }
550             }
551         }
552     }
553     return tok2;
554 }
555 
simplifyUsingToTypedef()556 void Tokenizer::simplifyUsingToTypedef()
557 {
558     if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
559         return;
560 
561     for (Token *tok = list.front(); tok; tok = tok->next()) {
562         // using a::b;  =>   typedef  a::b  b;
563         if ((Token::Match(tok, "[;{}] using %name% :: %name% ::|;") && !tok->tokAt(2)->isKeyword()) ||
564             (Token::Match(tok, "[;{}] using :: %name% :: %name% ::|;") && !tok->tokAt(3)->isKeyword())) {
565             Token *endtok = tok->tokAt(5);
566             if (Token::Match(endtok, "%name%"))
567                 endtok = endtok->next();
568             while (Token::Match(endtok, ":: %name%"))
569                 endtok = endtok->tokAt(2);
570             if (endtok && endtok->str() == ";") {
571                 tok->next()->str("typedef");
572                 endtok = endtok->previous();
573                 endtok->insertToken(endtok->str());
574             }
575         }
576     }
577 }
578 
simplifyTypedef()579 void Tokenizer::simplifyTypedef()
580 {
581     std::vector<Space> spaceInfo;
582     bool isNamespace = false;
583     std::string className;
584     std::string fullClassName;
585     bool hasClass = false;
586     bool goback = false;
587 
588     // add global namespace
589     spaceInfo.emplace_back(Space{});
590 
591     // Convert "using a::b;" to corresponding typedef statements
592     simplifyUsingToTypedef();
593 
594     for (Token *tok = list.front(); tok; tok = tok->next()) {
595         if (mErrorLogger && !list.getFiles().empty())
596             mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
597 
598         if (Settings::terminated())
599             return;
600 
601         if (isMaxTime())
602             return;
603 
604         if (goback) {
605             //jump back once, see the comment at the end of the function
606             goback = false;
607             tok = tok->previous();
608         }
609 
610         if (tok->str() != "typedef") {
611             if (Token::simpleMatch(tok, "( typedef")) {
612                 // Skip typedefs inside parentheses (#2453 and #4002)
613                 tok = tok->next();
614             } else if (Token::Match(tok, "class|struct|namespace %any%") &&
615                        (!tok->previous() || tok->previous()->str() != "enum")) {
616                 isNamespace = (tok->str() == "namespace");
617                 hasClass = true;
618                 className = tok->next()->str();
619                 const Token *tok1 = tok->next();
620                 fullClassName = className;
621                 while (Token::Match(tok1, "%name% :: %name%")) {
622                     tok1 = tok1->tokAt(2);
623                     fullClassName += " :: " + tok1->str();
624                 }
625             } else if (hasClass && tok->str() == ";") {
626                 hasClass = false;
627             } else if (hasClass && tok->str() == "{") {
628                 if (!isNamespace)
629                     spaceInfo.back().recordTypes.insert(fullClassName);
630 
631                 Space info;
632                 info.isNamespace = isNamespace;
633                 info.className = className;
634                 info.bodyEnd = tok->link();
635                 info.bodyEnd2 = tok->link();
636                 spaceInfo.push_back(info);
637 
638                 hasClass = false;
639             } else if (spaceInfo.size() > 1 && tok->str() == "}" && spaceInfo.back().bodyEnd == tok) {
640                 spaceInfo.pop_back();
641             }
642             continue;
643         }
644 
645         // pull struct, union, enum or class definition out of typedef
646         // use typedef name for unnamed struct, union, enum or class
647         if (Token::Match(tok->next(), "const| struct|enum|union|class %type%| {|:")) {
648             Token *tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
649             if (!tok1)
650                 continue;
651             tok = tok1;
652         }
653 
654         /** @todo add support for union */
655         if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
656             tok->deleteNext(3);
657             tok->deleteThis();
658             if (tok->next())
659                 tok->deleteThis();
660             //now the next token to process is 'tok', not 'tok->next()';
661             goback = true;
662             continue;
663         }
664 
665         Token *typeName;
666         Token *typeStart = nullptr;
667         Token *typeEnd = nullptr;
668         Token *argStart = nullptr;
669         Token *argEnd = nullptr;
670         Token *arrayStart = nullptr;
671         Token *arrayEnd = nullptr;
672         Token *specStart = nullptr;
673         Token *specEnd = nullptr;
674         Token *typeDef = tok;
675         Token *argFuncRetStart = nullptr;
676         Token *argFuncRetEnd = nullptr;
677         Token *funcStart = nullptr;
678         Token *funcEnd = nullptr;
679         Token *tokOffset = tok->next();
680         bool function = false;
681         bool functionPtr = false;
682         bool functionRetFuncPtr = false;
683         bool functionPtrRetFuncPtr = false;
684         bool ptrToArray = false;
685         bool refToArray = false;
686         bool ptrMember = false;
687         bool typeOf = false;
688         Token *namespaceStart = nullptr;
689         Token *namespaceEnd = nullptr;
690 
691         // check for invalid input
692         if (!tokOffset)
693             syntaxError(tok);
694 
695 
696         if (tokOffset->str() == "::") {
697             typeStart = tokOffset;
698             tokOffset = tokOffset->next();
699 
700             while (Token::Match(tokOffset, "%type% ::"))
701                 tokOffset = tokOffset->tokAt(2);
702 
703             typeEnd = tokOffset;
704 
705             if (Token::Match(tokOffset, "%type%"))
706                 tokOffset = tokOffset->next();
707         } else if (Token::Match(tokOffset, "%type% ::")) {
708             typeStart = tokOffset;
709 
710             do {
711                 tokOffset = tokOffset->tokAt(2);
712             } while (Token::Match(tokOffset, "%type% ::"));
713 
714             typeEnd = tokOffset;
715 
716             if (Token::Match(tokOffset, "%type%"))
717                 tokOffset = tokOffset->next();
718         } else if (Token::Match(tokOffset, "%type%")) {
719             typeStart = tokOffset;
720 
721             while (Token::Match(tokOffset, "const|struct|enum %type%") ||
722                    (tokOffset->next() && tokOffset->next()->isStandardType()))
723                 tokOffset = tokOffset->next();
724 
725             typeEnd = tokOffset;
726             tokOffset = tokOffset->next();
727 
728             while (Token::Match(tokOffset, "%type%") &&
729                    (tokOffset->isStandardType() || Token::Match(tokOffset, "unsigned|signed"))) {
730                 typeEnd = tokOffset;
731                 tokOffset = tokOffset->next();
732             }
733 
734             bool atEnd = false;
735             while (!atEnd) {
736                 if (tokOffset && tokOffset->str() == "::") {
737                     typeEnd = tokOffset;
738                     tokOffset = tokOffset->next();
739                 }
740 
741                 if (Token::Match(tokOffset, "%type%") &&
742                     tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
743                     typeEnd = tokOffset;
744                     tokOffset = tokOffset->next();
745                 } else if (Token::simpleMatch(tokOffset, "const (")) {
746                     typeEnd = tokOffset;
747                     tokOffset = tokOffset->next();
748                     atEnd = true;
749                 } else
750                     atEnd = true;
751             }
752         } else
753             continue; // invalid input
754 
755         // check for invalid input
756         if (!tokOffset)
757             syntaxError(tok);
758 
759         // check for template
760         if (!isC() && tokOffset->str() == "<") {
761             typeEnd = tokOffset->findClosingBracket();
762 
763             while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
764                 typeEnd = typeEnd->tokAt(2);
765 
766             if (!typeEnd) {
767                 // internal error
768                 return;
769             }
770 
771             while (Token::Match(typeEnd->next(), "const|volatile"))
772                 typeEnd = typeEnd->next();
773 
774             tok = typeEnd;
775             tokOffset = tok->next();
776         }
777 
778         std::list<std::string> pointers;
779         // check for pointers and references
780         while (Token::Match(tokOffset, "*|&|&&|const")) {
781             pointers.push_back(tokOffset->str());
782             tokOffset = tokOffset->next();
783         }
784 
785         // check for invalid input
786         if (!tokOffset)
787             syntaxError(tok);
788 
789         if (tokOffset->isName() && !tokOffset->isKeyword()) {
790             // found the type name
791             typeName = tokOffset;
792             tokOffset = tokOffset->next();
793 
794             // check for array
795             while (tokOffset && tokOffset->str() == "[") {
796                 if (!arrayStart)
797                     arrayStart = tokOffset;
798                 arrayEnd = tokOffset->link();
799                 tokOffset = arrayEnd->next();
800             }
801 
802             // check for end or another
803             if (Token::Match(tokOffset, ";|,"))
804                 tok = tokOffset;
805 
806             // or a function typedef
807             else if (tokOffset && tokOffset->str() == "(") {
808                 Token *tokOffset2 = nullptr;
809                 if (Token::Match(tokOffset, "( *|%name%")) {
810                     tokOffset2 = tokOffset->next();
811                     if (tokOffset2->str() == "typename")
812                         tokOffset2 = tokOffset2->next();
813                     while (Token::Match(tokOffset2, "%type% ::"))
814                         tokOffset2 = tokOffset2->tokAt(2);
815                 }
816 
817                 // unhandled typedef, skip it and continue
818                 if (typeName->str() == "void") {
819                     unsupportedTypedef(typeDef);
820                     tok = deleteInvalidTypedef(typeDef);
821                     if (tok == list.front())
822                         //now the next token to process is 'tok', not 'tok->next()';
823                         goback = true;
824                     continue;
825                 }
826 
827                 // function pointer
828                 else if (Token::Match(tokOffset2, "* %name% ) (")) {
829                     // name token wasn't a name, it was part of the type
830                     typeEnd = typeEnd->next();
831                     functionPtr = true;
832                     funcStart = funcEnd = tokOffset2; // *
833                     tokOffset = tokOffset2->tokAt(3); // (
834                     typeName = tokOffset->tokAt(-2);
835                     argStart = tokOffset;
836                     argEnd = tokOffset->link();
837                     tok = argEnd->next();
838                 }
839 
840                 // function
841                 else if (isFunctionHead(tokOffset->link(), ";,")) {
842                     function = true;
843                     if (tokOffset->link()->next()->str() == "const") {
844                         specStart = tokOffset->link()->next();
845                         specEnd = specStart;
846                     }
847                     argStart = tokOffset;
848                     argEnd = tokOffset->link();
849                     tok = argEnd->next();
850                     if (specStart)
851                         tok = tok->next();
852                 }
853 
854                 // syntax error
855                 else
856                     syntaxError(tok);
857             }
858 
859             // unhandled typedef, skip it and continue
860             else {
861                 unsupportedTypedef(typeDef);
862                 tok = deleteInvalidTypedef(typeDef);
863                 if (tok == list.front())
864                     //now the next token to process is 'tok', not 'tok->next()';
865                     goback = true;
866                 continue;
867             }
868         }
869 
870         // typeof: typedef typeof ( ... ) type;
871         else if (Token::simpleMatch(tokOffset->previous(), "typeof (") &&
872                  Token::Match(tokOffset->link(), ") %type% ;")) {
873             argStart = tokOffset;
874             argEnd = tokOffset->link();
875             typeName = tokOffset->link()->next();
876             tok = typeName->next();
877             typeOf = true;
878         }
879 
880         // function: typedef ... ( ... type )( ... );
881         //           typedef ... (( ... type )( ... ));
882         //           typedef ... ( * ( ... type )( ... ));
883         else if (tokOffset->str() == "(" && (
884                      (tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
885                       Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
886                      (Token::simpleMatch(tokOffset, "( (") &&
887                       tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
888                       Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
889                      (Token::simpleMatch(tokOffset, "( * (") &&
890                       tokOffset->linkAt(2) && Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
891                       Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
892             if (tokOffset->next()->str() == "(")
893                 tokOffset = tokOffset->next();
894             else if (Token::simpleMatch(tokOffset, "( * (")) {
895                 pointers.emplace_back("*");
896                 tokOffset = tokOffset->tokAt(2);
897             }
898 
899             if (tokOffset->link()->strAt(-2) == "*")
900                 functionPtr = true;
901             else
902                 function = true;
903             funcStart = tokOffset->next();
904             tokOffset = tokOffset->link();
905             funcEnd = tokOffset->tokAt(-2);
906             typeName = tokOffset->previous();
907             argStart = tokOffset->next();
908             argEnd = tokOffset->next()->link();
909             if (!argEnd)
910                 syntaxError(argStart);
911 
912             tok = argEnd->next();
913             Token *spec = tok;
914             if (Token::Match(spec, "const|volatile")) {
915                 specStart = spec;
916                 specEnd = spec;
917                 while (Token::Match(spec->next(), "const|volatile")) {
918                     specEnd = spec->next();
919                     spec = specEnd;
920                 }
921                 tok = specEnd->next();
922             }
923             if (!tok)
924                 syntaxError(specEnd);
925 
926             if (tok->str() == ")")
927                 tok = tok->next();
928         }
929 
930         else if (Token::Match(tokOffset, "( %type% (")) {
931             function = true;
932             if (tokOffset->link()->next()) {
933                 tok = tokOffset->link()->next();
934                 tokOffset = tokOffset->tokAt(2);
935                 typeName = tokOffset->previous();
936                 argStart = tokOffset;
937                 argEnd = tokOffset->link();
938             } else {
939                 // internal error
940                 continue;
941             }
942         }
943 
944         // pointer to function returning pointer to function
945         else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
946                  Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
947                  Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
948             functionPtrRetFuncPtr = true;
949 
950             tokOffset = tokOffset->tokAt(6);
951             typeName = tokOffset->tokAt(-2);
952             argStart = tokOffset;
953             argEnd = tokOffset->link();
954             if (!argEnd)
955                 syntaxError(arrayStart);
956 
957             argFuncRetStart = argEnd->tokAt(2);
958             argFuncRetEnd = argFuncRetStart->link();
959             if (!argFuncRetEnd)
960                 syntaxError(argFuncRetStart);
961 
962             tok = argFuncRetEnd->next();
963         }
964 
965         // function returning pointer to function
966         else if (Token::Match(tokOffset, "( * %type% (") &&
967                  Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
968                  Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
969             functionRetFuncPtr = true;
970 
971             tokOffset = tokOffset->tokAt(3);
972             typeName = tokOffset->previous();
973             argStart = tokOffset;
974             argEnd = tokOffset->link();
975 
976             argFuncRetStart = argEnd->tokAt(2);
977             if (!argFuncRetStart)
978                 syntaxError(tokOffset);
979 
980             argFuncRetEnd = argFuncRetStart->link();
981             if (!argFuncRetEnd)
982                 syntaxError(tokOffset);
983 
984             tok = argFuncRetEnd->next();
985         } else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
986             functionRetFuncPtr = true;
987 
988             tokOffset = tokOffset->tokAt(5);
989             typeName = tokOffset->tokAt(-2);
990             argStart = tokOffset;
991             argEnd = tokOffset->link();
992             if (!argEnd)
993                 syntaxError(arrayStart);
994 
995             argFuncRetStart = argEnd->tokAt(2);
996             if (!argFuncRetStart)
997                 syntaxError(tokOffset);
998 
999             argFuncRetEnd = argFuncRetStart->link();
1000             if (!argFuncRetEnd)
1001                 syntaxError(tokOffset);
1002 
1003             tok = argFuncRetEnd->next();
1004         }
1005 
1006         // pointer/reference to array
1007         else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
1008             ptrToArray = (tokOffset->next()->str() == "*");
1009             refToArray = !ptrToArray;
1010             tokOffset = tokOffset->tokAt(2);
1011             typeName = tokOffset;
1012             arrayStart = tokOffset->tokAt(2);
1013             arrayEnd = arrayStart->link();
1014             if (!arrayEnd)
1015                 syntaxError(arrayStart);
1016 
1017             tok = arrayEnd->next();
1018         }
1019 
1020         // pointer to class member
1021         else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
1022             tokOffset = tokOffset->tokAt(2);
1023             namespaceStart = tokOffset->previous();
1024             namespaceEnd = tokOffset;
1025             ptrMember = true;
1026             tokOffset = tokOffset->tokAt(2);
1027             typeName = tokOffset;
1028             tok = tokOffset->tokAt(2);
1029         }
1030 
1031         // unhandled typedef, skip it and continue
1032         else {
1033             unsupportedTypedef(typeDef);
1034             tok = deleteInvalidTypedef(typeDef);
1035             if (tok == list.front())
1036                 //now the next token to process is 'tok', not 'tok->next()';
1037                 goback = true;
1038             continue;
1039         }
1040 
1041         bool done = false;
1042         bool ok = true;
1043 
1044         TypedefInfo typedefInfo;
1045         typedefInfo.name = typeName->str();
1046         typedefInfo.filename = list.file(typeName);
1047         typedefInfo.lineNumber = typeName->linenr();
1048         typedefInfo.column = typeName->column();
1049         typedefInfo.used = false;
1050         mTypedefInfo.push_back(typedefInfo);
1051 
1052         while (!done) {
1053             std::string pattern = typeName->str();
1054             int scope = 0;
1055             bool simplifyType = false;
1056             bool inMemberFunc = false;
1057             int memberScope = 0;
1058             bool globalScope = false;
1059             int classLevel = spaceInfo.size();
1060             std::string removed;
1061             std::string classPath;
1062             for (size_t i = 1; i < spaceInfo.size(); ++i) {
1063                 if (!classPath.empty())
1064                     classPath += " :: ";
1065                 classPath += spaceInfo[i].className;
1066             }
1067 
1068             for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1069                 if (Settings::terminated())
1070                     return;
1071 
1072                 removed.clear();
1073 
1074                 if (tok2->link()) { // Pre-check for performance
1075                     // check for end of scope
1076                     if (tok2->str() == "}") {
1077                         // check for end of member function
1078                         if (inMemberFunc) {
1079                             --memberScope;
1080                             if (memberScope == 0)
1081                                 inMemberFunc = false;
1082                         }
1083 
1084                         if (classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd2) {
1085                             --classLevel;
1086                             pattern.clear();
1087 
1088                             for (int i = classLevel; i < spaceInfo.size(); ++i)
1089                                 pattern += (spaceInfo[i].className + " :: ");
1090 
1091                             pattern += typeName->str();
1092                         } else {
1093                             if (scope == 0)
1094                                 break;
1095                             --scope;
1096                         }
1097                     }
1098 
1099                     // check for member functions
1100                     else if (isCPP() && tok2->str() == "(" && isFunctionHead(tok2, "{")) {
1101                         const Token *func = tok2->previous();
1102 
1103                         /** @todo add support for multi-token operators */
1104                         if (func->previous()->str() == "operator")
1105                             func = func->previous();
1106 
1107                         if (!func->previous())
1108                             syntaxError(func);
1109 
1110                         // check for qualifier
1111                         if (Token::Match(func->tokAt(-2), "%name% ::")) {
1112                             int offset = -2;
1113                             while (Token::Match(func->tokAt(offset - 2), "%name% ::"))
1114                                 offset -= 2;
1115                             // check for available and matching class name
1116                             if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1117                                 func->strAt(offset) == spaceInfo[classLevel].className) {
1118                                 memberScope = 0;
1119                                 inMemberFunc = true;
1120                             }
1121                         }
1122                     }
1123 
1124                     // check for entering a new scope
1125                     else if (tok2->str() == "{") {
1126                         // check for entering a new namespace
1127                         if (isCPP() && tok2->strAt(-2) == "namespace") {
1128                             if (classLevel < spaceInfo.size() &&
1129                                 spaceInfo[classLevel].isNamespace &&
1130                                 spaceInfo[classLevel].className == tok2->previous()->str()) {
1131                                 spaceInfo[classLevel].bodyEnd2 = tok2->link();
1132                                 ++classLevel;
1133                                 pattern.clear();
1134                                 for (int i = classLevel; i < spaceInfo.size(); ++i)
1135                                     pattern += spaceInfo[i].className + " :: ";
1136 
1137                                 pattern += typeName->str();
1138                             }
1139                             ++scope;
1140                         }
1141 
1142                         // keep track of scopes within member function
1143                         if (inMemberFunc)
1144                             ++memberScope;
1145 
1146                         ++scope;
1147                     }
1148                 }
1149 
1150                 // check for operator typedef
1151                 /** @todo add support for multi-token operators */
1152                 else if (isCPP() &&
1153                          tok2->str() == "operator" &&
1154                          tok2->next() &&
1155                          tok2->next()->str() == typeName->str() &&
1156                          tok2->linkAt(2) &&
1157                          tok2->strAt(2) == "(" &&
1158                          Token::Match(tok2->linkAt(2), ") const| {")) {
1159                     // check for qualifier
1160                     if (tok2->previous()->str() == "::") {
1161                         // check for available and matching class name
1162                         if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1163                             tok2->strAt(-2) == spaceInfo[classLevel].className) {
1164                             tok2 = tok2->next();
1165                             simplifyType = true;
1166                         }
1167                     }
1168                 }
1169 
1170                 // check for typedef that can be substituted
1171                 else if ((tok2->isNameOnly() || (tok2->isName() && tok2->isExpandedMacro())) &&
1172                          (Token::simpleMatch(tok2, pattern.c_str(), pattern.size()) ||
1173                           (inMemberFunc && tok2->str() == typeName->str()))) {
1174                     // member function class variables don't need qualification
1175                     if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
1176                         Token *start = tok2;
1177                         int count = 0;
1178                         int back = classLevel - 1;
1179                         bool good = true;
1180                         // check for extra qualification
1181                         while (back >= 1) {
1182                             Token *qualificationTok = start->tokAt(-2);
1183                             if (!Token::Match(qualificationTok, "%type% ::"))
1184                                 break;
1185                             if (qualificationTok->str() == spaceInfo[back].className) {
1186                                 start = qualificationTok;
1187                                 back--;
1188                                 count++;
1189                             } else {
1190                                 good = false;
1191                                 break;
1192                             }
1193                         }
1194                         // check global namespace
1195                         if (good && back == 1 && start->strAt(-1) == "::")
1196                             good = false;
1197 
1198                         if (good) {
1199                             // remove any extra qualification if present
1200                             while (count) {
1201                                 if (!removed.empty())
1202                                     removed.insert(0, " ");
1203                                 removed.insert(0, tok2->strAt(-2) + " " + tok2->strAt(-1));
1204                                 tok2->tokAt(-3)->deleteNext(2);
1205                                 --count;
1206                             }
1207 
1208                             // remove global namespace if present
1209                             if (tok2->strAt(-1) == "::") {
1210                                 removed.insert(0, ":: ");
1211                                 tok2->tokAt(-2)->deleteNext();
1212                                 globalScope = true;
1213                             }
1214 
1215                             // remove qualification if present
1216                             for (int i = classLevel; i < spaceInfo.size(); ++i) {
1217                                 if (!removed.empty())
1218                                     removed += " ";
1219                                 removed += (tok2->str() + " " + tok2->strAt(1));
1220                                 tok2->deleteThis();
1221                                 tok2->deleteThis();
1222                             }
1223                             simplifyType = true;
1224                         }
1225                     } else {
1226                         if (tok2->strAt(-1) == "::") {
1227                             int relativeSpaceInfoSize = spaceInfo.size();
1228                             Token * tokBeforeType = tok2->previous();
1229                             while (relativeSpaceInfoSize > 1 &&
1230                                    tokBeforeType && tokBeforeType->str() == "::" &&
1231                                    tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
1232                                 tokBeforeType = tokBeforeType->tokAt(-2);
1233                                 --relativeSpaceInfoSize;
1234                             }
1235                             if (tokBeforeType && tokBeforeType->str() != "::") {
1236                                 Token::eraseTokens(tokBeforeType, tok2);
1237                                 simplifyType = true;
1238                             }
1239                         } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
1240                             tok2 = tok2->next();
1241                         } else if (duplicateTypedef(&tok2, typeName, typeDef)) {
1242                             // skip to end of scope if not already there
1243                             if (tok2->str() != "}") {
1244                                 while (tok2->next()) {
1245                                     if (tok2->next()->str() == "{")
1246                                         tok2 = tok2->linkAt(1)->previous();
1247                                     else if (tok2->next()->str() == "}")
1248                                         break;
1249 
1250                                     tok2 = tok2->next();
1251                                 }
1252                             }
1253                         } else if (Token::Match(tok2->tokAt(-2), "%type% *|&")) {
1254                             // Ticket #5868: Don't substitute variable names
1255                         } else if (tok2->previous()->str() != ".") {
1256                             simplifyType = true;
1257                         }
1258                     }
1259                 }
1260 
1261                 if (simplifyType) {
1262                     mTypedefInfo.back().used = true;
1263 
1264                     // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
1265                     if (functionPtr && (tok2->previous()->str() == "operator" ||
1266                                         (tok2->next() && tok2->next()->str() == "operator"))) {
1267                         simplifyType = false;
1268                         tok2 = tok2->next();
1269                         continue;
1270                     }
1271 
1272                     // There are 2 categories of typedef substitutions:
1273                     // 1. variable declarations that preserve the variable name like
1274                     //    global, local, and function parameters
1275                     // 2. not variable declarations that have no name like derived
1276                     //    classes, casts, operators, and template parameters
1277 
1278                     // try to determine which category this substitution is
1279                     bool inCast = false;
1280                     bool inTemplate = false;
1281                     bool inOperator = false;
1282                     bool inSizeof = false;
1283 
1284                     const bool sameStartEnd = (typeStart == typeEnd);
1285 
1286                     // check for derived class: class A : some_typedef {
1287                     const bool isDerived = Token::Match(tok2->previous(), "public|protected|private %type% {|,");
1288 
1289                     // check for cast: (some_typedef) A or static_cast<some_typedef>(A)
1290                     // todo: check for more complicated casts like: (const some_typedef *)A
1291                     if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
1292                         (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")) ||
1293                         Token::Match(tok2->tokAt(-2), "( const %name% )"))
1294                         inCast = true;
1295 
1296                     // check for template parameters: t<some_typedef> t1
1297                     else if (Token::Match(tok2->previous(), "<|,") &&
1298                              Token::Match(tok2->next(), "&|*| &|*| >|,"))
1299                         inTemplate = true;
1300 
1301                     else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
1302                         inSizeof = true;
1303 
1304                     // check for operator
1305                     if (tok2->strAt(-1) == "operator" ||
1306                         Token::simpleMatch(tok2->tokAt(-2), "operator const"))
1307                         inOperator = true;
1308 
1309                     if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
1310                         // Remove one typename if it is already contained in the goal
1311                         typeStart = typeStart->next();
1312                     }
1313 
1314                     // skip over class or struct in derived class declaration
1315                     bool structRemoved = false;
1316                     if (isDerived && Token::Match(typeStart, "class|struct")) {
1317                         if (typeStart->str() == "struct")
1318                             structRemoved = true;
1319                         typeStart = typeStart->next();
1320                     }
1321                     if (Token::Match(typeStart, "struct|class") && Token::Match(tok2, "%name% ::"))
1322                         typeStart = typeStart->next();
1323 
1324                     if (sameStartEnd)
1325                         typeEnd = typeStart;
1326 
1327                     // start substituting at the typedef name by replacing it with the type
1328                     tok2->str(typeStart->str());
1329 
1330                     // restore qualification if it was removed
1331                     if (typeStart->str() == "struct" || structRemoved) {
1332                         if (structRemoved)
1333                             tok2 = tok2->previous();
1334 
1335                         if (globalScope) {
1336                             tok2->insertToken("::");
1337                             tok2 = tok2->next();
1338                         }
1339 
1340                         for (int i = classLevel; i < spaceInfo.size(); ++i) {
1341                             tok2->insertToken(spaceInfo[i].className);
1342                             tok2 = tok2->next();
1343                             tok2->insertToken("::");
1344                             tok2 = tok2->next();
1345                         }
1346                     }
1347 
1348                     // add some qualification back if needed
1349                     Token *start = tok2;
1350                     std::string removed1 = removed;
1351                     std::string::size_type idx = removed1.rfind(" ::");
1352 
1353                     if (idx != std::string::npos)
1354                         removed1.resize(idx);
1355                     if (removed1 == classPath && !removed1.empty()) {
1356                         for (std::vector<Space>::const_reverse_iterator it = spaceInfo.crbegin(); it != spaceInfo.crend(); ++it) {
1357                             if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
1358                                 std::string::size_type spaceIdx = 0;
1359                                 std::string::size_type startIdx = 0;
1360                                 while ((spaceIdx = removed1.find(" ", startIdx)) != std::string::npos) {
1361                                     tok2->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
1362                                     startIdx = spaceIdx + 1;
1363                                 }
1364                                 tok2->previous()->insertToken(removed1.substr(startIdx));
1365                                 tok2->previous()->insertToken("::");
1366                                 break;
1367                             }
1368                             idx = removed1.rfind(" ::");
1369                             if (idx == std::string::npos)
1370                                 break;
1371 
1372                             removed1.resize(idx);
1373                         }
1374                     }
1375                     // add remainder of type
1376                     tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
1377 
1378                     if (!pointers.empty()) {
1379                         for (const std::string &p : pointers) {
1380                             tok2->insertToken(p);
1381                             tok2 = tok2->next();
1382                         }
1383                     }
1384 
1385                     if (funcStart && funcEnd) {
1386                         tok2->insertToken("(");
1387                         tok2 = tok2->next();
1388                         Token *paren = tok2;
1389                         tok2 = TokenList::copyTokens(tok2, funcStart, funcEnd);
1390 
1391                         if (!inCast)
1392                             tok2 = processFunc(tok2, inOperator);
1393 
1394                         if (!tok2)
1395                             break;
1396 
1397                         while (Token::Match(tok2, "%name%|] ["))
1398                             tok2 = tok2->linkAt(1);
1399 
1400                         tok2->insertToken(")");
1401                         tok2 = tok2->next();
1402                         Token::createMutualLinks(tok2, paren);
1403 
1404                         tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
1405 
1406                         if (specStart) {
1407                             Token *spec = specStart;
1408                             tok2->insertToken(spec->str());
1409                             tok2 = tok2->next();
1410                             while (spec != specEnd) {
1411                                 spec = spec->next();
1412                                 tok2->insertToken(spec->str());
1413                                 tok2 = tok2->next();
1414                             }
1415                         }
1416                     }
1417 
1418                     else if (functionPtr || function) {
1419                         // don't add parentheses around function names because it
1420                         // confuses other simplifications
1421                         bool needParen = true;
1422                         if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
1423                             needParen = false;
1424                         if (needParen) {
1425                             tok2->insertToken("(");
1426                             tok2 = tok2->next();
1427                         }
1428                         Token *tok3 = tok2;
1429                         if (namespaceStart) {
1430                             const Token *tok4 = namespaceStart;
1431 
1432                             while (tok4 != namespaceEnd) {
1433                                 tok2->insertToken(tok4->str());
1434                                 tok2 = tok2->next();
1435                                 tok4 = tok4->next();
1436                             }
1437                             tok2->insertToken(namespaceEnd->str());
1438                             tok2 = tok2->next();
1439                         }
1440                         if (functionPtr) {
1441                             tok2->insertToken("*");
1442                             tok2 = tok2->next();
1443                         }
1444 
1445                         if (!inCast)
1446                             tok2 = processFunc(tok2, inOperator);
1447 
1448                         if (needParen) {
1449                             if (!tok2)
1450                                 syntaxError(nullptr);
1451 
1452                             tok2->insertToken(")");
1453                             tok2 = tok2->next();
1454                             Token::createMutualLinks(tok2, tok3);
1455                         }
1456                         if (!tok2)
1457                             syntaxError(nullptr);
1458 
1459                         tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
1460                         if (inTemplate) {
1461                             if (!tok2)
1462                                 syntaxError(nullptr);
1463 
1464                             tok2 = tok2->next();
1465                         }
1466 
1467                         if (specStart) {
1468                             Token *spec = specStart;
1469                             tok2->insertToken(spec->str());
1470                             tok2 = tok2->next();
1471                             while (spec != specEnd) {
1472                                 spec = spec->next();
1473                                 tok2->insertToken(spec->str());
1474                                 tok2 = tok2->next();
1475                             }
1476                         }
1477                     } else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
1478                         tok2->insertToken("(");
1479                         tok2 = tok2->next();
1480                         Token *tok3 = tok2;
1481                         tok2->insertToken("*");
1482                         tok2 = tok2->next();
1483 
1484                         Token * tok4 = nullptr;
1485                         if (functionPtrRetFuncPtr) {
1486                             tok2->insertToken("(");
1487                             tok2 = tok2->next();
1488                             tok4 = tok2;
1489                             tok2->insertToken("*");
1490                             tok2 = tok2->next();
1491                         }
1492 
1493                         // skip over variable name if there
1494                         if (!inCast) {
1495                             if (!tok2 || !tok2->next())
1496                                 syntaxError(nullptr);
1497 
1498                             if (tok2->next()->str() != ")")
1499                                 tok2 = tok2->next();
1500                         }
1501 
1502                         if (tok4 && functionPtrRetFuncPtr) {
1503                             tok2->insertToken(")");
1504                             tok2 = tok2->next();
1505                             Token::createMutualLinks(tok2, tok4);
1506                         }
1507 
1508                         tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
1509 
1510                         tok2->insertToken(")");
1511                         tok2 = tok2->next();
1512                         Token::createMutualLinks(tok2, tok3);
1513 
1514                         tok2 = TokenList::copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
1515                     } else if (ptrToArray || refToArray) {
1516                         tok2->insertToken("(");
1517                         tok2 = tok2->next();
1518                         Token *tok3 = tok2;
1519 
1520                         if (ptrToArray)
1521                             tok2->insertToken("*");
1522                         else
1523                             tok2->insertToken("&");
1524                         tok2 = tok2->next();
1525 
1526                         bool hasName = false;
1527                         // skip over name
1528                         if (tok2->next() && tok2->next()->str() != ")" && tok2->next()->str() != "," &&
1529                             tok2->next()->str() != ">") {
1530                             hasName = true;
1531                             if (tok2->next()->str() != "(")
1532                                 tok2 = tok2->next();
1533 
1534                             // check for function and skip over args
1535                             if (tok2 && tok2->next() && tok2->next()->str() == "(")
1536                                 tok2 = tok2->next()->link();
1537 
1538                             // check for array
1539                             if (tok2 && tok2->next() && tok2->next()->str() == "[")
1540                                 tok2 = tok2->next()->link();
1541                         }
1542 
1543                         tok2->insertToken(")");
1544                         Token::createMutualLinks(tok2->next(), tok3);
1545 
1546                         if (!hasName)
1547                             tok2 = tok2->next();
1548                     } else if (ptrMember) {
1549                         if (Token::simpleMatch(tok2, "* (")) {
1550                             tok2->insertToken("*");
1551                             tok2 = tok2->next();
1552                         } else {
1553                             // This is the case of casting operator.
1554                             // Name is not available, and () should not be
1555                             // inserted
1556                             const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
1557                             Token *openParenthesis = nullptr;
1558 
1559                             if (!castOperator) {
1560                                 tok2->insertToken("(");
1561                                 tok2 = tok2->next();
1562 
1563                                 openParenthesis = tok2;
1564                             }
1565 
1566                             const Token *tok4 = namespaceStart;
1567 
1568                             while (tok4 != namespaceEnd) {
1569                                 tok2->insertToken(tok4->str());
1570                                 tok2 = tok2->next();
1571                                 tok4 = tok4->next();
1572                             }
1573                             tok2->insertToken(namespaceEnd->str());
1574                             tok2 = tok2->next();
1575 
1576                             tok2->insertToken("*");
1577                             tok2 = tok2->next();
1578 
1579                             if (openParenthesis) {
1580                                 // Skip over name, if any
1581                                 if (Token::Match(tok2->next(), "%name%"))
1582                                     tok2 = tok2->next();
1583 
1584                                 tok2->insertToken(")");
1585                                 tok2 = tok2->next();
1586 
1587                                 Token::createMutualLinks(tok2, openParenthesis);
1588                             }
1589                         }
1590                     } else if (typeOf) {
1591                         tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
1592                     } else if (Token::Match(tok2, "%name% [")) {
1593                         while (Token::Match(tok2, "%name%|] [")) {
1594                             tok2 = tok2->linkAt(1);
1595                         }
1596                         tok2 = tok2->previous();
1597                     }
1598 
1599                     if (arrayStart && arrayEnd) {
1600                         do {
1601                             if (!tok2->next())
1602                                 syntaxError(tok2); // can't recover so quit
1603 
1604                             if (!inCast && !inSizeof && !inTemplate)
1605                                 tok2 = tok2->next();
1606 
1607                             if (tok2->str() == "const")
1608                                 tok2 = tok2->next();
1609 
1610                             // reference or pointer to array?
1611                             if (Token::Match(tok2, "&|*|&&")) {
1612                                 tok2 = tok2->previous();
1613                                 tok2->insertToken("(");
1614                                 Token *tok3 = tok2->next();
1615 
1616                                 // handle missing variable name
1617                                 if (Token::Match(tok3, "( *|&|&& *|&|&& %name%"))
1618                                     tok2 = tok3->tokAt(3);
1619                                 else if (Token::Match(tok2->tokAt(3), "[(),;]"))
1620                                     tok2 = tok2->tokAt(2);
1621                                 else
1622                                     tok2 = tok2->tokAt(3);
1623                                 if (!tok2)
1624                                     syntaxError(nullptr);
1625 
1626                                 while (tok2->strAt(1) == "::")
1627                                     tok2 = tok2->tokAt(2);
1628 
1629                                 // skip over function parameters
1630                                 if (tok2->str() == "(")
1631                                     tok2 = tok2->link();
1632 
1633                                 if (tok2->strAt(1) == "(")
1634                                     tok2 = tok2->linkAt(1);
1635 
1636                                 // skip over const/noexcept
1637                                 while (Token::Match(tok2->next(), "const|noexcept"))
1638                                     tok2 = tok2->next();
1639 
1640                                 tok2->insertToken(")");
1641                                 tok2 = tok2->next();
1642                                 Token::createMutualLinks(tok2, tok3);
1643                             }
1644 
1645                             if (!tok2->next())
1646                                 syntaxError(tok2); // can't recover so quit
1647 
1648                             // skip over array dimensions
1649                             while (tok2->next()->str() == "[")
1650                                 tok2 = tok2->linkAt(1);
1651 
1652                             tok2 = TokenList::copyTokens(tok2, arrayStart, arrayEnd);
1653                             if (!tok2->next())
1654                                 syntaxError(tok2);
1655 
1656                             if (tok2->str() == "=") {
1657                                 if (!tok2->next())
1658                                     syntaxError(tok2);
1659                                 if (tok2->next()->str() == "{")
1660                                     tok2 = tok2->next()->link()->next();
1661                                 else if (tok2->next()->str().at(0) == '\"')
1662                                     tok2 = tok2->tokAt(2);
1663                             }
1664                         } while (Token::Match(tok2, ", %name% ;|=|,"));
1665                     }
1666 
1667                     simplifyType = false;
1668                 }
1669                 if (!tok2)
1670                     break;
1671             }
1672 
1673             if (!tok)
1674                 syntaxError(nullptr);
1675 
1676             if (tok->str() == ";")
1677                 done = true;
1678             else if (tok->str() == ",") {
1679                 arrayStart = nullptr;
1680                 arrayEnd = nullptr;
1681                 tokOffset = tok->next();
1682                 pointers.clear();
1683 
1684                 while (Token::Match(tokOffset, "*|&")) {
1685                     pointers.push_back(tokOffset->str());
1686                     tokOffset = tokOffset->next();
1687                 }
1688 
1689                 if (Token::Match(tokOffset, "%type%")) {
1690                     typeName = tokOffset;
1691                     tokOffset = tokOffset->next();
1692 
1693                     if (tokOffset && tokOffset->str() == "[") {
1694                         arrayStart = tokOffset;
1695 
1696                         for (;;) {
1697                             while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
1698                                 tokOffset = tokOffset->next();
1699 
1700                             if (!tokOffset->next())
1701                                 return; // invalid input
1702                             else if (tokOffset->next()->str() == ";")
1703                                 break;
1704                             else if (tokOffset->str() == "]")
1705                                 break;
1706                             else
1707                                 tokOffset = tokOffset->next();
1708                         }
1709 
1710                         arrayEnd = tokOffset;
1711                         tokOffset = tokOffset->next();
1712                     }
1713 
1714                     if (Token::Match(tokOffset, ";|,"))
1715                         tok = tokOffset;
1716                     else {
1717                         // we encountered a typedef we don't support yet so just continue
1718                         done = true;
1719                         ok = false;
1720                     }
1721                 } else {
1722                     // we encountered a typedef we don't support yet so just continue
1723                     done = true;
1724                     ok = false;
1725                 }
1726             } else {
1727                 // something is really wrong (internal error)
1728                 done = true;
1729                 ok = false;
1730             }
1731         }
1732 
1733         if (ok) {
1734             // remove typedef
1735             Token::eraseTokens(typeDef, tok);
1736 
1737             if (typeDef != list.front()) {
1738                 tok = typeDef->previous();
1739                 tok->deleteNext();
1740                 //no need to remove last token in the list
1741                 if (tok->tokAt(2))
1742                     tok->deleteNext();
1743             } else {
1744                 list.front()->deleteThis();
1745                 //no need to remove last token in the list
1746                 if (list.front()->next())
1747                     list.front()->deleteThis();
1748                 tok = list.front();
1749                 //now the next token to process is 'tok', not 'tok->next()';
1750                 goback = true;
1751             }
1752         }
1753     }
1754 }
1755 
1756 namespace {
1757     struct ScopeInfo3 {
1758         enum Type { Global, Namespace, Record, MemberFunction, Other };
ScopeInfo3__anon5685b77f0311::ScopeInfo31759         ScopeInfo3() : parent(nullptr), type(Global), bodyStart(nullptr), bodyEnd(nullptr) {}
ScopeInfo3__anon5685b77f0311::ScopeInfo31760         ScopeInfo3(ScopeInfo3 *parent_, Type type_, const std::string &name_, const Token *bodyStart_, const Token *bodyEnd_)
1761             : parent(parent_), type(type_), name(name_), bodyStart(bodyStart_), bodyEnd(bodyEnd_) {
1762             if (name.empty())
1763                 return;
1764             fullName = name;
1765             ScopeInfo3 *scope = parent;
1766             while (scope && scope->parent) {
1767                 if (scope->name.empty())
1768                     break;
1769                 fullName = scope->name + " :: " + fullName;
1770                 scope = scope->parent;
1771             }
1772         }
1773         ScopeInfo3 *parent;
1774         std::list<ScopeInfo3> children;
1775         Type type;
1776         std::string fullName;
1777         std::string name;
1778         const Token * bodyStart;
1779         const Token * bodyEnd;
1780         std::set<std::string> usingNamespaces;
1781         std::set<std::string> recordTypes;
1782         std::set<std::string> baseTypes;
1783 
addChild__anon5685b77f0311::ScopeInfo31784         ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) {
1785             children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken);
1786             return &children.back();
1787         }
1788 
hasChild__anon5685b77f0311::ScopeInfo31789         bool hasChild(const std::string &childName) const {
1790             for (const auto & child : children) {
1791                 if (child.name == childName)
1792                     return true;
1793             }
1794             return false;
1795         }
1796 
printOut__anon5685b77f0311::ScopeInfo31797         void  printOut(const std::string & indent = "  ") const {
1798             std::cerr << indent << "type: " << (type == Global ? "Global" :
1799                                                 type == Namespace ? "Namespace" :
1800                                                 type == Record ? "Record" :
1801                                                 type == MemberFunction ? "MemberFunction" :
1802                                                 type == Other ? "Other" :
1803                                                 "Unknown") << std::endl;
1804             std::cerr << indent << "fullName: " << fullName << std::endl;
1805             std::cerr << indent << "name: " << name << std::endl;
1806             std::cerr << indent << usingNamespaces.size() << " usingNamespaces:";
1807             for (const auto & usingNamespace : usingNamespaces)
1808                 std::cerr << " " << usingNamespace;
1809             std::cerr << std::endl;
1810             std::cerr << indent << baseTypes.size() << " baseTypes:";
1811             for (const auto & baseType : baseTypes)
1812                 std::cerr << " " << baseType;
1813             std::cerr << std::endl;
1814             std::cerr << indent << children.size() << " children:" << std::endl;
1815             size_t i = 0;
1816             for (const auto & child : children) {
1817                 std::cerr << indent << "child " << i++ << std::endl;
1818                 child.printOut(indent + "  ");
1819             }
1820         }
1821 
findScopeRecursive__anon5685b77f0311::ScopeInfo31822         const ScopeInfo3 * findScopeRecursive(const std::string & scope) const {
1823             if (fullName.size() < scope.size() &&
1824                 fullName == scope.substr(0, fullName.size())) {
1825                 for (const auto & child : children) {
1826                     if (child.fullName == scope && &child != this)
1827                         return &child;
1828                     else {
1829                         const ScopeInfo3 * temp1 = child.findScopeRecursive(scope);
1830                         if (temp1)
1831                             return temp1;
1832                     }
1833                 }
1834             }
1835             return nullptr;
1836         }
1837 
findInChildren__anon5685b77f0311::ScopeInfo31838         const ScopeInfo3 * findInChildren(const std::string & scope) const {
1839             for (const auto & child : children) {
1840                 if (child.type == Record && (child.name == scope || child.fullName == scope))
1841                     return &child;
1842                 else {
1843                     const ScopeInfo3 * temp = child.findInChildren(scope);
1844                     if (temp)
1845                         return temp;
1846                 }
1847             }
1848             return nullptr;
1849         }
1850 
findScope__anon5685b77f0311::ScopeInfo31851         const ScopeInfo3 * findScope(const std::string & scope) const {
1852             const ScopeInfo3 * tempScope = this;
1853             while (tempScope) {
1854                 // check children
1855                 for (const auto & child : tempScope->children) {
1856                     if (&child != this && child.type == Record && (child.name == scope || child.fullName == scope))
1857                         return &child;
1858                 }
1859                 // check siblings for same name
1860                 if (tempScope->parent) {
1861                     for (const auto &sibling : tempScope->parent->children) {
1862                         if (sibling.name == tempScope->name && &sibling != this) {
1863                             const ScopeInfo3 * temp = sibling.findInChildren(scope);
1864                             if (temp)
1865                                 return temp;
1866                         }
1867                     }
1868                 }
1869                 tempScope = tempScope->parent;
1870             }
1871             return nullptr;
1872         }
1873 
findTypeInBase__anon5685b77f0311::ScopeInfo31874         bool findTypeInBase(const std::string &scope) const {
1875             // check in base types first
1876             if (baseTypes.find(scope) != baseTypes.end())
1877                 return true;
1878             // check in base types base types
1879             for (const std::string & base : baseTypes) {
1880                 const ScopeInfo3 * baseScope = findScope(base);
1881                 // bail on uninstantiated recursive template
1882                 if (baseScope == this)
1883                     return false;
1884                 if (baseScope && baseScope->fullName == scope)
1885                     return true;
1886                 if (baseScope && baseScope->findTypeInBase(scope))
1887                     return true;
1888             }
1889             return false;
1890         }
1891 
findScope__anon5685b77f0311::ScopeInfo31892         ScopeInfo3 * findScope(const ScopeInfo3 * scope) {
1893             if (scope->bodyStart == bodyStart)
1894                 return this;
1895             for (auto & child : children) {
1896                 ScopeInfo3 * temp = child.findScope(scope);
1897                 if (temp)
1898                     return temp;
1899             }
1900             return nullptr;
1901         }
1902     };
1903 
setScopeInfo(Token * tok,ScopeInfo3 ** scopeInfo,bool debug=false)1904     void setScopeInfo(Token *tok, ScopeInfo3 **scopeInfo, bool debug=false)
1905     {
1906         if (!tok)
1907             return;
1908         if (tok->str() == "{" && (*scopeInfo)->parent && tok == (*scopeInfo)->bodyStart)
1909             return;
1910         if (tok->str() == "}") {
1911             if ((*scopeInfo)->parent && tok == (*scopeInfo)->bodyEnd)
1912                 *scopeInfo = (*scopeInfo)->parent;
1913             else {
1914                 // Try to find parent scope
1915                 ScopeInfo3 *parent = (*scopeInfo)->parent;
1916                 while (parent && parent->bodyEnd != tok)
1917                     parent = parent->parent;
1918                 if (parent) {
1919                     *scopeInfo = parent;
1920                     if (debug)
1921                         throw std::runtime_error("Internal error: unmatched }");
1922                 }
1923             }
1924             return;
1925         }
1926         if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::|<")) {
1927             // check for using namespace
1928             if (Token::Match(tok, "using namespace %name% ;|::")) {
1929                 const Token * tok1 = tok->tokAt(2);
1930                 std::string nameSpace;
1931                 while (tok1 && tok1->str() != ";") {
1932                     if (!nameSpace.empty())
1933                         nameSpace += " ";
1934                     nameSpace += tok1->str();
1935                     tok1 = tok1->next();
1936                 }
1937                 (*scopeInfo)->usingNamespaces.insert(nameSpace);
1938             }
1939             // check for member function
1940             else if (tok->str() == "{") {
1941                 bool added = false;
1942                 Token *tok1 = tok;
1943                 while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
1944                     tok1 = tok1->previous();
1945                 if (tok1->previous() && (tok1->strAt(-1) == ")" || tok->strAt(-1) == "}")) {
1946                     tok1 = tok1->linkAt(-1);
1947                     if (Token::Match(tok1->previous(), "throw|noexcept (")) {
1948                         tok1 = tok1->previous();
1949                         while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
1950                             tok1 = tok1->previous();
1951                         if (tok1->strAt(-1) != ")")
1952                             return;
1953                         tok1 = tok1->linkAt(-1);
1954                     } else {
1955                         while (Token::Match(tok1->tokAt(-2), ":|, %name%")) {
1956                             tok1 = tok1->tokAt(-2);
1957                             if (tok1->strAt(-1) != ")" && tok1->strAt(-1) != "}")
1958                                 return;
1959                             tok1 = tok1->linkAt(-1);
1960                         }
1961                     }
1962                     if (tok1->strAt(-1) == ">")
1963                         tok1 = tok1->previous()->findOpeningBracket();
1964                     if (tok1 && (Token::Match(tok1->tokAt(-3), "%name% :: %name%") ||
1965                                  Token::Match(tok1->tokAt(-4), "%name% :: ~ %name%"))) {
1966                         tok1 = tok1->tokAt(-2);
1967                         if (tok1->str() == "~")
1968                             tok1 = tok1->previous();
1969                         std::string scope = tok1->strAt(-1);
1970                         while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
1971                             scope = tok1->strAt(-3) + " :: " + scope;
1972                             tok1 = tok1->tokAt(-2);
1973                         }
1974                         *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link());
1975                         added = true;
1976                     }
1977                 }
1978 
1979                 if (!added)
1980                     *scopeInfo = (*scopeInfo)->addChild(ScopeInfo3::Other, "", tok, tok->link());
1981             }
1982             return;
1983         }
1984 
1985         const bool record = Token::Match(tok, "class|struct|union %name%");
1986         tok = tok->next();
1987         std::string classname = tok->str();
1988         while (Token::Match(tok, "%name% :: %name%")) {
1989             tok = tok->tokAt(2);
1990             classname += " :: " + tok->str();
1991         }
1992 
1993         // add record type to scope info
1994         if (record)
1995             (*scopeInfo)->recordTypes.insert(classname);
1996         tok = tok->next();
1997 
1998         // skip template parameters
1999         if (tok && tok->str() == "<") {
2000             tok = tok->findClosingBracket();
2001             if (tok)
2002                 tok = tok->next();
2003         }
2004 
2005         // get base class types
2006         std::set<std::string> baseTypes;
2007         if (tok && tok->str() == ":") {
2008             do {
2009                 tok = tok->next();
2010                 while (Token::Match(tok, "public|protected|private|virtual"))
2011                     tok = tok->next();
2012                 std::string base;
2013                 while (tok && !Token::Match(tok, ";|,|{")) {
2014                     if (!base.empty())
2015                         base += ' ';
2016                     base += tok->str();
2017                     tok = tok->next();
2018                     // skip template parameters
2019                     if (tok && tok->str() == "<") {
2020                         tok = tok->findClosingBracket();
2021                         if (tok)
2022                             tok = tok->next();
2023                     }
2024                 }
2025                 baseTypes.insert(base);
2026             } while (tok && !Token::Match(tok, ";|{"));
2027         }
2028 
2029         if (tok && tok->str() == "{") {
2030             *scopeInfo = (*scopeInfo)->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link());
2031             (*scopeInfo)->baseTypes = baseTypes;
2032         }
2033     }
2034 
findSemicolon(Token * tok)2035     Token *findSemicolon(Token *tok)
2036     {
2037         int level = 0;
2038 
2039         for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
2040             if (tok->str() == "{")
2041                 ++level;
2042             else if (level > 0 && tok->str() == "}")
2043                 --level;
2044         }
2045 
2046         return tok;
2047     }
2048 
usingMatch(const Token * nameToken,const std::string & scope,Token ** tok,const std::string & scope1,const ScopeInfo3 * currentScope,const ScopeInfo3 * memberClassScope)2049     bool usingMatch(
2050         const Token *nameToken,
2051         const std::string &scope,
2052         Token **tok,
2053         const std::string &scope1,
2054         const ScopeInfo3 *currentScope,
2055         const ScopeInfo3 *memberClassScope)
2056     {
2057         Token *tok1 = *tok;
2058 
2059         if (tok1 && tok1->str() != nameToken->str())
2060             return false;
2061 
2062         // skip this using
2063         if (tok1 == nameToken) {
2064             *tok = findSemicolon(tok1);
2065             return false;
2066         }
2067 
2068         // skip other using with this name
2069         if (tok1->strAt(-1) == "using") {
2070             // fixme: this is wrong
2071             // skip to end of scope
2072             if (currentScope->bodyEnd)
2073                 *tok = currentScope->bodyEnd->previous();
2074             return false;
2075         }
2076 
2077         if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) {
2078             // fixme
2079             return false;
2080         }
2081 
2082         // get qualification
2083         std::string qualification;
2084         const Token* tok2 = tok1;
2085         std::string::size_type index = scope.size();
2086         std::string::size_type new_index = std::string::npos;
2087         bool match = true;
2088         while (Token::Match(tok2->tokAt(-2), "%name% ::") && !tok2->tokAt(-2)->isKeyword()) {
2089             std::string last;
2090             if (match && !scope1.empty()) {
2091                 new_index = scope1.rfind(' ', index - 1);
2092                 if (new_index != std::string::npos)
2093                     last = scope1.substr(new_index, index - new_index);
2094                 else if (!qualification.empty())
2095                     last.clear();
2096                 else
2097                     last = scope1;
2098             } else
2099                 match = false;
2100             if (match && tok2->strAt(-2) == last)
2101                 index = new_index;
2102             else {
2103                 if (!qualification.empty())
2104                     qualification = " :: " + qualification;
2105                 qualification = tok2->strAt(-2) + qualification;
2106             }
2107             tok2 = tok2->tokAt(-2);
2108         }
2109 
2110         std::string fullScope1 = scope1;
2111         if (!scope1.empty() && !qualification.empty())
2112             fullScope1 += " :: ";
2113         fullScope1 += qualification;
2114 
2115         if (scope == fullScope1)
2116             return true;
2117 
2118         const ScopeInfo3 *scopeInfo = memberClassScope ? memberClassScope : currentScope;
2119 
2120         // check in base types
2121         if (scopeInfo->findTypeInBase(scope))
2122             return true;
2123 
2124         // check using namespace
2125         const ScopeInfo3 * tempScope = scopeInfo;
2126         while (tempScope) {
2127             //if (!tempScope->parent->usingNamespaces.empty()) {
2128             if (!tempScope->usingNamespaces.empty()) {
2129                 if (qualification.empty()) {
2130                     if (tempScope->usingNamespaces.find(scope) != tempScope->usingNamespaces.end())
2131                         return true;
2132                 } else {
2133                     for (auto ns : tempScope->usingNamespaces) {
2134                         if (scope == ns + " :: " + qualification)
2135                             return true;
2136                     }
2137                 }
2138             }
2139             tempScope = tempScope->parent;
2140         }
2141 
2142         std::string newScope1 = scope1;
2143 
2144         // scopes didn't match so try higher scopes
2145         index = newScope1.size();
2146         while (!newScope1.empty()) {
2147             std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
2148             if (separator != std::string::npos)
2149                 newScope1 = newScope1.substr(0, separator);
2150             else
2151                 newScope1.clear();
2152 
2153             std::string newFullScope1 = newScope1;
2154             if (!newScope1.empty() && !qualification.empty())
2155                 newFullScope1 += " :: ";
2156             newFullScope1 += qualification;
2157 
2158             if (scope == newFullScope1)
2159                 return true;
2160         }
2161 
2162         return false;
2163     }
2164 
memberFunctionScope(const Token * tok)2165     std::string memberFunctionScope(const Token *tok)
2166     {
2167         std::string qualification;
2168         const Token *qualTok = tok->strAt(-2) == "~" ? tok->tokAt(-4) : tok->tokAt(-3);
2169         while (Token::Match(qualTok, "%type% ::")) {
2170             if (!qualification.empty())
2171                 qualification = " :: " + qualification;
2172             qualification = qualTok->str() + qualification;
2173             qualTok = qualTok->tokAt(-2);
2174         }
2175         return qualification;
2176     }
2177 
memberFunctionEnd(const Token * tok)2178     const Token * memberFunctionEnd(const Token *tok)
2179     {
2180         if (tok->str() != "(")
2181             return nullptr;
2182         const Token *end = tok->link()->next();
2183         while (end) {
2184             if (end->str() == "{" && !Token::Match(end->tokAt(-2), ":|, %name%"))
2185                 return end;
2186             else if (end->str() == ";")
2187                 break;
2188             end = end->next();
2189         }
2190         return nullptr;
2191     }
2192 } // namespace
2193 
isMemberFunction(const Token * openParen) const2194 bool Tokenizer::isMemberFunction(const Token *openParen) const
2195 {
2196     return (Token::Match(openParen->tokAt(-2), ":: %name% (") ||
2197             Token::Match(openParen->tokAt(-3), ":: ~ %name% (")) &&
2198            isFunctionHead(openParen, "{|:");
2199 }
2200 
scopesMatch(const std::string & scope1,const std::string & scope2,const ScopeInfo3 * globalScope)2201 static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
2202 {
2203     if (scope1.empty() || scope2.empty())
2204         return false;
2205 
2206     // check if scopes match
2207     if (scope1 == scope2)
2208         return true;
2209 
2210     // check if scopes only differ by global qualification
2211     if (scope1 == (":: " + scope2)) {
2212         std::string::size_type end = scope2.find_first_of(' ');
2213         if (end == std::string::npos)
2214             end = scope2.size();
2215         if (globalScope->hasChild(scope2.substr(0, end)))
2216             return true;
2217     } else if (scope2 == (":: " + scope1)) {
2218         std::string::size_type end = scope1.find_first_of(' ');
2219         if (end == std::string::npos)
2220             end = scope1.size();
2221         if (globalScope->hasChild(scope1.substr(0, end)))
2222             return true;
2223     }
2224 
2225     return false;
2226 }
2227 
simplifyUsing()2228 bool Tokenizer::simplifyUsing()
2229 {
2230     if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
2231         return false;
2232 
2233     bool substitute = false;
2234     ScopeInfo3 scopeInfo;
2235     ScopeInfo3 *currentScope = &scopeInfo;
2236     struct Using {
2237         Using(Token *start, Token *end) : startTok(start), endTok(end) {}
2238         Token *startTok;
2239         Token *endTok;
2240     };
2241     std::list<Using> usingList;
2242 
2243     for (Token *tok = list.front(); tok; tok = tok->next()) {
2244         if (mErrorLogger && !list.getFiles().empty())
2245             mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue());
2246 
2247         if (Settings::terminated())
2248             return substitute;
2249 
2250         if (Token::Match(tok, "enum class|struct")) {
2251             Token *bodyStart = tok;
2252             while (Token::Match(bodyStart, "%name%|:|::|<")) {
2253                 if (bodyStart->str() == "<")
2254                     bodyStart = bodyStart->findClosingBracket();
2255                 bodyStart = bodyStart ? bodyStart->next() : nullptr;
2256             }
2257             if (Token::simpleMatch(bodyStart, "{"))
2258                 tok = bodyStart->link();
2259             continue;
2260         }
2261 
2262         if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
2263             Token::Match(tok, "using namespace %name% ;|::")) {
2264             try {
2265                 setScopeInfo(tok, &currentScope, mSettings->debugwarnings);
2266             } catch (const std::runtime_error &) {
2267                 reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2268                             "simplifyUsing: unmatched body end");
2269             }
2270             continue;
2271         }
2272 
2273         // skip template declarations
2274         if (Token::Match(tok, "template < !!>")) {
2275             // add template record type to scope info
2276             const Token *end = tok->next()->findClosingBracket();
2277             if (end && Token::Match(end->next(), "class|struct|union %name%"))
2278                 currentScope->recordTypes.insert(end->strAt(2));
2279 
2280             Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
2281             if (declEndToken)
2282                 tok = declEndToken;
2283             continue;
2284         }
2285 
2286         // look for non-template type aliases
2287         if (!(tok->strAt(-1) != ">" &&
2288               (Token::Match(tok, "using %name% = ::| %name%") ||
2289                (Token::Match(tok, "using %name% [ [") &&
2290                 Token::Match(tok->linkAt(2), "] ] = ::| %name%")))))
2291             continue;
2292 
2293         std::string name = tok->strAt(1);
2294         const Token *nameToken = tok->next();
2295         std::string scope = currentScope->fullName;
2296         Token *usingStart = tok;
2297         Token *start;
2298         if (tok->strAt(2) == "=")
2299             start = tok->tokAt(3);
2300         else
2301             start = tok->linkAt(2)->tokAt(3);
2302         Token *usingEnd = findSemicolon(start);
2303         if (!usingEnd)
2304             continue;
2305 
2306         // Move struct defined in using out of using.
2307         // using T = struct t { }; => struct t { }; using T = struct t;
2308         // fixme: this doesn't handle attributes
2309         if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
2310             Token *structEnd = start->tokAt(1);
2311             const bool hasName = Token::Match(structEnd, "%name%");
2312 
2313             // skip over name if present
2314             if (hasName)
2315                 structEnd = structEnd->next();
2316 
2317             // skip over base class information
2318             if (structEnd->str() == ":") {
2319                 structEnd = structEnd->next(); // skip over ":"
2320                 while (structEnd && structEnd->str() != "{")
2321                     structEnd = structEnd->next();
2322                 if (!structEnd)
2323                     continue;
2324             }
2325 
2326             // use link to go to end
2327             structEnd = structEnd->link();
2328 
2329             // add ';' after end of struct
2330             structEnd->insertToken(";", "");
2331 
2332             // add name for anonymous struct
2333             if (!hasName) {
2334                 std::string newName;
2335                 if (structEnd->strAt(2) == ";")
2336                     newName = name;
2337                 else
2338                     newName = "Unnamed" + MathLib::toString(mUnnamedCount++);
2339                 TokenList::copyTokens(structEnd->next(), tok, start);
2340                 structEnd->tokAt(5)->insertToken(newName, "");
2341                 start->insertToken(newName, "");
2342             } else
2343                 TokenList::copyTokens(structEnd->next(), tok, start->next());
2344 
2345             // add using after end of struct
2346             usingStart = structEnd->tokAt(2);
2347             nameToken = usingStart->next();
2348             if (usingStart->strAt(2) == "=")
2349                 start = usingStart->tokAt(3);
2350             else
2351                 start = usingStart->linkAt(2)->tokAt(3);
2352             usingEnd = findSemicolon(start);
2353 
2354             // delete original using before struct
2355             tok->deleteThis();
2356             tok->deleteThis();
2357             tok->deleteThis();
2358             tok = usingStart;
2359         }
2360 
2361         // remove 'typename' and 'template'
2362         else if (start->str() == "typename") {
2363             start->deleteThis();
2364             Token *temp = start;
2365             while (Token::Match(temp, "%name% ::"))
2366                 temp = temp->tokAt(2);
2367             if (Token::Match(temp, "template %name%"))
2368                 temp->deleteThis();
2369         }
2370 
2371         if (usingEnd)
2372             tok = usingEnd;
2373 
2374         // Unfortunately we have to start searching from the beginning
2375         // of the token stream because templates are instantiated at
2376         // the end of the token stream and it may be used before then.
2377         ScopeInfo3 scopeInfo1;
2378         ScopeInfo3 *currentScope1 = &scopeInfo1;
2379         Token *startToken = list.front();
2380         Token *endToken = nullptr;
2381         bool inMemberFunc = false;
2382         const ScopeInfo3 * memberFuncScope = nullptr;
2383         const Token * memberFuncEnd = nullptr;
2384 
2385         // We can limit the search to the current function when the type alias
2386         // is defined in that function.
2387         if (currentScope->type == ScopeInfo3::Other ||
2388             currentScope->type == ScopeInfo3::MemberFunction) {
2389             scopeInfo1 = scopeInfo;
2390             currentScope1 = scopeInfo1.findScope(currentScope);
2391             if (!currentScope1)
2392                 return substitute; // something bad happened
2393             startToken = usingEnd->next();
2394             endToken = currentScope->bodyEnd->next();
2395             if (currentScope->type == ScopeInfo3::MemberFunction) {
2396                 const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName);
2397                 if (temp) {
2398                     inMemberFunc = true;
2399                     memberFuncScope = temp;
2400                     memberFuncEnd = endToken;
2401                 }
2402             }
2403         }
2404 
2405         std::string scope1 = currentScope1->fullName;
2406         bool skip = false; // don't erase type aliases we can't parse
2407         Token *enumOpenBrace = nullptr;
2408         for (Token* tok1 = startToken; !skip && tok1 && tok1 != endToken; tok1 = tok1->next()) {
2409             // skip enum body
2410             if (tok1 && tok1 == enumOpenBrace) {
2411                 tok1 = tok1->link();
2412                 enumOpenBrace = nullptr;
2413                 continue;
2414             }
2415 
2416             if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
2417                 Token::Match(tok1, "using namespace %name% ;|::")) {
2418                 try {
2419                     setScopeInfo(tok1, &currentScope1, mSettings->debugwarnings);
2420                 } catch (const std::runtime_error &) {
2421                     reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2422                                 "simplifyUsing: unmatched body end");
2423                 }
2424                 scope1 = currentScope1->fullName;
2425                 if (inMemberFunc && memberFuncEnd && tok1 == memberFuncEnd) {
2426                     inMemberFunc = false;
2427                     memberFuncScope = nullptr;
2428                     memberFuncEnd = nullptr;
2429                 }
2430                 continue;
2431             }
2432 
2433             // skip template definitions
2434             if (Token::Match(tok1, "template < !!>")) {
2435                 Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok1);
2436                 if (declEndToken)
2437                     tok1 = declEndToken;
2438                 continue;
2439             }
2440 
2441             // check for enum with body
2442             if (tok1->str() == "enum") {
2443                 if (Token::Match(tok1, "enum class|struct"))
2444                     tok1 = tok1->next();
2445                 Token *defStart = tok1;
2446                 while (Token::Match(defStart, "%name%|::|:"))
2447                     defStart = defStart->next();
2448                 if (Token::simpleMatch(defStart, "{"))
2449                     enumOpenBrace = defStart;
2450                 continue;
2451             }
2452 
2453             // check for member function and adjust scope
2454             if (isMemberFunction(tok1)) {
2455                 if (!scope1.empty())
2456                     scope1 += " :: ";
2457                 scope1 += memberFunctionScope(tok1);
2458                 const ScopeInfo3 * temp = currentScope1->findScope(scope1);
2459                 if (temp) {
2460                     const Token *end = memberFunctionEnd(tok1);
2461                     if (end) {
2462                         inMemberFunc = true;
2463                         memberFuncScope = temp;
2464                         memberFuncEnd = end;
2465                     }
2466                 }
2467                 continue;
2468             } else if (inMemberFunc && memberFuncScope) {
2469                 if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, memberFuncScope))
2470                     continue;
2471             } else if (!usingMatch(nameToken, scope, &tok1, scope1, currentScope1, nullptr))
2472                 continue;
2473 
2474             // remove the qualification
2475             std::string fullScope = scope;
2476             std::string removed;
2477             while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
2478                 removed = (tok1->strAt(-2) + " :: ") + removed;
2479                 if (fullScope == tok1->strAt(-2)) {
2480                     tok1->deletePrevious();
2481                     tok1->deletePrevious();
2482                     break;
2483                 } else {
2484                     const std::string::size_type idx = fullScope.rfind(" ");
2485 
2486                     if (idx == std::string::npos)
2487                         break;
2488 
2489                     if (tok1->strAt(-2) == fullScope.substr(idx + 1)) {
2490                         tok1->deletePrevious();
2491                         tok1->deletePrevious();
2492                         fullScope.resize(idx - 3);
2493                     } else
2494                         break;
2495                 }
2496             }
2497 
2498             // remove global namespace if present
2499             if (tok1->strAt(-1) == "::") {
2500                 removed.insert(0, ":: ");
2501                 tok1->deletePrevious();
2502             }
2503 
2504             Token * arrayStart = nullptr;
2505 
2506             // parse the type
2507             Token *type = start;
2508             if (type->str() == "::") {
2509                 type = type->next();
2510                 while (Token::Match(type, "%type% ::"))
2511                     type = type->tokAt(2);
2512                 if (Token::Match(type, "%type%"))
2513                     type = type->next();
2514             } else if (Token::Match(type, "%type% ::")) {
2515                 do {
2516                     type = type->tokAt(2);
2517                 } while (Token::Match(type, "%type% ::"));
2518                 if (Token::Match(type, "%type%"))
2519                     type = type->next();
2520             } else if (Token::Match(type, "%type%")) {
2521                 while (Token::Match(type, "const|class|struct|union|enum %type%") ||
2522                        (type->next() && type->next()->isStandardType()))
2523                     type = type->next();
2524 
2525                 type = type->next();
2526 
2527                 while (Token::Match(type, "%type%") &&
2528                        (type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
2529                     type = type->next();
2530                 }
2531 
2532                 bool atEnd = false;
2533                 while (!atEnd) {
2534                     if (type && type->str() == "::") {
2535                         type = type->next();
2536                     }
2537 
2538                     if (Token::Match(type, "%type%") &&
2539                         type->next() && !Token::Match(type->next(), "[|,|(")) {
2540                         type = type->next();
2541                     } else if (Token::simpleMatch(type, "const (")) {
2542                         type = type->next();
2543                         atEnd = true;
2544                     } else
2545                         atEnd = true;
2546                 }
2547             } else
2548                 syntaxError(type);
2549 
2550             // check for invalid input
2551             if (!type)
2552                 syntaxError(tok1);
2553 
2554             // check for template
2555             if (type->str() == "<") {
2556                 type = type->findClosingBracket();
2557 
2558                 while (type && Token::Match(type->next(), ":: %type%"))
2559                     type = type->tokAt(2);
2560 
2561                 if (!type) {
2562                     syntaxError(tok1);
2563                 }
2564 
2565                 while (Token::Match(type->next(), "const|volatile"))
2566                     type = type->next();
2567 
2568                 type = type->next();
2569             }
2570 
2571             // check for pointers and references
2572             std::list<std::string> pointers;
2573             while (Token::Match(type, "*|&|&&|const")) {
2574                 pointers.push_back(type->str());
2575                 type = type->next();
2576             }
2577 
2578             // check for array
2579             if (type && type->str() == "[") {
2580                 do {
2581                     if (!arrayStart)
2582                         arrayStart = type;
2583 
2584                     bool atEnd = false;
2585                     while (!atEnd) {
2586                         while (type->next() && !Token::Match(type->next(), ";|,")) {
2587                             type = type->next();
2588                         }
2589 
2590                         if (!type->next())
2591                             syntaxError(type); // invalid input
2592                         else if (type->next()->str() == ";")
2593                             atEnd = true;
2594                         else if (type->str() == "]")
2595                             atEnd = true;
2596                         else
2597                             type = type->next();
2598                     }
2599 
2600                     type = type->next();
2601                 } while (type && type->str() == "[");
2602             }
2603 
2604             // make sure we are in a good state
2605             if (!tok1 || !tok1->next())
2606                 break; // bail
2607 
2608             Token* after = tok1->next();
2609             // check if type was parsed
2610             if (type && type == usingEnd) {
2611                 // check for array syntax and add type around variable
2612                 if (arrayStart) {
2613                     if (Token::Match(tok1->next(), "%name%")) {
2614                         TokenList::copyTokens(tok1->next(), arrayStart, usingEnd->previous());
2615                         TokenList::copyTokens(tok1, start, arrayStart->previous());
2616                         tok1->deleteThis();
2617                         substitute = true;
2618                     }
2619                 } else {
2620                     // add some qualification back if needed
2621                     std::string removed1 = removed;
2622                     std::string::size_type idx = removed1.rfind(" ::");
2623                     if (idx != std::string::npos)
2624                         removed1.resize(idx);
2625                     if (scopesMatch(removed1, scope, &scopeInfo1)) {
2626                         ScopeInfo3 * tempScope = currentScope;
2627                         while (tempScope->parent) {
2628                             if (tempScope->recordTypes.find(start->str()) != tempScope->recordTypes.end()) {
2629                                 std::string::size_type spaceIdx = 0;
2630                                 std::string::size_type startIdx = 0;
2631                                 while ((spaceIdx = removed1.find(" ", startIdx)) != std::string::npos) {
2632                                     tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
2633                                     startIdx = spaceIdx + 1;
2634                                 }
2635                                 tok1->previous()->insertToken(removed1.substr(startIdx));
2636                                 tok1->previous()->insertToken("::");
2637                                 break;
2638                             }
2639                             idx = removed1.rfind(" ::");
2640                             if (idx == std::string::npos)
2641                                 break;
2642 
2643                             removed1.resize(idx);
2644                             tempScope = tempScope->parent;
2645                         }
2646                     }
2647 
2648                     // just replace simple type aliases
2649                     TokenList::copyTokens(tok1, start, usingEnd->previous());
2650                     tok1->deleteThis();
2651                     substitute = true;
2652                 }
2653             } else {
2654                 skip = true;
2655                 if (mSettings->debugwarnings && mErrorLogger) {
2656                     std::string str;
2657                     for (Token *tok3 = usingStart; tok3 && tok3 != usingEnd; tok3 = tok3->next()) {
2658                         if (!str.empty())
2659                             str += ' ';
2660                         str += tok3->str();
2661                     }
2662                     str += " ;";
2663                     std::list<const Token *> callstack(1, usingStart);
2664                     mErrorLogger->reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
2665                                                          "Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
2666                 }
2667             }
2668             tok1 = after;
2669         }
2670 
2671         if (!skip)
2672             usingList.emplace_back(usingStart, usingEnd);
2673     }
2674 
2675     // delete all used type alias definitions
2676     for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
2677         Token *usingStart = it->startTok;
2678         Token *usingEnd = it->endTok;
2679         if (usingStart->previous()) {
2680             if (usingEnd->next())
2681                 Token::eraseTokens(usingStart->previous(), usingEnd->next());
2682             else {
2683                 Token::eraseTokens(usingStart->previous(), usingEnd);
2684                 usingEnd->deleteThis();
2685             }
2686         } else {
2687             if (usingEnd->next()) {
2688                 Token::eraseTokens(usingStart, usingEnd->next());
2689                 usingStart->deleteThis();
2690             } else {
2691                 // this is the only code being checked so leave ';'
2692                 Token::eraseTokens(usingStart, usingEnd);
2693                 usingStart->deleteThis();
2694             }
2695         }
2696     }
2697 
2698     return substitute;
2699 }
simplifyMulAndParens()2700 void Tokenizer::simplifyMulAndParens()
2701 {
2702     if (!list.front())
2703         return;
2704     for (Token *tok = list.front()->tokAt(3); tok; tok = tok->next()) {
2705         if (!tok->isName())
2706             continue;
2707         //fix ticket #2784 - improved by ticket #3184
2708         int closedPars = 0;
2709         Token *tokend = tok->next();
2710         Token *tokbegin = tok->previous();
2711         while (tokend && tokend->str() == ")") {
2712             ++closedPars;
2713             tokend = tokend->next();
2714         }
2715         if (!tokend || !(tokend->isAssignmentOp()))
2716             continue;
2717         while (Token::Match(tokbegin, "&|(")) {
2718             if (tokbegin->str() == "&") {
2719                 if (Token::Match(tokbegin->tokAt(-2), "[;{}&(] *")) {
2720                     //remove '* &'
2721                     tokbegin = tokbegin->tokAt(-2);
2722                     tokbegin->deleteNext(2);
2723                 } else if (Token::Match(tokbegin->tokAt(-3), "[;{}&(] * (")) {
2724                     if (closedPars == 0)
2725                         break;
2726                     --closedPars;
2727                     //remove ')'
2728                     tok->deleteNext();
2729                     //remove '* ( &'
2730                     tokbegin = tokbegin->tokAt(-3);
2731                     tokbegin->deleteNext(3);
2732                 } else
2733                     break;
2734             } else if (tokbegin->str() == "(") {
2735                 if (closedPars == 0)
2736                     break;
2737 
2738                 //find consecutive opening parentheses
2739                 int openPars = 0;
2740                 while (tokbegin && tokbegin->str() == "(" && openPars <= closedPars) {
2741                     ++openPars;
2742                     tokbegin = tokbegin->previous();
2743                 }
2744                 if (!tokbegin || openPars > closedPars)
2745                     break;
2746 
2747                 if ((openPars == closedPars && Token::Match(tokbegin, "[;{}]")) ||
2748                     Token::Match(tokbegin->tokAt(-2), "[;{}&(] * &") ||
2749                     Token::Match(tokbegin->tokAt(-3), "[;{}&(] * ( &")) {
2750                     //remove the excessive parentheses around the variable
2751                     while (openPars > 0) {
2752                         tok->deleteNext();
2753                         tokbegin->deleteNext();
2754                         --closedPars;
2755                         --openPars;
2756                     }
2757                 } else
2758                     break;
2759             }
2760         }
2761     }
2762 }
2763 
createTokens(std::istream & code,const std::string & FileName)2764 bool Tokenizer::createTokens(std::istream &code,
2765                              const std::string& FileName)
2766 {
2767     // make sure settings specified
2768     assert(mSettings);
2769 
2770     return list.createTokens(code, FileName);
2771 }
2772 
createTokens(simplecpp::TokenList && tokenList)2773 void Tokenizer::createTokens(simplecpp::TokenList&& tokenList)
2774 {
2775     // make sure settings specified
2776     assert(mSettings);
2777     list.createTokens(std::move(tokenList));
2778 }
2779 
simplifyTokens1(const std::string & configuration)2780 bool Tokenizer::simplifyTokens1(const std::string &configuration)
2781 {
2782     // Fill the map mTypeSize..
2783     fillTypeSizes();
2784 
2785     mConfiguration = configuration;
2786 
2787     if (!simplifyTokenList1(list.getFiles().front().c_str()))
2788         return false;
2789 
2790     if (mTimerResults) {
2791         Timer t("Tokenizer::simplifyTokens1::createAst", mSettings->showtime, mTimerResults);
2792         list.createAst();
2793         list.validateAst();
2794     } else {
2795         list.createAst();
2796         list.validateAst();
2797     }
2798 
2799     if (mTimerResults) {
2800         Timer t("Tokenizer::simplifyTokens1::createSymbolDatabase", mSettings->showtime, mTimerResults);
2801         createSymbolDatabase();
2802     } else {
2803         createSymbolDatabase();
2804     }
2805 
2806     if (mTimerResults) {
2807         Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings->showtime, mTimerResults);
2808         mSymbolDatabase->setValueTypeInTokenList(true);
2809     } else {
2810         mSymbolDatabase->setValueTypeInTokenList(true);
2811     }
2812 
2813     if (!mSettings->buildDir.empty())
2814         Summaries::create(this, configuration);
2815 
2816     if (mTimerResults) {
2817         Timer t("Tokenizer::simplifyTokens1::ValueFlow", mSettings->showtime, mTimerResults);
2818         ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
2819     } else {
2820         ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
2821     }
2822 
2823     // Warn about unhandled character literals
2824     if (mSettings->severity.isEnabled(Severity::portability)) {
2825         for (const Token *tok = tokens(); tok; tok = tok->next()) {
2826             if (tok->tokType() == Token::eChar && tok->values().empty()) {
2827                 try {
2828                     simplecpp::characterLiteralToLL(tok->str());
2829                 } catch (const std::exception &e) {
2830                     unhandledCharLiteral(tok, e.what());
2831                 }
2832             }
2833         }
2834     }
2835 
2836     mSymbolDatabase->setArrayDimensionsUsingValueFlow();
2837 
2838     printDebugOutput(1);
2839 
2840     return true;
2841 }
2842 
tokenize(std::istream & code,const char FileName[],const std::string & configuration)2843 bool Tokenizer::tokenize(std::istream &code,
2844                          const char FileName[],
2845                          const std::string &configuration)
2846 {
2847     if (!createTokens(code, FileName))
2848         return false;
2849 
2850     return simplifyTokens1(configuration);
2851 }
2852 //---------------------------------------------------------------------------
2853 
findComplicatedSyntaxErrorsInTemplates()2854 void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
2855 {
2856     validate();
2857     mTemplateSimplifier->checkComplicatedSyntaxErrorsInTemplates();
2858 }
2859 
checkForEnumsWithTypedef()2860 void Tokenizer::checkForEnumsWithTypedef()
2861 {
2862     for (const Token *tok = list.front(); tok; tok = tok->next()) {
2863         if (Token::Match(tok, "enum %name% {")) {
2864             tok = tok->tokAt(2);
2865             const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
2866             if (tok2)
2867                 syntaxError(tok2);
2868             tok = tok->link();
2869         }
2870     }
2871 }
2872 
fillTypeSizes()2873 void Tokenizer::fillTypeSizes()
2874 {
2875     mTypeSize.clear();
2876     mTypeSize["char"] = 1;
2877     mTypeSize["_Bool"] = mSettings->sizeof_bool;
2878     mTypeSize["bool"] = mSettings->sizeof_bool;
2879     mTypeSize["short"] = mSettings->sizeof_short;
2880     mTypeSize["int"] = mSettings->sizeof_int;
2881     mTypeSize["long"] = mSettings->sizeof_long;
2882     mTypeSize["float"] = mSettings->sizeof_float;
2883     mTypeSize["double"] = mSettings->sizeof_double;
2884     mTypeSize["wchar_t"] = mSettings->sizeof_wchar_t;
2885     mTypeSize["size_t"] = mSettings->sizeof_size_t;
2886     mTypeSize["*"] = mSettings->sizeof_pointer;
2887 }
2888 
combineOperators()2889 void Tokenizer::combineOperators()
2890 {
2891     const bool cpp = isCPP();
2892 
2893     // Combine tokens..
2894     for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
2895         const char c1 = tok->str()[0];
2896 
2897         if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
2898             const char c2 = tok->next()->str()[0];
2899 
2900             // combine +-*/ and =
2901             if (c2 == '=' && (std::strchr("+-*/%|^=!<>", c1))) {
2902                 // skip templates
2903                 if (cpp && (tok->str() == ">" || Token::simpleMatch(tok->previous(), "> *"))) {
2904                     const Token* opening =
2905                         tok->str() == ">" ? tok->findOpeningBracket() : tok->previous()->findOpeningBracket();
2906                     if (opening && Token::Match(opening->previous(), "%name%"))
2907                         continue;
2908                 }
2909                 tok->str(tok->str() + c2);
2910                 tok->deleteNext();
2911                 continue;
2912             }
2913         } else if (tok->next()->str() == "=") {
2914             if (tok->str() == ">>") {
2915                 tok->str(">>=");
2916                 tok->deleteNext();
2917             } else if (tok->str() == "<<") {
2918                 tok->str("<<=");
2919                 tok->deleteNext();
2920             }
2921         } else if (cpp && (c1 == 'p' || c1 == '_') &&
2922                    Token::Match(tok, "private|protected|public|__published : !!:")) {
2923             bool simplify = false;
2924             int par = 0;
2925             for (const Token *prev = tok->previous(); prev; prev = prev->previous()) {
2926                 if (prev->str() == ")") {
2927                     ++par;
2928                 } else if (prev->str() == "(") {
2929                     if (par == 0U)
2930                         break;
2931                     --par;
2932                 }
2933                 if (par != 0U || prev->str() == "(")
2934                     continue;
2935                 if (Token::Match(prev, "[;{}]")) {
2936                     simplify = true;
2937                     break;
2938                 }
2939                 if (prev->isName() && prev->isUpperCaseName())
2940                     continue;
2941                 if (prev->isName() && endsWith(prev->str(), ':'))
2942                     simplify = true;
2943                 break;
2944             }
2945             if (simplify) {
2946                 tok->str(tok->str() + ":");
2947                 tok->deleteNext();
2948             }
2949         } else if (tok->str() == "->") {
2950             // If the preceding sequence is "( & %name% )", replace it by "%name%"
2951             Token *t = tok->tokAt(-4);
2952             if (Token::Match(t, "( & %name% )") && !Token::simpleMatch(t->previous(), ">")) {
2953                 t->deleteThis();
2954                 t->deleteThis();
2955                 t->deleteNext();
2956                 tok->str(".");
2957             } else {
2958                 tok->str(".");
2959                 tok->originalName("->");
2960             }
2961         }
2962     }
2963 }
2964 
combineStringAndCharLiterals()2965 void Tokenizer::combineStringAndCharLiterals()
2966 {
2967     // Combine strings
2968     for (Token *tok = list.front(); tok; tok = tok->next()) {
2969         if (!isStringLiteral(tok->str()))
2970             continue;
2971 
2972         tok->str(simplifyString(tok->str()));
2973 
2974         while (Token::Match(tok->next(), "%str%") || Token::Match(tok->next(), "_T|_TEXT|TEXT ( %str% )")) {
2975             if (tok->next()->isName()) {
2976                 if (!mSettings->isWindowsPlatform())
2977                     break;
2978                 tok->deleteNext(2);
2979                 tok->next()->deleteNext();
2980             }
2981             // Two strings after each other, combine them
2982             tok->concatStr(simplifyString(tok->next()->str()));
2983             tok->deleteNext();
2984         }
2985     }
2986 }
2987 
concatenateNegativeNumberAndAnyPositive()2988 void Tokenizer::concatenateNegativeNumberAndAnyPositive()
2989 {
2990     for (Token *tok = list.front(); tok; tok = tok->next()) {
2991         if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->tokType() == Token::eIncDecOp)
2992             continue;
2993 
2994         while (tok->str() != ">" && tok->next() && tok->next()->str() == "+")
2995             tok->deleteNext();
2996 
2997         if (Token::Match(tok->next(), "- %num%")) {
2998             tok->deleteNext();
2999             tok->next()->str("-" + tok->next()->str());
3000         }
3001     }
3002 }
3003 
simplifyExternC()3004 void Tokenizer::simplifyExternC()
3005 {
3006     if (isC())
3007         return;
3008 
3009     // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens.
3010     for (Token *tok = list.front(); tok; tok = tok->next()) {
3011         if (Token::simpleMatch(tok, "extern \"C\"")) {
3012             Token *tok2 = tok->next();
3013             if (tok->strAt(2) == "{") {
3014                 tok2 = tok2->next(); // skip {
3015                 while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2))
3016                     tok2->isExternC(true);
3017                 tok->linkAt(2)->deleteThis(); // }
3018                 tok->deleteNext(2); // "C" {
3019             } else {
3020                 while ((tok2 = tok2->next()) && !Token::simpleMatch(tok2, ";"))
3021                     tok2->isExternC(true);
3022                 tok->deleteNext(); // "C"
3023             }
3024             tok->deleteThis(); // extern
3025         }
3026     }
3027 }
3028 
simplifyRoundCurlyParentheses()3029 void Tokenizer::simplifyRoundCurlyParentheses()
3030 {
3031     for (Token *tok = list.front(); tok; tok = tok->next()) {
3032         while (Token::Match(tok, "[;{}:] ( {") &&
3033                Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
3034             if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
3035                 break;
3036             Token *end = tok->linkAt(2)->tokAt(-3);
3037             if (Token::Match(end, "[;{}] %num%|%str% ;"))
3038                 end->deleteNext(2);
3039             tok->linkAt(2)->previous()->deleteNext(3);
3040             tok->deleteNext(2);
3041         }
3042         if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
3043             tok->deleteNext();
3044             tok->deleteThis();
3045             tok->deleteNext(3);
3046         }
3047     }
3048 }
3049 
simplifySQL()3050 void Tokenizer::simplifySQL()
3051 {
3052     for (Token *tok = list.front(); tok; tok = tok->next()) {
3053         if (!Token::simpleMatch(tok, "__CPPCHECK_EMBEDDED_SQL_EXEC__ SQL"))
3054             continue;
3055 
3056         const Token *end = findSQLBlockEnd(tok);
3057         if (end == nullptr)
3058             syntaxError(nullptr);
3059 
3060         const std::string instruction = tok->stringifyList(end);
3061         // delete all tokens until the embedded SQL block end
3062         Token::eraseTokens(tok, end);
3063 
3064         // insert "asm ( "instruction" ) ;"
3065         tok->str("asm");
3066         // it can happen that 'end' is NULL when wrong code is inserted
3067         if (!tok->next())
3068             tok->insertToken(";");
3069         tok->insertToken(")");
3070         tok->insertToken("\"" + instruction + "\"");
3071         tok->insertToken("(");
3072         // jump to ';' and continue
3073         tok = tok->tokAt(3);
3074     }
3075 }
3076 
simplifyArrayAccessSyntax()3077 void Tokenizer::simplifyArrayAccessSyntax()
3078 {
3079     // 0[a] -> a[0]
3080     for (Token *tok = list.front(); tok; tok = tok->next()) {
3081         if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
3082             const std::string number(tok->str());
3083             Token* indexTok = tok->tokAt(2);
3084             tok->str(indexTok->str());
3085             tok->varId(indexTok->varId());
3086             indexTok->str(number);
3087         }
3088     }
3089 }
3090 
simplifyRedundantConsecutiveBraces()3091 void Tokenizer::simplifyRedundantConsecutiveBraces()
3092 {
3093     // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
3094     for (Token *tok = list.front(); tok;) {
3095         if (Token::simpleMatch(tok, "= {")) {
3096             tok = tok->linkAt(1);
3097         } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
3098             //remove internal parentheses
3099             tok->next()->link()->deleteThis();
3100             tok->deleteNext();
3101         } else
3102             tok = tok->next();
3103     }
3104 }
3105 
simplifyDoublePlusAndDoubleMinus()3106 void Tokenizer::simplifyDoublePlusAndDoubleMinus()
3107 {
3108     // Convert - - into + and + - into -
3109     for (Token *tok = list.front(); tok; tok = tok->next()) {
3110         while (tok->next()) {
3111             if (tok->str() == "+") {
3112                 if (tok->next()->str()[0] == '-') {
3113                     tok = tok->next();
3114                     if (tok->str().size() == 1) {
3115                         tok = tok->previous();
3116                         tok->str("-");
3117                         tok->deleteNext();
3118                     } else if (tok->isNumber()) {
3119                         tok->str(tok->str().substr(1));
3120                         tok = tok->previous();
3121                         tok->str("-");
3122                     }
3123                     continue;
3124                 }
3125             } else if (tok->str() == "-") {
3126                 if (tok->next()->str()[0] == '-') {
3127                     tok = tok->next();
3128                     if (tok->str().size() == 1) {
3129                         tok = tok->previous();
3130                         tok->str("+");
3131                         tok->deleteNext();
3132                     } else if (tok->isNumber()) {
3133                         tok->str(tok->str().substr(1));
3134                         tok = tok->previous();
3135                         tok->str("+");
3136                     }
3137                     continue;
3138                 }
3139             }
3140 
3141             break;
3142         }
3143     }
3144 }
3145 
3146 /** Specify array size if it hasn't been given */
3147 
arraySize()3148 void Tokenizer::arraySize()
3149 {
3150     for (Token *tok = list.front(); tok; tok = tok->next()) {
3151         if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
3152             continue;
3153         bool addlength = false;
3154         if (Token::Match(tok, "%var% [ ] = { %str% } ;")) {
3155             Token *t = tok->tokAt(3);
3156             t->deleteNext();
3157             t->next()->deleteNext();
3158             addlength = true;
3159         }
3160 
3161         if (addlength || Token::Match(tok, "%var% [ ] = %str% ;")) {
3162             tok = tok->next();
3163             const int sz = Token::getStrArraySize(tok->tokAt(3));
3164             tok->insertToken(MathLib::toString(sz));
3165             tok = tok->tokAt(5);
3166         }
3167 
3168         else if (Token::Match(tok, "%var% [ ] = {")) {
3169             MathLib::biguint sz = 1;
3170             tok = tok->next();
3171             Token *end = tok->linkAt(3);
3172             for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
3173                 if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
3174                     if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
3175                         if (Token::Match(tok2, "[ %num% ]"))
3176                             sz = std::max(sz, MathLib::toULongNumber(tok2->strAt(1)) + 1U);
3177                         else {
3178                             sz = 0;
3179                             break;
3180                         }
3181                     }
3182                     tok2 = tok2->link();
3183                 } else if (tok2->str() == ",") {
3184                     if (!Token::Match(tok2->next(), "[},]"))
3185                         ++sz;
3186                     else {
3187                         tok2 = tok2->previous();
3188                         tok2->deleteNext();
3189                     }
3190                 }
3191             }
3192 
3193             if (sz != 0)
3194                 tok->insertToken(MathLib::toString(sz));
3195 
3196             tok = end->next() ? end->next() : end;
3197         }
3198     }
3199 }
3200 
skipTernaryOp(Token * tok)3201 static Token *skipTernaryOp(Token *tok)
3202 {
3203     int colonLevel = 1;
3204     while (nullptr != (tok = tok->next())) {
3205         if (tok->str() == "?") {
3206             ++colonLevel;
3207         } else if (tok->str() == ":") {
3208             --colonLevel;
3209             if (colonLevel == 0) {
3210                 tok = tok->next();
3211                 break;
3212             }
3213         }
3214         if (tok->link() && Token::Match(tok, "[(<]"))
3215             tok = tok->link();
3216         else if (Token::Match(tok->next(), "[{};)]"))
3217             break;
3218     }
3219     if (colonLevel > 0) // Ticket #5214: Make sure the ':' matches the proper '?'
3220         return nullptr;
3221     return tok;
3222 }
3223 
3224 // Skips until the colon at the end of the case label, the argument must point to the "case" token.
3225 // In case of success returns the colon token.
3226 // In case of failure returns the token that caused the error.
skipCaseLabel(Token * tok)3227 static Token *skipCaseLabel(Token *tok)
3228 {
3229     assert(tok->str() == "case");
3230     while (nullptr != (tok = tok->next())) {
3231         if (Token::Match(tok, "(|["))
3232             tok = tok->link();
3233         else if (tok->str() == "?") {
3234             Token * tok1 = skipTernaryOp(tok);
3235             if (!tok1)
3236                 return tok;
3237             tok = tok1;
3238         }
3239         if (Token::Match(tok, "[:{};]"))
3240             return tok;
3241     }
3242     return nullptr;
3243 }
3244 
startOfExecutableScope(const Token * tok)3245 const Token * Tokenizer::startOfExecutableScope(const Token * tok)
3246 {
3247     if (tok->str() != ")")
3248         return nullptr;
3249 
3250     tok = isFunctionHead(tok, ":{", true);
3251 
3252     if (Token::Match(tok, ": %name% [({]")) {
3253         while (Token::Match(tok, "[:,] %name% [({]"))
3254             tok = tok->linkAt(2)->next();
3255     }
3256 
3257     return (tok && tok->str() == "{") ? tok : nullptr;
3258 }
3259 
3260 
3261 /** simplify labels and case|default in the code: add a ";" if not already in.*/
3262 
simplifyLabelsCaseDefault()3263 void Tokenizer::simplifyLabelsCaseDefault()
3264 {
3265     const bool cpp = isCPP();
3266     bool executablescope = false;
3267     int indentLevel = 0;
3268     for (Token *tok = list.front(); tok; tok = tok->next()) {
3269         // Simplify labels in the executable scope..
3270         Token *start = const_cast<Token *>(startOfExecutableScope(tok));
3271         if (start) {
3272             tok = start;
3273             executablescope = true;
3274         }
3275 
3276         if (!executablescope)
3277             continue;
3278 
3279         if (tok->str() == "{") {
3280             if (tok->previous()->str() == "=")
3281                 tok = tok->link();
3282             else
3283                 ++indentLevel;
3284         } else if (tok->str() == "}") {
3285             --indentLevel;
3286             if (indentLevel == 0) {
3287                 executablescope = false;
3288                 continue;
3289             }
3290         } else if (Token::Match(tok, "(|["))
3291             tok = tok->link();
3292 
3293         if (Token::Match(tok, "[;{}:] case")) {
3294             tok = skipCaseLabel(tok->next());
3295             if (!tok)
3296                 break;
3297             if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next())
3298                 syntaxError(tok);
3299             if (tok->next()->str() != ";" && tok->next()->str() != "case")
3300                 tok->insertToken(";");
3301             else
3302                 tok = tok->previous();
3303         } else if (Token::Match(tok, "[;{}] %name% : !!;")) {
3304             if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) {
3305                 tok = tok->tokAt(2);
3306                 tok->insertToken(";");
3307             }
3308         }
3309     }
3310 }
3311 
3312 
simplifyCaseRange()3313 void Tokenizer::simplifyCaseRange()
3314 {
3315     for (Token* tok = list.front(); tok; tok = tok->next()) {
3316         if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
3317             const MathLib::bigint start = MathLib::toLongNumber(tok->strAt(1));
3318             MathLib::bigint end = MathLib::toLongNumber(tok->strAt(3));
3319             end = std::min(start + 50, end); // Simplify it 50 times at maximum
3320             if (start < end) {
3321                 tok = tok->tokAt(2);
3322                 tok->str(":");
3323                 tok->insertToken("case");
3324                 for (MathLib::bigint i = end-1; i > start; i--) {
3325                     tok->insertToken(":");
3326                     tok->insertToken(MathLib::toString(i));
3327                     tok->insertToken("case");
3328                 }
3329             }
3330         }
3331     }
3332 }
3333 
calculateScopes()3334 void Tokenizer::calculateScopes()
3335 {
3336     for (auto *tok = list.front(); tok; tok = tok->next())
3337         tok->scopeInfo(nullptr);
3338 
3339     std::string nextScopeNameAddition;
3340     std::shared_ptr<ScopeInfo2> primaryScope = std::make_shared<ScopeInfo2>("", nullptr);
3341     list.front()->scopeInfo(primaryScope);
3342 
3343     for (Token* tok = list.front(); tok; tok = tok->next()) {
3344         if (tok == list.front() || !tok->scopeInfo()) {
3345             if (tok != list.front())
3346                 tok->scopeInfo(tok->previous()->scopeInfo());
3347 
3348             if (Token::Match(tok, "using namespace %name% ::|<|;")) {
3349                 std::string usingNamespaceName;
3350                 for (const Token* namespaceNameToken = tok->tokAt(2);
3351                      namespaceNameToken && namespaceNameToken->str() != ";";
3352                      namespaceNameToken = namespaceNameToken->next()) {
3353                     usingNamespaceName += namespaceNameToken->str();
3354                     usingNamespaceName += " ";
3355                 }
3356                 if (usingNamespaceName.length() > 0)
3357                     usingNamespaceName = usingNamespaceName.substr(0, usingNamespaceName.length() - 1);
3358                 tok->scopeInfo()->usingNamespaces.insert(usingNamespaceName);
3359             } else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
3360                 for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
3361                     if (Token::Match(nameTok, ";|<")) {
3362                         nextScopeNameAddition = "";
3363                         break;
3364                     }
3365                     nextScopeNameAddition.append(nameTok->str());
3366                     nextScopeNameAddition.append(" ");
3367                 }
3368                 if (nextScopeNameAddition.length() > 0)
3369                     nextScopeNameAddition = nextScopeNameAddition.substr(0, nextScopeNameAddition.length() - 1);
3370             }
3371 
3372             if (Token::simpleMatch(tok, "{")) {
3373                 // This might be the opening of a member function
3374                 Token *tok1 = tok;
3375                 while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
3376                     tok1 = tok1->previous();
3377                 if (tok1->previous() && tok1->strAt(-1) == ")") {
3378                     bool member = true;
3379                     tok1 = tok1->linkAt(-1);
3380                     if (Token::Match(tok1->previous(), "throw|noexcept")) {
3381                         tok1 = tok1->previous();
3382                         while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
3383                             tok1 = tok1->previous();
3384                         if (tok1->strAt(-1) != ")")
3385                             member = false;
3386                     } else if (Token::Match(tok->tokAt(-2), ":|, %name%")) {
3387                         tok1 = tok1->tokAt(-2);
3388                         if (tok1->strAt(-1) != ")")
3389                             member = false;
3390                     }
3391                     if (member) {
3392                         if (tok1->strAt(-1) == ">")
3393                             tok1 = tok1->previous()->findOpeningBracket();
3394                         if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
3395                             tok1 = tok1->tokAt(-2);
3396                             std::string scope = tok1->strAt(-1);
3397                             while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
3398                                 scope = tok1->strAt(-3) + " :: " + scope;
3399                                 tok1 = tok1->tokAt(-2);
3400                             }
3401 
3402                             if (!nextScopeNameAddition.empty() && !scope.empty())
3403                                 nextScopeNameAddition += " :: ";
3404                             nextScopeNameAddition += scope;
3405                         }
3406                     }
3407                 }
3408 
3409                 // New scope is opening, record it here
3410                 std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(tok->scopeInfo()->name, tok->link(), tok->scopeInfo()->usingNamespaces);
3411 
3412                 if (newScopeInfo->name != "" && nextScopeNameAddition != "")
3413                     newScopeInfo->name.append(" :: ");
3414                 newScopeInfo->name.append(nextScopeNameAddition);
3415                 nextScopeNameAddition = "";
3416 
3417                 if (tok->link())
3418                     tok->link()->scopeInfo(tok->scopeInfo());
3419                 tok->scopeInfo(newScopeInfo);
3420             }
3421         }
3422     }
3423 }
3424 
simplifyTemplates()3425 void Tokenizer::simplifyTemplates()
3426 {
3427     if (isC())
3428         return;
3429 
3430     mTemplateSimplifier->simplifyTemplates(
3431 #ifdef MAXTIME
3432         mMaxTime,
3433 #else
3434         0, // ignored
3435 #endif
3436         mCodeWithTemplates);
3437 }
3438 //---------------------------------------------------------------------------
3439 
3440 
setVarIdParseDeclaration(const Token ** tok,const std::map<std::string,int> & variableId,bool executableScope,bool cpp,bool c)3441 static bool setVarIdParseDeclaration(const Token **tok, const std::map<std::string,int> &variableId, bool executableScope, bool cpp, bool c)
3442 {
3443     const Token *tok2 = *tok;
3444     if (!tok2->isName())
3445         return false;
3446 
3447     int typeCount = 0;
3448     int singleNameCount = 0;
3449     bool hasstruct = false;   // Is there a "struct" or "class"?
3450     bool bracket = false;
3451     bool ref = false;
3452     while (tok2) {
3453         if (tok2->isName()) {
3454             if (cpp && Token::Match(tok2, "namespace|public|private|protected"))
3455                 return false;
3456             if (cpp && Token::simpleMatch(tok2, "decltype (")) {
3457                 typeCount = 1;
3458                 tok2 = tok2->linkAt(1)->next();
3459                 continue;
3460             }
3461             if (Token::Match(tok2, "struct|union|enum") || (!c && Token::Match(tok2, "class|typename"))) {
3462                 hasstruct = true;
3463                 typeCount = 0;
3464                 singleNameCount = 0;
3465             } else if (tok2->str() == "const") {
3466                 // just skip "const"
3467             } else if (!hasstruct && variableId.find(tok2->str()) != variableId.end() && tok2->previous()->str() != "::") {
3468                 ++typeCount;
3469                 tok2 = tok2->next();
3470                 if (!tok2 || tok2->str() != "::")
3471                     break;
3472             } else {
3473                 if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
3474                     ++typeCount;
3475                 ++singleNameCount;
3476             }
3477         } else if (!c && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
3478                           Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
3479             const Token *start = *tok;
3480             if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/"))
3481                 return false;
3482             const Token * const closingBracket = tok2->findClosingBracket();
3483             if (closingBracket == nullptr) { /* Ticket #8151 */
3484                 throw tok2;
3485             }
3486             tok2 = closingBracket;
3487             if (tok2->str() != ">")
3488                 break;
3489             singleNameCount = 1;
3490             if (Token::Match(tok2, "> %name% %or%|%oror%|&&|&|^|+|-|*|/") && !Token::Match(tok2, "> const [*&]"))
3491                 return false;
3492             if (Token::Match(tok2, "> %name% )")) {
3493                 if (Token::Match(tok2->linkAt(2)->previous(), "if|for|while ("))
3494                     return false;
3495                 if (!Token::Match(tok2->linkAt(2)->previous(), "%name% ("))
3496                     return false;
3497             }
3498         } else if (Token::Match(tok2, "&|&&")) {
3499             ref = !bracket;
3500         } else if (singleNameCount >= 1 && Token::Match(tok2, "( [*&]") && Token::Match(tok2->link()->next(), "(|[")) {
3501             bracket = true; // Skip: Seems to be valid pointer to array or function pointer
3502         } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]")) {
3503             bracket = true;
3504         } else if (tok2->str() == "::") {
3505             singleNameCount = 0;
3506         } else if (tok2->str() != "*" && tok2->str() != "::" && tok2->str() != "...") {
3507             break;
3508         }
3509         tok2 = tok2->next();
3510     }
3511 
3512     if (tok2) {
3513         bool isLambdaArg = false;
3514         {
3515             const Token *tok3 = (*tok)->previous();
3516             if (tok3 && tok3->str() == ",") {
3517                 while (tok3 && !Token::Match(tok3,";|(|[|{")) {
3518                     if (Token::Match(tok3, ")|]"))
3519                         tok3 = tok3->link();
3520                     tok3 = tok3->previous();
3521                 }
3522 
3523                 if (tok3 && executableScope && Token::Match(tok3->previous(), "%name% (")) {
3524                     const Token *fdecl = tok3->previous();
3525                     int count = 0;
3526                     while (Token::Match(fdecl, "%name%|*")) {
3527                         fdecl = fdecl->previous();
3528                         count++;
3529                     }
3530                     if (!Token::Match(fdecl, "[;{}] %name%") || count <= 1)
3531                         return false;
3532                 }
3533             }
3534 
3535             if (cpp && tok3 && Token::simpleMatch(tok3->previous(), "] (") && Token::simpleMatch(tok3->link(), ") {"))
3536                 isLambdaArg = true;
3537         }
3538 
3539 
3540         *tok = tok2;
3541 
3542         // In executable scopes, references must be assigned
3543         // Catching by reference is an exception
3544         if (executableScope && ref && !isLambdaArg) {
3545             if (Token::Match(tok2, "(|=|{|:"))
3546                 ;   // reference is assigned => ok
3547             else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
3548                 return false;   // not catching by reference => not declaration
3549         }
3550     }
3551 
3552     // Check if array declaration is valid (#2638)
3553     // invalid declaration: AAA a[4] = 0;
3554     if (typeCount >= 2 && executableScope && tok2 && tok2->str() == "[") {
3555         const Token *tok3 = tok2->link()->next();
3556         while (tok3 && tok3->str() == "[") {
3557             tok3 = tok3->link()->next();
3558         }
3559         if (Token::Match(tok3, "= %num%"))
3560             return false;
3561     }
3562 
3563     return (typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
3564 }
3565 
3566 
setVarIdStructMembers(Token ** tok1,std::map<int,std::map<std::string,int>> & structMembers,nonneg int * varId) const3567 void Tokenizer::setVarIdStructMembers(Token **tok1,
3568                                       std::map<int, std::map<std::string, int>>& structMembers,
3569                                       nonneg int *varId) const
3570 {
3571     Token *tok = *tok1;
3572 
3573     if (Token::Match(tok, "%name% = { . %name% =|{")) {
3574         const int struct_varid = tok->varId();
3575         if (struct_varid == 0)
3576             return;
3577 
3578         std::map<std::string, int>& members = structMembers[struct_varid];
3579 
3580         tok = tok->tokAt(3);
3581         while (tok->str() != "}") {
3582             if (Token::Match(tok, "{|[|("))
3583                 tok = tok->link();
3584             if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
3585                 tok = tok->next();
3586                 const std::map<std::string, int>::iterator it = members.find(tok->str());
3587                 if (it == members.end()) {
3588                     members[tok->str()] = ++(*varId);
3589                     tok->varId(*varId);
3590                 } else {
3591                     tok->varId(it->second);
3592                 }
3593             }
3594             tok = tok->next();
3595         }
3596 
3597         return;
3598     }
3599 
3600     while (Token::Match(tok->next(), ")| . %name% !!(")) {
3601         // Don't set varid for trailing return type
3602         if (tok->strAt(1) == ")" && tok->linkAt(1)->previous()->isName() &&
3603             isFunctionHead(tok->linkAt(1), "{|;")) {
3604             tok = tok->tokAt(3);
3605             continue;
3606         }
3607         const int struct_varid = tok->varId();
3608         tok = tok->tokAt(2);
3609         if (struct_varid == 0)
3610             continue;
3611 
3612         if (tok->str() == ".")
3613             tok = tok->next();
3614 
3615         // Don't set varid for template function
3616         if (TemplateSimplifier::templateParameters(tok->next()) > 0)
3617             break;
3618 
3619         std::map<std::string, int>& members = structMembers[struct_varid];
3620         const std::map<std::string, int>::iterator it = members.find(tok->str());
3621         if (it == members.end()) {
3622             members[tok->str()] = ++(*varId);
3623             tok->varId(*varId);
3624         } else {
3625             tok->varId(it->second);
3626         }
3627     }
3628     // tok can't be null
3629     *tok1 = tok;
3630 }
3631 
3632 
setVarIdClassDeclaration(const Token * const startToken,const VariableMap & variableMap,const nonneg int scopeStartVarId,std::map<int,std::map<std::string,int>> & structMembers)3633 void Tokenizer::setVarIdClassDeclaration(const Token * const startToken,
3634                                          const VariableMap &variableMap,
3635                                          const nonneg int scopeStartVarId,
3636                                          std::map<int, std::map<std::string,int>>& structMembers)
3637 {
3638     // end of scope
3639     const Token * const endToken = startToken->link();
3640 
3641     // determine class name
3642     std::string className;
3643     for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
3644         if (!tok->isName() && tok->str() != ":")
3645             break;
3646         if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
3647             className = tok->next()->str();
3648             break;
3649         }
3650     }
3651 
3652     // replace varids..
3653     int indentlevel = 0;
3654     bool initList = false;
3655     bool inEnum = false;
3656     const Token *initListArgLastToken = nullptr;
3657     for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
3658         if (!tok)
3659             syntaxError(nullptr);
3660         if (initList) {
3661             if (tok == initListArgLastToken)
3662                 initListArgLastToken = nullptr;
3663             else if (!initListArgLastToken &&
3664                      Token::Match(tok->previous(), "%name%|>|>> {|(") &&
3665                      Token::Match(tok->link(), "}|) ,|{"))
3666                 initListArgLastToken = tok->link();
3667         }
3668         if (tok->str() == "{") {
3669             inEnum = isEnumStart(tok);
3670             if (initList && !initListArgLastToken)
3671                 initList = false;
3672             ++indentlevel;
3673         } else if (tok->str() == "}") {
3674             --indentlevel;
3675             inEnum = false;
3676         } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
3677             const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str());
3678             if (it != variableMap.end()) {
3679                 tok->varId(it->second);
3680             }
3681         } else if (tok->isName() && tok->varId() <= scopeStartVarId) {
3682             if (indentlevel > 0 || initList) {
3683                 if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
3684                     continue;
3685                 if (!tok->next())
3686                     syntaxError(nullptr);
3687                 if (tok->next()->str() == "::") {
3688                     if (tok->str() == className)
3689                         tok = tok->tokAt(2);
3690                     else
3691                         continue;
3692                 }
3693 
3694                 if (!inEnum) {
3695                     const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str());
3696                     if (it != variableMap.end()) {
3697                         tok->varId(it->second);
3698                         setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
3699                     }
3700                 }
3701             }
3702         } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
3703             initList = true;
3704     }
3705 }
3706 
3707 
3708 
3709 // Update the variable ids..
3710 // Parse each function..
setVarIdClassFunction(const std::string & classname,Token * const startToken,const Token * const endToken,const std::map<std::string,int> & varlist,std::map<int,std::map<std::string,int>> & structMembers,nonneg int * varId_)3711 void Tokenizer::setVarIdClassFunction(const std::string &classname,
3712                                       Token * const startToken,
3713                                       const Token * const endToken,
3714                                       const std::map<std::string, int> &varlist,
3715                                       std::map<int, std::map<std::string, int>>& structMembers,
3716                                       nonneg int *varId_)
3717 {
3718     for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
3719         if (tok2->varId() != 0 || !tok2->isName())
3720             continue;
3721         if (Token::Match(tok2->tokAt(-2), ("!!" + classname + " ::").c_str()))
3722             continue;
3723         if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
3724             continue;
3725         if (Token::Match(tok2->tokAt(-2), "!!this .") && !Token::simpleMatch(tok2->tokAt(-5), "( * this ) ."))
3726             continue;
3727 
3728         const std::map<std::string,int>::const_iterator it = varlist.find(tok2->str());
3729         if (it != varlist.end()) {
3730             tok2->varId(it->second);
3731             setVarIdStructMembers(&tok2, structMembers, varId_);
3732         }
3733     }
3734 }
3735 
3736 
3737 
setVarId()3738 void Tokenizer::setVarId()
3739 {
3740     // Clear all variable ids
3741     for (Token *tok = list.front(); tok; tok = tok->next()) {
3742         if (tok->isName())
3743             tok->varId(0);
3744     }
3745 
3746     setPodTypes();
3747 
3748     setVarIdPass1();
3749 
3750     setVarIdPass2();
3751 }
3752 
3753 
3754 // Variable declarations can't start with "return" etc.
3755 #define NOTSTART_C "NOT", "case", "default", "goto", "not", "return", "sizeof", "typedef"
3756 static const std::unordered_set<std::string> notstart_c = { NOTSTART_C };
3757 static const std::unordered_set<std::string> notstart_cpp = { NOTSTART_C,
3758                                                               "delete", "friend", "new", "throw", "using", "virtual", "explicit", "const_cast", "dynamic_cast", "reinterpret_cast", "static_cast", "template"
3759 };
3760 
setVarIdPass1()3761 void Tokenizer::setVarIdPass1()
3762 {
3763     // Variable declarations can't start with "return" etc.
3764     const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
3765 
3766     VariableMap variableMap;
3767     std::map<int, std::map<std::string, int>> structMembers;
3768 
3769     std::stack<VarIdScopeInfo> scopeStack;
3770 
3771     scopeStack.push(VarIdScopeInfo());
3772     std::stack<const Token *> functionDeclEndStack;
3773     const Token *functionDeclEndToken = nullptr;
3774     bool initlist = false;
3775     bool inlineFunction = false;
3776     for (Token *tok = list.front(); tok; tok = tok->next()) {
3777         if (tok->isOp())
3778             continue;
3779         if (tok == functionDeclEndToken) {
3780             functionDeclEndStack.pop();
3781             functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
3782             if (tok->str() == ":")
3783                 initlist = true;
3784             else if (tok->str() == ";") {
3785                 if (!variableMap.leaveScope())
3786                     cppcheckError(tok);
3787             } else if (tok->str() == "{") {
3788                 scopeStack.push(VarIdScopeInfo(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/ false, *variableMap.getVarId()));
3789 
3790                 // check if this '{' is a start of an "if" body
3791                 const Token * ifToken = tok->previous();
3792                 if (ifToken && ifToken->str() == ")")
3793                     ifToken = ifToken->link();
3794                 else
3795                     ifToken = nullptr;
3796                 if (ifToken)
3797                     ifToken = ifToken->previous();
3798                 if (ifToken && ifToken->str() == "if") {
3799                     // open another scope to differentiate between variables declared in the "if" condition and in the "if" body
3800                     variableMap.enterScope();
3801                 }
3802             }
3803         } else if (!initlist && tok->str()=="(") {
3804             const Token * newFunctionDeclEnd = nullptr;
3805             if (!scopeStack.top().isExecutable)
3806                 newFunctionDeclEnd = isFunctionHead(tok, "{:;");
3807             else {
3808                 Token const * const tokenLinkNext = tok->link()->next();
3809                 if (tokenLinkNext && tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
3810                     newFunctionDeclEnd = tokenLinkNext;
3811             }
3812             if (newFunctionDeclEnd && newFunctionDeclEnd != functionDeclEndToken) {
3813                 functionDeclEndStack.push(newFunctionDeclEnd);
3814                 functionDeclEndToken = newFunctionDeclEnd;
3815                 variableMap.enterScope();
3816             }
3817         } else if (Token::Match(tok, "{|}")) {
3818             inlineFunction = false;
3819 
3820             const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
3821 
3822             // parse anonymous unions as part of the current scope
3823             if (!Token::Match(startToken->previous(), "union|struct|enum {") &&
3824                 !(initlist && Token::Match(startToken->previous(), "%name%|>|>>") && Token::Match(startToken->link(), "} ,|{"))) {
3825 
3826                 if (tok->str() == "{") {
3827                     bool isExecutable;
3828                     const Token *prev = tok->previous();
3829                     while (Token::Match(prev, "%name%|."))
3830                         prev = prev->previous();
3831                     const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] (");
3832                     if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) ||
3833                         (initlist && tok->strAt(-1) == "}")) {
3834                         isExecutable = true;
3835                     } else {
3836                         isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
3837                                         !isClassStructUnionEnumStart(tok));
3838                         if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
3839                             variableMap.enterScope();
3840                     }
3841                     initlist = false;
3842                     scopeStack.push(VarIdScopeInfo(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), *variableMap.getVarId()));
3843                 } else { /* if (tok->str() == "}") */
3844                     bool isNamespace = false;
3845                     for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) {
3846                         if (tok1->str() == "namespace") {
3847                             isNamespace = true;
3848                             break;
3849                         }
3850                     }
3851                     // Set variable ids in class declaration..
3852                     if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
3853                         setVarIdClassDeclaration(tok->link(),
3854                                                  variableMap,
3855                                                  scopeStack.top().startVarid,
3856                                                  structMembers);
3857                     }
3858 
3859                     if (!scopeStack.top().isStructInit) {
3860                         variableMap.leaveScope();
3861 
3862                         // check if this '}' is an end of an "else" body or an "if" body without an "else" part
3863                         const Token * ifToken = startToken->previous();
3864                         if (ifToken && ifToken->str() == ")")
3865                             ifToken = ifToken->link()->previous();
3866                         else
3867                             ifToken = nullptr;
3868                         if (startToken->strAt(-1) == "else" || (ifToken && ifToken->str() == "if" && tok->strAt(1) != "else")) {
3869                             // leave the extra scope used to differentiate between variables declared in the "if" condition and in the "if" body
3870                             variableMap.leaveScope();
3871                         }
3872                     }
3873 
3874                     scopeStack.pop();
3875                     if (scopeStack.empty()) {  // should be impossible
3876                         scopeStack.push(VarIdScopeInfo());
3877                     }
3878                 }
3879             }
3880         }
3881 
3882         if (!scopeStack.top().isStructInit &&
3883             (tok == list.front() ||
3884              Token::Match(tok, "[;{}]") ||
3885              (tok->str() == "(" && isFunctionHead(tok,"{")) ||
3886              (tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
3887              (tok->str() == "," && (!scopeStack.top().isExecutable || inlineFunction)) ||
3888              (tok->isName() && endsWith(tok->str(), ':')))) {
3889 
3890             // No variable declarations in sizeof
3891             if (Token::simpleMatch(tok->previous(), "sizeof (")) {
3892                 continue;
3893             }
3894 
3895             if (Settings::terminated())
3896                 return;
3897 
3898             // locate the variable name..
3899             const Token *tok2 = (tok->isName()) ? tok : tok->next();
3900 
3901             // private: protected: public: etc
3902             while (tok2 && endsWith(tok2->str(), ':')) {
3903                 tok2 = tok2->next();
3904             }
3905             if (!tok2)
3906                 break;
3907 
3908             // Variable declaration can't start with "return", etc
3909             if (notstart.find(tok2->str()) != notstart.end())
3910                 continue;
3911 
3912             if (!isC() && Token::simpleMatch(tok2, "const new"))
3913                 continue;
3914 
3915             bool decl;
3916             if (isCPP() && mSettings->standards.cpp >= Standards::CPP17 && Token::Match(tok, "[(;{}] const| auto &|&&| [")) {
3917                 // Structured bindings
3918                 tok2 = Token::findsimplematch(tok, "[");
3919                 if ((Token::simpleMatch(tok->previous(), "for (") && Token::simpleMatch(tok2->link(), "] :")) ||
3920                     Token::simpleMatch(tok2->link(), "] =")) {
3921                     while (tok2 && tok2->str() != "]") {
3922                         if (Token::Match(tok2, "%name% [,]]"))
3923                             variableMap.addVariable(tok2->str());
3924                         tok2 = tok2->next();
3925                     }
3926                     continue;
3927                 }
3928             }
3929 
3930             try { /* Ticket #8151 */
3931                 decl = setVarIdParseDeclaration(&tok2, variableMap.map(), scopeStack.top().isExecutable, isCPP(), isC());
3932             } catch (const Token * errTok) {
3933                 syntaxError(errTok);
3934             }
3935             if (decl) {
3936                 if (isCPP()) {
3937                     if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
3938                         for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
3939                             if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
3940                                 declTok->varId(variableMap.find(declTok->str())->second);
3941                         }
3942                     }
3943                 }
3944 
3945                 if (tok->str() == "(" && isFunctionHead(tok,"{") && scopeStack.top().isExecutable)
3946                     inlineFunction = true;
3947 
3948                 const Token* prev2 = tok2->previous();
3949                 if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
3950                     ;
3951                 else if (Token::Match(prev2, "%type% :") && tok->strAt(-1) == "for")
3952                     ;
3953                 else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
3954                     // In C++ , a variable can't be called operator+ or something like that.
3955                     if (isCPP() &&
3956                         prev2->isOperatorKeyword())
3957                         continue;
3958 
3959                     const Token *tok3 = tok2->next();
3960                     if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
3961                         if (!scopeStack.top().isExecutable) {
3962                             // 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.
3963                             decl = false;
3964                             bool rhs = false;
3965                             for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
3966                                 if (tok3->str() == "=") {
3967                                     rhs = true;
3968                                     continue;
3969                                 }
3970 
3971                                 if (tok3->str() == ",") {
3972                                     rhs = false;
3973                                     continue;
3974                                 }
3975 
3976                                 if (rhs)
3977                                     continue;
3978 
3979                                 if (tok3->isLiteral() ||
3980                                     (tok3->isName() && variableMap.hasVariable(tok3->str())) ||
3981                                     tok3->isOp() ||
3982                                     tok3->str() == "(" ||
3983                                     notstart.find(tok3->str()) != notstart.end()) {
3984                                     decl = true;
3985                                     break;
3986                                 }
3987                             }
3988                         }
3989                     } else
3990                         decl = false;
3991                 } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
3992                     if (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:"))
3993                         continue;
3994                 } else
3995                     decl = false;
3996 
3997                 if (decl) {
3998                     variableMap.addVariable(prev2->str());
3999 
4000                     if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
4001                         for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
4002                             if (Token::Match(tok3, "[([]"))
4003                                 tok3 = tok3->link();
4004                             if (Token::Match(tok3, ", %name% [,=;]"))
4005                                 variableMap.addVariable(tok3->next()->str());
4006                         }
4007                     }
4008 
4009                     // set varid for template parameters..
4010                     tok = tok->next();
4011                     while (Token::Match(tok, "%name%|::"))
4012                         tok = tok->next();
4013                     if (tok && tok->str() == "<") {
4014                         const Token *end = tok->findClosingBracket();
4015                         while (tok != end) {
4016                             if (tok->isName()) {
4017                                 const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str());
4018                                 if (it != variableMap.end())
4019                                     tok->varId(it->second);
4020                             }
4021                             tok = tok->next();
4022                         }
4023                     }
4024 
4025                     tok = tok2->previous();
4026                 }
4027             }
4028         }
4029 
4030         if (tok->isName()) {
4031             // don't set variable id after a struct|enum|union
4032             if (Token::Match(tok->previous(), "struct|enum|union") || (isCPP() && tok->strAt(-1) == "class"))
4033                 continue;
4034 
4035             if (!isC()) {
4036                 if (tok->previous() && tok->previous()->str() == "::")
4037                     continue;
4038                 if (tok->next() && tok->next()->str() == "::")
4039                     continue;
4040                 if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
4041                     continue;
4042             }
4043 
4044             // function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
4045             if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)]")) {
4046                 bool par = false;
4047                 const Token *start, *end;
4048 
4049                 // search begin of function declaration
4050                 for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
4051                     if (start->str() == "(") {
4052                         if (par)
4053                             break;
4054                         par = true;
4055                     }
4056                     if (Token::Match(start, "[(,]")) {
4057                         if (!Token::Match(start, "[(,] %type% %name%|*|&"))
4058                             break;
4059                     }
4060                     if (start->varId() > 0)
4061                         break;
4062                 }
4063 
4064                 // search end of function declaration
4065                 for (end = tok->next(); Token::Match(end, "%name%|*|&|,"); end = end->next()) {}
4066 
4067                 // there are tokens which can't appear at the begin of a function declaration such as "return"
4068                 const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();
4069 
4070                 // now check if it is a function declaration
4071                 if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword)
4072                     // function declaration => don't set varid
4073                     continue;
4074             }
4075 
4076             if (!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) {
4077                 const std::map<std::string, int>::const_iterator it = variableMap.find(tok->str());
4078                 if (it != variableMap.end()) {
4079                     tok->varId(it->second);
4080                     setVarIdStructMembers(&tok, structMembers, variableMap.getVarId());
4081                 }
4082             }
4083         } else if (Token::Match(tok, "::|. %name%")) {
4084             // Don't set varid after a :: or . token
4085             tok = tok->next();
4086         } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
4087             do {
4088                 tok = tok->next();
4089             } while (tok && (tok->isName() || tok->str() == ","));
4090             if (!tok)
4091                 break;
4092             tok = tok->previous();
4093         }
4094     }
4095 
4096     mVarId = *variableMap.getVarId();
4097 }
4098 
4099 namespace {
4100     struct Member {
Member__anon5685b77f0411::Member4101         Member(const std::list<std::string> &s, const std::list<const Token *> &ns, Token *t) : usingnamespaces(ns), scope(s), tok(t) {}
4102         std::list<const Token *> usingnamespaces;
4103         std::list<std::string> scope;
4104         Token *tok;
4105     };
4106 }
4107 
getScopeName(const std::list<ScopeInfo2> & scopeInfo)4108 static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
4109 {
4110     std::string ret;
4111     for (const ScopeInfo2 &si : scopeInfo)
4112         ret += (ret.empty() ? "" : " :: ") + (si.name);
4113     return ret;
4114 }
4115 
matchMemberName(const std::list<std::string> & scope,const Token * nsToken,Token * memberToken,const std::list<ScopeInfo2> & scopeInfo)4116 static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
4117 {
4118     std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.begin();
4119 
4120     // Current scope..
4121     for (std::list<std::string>::const_iterator it = scope.begin(); it != scope.end(); ++it) {
4122         if (scopeIt == scopeInfo.end() || scopeIt->name != *it)
4123             return nullptr;
4124         ++scopeIt;
4125     }
4126 
4127     // using namespace..
4128     if (nsToken) {
4129         while (Token::Match(nsToken, "%name% ::")) {
4130             if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
4131                 nsToken = nsToken->tokAt(2);
4132                 ++scopeIt;
4133             } else {
4134                 return nullptr;
4135             }
4136         }
4137         if (!Token::Match(nsToken, "%name% ;"))
4138             return nullptr;
4139         if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
4140             return nullptr;
4141         ++scopeIt;
4142     }
4143 
4144     // Parse member tokens..
4145     while (scopeIt != scopeInfo.end()) {
4146         if (!Token::Match(memberToken, "%name% ::|<"))
4147             return nullptr;
4148         if (memberToken->str() != scopeIt->name)
4149             return nullptr;
4150         if (memberToken->next()->str() == "<") {
4151             memberToken = memberToken->next()->findClosingBracket();
4152             if (!Token::simpleMatch(memberToken, "> ::"))
4153                 return nullptr;
4154         }
4155         memberToken = memberToken->tokAt(2);
4156         ++scopeIt;
4157     }
4158 
4159     return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
4160 }
4161 
matchMemberName(const Member & member,const std::list<ScopeInfo2> & scopeInfo)4162 static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
4163 {
4164     if (scopeInfo.empty())
4165         return nullptr;
4166 
4167     // Does this member match without "using namespace"..
4168     Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
4169     if (ret)
4170         return ret;
4171 
4172     // Try to match member using the "using namespace ..." namespaces..
4173     for (const Token *ns : member.usingnamespaces) {
4174         ret = matchMemberName(member.scope, ns, member.tok, scopeInfo);
4175         if (ret)
4176             return ret;
4177     }
4178 
4179     return nullptr;
4180 }
4181 
matchMemberVarName(const Member & var,const std::list<ScopeInfo2> & scopeInfo)4182 static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
4183 {
4184     Token *tok = matchMemberName(var, scopeInfo);
4185     return Token::Match(tok, "%name% !!(") ? tok : nullptr;
4186 }
4187 
matchMemberFunctionName(const Member & func,const std::list<ScopeInfo2> & scopeInfo)4188 static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
4189 {
4190     Token *tok = matchMemberName(func, scopeInfo);
4191     return Token::Match(tok, "~| %name% (") ? tok : nullptr;
4192 }
4193 
setVarIdPass2()4194 void Tokenizer::setVarIdPass2()
4195 {
4196     std::map<int, std::map<std::string, int>> structMembers;
4197 
4198     // Member functions and variables in this source
4199     std::list<Member> allMemberFunctions;
4200     std::list<Member> allMemberVars;
4201     if (!isC()) {
4202         std::map<const Token *, std::string> endOfScope;
4203         std::list<std::string> scope;
4204         std::list<const Token *> usingnamespaces;
4205         for (Token *tok = list.front(); tok; tok = tok->next()) {
4206             if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
4207                 if (Token::Match(tok, "using namespace %name% ::|;")) {
4208                     Token *endtok = tok->tokAt(2);
4209                     while (Token::Match(endtok, "%name% ::"))
4210                         endtok = endtok->tokAt(2);
4211                     if (Token::Match(endtok, "%name% ;"))
4212                         usingnamespaces.push_back(tok->tokAt(2));
4213                     tok = endtok;
4214                     continue;
4215                 } else if (Token::Match(tok, "namespace %name% {")) {
4216                     scope.push_back(tok->strAt(1));
4217                     endOfScope[tok->linkAt(2)] = tok->strAt(1);
4218                 }
4219             }
4220 
4221             if (tok->str() == "}") {
4222                 const std::map<const Token *, std::string>::iterator it = endOfScope.find(tok);
4223                 if (it != endOfScope.end())
4224                     scope.remove(it->second);
4225             }
4226 
4227             Token* const tok1 = tok;
4228             if (Token::Match(tok->previous(), "!!:: %name% :: ~| %name%"))
4229                 tok = tok->next();
4230             else if (Token::Match(tok->previous(), "!!:: %name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
4231                 tok = tok->next()->findClosingBracket()->next();
4232             else
4233                 continue;
4234 
4235             while (Token::Match(tok, ":: ~| %name%")) {
4236                 tok = tok->next();
4237                 if (tok->str() == "~")
4238                     tok = tok->next();
4239                 else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
4240                     tok = tok->next()->findClosingBracket()->next();
4241                 else if (Token::Match(tok, "%name% ::"))
4242                     tok = tok->next();
4243                 else
4244                     break;
4245             }
4246             if (!tok->next())
4247                 syntaxError(tok);
4248             if (Token::Match(tok, "%name% ("))
4249                 allMemberFunctions.emplace_back(scope, usingnamespaces, tok1);
4250             else
4251                 allMemberVars.emplace_back(scope, usingnamespaces, tok1);
4252         }
4253     }
4254 
4255     std::list<ScopeInfo2> scopeInfo;
4256 
4257     // class members..
4258     std::map<std::string, std::map<std::string, int>> varsByClass;
4259     for (Token *tok = list.front(); tok; tok = tok->next()) {
4260         while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
4261             scopeInfo.pop_back();
4262 
4263         if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<"))
4264             continue;
4265 
4266         const std::string &scopeName(getScopeName(scopeInfo));
4267         const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
4268 
4269         std::list<const Token *> classnameTokens;
4270         classnameTokens.push_back(tok->next());
4271         const Token* tokStart = tok->tokAt(2);
4272         while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") {
4273             if (tokStart->str() == "<") {
4274                 // skip the template part
4275                 tokStart = tokStart->findClosingBracket()->next();
4276             } else {
4277                 classnameTokens.push_back(tokStart->next());
4278                 tokStart = tokStart->tokAt(2);
4279             }
4280         }
4281 
4282         std::string classname;
4283         for (const Token *it : classnameTokens)
4284             classname += (classname.empty() ? "" : " :: ") + it->str();
4285 
4286         std::map<std::string, int> &thisClassVars = varsByClass[scopeName2 + classname];
4287         while (Token::Match(tokStart, ":|::|,|%name%")) {
4288             if (Token::Match(tokStart, "%name% <")) {
4289                 tokStart = tokStart->next()->findClosingBracket();
4290                 if (tokStart)
4291                     tokStart = tokStart->next();
4292                 continue;
4293             }
4294             if (Token::Match(tokStart, "%name% ,|{")) {
4295                 std::string baseClassName = tokStart->str();
4296                 std::string scopeName3(scopeName2);
4297                 while (!scopeName3.empty()) {
4298                     const std::string name = scopeName3 + baseClassName;
4299                     if (varsByClass.find(name) != varsByClass.end()) {
4300                         baseClassName = name;
4301                         break;
4302                     }
4303                     // Remove last scope name
4304                     if (scopeName3.size() <= 8)
4305                         break;
4306                     scopeName3.erase(scopeName3.size() - 4);
4307                     const std::string::size_type pos = scopeName3.rfind(" :: ");
4308                     if (pos == std::string::npos)
4309                         break;
4310                     scopeName3.erase(pos + 4);
4311                 }
4312                 const std::map<std::string, int>& baseClassVars = varsByClass[baseClassName];
4313                 thisClassVars.insert(baseClassVars.begin(), baseClassVars.end());
4314             }
4315             tokStart = tokStart->next();
4316         }
4317         if (!Token::simpleMatch(tokStart, "{"))
4318             continue;
4319 
4320         // What member variables are there in this class?
4321         for (const Token *it : classnameTokens)
4322             scopeInfo.emplace_back(it->str(), tokStart->link());
4323 
4324         for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
4325             // skip parentheses..
4326             if (tok2->link()) {
4327                 if (tok2->str() == "(") {
4328                     Token *funcstart = const_cast<Token*>(isFunctionHead(tok2, "{"));
4329                     if (funcstart) {
4330                         setVarIdClassFunction(scopeName2 + classname, funcstart, funcstart->link(), thisClassVars, structMembers, &mVarId);
4331                         tok2 = funcstart->link();
4332                         continue;
4333                     }
4334                 }
4335                 if (tok2->str() == "{") {
4336                     if (tok2->strAt(-1) == ")")
4337                         setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, &mVarId);
4338                     tok2 = tok2->link();
4339                 } else if (Token::Match(tok2, "( %name%|)") && !Token::Match(tok2->link(), "(|[")) {
4340                     tok2 = tok2->link();
4341 
4342                     // Skip initialization list
4343                     while (Token::Match(tok2, ") [:,] %name% ("))
4344                         tok2 = tok2->linkAt(3);
4345                 }
4346             }
4347 
4348             // Found a member variable..
4349             else if (tok2->varId() > 0)
4350                 thisClassVars[tok2->str()] = tok2->varId();
4351         }
4352 
4353         // Are there any member variables in this class?
4354         if (thisClassVars.empty())
4355             continue;
4356 
4357         // Member variables
4358         for (const Member &var : allMemberVars) {
4359             Token *tok2 = matchMemberVarName(var, scopeInfo);
4360             if (!tok2)
4361                 continue;
4362             tok2->varId(thisClassVars[tok2->str()]);
4363         }
4364 
4365         if (isC() || tok->str() == "namespace")
4366             continue;
4367 
4368         // Set variable ids in member functions for this class..
4369         for (const Member &func : allMemberFunctions) {
4370             Token *tok2 = matchMemberFunctionName(func, scopeInfo);
4371             if (!tok2)
4372                 continue;
4373 
4374             if (tok2->str() == "~")
4375                 tok2 = tok2->linkAt(2);
4376             else
4377                 tok2 = tok2->linkAt(1);
4378 
4379             // If this is a function implementation.. add it to funclist
4380             Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
4381             if (start) {
4382                 setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, &mVarId);
4383             }
4384 
4385             if (Token::Match(tok2, ") %name% ("))
4386                 tok2 = tok2->linkAt(2);
4387 
4388             // constructor with initializer list
4389             if (!Token::Match(tok2, ") : ::| %name%"))
4390                 continue;
4391 
4392             Token *tok3 = tok2;
4393             while (Token::Match(tok3, "[)}] [,:]")) {
4394                 tok3 = tok3->tokAt(2);
4395                 if (Token::Match(tok3, ":: %name%"))
4396                     tok3 = tok3->next();
4397                 while (Token::Match(tok3, "%name% :: %name%"))
4398                     tok3 = tok3->tokAt(2);
4399                 if (!Token::Match(tok3, "%name% (|{|<"))
4400                     break;
4401 
4402                 // set varid
4403                 const std::map<std::string, int>::const_iterator varpos = thisClassVars.find(tok3->str());
4404                 if (varpos != thisClassVars.end())
4405                     tok3->varId(varpos->second);
4406 
4407                 // goto end of var
4408                 if (tok3->strAt(1) == "<") {
4409                     tok3 = tok3->next()->findClosingBracket();
4410                     if (tok3 && tok3->next() && tok3->next()->link())
4411                         tok3 = tok3->next()->link();
4412                 } else
4413                     tok3 = tok3->linkAt(1);
4414             }
4415             if (Token::Match(tok3, ")|} {")) {
4416                 setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, structMembers, &mVarId);
4417             }
4418         }
4419     }
4420 }
4421 
linkBrackets(const Tokenizer * const tokenizer,std::stack<const Token * > & type,std::stack<Token * > & links,Token * const token,const char open,const char close)4422 static void linkBrackets(const Tokenizer * const tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token * const token, const char open, const char close)
4423 {
4424     if (token->str()[0] == open) {
4425         links.push(token);
4426         type.push(token);
4427     } else if (token->str()[0] == close) {
4428         if (links.empty()) {
4429             // Error, { and } don't match.
4430             tokenizer->unmatchedToken(token);
4431         }
4432         if (type.top()->str()[0] != open) {
4433             tokenizer->unmatchedToken(type.top());
4434         }
4435         type.pop();
4436 
4437         Token::createMutualLinks(links.top(), token);
4438         links.pop();
4439     }
4440 }
4441 
createLinks()4442 void Tokenizer::createLinks()
4443 {
4444     std::stack<const Token*> type;
4445     std::stack<Token*> links1;
4446     std::stack<Token*> links2;
4447     std::stack<Token*> links3;
4448     for (Token *token = list.front(); token; token = token->next()) {
4449         if (token->link()) {
4450             token->link(nullptr);
4451         }
4452 
4453         linkBrackets(this, type, links1, token, '{', '}');
4454 
4455         linkBrackets(this, type, links2, token, '(', ')');
4456 
4457         linkBrackets(this, type, links3, token, '[', ']');
4458     }
4459 
4460     if (!links1.empty()) {
4461         // Error, { and } don't match.
4462         unmatchedToken(links1.top());
4463     }
4464 
4465     if (!links2.empty()) {
4466         // Error, ( and ) don't match.
4467         unmatchedToken(links2.top());
4468     }
4469 
4470     if (!links3.empty()) {
4471         // Error, [ and ] don't match.
4472         unmatchedToken(links3.top());
4473     }
4474 }
4475 
createLinks2()4476 void Tokenizer::createLinks2()
4477 {
4478     if (isC())
4479         return;
4480 
4481     const Token * templateToken = nullptr;
4482     bool isStruct = false;
4483 
4484     std::stack<Token*> type;
4485     std::stack<Token*> templateTokens;
4486     for (Token *token = list.front(); token; token = token->next()) {
4487         if (Token::Match(token, "%name%|> %name% [:<]"))
4488             isStruct = true;
4489         else if (Token::Match(token, "[;{}]"))
4490             isStruct = false;
4491 
4492         if (token->link()) {
4493             if (Token::Match(token, "{|[|("))
4494                 type.push(token);
4495             else if (!type.empty() && Token::Match(token, "}|]|)")) {
4496                 while (type.top()->str() == "<") {
4497                     if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
4498                         templateTokens.pop();
4499                     type.pop();
4500                 }
4501                 type.pop();
4502             } else
4503                 token->link(nullptr);
4504         } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
4505             if (Token::Match(token, "&& [,>]"))
4506                 continue;
4507             // If there is some such code:  A<B||C>..
4508             // Then this is probably a template instantiation if either "B" or "C" has comparisons
4509             if (token->tokType() == Token::eLogicalOp && !type.empty() && type.top()->str() == "<") {
4510                 const Token *prev = token->previous();
4511                 bool foundComparison = false;
4512                 while (Token::Match(prev, "%name%|%num%|%str%|%cop%|)|]") && prev != type.top()) {
4513                     if (prev->str() == ")" || prev->str() == "]")
4514                         prev = prev->link();
4515                     else if (prev->tokType() == Token::eLogicalOp)
4516                         break;
4517                     else if (prev->isComparisonOp())
4518                         foundComparison = true;
4519                     prev = prev->previous();
4520                 }
4521                 if (prev == type.top() && foundComparison)
4522                     continue;
4523                 const Token *next = token->next();
4524                 foundComparison = false;
4525                 while (Token::Match(next, "%name%|%num%|%str%|%cop%|(|[") && next->str() != ">") {
4526                     if (next->str() == "(" || next->str() == "[")
4527                         next = next->link();
4528                     else if (next->tokType() == Token::eLogicalOp)
4529                         break;
4530                     else if (next->isComparisonOp())
4531                         foundComparison = true;
4532                     next = next->next();
4533                 }
4534                 if (next && next->str() == ">" && foundComparison)
4535                     continue;
4536             }
4537 
4538             while (!type.empty() && type.top()->str() == "<") {
4539                 const Token* end = type.top()->findClosingBracket();
4540                 if (Token::Match(end, "> %comp%|;|.|=|{|::"))
4541                     break;
4542                 // Variable declaration
4543                 if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
4544                     break;
4545                 type.pop();
4546             }
4547         } else if (token->str() == "<" &&
4548                    ((token->previous() && (token->previous()->isTemplate() ||
4549                                            (token->previous()->isName() && !token->previous()->varId()))) ||
4550                     Token::Match(token->next(), ">|>>"))) {
4551             type.push(token);
4552             if (token->previous()->str() == "template")
4553                 templateTokens.push(token);
4554         } else if (token->str() == ">" || token->str() == ">>") {
4555             if (type.empty() || type.top()->str() != "<") // < and > don't match.
4556                 continue;
4557             Token * const top1 = type.top();
4558             type.pop();
4559             Token * const top2 = type.empty() ? nullptr : type.top();
4560             type.push(top1);
4561             if (!top2 || top2->str() != "<") {
4562                 if (token->str() == ">>")
4563                     continue;
4564                 if (!Token::Match(token->next(), "%name%|%cop%|%assign%|::|,|(|)|{|}|;|[|:|.|=|...") &&
4565                     !Token::Match(token->next(), "&& %name% ="))
4566                     continue;
4567             }
4568             // if > is followed by [ .. "new a<b>[" is expected
4569             // unless this is from varidiac expansion
4570             if (token->strAt(1) == "[" && !Token::simpleMatch(token->tokAt(-1), "... >")) {
4571                 Token *prev = type.top()->previous();
4572                 while (prev && Token::Match(prev->previous(), ":: %name%"))
4573                     prev = prev->tokAt(-2);
4574                 if (prev && prev->str() != "new")
4575                     prev = prev->previous();
4576                 if (!prev || prev->str() != "new")
4577                     continue;
4578             }
4579 
4580             if (token->str() == ">>") {
4581                 type.pop();
4582                 type.pop();
4583                 Token::createMutualLinks(top2, token);
4584                 if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
4585                     templateTokens.pop();
4586                     templateTokens.pop();
4587                 }
4588             } else {
4589                 type.pop();
4590                 if (Token::Match(token, "> %name%") && Token::Match(top1->tokAt(-2), "%op% %name% <") &&
4591                     (templateTokens.empty() || top1 != templateTokens.top()))
4592                     continue;
4593                 Token::createMutualLinks(top1, token);
4594                 if (!templateTokens.empty() && top1 == templateTokens.top())
4595                     templateTokens.pop();
4596             }
4597         }
4598     }
4599 }
4600 
sizeofAddParentheses()4601 void Tokenizer::sizeofAddParentheses()
4602 {
4603     for (Token *tok = list.front(); tok; tok = tok->next()) {
4604         if (!Token::Match(tok, "sizeof !!("))
4605             continue;
4606         if (tok->next()->isLiteral() || Token::Match(tok->next(), "%name%|*|~|!|&")) {
4607             Token *endToken = tok->next();
4608             while (Token::simpleMatch(endToken, "* *"))
4609                 endToken = endToken->next();
4610             while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
4611                 if (Token::Match(endToken->next(), "(|["))
4612                     endToken = endToken->linkAt(1);
4613                 else
4614                     endToken = endToken->next();
4615             }
4616 
4617             // Add ( after sizeof and ) behind endToken
4618             tok->insertToken("(");
4619             endToken->insertToken(")");
4620             Token::createMutualLinks(tok->next(), endToken->next());
4621         }
4622     }
4623 }
4624 
simplifySizeof()4625 bool Tokenizer::simplifySizeof()
4626 {
4627     // Locate variable declarations and calculate the size
4628     std::map<int, int> sizeOfVar;
4629     std::map<int, const Token *> declTokOfVar;
4630     for (const Token *tok = list.front(); tok; tok = tok->next()) {
4631         if (tok->varId() != 0 && sizeOfVar.find(tok->varId()) == sizeOfVar.end()) {
4632             const int varId = tok->varId();
4633             if (Token::Match(tok->tokAt(-3), "[;{}(,] %type% * %name% [;,)]") ||
4634                 Token::Match(tok->tokAt(-4), "[;{}(,] const %type% * %name% [;),]") ||
4635                 Token::Match(tok->tokAt(-2), "[;{}(,] %type% %name% [;),]") ||
4636                 Token::Match(tok->tokAt(-3), "[;{}(,] const %type% %name% [;),]")) {
4637                 const int size = sizeOfType(tok->previous());
4638                 if (size == 0) {
4639                     continue;
4640                 }
4641 
4642                 sizeOfVar[varId] = size;
4643                 declTokOfVar[varId] = tok;
4644             }
4645 
4646             else if (Token::Match(tok->previous(), "%type% %name% [ %num% ] [[;=]") ||
4647                      Token::Match(tok->tokAt(-2), "%type% * %name% [ %num% ] [[;=]")) {
4648                 int size = sizeOfType(tok->previous());
4649                 if (size == 0)
4650                     continue;
4651 
4652                 const Token* tok2 = tok->next();
4653                 do {
4654                     const MathLib::bigint num = MathLib::toLongNumber(tok2->strAt(1));
4655                     if (num<0)
4656                         break;
4657                     size *= num;
4658                     tok2 = tok2->tokAt(3);
4659                 } while (Token::Match(tok2, "[ %num% ]"));
4660                 if (Token::Match(tok2, "[;=]")) {
4661                     sizeOfVar[varId] = size;
4662                     declTokOfVar[varId] = tok;
4663                 }
4664                 if (!tok2) {
4665                     syntaxError(tok);
4666                 }
4667                 tok = tok2;
4668             }
4669 
4670             else if (Token::Match(tok->previous(), "%type% %name% [ %num% ] [,)]") ||
4671                      Token::Match(tok->tokAt(-2), "%type% * %name% [ %num% ] [,)]")) {
4672                 Token tempTok;
4673                 tempTok.str("*");
4674                 sizeOfVar[varId] = sizeOfType(&tempTok);
4675                 declTokOfVar[varId] = tok;
4676             }
4677         }
4678     }
4679 
4680     bool ret = false;
4681     for (Token *tok = list.front(); tok; tok = tok->next()) {
4682         if (tok->str() != "sizeof")
4683             continue;
4684 
4685         if (Token::simpleMatch(tok->next(), "...")) {
4686             //tok->deleteNext(3);
4687             tok->deleteNext();
4688         }
4689 
4690         // sizeof('x')
4691         if (Token::Match(tok->next(), "( %char% )")) {
4692             tok->deleteNext();
4693             tok->deleteThis();
4694             tok->deleteNext();
4695             std::ostringstream sz;
4696             sz << ((isC()) ? mSettings->sizeof_int : 1);
4697             tok->str(sz.str());
4698             ret = true;
4699             continue;
4700         }
4701 
4702         // sizeof ("text")
4703         if (Token::Match(tok->next(), "( %str% )")) {
4704             tok->deleteNext();
4705             tok->deleteThis();
4706             tok->deleteNext();
4707             std::ostringstream ostr;
4708             ostr << (Token::getStrLength(tok) + 1);
4709             tok->str(ostr.str());
4710             ret = true;
4711             continue;
4712         }
4713 
4714         // sizeof(type *) => sizeof(*)
4715         if (Token::Match(tok->next(), "( %type% * )")) {
4716             tok->next()->deleteNext();
4717         }
4718 
4719         if (Token::simpleMatch(tok->next(), "( * )")) {
4720             tok->str(MathLib::toString(sizeOfType(tok->tokAt(2))));
4721             tok->deleteNext(3);
4722             ret = true;
4723         }
4724 
4725         // sizeof( a )
4726         else if (Token::Match(tok->next(), "( %var% )")) {
4727             const std::map<int, int>::const_iterator sizeOfVarPos = sizeOfVar.find(tok->tokAt(2)->varId());
4728             if (sizeOfVarPos != sizeOfVar.end()) {
4729                 tok->deleteNext();
4730                 tok->deleteThis();
4731                 tok->deleteNext();
4732                 tok->str(MathLib::toString(sizeOfVarPos->second));
4733                 ret = true;
4734             } else {
4735                 // don't try to replace size of variable if variable has
4736                 // similar name with type (#329)
4737             }
4738         }
4739 
4740         else if (Token::Match(tok->next(), "( %type% )")) {
4741             const int size = sizeOfType(tok->tokAt(2));
4742             if (size > 0) {
4743                 tok->str(MathLib::toString(size));
4744                 tok->deleteNext(3);
4745                 ret = true;
4746             }
4747         }
4748 
4749         else if (Token::simpleMatch(tok->next(), "( *") || Token::Match(tok->next(), "( %name% [")) {
4750             int derefs = 0;
4751 
4752             const Token* nametok = tok->tokAt(2);
4753             if (nametok->str() == "*") {
4754                 do {
4755                     nametok = nametok->next();
4756                     derefs++;
4757                 } while (nametok && nametok->str() == "*");
4758 
4759                 if (!Token::Match(nametok, "%name% )"))
4760                     continue;
4761             } else {
4762                 const Token* tok2 = nametok->next();
4763                 do {
4764                     tok2 = tok2->link()->next();
4765                     derefs++;
4766                 } while (tok2 && tok2->str() == "[");
4767 
4768                 if (!tok2 || tok2->str() != ")")
4769                     continue;
4770             }
4771 
4772             // Some default value
4773             MathLib::biguint size = 0;
4774 
4775             const int varid = nametok->varId();
4776             if (derefs != 0 && varid != 0 && declTokOfVar.find(varid) != declTokOfVar.end()) {
4777                 // Try to locate variable declaration..
4778                 const Token *decltok = declTokOfVar[varid];
4779                 if (Token::Match(decltok->previous(), "%type%|* %name% [")) {
4780                     size = sizeOfType(decltok->previous());
4781                 } else if (Token::Match(decltok->tokAt(-2), "%type% * %name%")) {
4782                     size = sizeOfType(decltok->tokAt(-2));
4783                 }
4784                 // Multi-dimensional array..
4785                 if (Token::Match(decltok, "%name% [") && Token::simpleMatch(decltok->linkAt(1), "] [")) {
4786                     const Token *tok2 = decltok;
4787                     for (int i = 0; i < derefs; i++)
4788                         tok2 = tok2->linkAt(1); // Skip all dimensions that are dereferenced before the sizeof call
4789                     while (Token::Match(tok2, "] [ %num% ]")) {
4790                         size *= MathLib::toULongNumber(tok2->strAt(2));
4791                         tok2 = tok2->linkAt(1);
4792                     }
4793                     if (Token::simpleMatch(tok2, "] ["))
4794                         continue;
4795                 }
4796             } else if (nametok->strAt(1) == "[" && nametok->isStandardType()) {
4797                 size = sizeOfType(nametok);
4798                 if (size == 0)
4799                     continue;
4800                 const Token *tok2 = nametok->next();
4801                 while (Token::Match(tok2, "[ %num% ]")) {
4802                     size *= MathLib::toULongNumber(tok2->strAt(1));
4803                     tok2 = tok2->link()->next();
4804                 }
4805                 if (!tok2 || tok2->str() != ")")
4806                     continue;
4807             }
4808 
4809             if (size > 0) {
4810                 tok->str(MathLib::toString(size));
4811                 Token::eraseTokens(tok, tok->next()->link()->next());
4812                 ret = true;
4813             }
4814         }
4815     }
4816     return ret;
4817 }
4818 
simplifyTokenList1(const char FileName[])4819 bool Tokenizer::simplifyTokenList1(const char FileName[])
4820 {
4821     if (Settings::terminated())
4822         return false;
4823 
4824     // if MACRO
4825     for (Token *tok = list.front(); tok; tok = tok->next()) {
4826         if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
4827             if (Token::simpleMatch(tok, "for each")) {
4828                 // 'for each ( )' -> 'asm ( )'
4829                 tok->str("asm");
4830                 tok->deleteNext();
4831             } else if (tok->strAt(1) == "constexpr") {
4832                 tok->deleteNext();
4833                 tok->isConstexpr(true);
4834             } else {
4835                 syntaxError(tok);
4836             }
4837         }
4838     }
4839 
4840     // Is there C++ code in C file?
4841     validateC();
4842 
4843     // remove MACRO in variable declaration: MACRO int x;
4844     removeMacroInVarDecl();
4845 
4846     // Combine strings and character literals, e.g. L"string", L'c', "string1" "string2"
4847     combineStringAndCharLiterals();
4848 
4849     // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
4850     simplifySQL();
4851 
4852     createLinks();
4853 
4854     removePragma();
4855 
4856     // Simplify the C alternative tokens (and, or, etc.)
4857     simplifyCAlternativeTokens();
4858 
4859     reportUnknownMacros();
4860 
4861     simplifyFunctionTryCatch();
4862 
4863     simplifyHeadersAndUnusedTemplates();
4864 
4865     // Remove __asm..
4866     simplifyAsm();
4867 
4868     // foo < bar < >> => foo < bar < > >
4869     if (isCPP() || mSettings->daca)
4870         splitTemplateRightAngleBrackets(!isCPP());
4871 
4872     // Remove extra "template" tokens that are not used by cppcheck
4873     removeExtraTemplateKeywords();
4874 
4875     removeAlignas();
4876 
4877     simplifySpaceshipOperator();
4878 
4879     // Bail out if code is garbage
4880     if (mTimerResults) {
4881         Timer t("Tokenizer::tokenize::findGarbageCode", mSettings->showtime, mTimerResults);
4882         findGarbageCode();
4883     } else {
4884         findGarbageCode();
4885     }
4886 
4887     checkConfiguration();
4888 
4889     // if (x) MACRO() ..
4890     for (const Token *tok = list.front(); tok; tok = tok->next()) {
4891         if (Token::simpleMatch(tok, "if (")) {
4892             tok = tok->next()->link();
4893             if (Token::Match(tok, ") %name% (") &&
4894                 tok->next()->isUpperCaseName() &&
4895                 Token::Match(tok->linkAt(2), ") {|else")) {
4896                 syntaxError(tok->next());
4897             }
4898         }
4899     }
4900 
4901     if (Settings::terminated())
4902         return false;
4903 
4904     // convert C++17 style nested namespaces to old style namespaces
4905     simplifyNestedNamespace();
4906 
4907     // convert c++20 coroutines
4908     simplifyCoroutines();
4909 
4910     // simplify namespace aliases
4911     simplifyNamespaceAliases();
4912 
4913     // Remove [[attribute]] and alignas(?)
4914     simplifyCPPAttribute();
4915 
4916     // remove __attribute__((?))
4917     simplifyAttribute();
4918 
4919     // simplify cppcheck attributes __cppcheck_?__(?)
4920     simplifyCppcheckAttribute();
4921 
4922     // Combine tokens..
4923     combineOperators();
4924 
4925     // replace 'sin(0)' to '0' and other similar math expressions
4926     simplifyMathExpressions();
4927 
4928     // combine "- %num%"
4929     concatenateNegativeNumberAndAnyPositive();
4930 
4931     // remove extern "C" and extern "C" {}
4932     if (isCPP())
4933         simplifyExternC();
4934 
4935     // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
4936     simplifyRoundCurlyParentheses();
4937 
4938     // check for simple syntax errors..
4939     for (const Token *tok = list.front(); tok; tok = tok->next()) {
4940         if (Token::simpleMatch(tok, "> struct {") &&
4941             Token::simpleMatch(tok->linkAt(2), "} ;")) {
4942             syntaxError(tok);
4943         }
4944     }
4945 
4946     if (!simplifyAddBraces())
4947         return false;
4948 
4949     sizeofAddParentheses();
4950 
4951     // Simplify: 0[foo] -> *(foo)
4952     for (Token* tok = list.front(); tok; tok = tok->next()) {
4953         if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
4954             tok->str("*");
4955             tok->next()->str("(");
4956             tok->linkAt(1)->str(")");
4957         }
4958     }
4959 
4960     if (Settings::terminated())
4961         return false;
4962 
4963     // Remove __declspec()
4964     simplifyDeclspec();
4965     validate();
4966 
4967     // Remove "inline", "register", and "restrict"
4968     simplifyKeyword();
4969 
4970     // simplify simple calculations inside <..>
4971     if (isCPP()) {
4972         Token *lt = nullptr;
4973         for (Token *tok = list.front(); tok; tok = tok->next()) {
4974             if (Token::Match(tok, "[;{}]"))
4975                 lt = nullptr;
4976             else if (Token::Match(tok, "%type% <"))
4977                 lt = tok->next();
4978             else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
4979                 const Token * const end = tok;
4980                 for (tok = lt; tok != end; tok = tok->next()) {
4981                     if (tok->isNumber())
4982                         TemplateSimplifier::simplifyNumericCalculations(tok);
4983                 }
4984                 lt = tok->next();
4985             }
4986         }
4987     }
4988 
4989     // Convert K&R function declarations to modern C
4990     simplifyVarDecl(true);
4991     simplifyFunctionParameters();
4992 
4993     // simplify case ranges (gcc extension)
4994     simplifyCaseRange();
4995 
4996     // simplify labels and 'case|default'-like syntaxes
4997     simplifyLabelsCaseDefault();
4998 
4999     // simplify '[;{}] * & ( %any% ) =' to '%any% ='
5000     simplifyMulAndParens();
5001 
5002     if (!isC() && !mSettings->library.markupFile(FileName)) {
5003         findComplicatedSyntaxErrorsInTemplates();
5004     }
5005 
5006     if (Settings::terminated())
5007         return false;
5008 
5009     // remove calling conventions __cdecl, __stdcall..
5010     simplifyCallingConvention();
5011 
5012     addSemicolonAfterUnknownMacro();
5013 
5014     // remove some unhandled macros in global scope
5015     removeMacrosInGlobalScope();
5016 
5017     // remove undefined macro in class definition:
5018     // class DLLEXPORT Fred { };
5019     // class Fred FINAL : Base { };
5020     removeMacroInClassDef();
5021 
5022     // That call here fixes #7190
5023     validate();
5024 
5025     // remove unnecessary member qualification..
5026     removeUnnecessaryQualification();
5027 
5028     // convert Microsoft memory functions
5029     simplifyMicrosoftMemoryFunctions();
5030 
5031     // convert Microsoft string functions
5032     simplifyMicrosoftStringFunctions();
5033 
5034     if (Settings::terminated())
5035         return false;
5036 
5037     // Remove Qt signals and slots
5038     simplifyQtSignalsSlots();
5039 
5040     // remove Borland stuff..
5041     simplifyBorland();
5042 
5043     // syntax error: enum with typedef in it
5044     checkForEnumsWithTypedef();
5045 
5046     // Add parentheses to ternary operator where necessary
5047     prepareTernaryOpForAST();
5048 
5049     // Change initialisation of variable to assignment
5050     simplifyInitVar();
5051 
5052     // Split up variable declarations.
5053     simplifyVarDecl(false);
5054 
5055     // typedef..
5056     if (mTimerResults) {
5057         Timer t("Tokenizer::tokenize::simplifyTypedef", mSettings->showtime, mTimerResults);
5058         simplifyTypedef();
5059     } else {
5060         simplifyTypedef();
5061     }
5062 
5063     // using A = B;
5064     while (simplifyUsing())
5065         ;
5066 
5067     // Add parentheses to ternary operator where necessary
5068     // TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
5069     // If typedef handling is refactored and moved to symboldatabase someday we can remove this
5070     prepareTernaryOpForAST();
5071 
5072     for (Token* tok = list.front(); tok;) {
5073         if (Token::Match(tok, "union|struct|class union|struct|class"))
5074             tok->deleteNext();
5075         else
5076             tok = tok->next();
5077     }
5078 
5079     // class x y {
5080     if (isCPP() && mSettings->severity.isEnabled(Severity::information)) {
5081         for (const Token *tok = list.front(); tok; tok = tok->next()) {
5082             if (Token::Match(tok, "class %type% %type% [:{]")) {
5083                 unhandled_macro_class_x_y(tok);
5084             }
5085         }
5086     }
5087 
5088     // catch bad typedef canonicalization
5089     //
5090     // to reproduce bad typedef, download upx-ucl from:
5091     // http://packages.debian.org/sid/upx-ucl
5092     // analyse the file src/stub/src/i386-linux.elf.interp-main.c
5093     validate();
5094 
5095     // The simplify enum have inner loops
5096     if (Settings::terminated())
5097         return false;
5098 
5099     // Put ^{} statements in asm()
5100     simplifyAsm2();
5101 
5102     // @..
5103     simplifyAt();
5104 
5105     // When the assembly code has been cleaned up, no @ is allowed
5106     for (const Token *tok = list.front(); tok; tok = tok->next()) {
5107         if (tok->str() == "(") {
5108             const Token *tok1 = tok;
5109             tok = tok->link();
5110             if (!tok)
5111                 syntaxError(tok1);
5112         } else if (tok->str() == "@") {
5113             syntaxError(tok);
5114         }
5115     }
5116 
5117     // Order keywords "static" and "const"
5118     simplifyStaticConst();
5119 
5120     // convert platform dependent types to standard types
5121     // 32 bits: size_t -> unsigned long
5122     // 64 bits: size_t -> unsigned long long
5123     list.simplifyPlatformTypes();
5124 
5125     // collapse compound standard types into a single token
5126     // unsigned long long int => long (with _isUnsigned=true,_isLong=true)
5127     list.simplifyStdType();
5128 
5129     if (Settings::terminated())
5130         return false;
5131 
5132     // simplify bit fields..
5133     simplifyBitfields();
5134 
5135     if (Settings::terminated())
5136         return false;
5137 
5138     // struct simplification "struct S {} s; => struct S { } ; S s ;
5139     simplifyStructDecl();
5140 
5141     if (Settings::terminated())
5142         return false;
5143 
5144     // x = ({ 123; });  =>   { x = 123; }
5145     simplifyAssignmentBlock();
5146 
5147     if (Settings::terminated())
5148         return false;
5149 
5150     simplifyVariableMultipleAssign();
5151 
5152     // Collapse operator name tokens into single token
5153     // operator = => operator=
5154     simplifyOperatorName();
5155 
5156     // Remove redundant parentheses
5157     simplifyRedundantParentheses();
5158 
5159     if (isCPP())
5160         simplifyTypeIntrinsics();
5161 
5162     if (!isC()) {
5163         // Handle templates..
5164         if (mTimerResults) {
5165             Timer t("Tokenizer::tokenize::simplifyTemplates", mSettings->showtime, mTimerResults);
5166             simplifyTemplates();
5167         } else {
5168             simplifyTemplates();
5169         }
5170 
5171         // The simplifyTemplates have inner loops
5172         if (Settings::terminated())
5173             return false;
5174 
5175         validate(); // #6847 - invalid code
5176     }
5177 
5178     // Simplify pointer to standard types (C only)
5179     simplifyPointerToStandardType();
5180 
5181     // simplify function pointers
5182     simplifyFunctionPointers();
5183 
5184     // Change initialisation of variable to assignment
5185     simplifyInitVar();
5186 
5187     // Split up variable declarations.
5188     simplifyVarDecl(false);
5189 
5190     elseif();
5191 
5192     validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
5193 
5194     if (mTimerResults) {
5195         Timer t("Tokenizer::tokenize::setVarId", mSettings->showtime, mTimerResults);
5196         setVarId();
5197     } else {
5198         setVarId();
5199     }
5200 
5201     // Link < with >
5202     createLinks2();
5203 
5204     // Mark C++ casts
5205     for (Token *tok = list.front(); tok; tok = tok->next()) {
5206         if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <") && Token::simpleMatch(tok->linkAt(1), "> (")) {
5207             tok = tok->linkAt(1)->next();
5208             tok->isCast(true);
5209         }
5210     }
5211 
5212     // specify array size
5213     arraySize();
5214 
5215     // The simplify enum might have inner loops
5216     if (Settings::terminated())
5217         return false;
5218 
5219     // Add std:: in front of std classes, when using namespace std; was given
5220     simplifyNamespaceStd();
5221 
5222     // Change initialisation of variable to assignment
5223     simplifyInitVar();
5224 
5225     simplifyDoublePlusAndDoubleMinus();
5226 
5227     simplifyArrayAccessSyntax();
5228 
5229     Token::assignProgressValues(list.front());
5230 
5231     removeRedundantSemicolons();
5232 
5233     simplifyRedundantConsecutiveBraces();
5234 
5235     simplifyEmptyNamespaces();
5236 
5237     simplifyIfSwitchForInit();
5238 
5239     simplifyOverloadedOperators();
5240 
5241     validate();
5242 
5243     list.front()->assignIndexes();
5244 
5245     return true;
5246 }
5247 
simplifyTokenList2()5248 bool Tokenizer::simplifyTokenList2()
5249 {
5250     // clear the _functionList so it can't contain dead pointers
5251     deleteSymbolDatabase();
5252 
5253     // Clear AST,ValueFlow. These will be created again at the end of this function.
5254     for (Token *tok = list.front(); tok; tok = tok->next()) {
5255         tok->clearAst();
5256         tok->clearValueFlow();
5257     }
5258 
5259     // Convert e.g. atol("0") into 0
5260     simplifyMathFunctions();
5261 
5262     // f(x=g())   =>   x=g(); f(x)
5263     simplifyAssignmentInFunctionCall();
5264 
5265     // ";a+=b;" => ";a=a+b;"
5266     simplifyCompoundAssignment();
5267 
5268     simplifyCharAt();
5269 
5270     // simplify references
5271     simplifyReference();
5272 
5273     simplifyStd();
5274 
5275     if (Settings::terminated())
5276         return false;
5277 
5278     simplifySizeof();
5279 
5280     simplifyUndefinedSizeArray();
5281 
5282     simplifyCasts();
5283 
5284     // Simplify simple calculations before replace constants, this allows the replacement of constants that are calculated
5285     // e.g. const static int value = sizeof(X)/sizeof(Y);
5286     simplifyCalculations();
5287 
5288     if (Settings::terminated())
5289         return false;
5290 
5291     // Replace "*(ptr + num)" => "ptr[num]"
5292     simplifyOffsetPointerDereference();
5293 
5294     // Replace "&str[num]" => "(str + num)"
5295     simplifyOffsetPointerReference();
5296 
5297     removeRedundantAssignment();
5298 
5299     simplifyRealloc();
5300 
5301     // Change initialisation of variable to assignment
5302     simplifyInitVar();
5303 
5304     // Simplify variable declarations
5305     simplifyVarDecl(false);
5306 
5307     simplifyErrNoInWhile();
5308     simplifyIfAndWhileAssign();
5309     simplifyRedundantParentheses();
5310     simplifyNestedStrcat();
5311     simplifyFuncInWhile();
5312 
5313     simplifyIfAndWhileAssign();
5314 
5315     // replace strlen(str)
5316     for (Token *tok = list.front(); tok; tok = tok->next()) {
5317         if (Token::Match(tok, "strlen ( %str% )")) {
5318             tok->str(MathLib::toString(Token::getStrLength(tok->tokAt(2))));
5319             tok->deleteNext(3);
5320         }
5321     }
5322 
5323     bool modified = true;
5324     while (modified) {
5325         if (Settings::terminated())
5326             return false;
5327 
5328         modified = false;
5329         modified |= simplifyConditions();
5330         modified |= simplifyFunctionReturn();
5331         modified |= simplifyKnownVariables();
5332         modified |= simplifyStrlen();
5333 
5334         modified |= removeRedundantConditions();
5335         modified |= simplifyRedundantParentheses();
5336         modified |= simplifyConstTernaryOp();
5337         modified |= simplifyCalculations();
5338         validate();
5339     }
5340 
5341     // simplify redundant loops
5342     simplifyWhile0();
5343     removeRedundantFor();
5344 
5345     // Remove redundant parentheses in return..
5346     for (Token *tok = list.front(); tok; tok = tok->next()) {
5347         while (Token::simpleMatch(tok, "return (")) {
5348             Token *tok2 = tok->next()->link();
5349             if (Token::simpleMatch(tok2, ") ;")) {
5350                 tok->deleteNext();
5351                 tok2->deleteThis();
5352             } else {
5353                 break;
5354             }
5355         }
5356     }
5357 
5358     simplifyReturnStrncat();
5359 
5360     removeRedundantAssignment();
5361 
5362     simplifyComma();
5363 
5364     removeRedundantSemicolons();
5365 
5366     simplifyFlowControl();
5367 
5368     simplifyRedundantConsecutiveBraces();
5369 
5370     simplifyEmptyNamespaces();
5371 
5372     simplifyMathFunctions();
5373 
5374     validate();
5375 
5376     Token::assignProgressValues(list.front());
5377 
5378     list.front()->assignIndexes();
5379 
5380     list.createAst();
5381     // needed for #7208 (garbage code) and #7724 (ast max depth limit)
5382     list.validateAst();
5383 
5384     // Create symbol database and then remove const keywords
5385     createSymbolDatabase();
5386     mSymbolDatabase->setValueTypeInTokenList(true);
5387 
5388     ValueFlow::setValues(&list, mSymbolDatabase, mErrorLogger, mSettings);
5389 
5390     if (Settings::terminated())
5391         return false;
5392 
5393     printDebugOutput(2);
5394 
5395     return true;
5396 }
5397 //---------------------------------------------------------------------------
5398 
printDebugOutput(int simplification) const5399 void Tokenizer::printDebugOutput(int simplification) const
5400 {
5401     const bool debug = (simplification != 1U && mSettings->debugSimplified) ||
5402                        (simplification != 2U && mSettings->debugnormal);
5403 
5404     if (debug && list.front()) {
5405         list.front()->printOut(nullptr, list.getFiles());
5406 
5407         if (mSettings->xml)
5408             std::cout << "<debug>" << std::endl;
5409 
5410         if (mSymbolDatabase) {
5411             if (mSettings->xml)
5412                 mSymbolDatabase->printXml(std::cout);
5413             else if (mSettings->verbose) {
5414                 mSymbolDatabase->printOut("Symbol database");
5415             }
5416         }
5417 
5418         if (mSettings->verbose)
5419             list.front()->printAst(mSettings->verbose, mSettings->xml, list.getFiles(), std::cout);
5420 
5421         list.front()->printValueFlow(mSettings->xml, std::cout);
5422 
5423         if (mSettings->xml)
5424             std::cout << "</debug>" << std::endl;
5425     }
5426 
5427     if (mSymbolDatabase && simplification == 2U && mSettings->debugwarnings) {
5428         printUnknownTypes();
5429 
5430         // the typeStartToken() should come before typeEndToken()
5431         for (const Variable *var : mSymbolDatabase->variableList()) {
5432             if (!var)
5433                 continue;
5434 
5435             const Token * typetok = var->typeStartToken();
5436             while (typetok && typetok != var->typeEndToken())
5437                 typetok = typetok->next();
5438 
5439             if (typetok != var->typeEndToken()) {
5440                 reportError(var->typeStartToken(),
5441                             Severity::debug,
5442                             "debug",
5443                             "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + MathLib::toString(var->typeStartToken()->linenr()));
5444             }
5445         }
5446     }
5447 }
5448 
dump(std::ostream & out) const5449 void Tokenizer::dump(std::ostream &out) const
5450 {
5451     // Create a xml data dump.
5452     // The idea is not that this will be readable for humans. It's a
5453     // data dump that 3rd party tools could load and get useful info from.
5454 
5455     // tokens..
5456     out << "  <tokenlist>" << std::endl;
5457     for (const Token *tok = list.front(); tok; tok = tok->next()) {
5458         out << "    <token id=\"" << tok << "\" file=\"" << ErrorLogger::toxml(list.file(tok)) << "\" linenr=\"" << tok->linenr() << "\" column=\"" << tok->column() << "\"";
5459         out << " str=\"" << ErrorLogger::toxml(tok->str()) << '\"';
5460         out << " scope=\"" << tok->scope() << '\"';
5461         if (tok->isName()) {
5462             out << " type=\"name\"";
5463             if (tok->isUnsigned())
5464                 out << " isUnsigned=\"true\"";
5465             else if (tok->isSigned())
5466                 out << " isSigned=\"true\"";
5467         } else if (tok->isNumber()) {
5468             out << " type=\"number\"";
5469             if (MathLib::isInt(tok->str()))
5470                 out << " isInt=\"true\"";
5471             if (MathLib::isFloat(tok->str()))
5472                 out << " isFloat=\"true\"";
5473         } else if (tok->tokType() == Token::eString)
5474             out << " type=\"string\" strlen=\"" << Token::getStrLength(tok) << '\"';
5475         else if (tok->tokType() == Token::eChar)
5476             out << " type=\"char\"";
5477         else if (tok->isBoolean())
5478             out << " type=\"boolean\"";
5479         else if (tok->isOp()) {
5480             out << " type=\"op\"";
5481             if (tok->isArithmeticalOp())
5482                 out << " isArithmeticalOp=\"true\"";
5483             else if (tok->isAssignmentOp())
5484                 out << " isAssignmentOp=\"true\"";
5485             else if (tok->isComparisonOp())
5486                 out << " isComparisonOp=\"true\"";
5487             else if (tok->tokType() == Token::eLogicalOp)
5488                 out << " isLogicalOp=\"true\"";
5489         }
5490         if (tok->isExpandedMacro())
5491             out << " isExpandedMacro=\"true\"";
5492         if (tok->isSplittedVarDeclComma())
5493             out << " isSplittedVarDeclComma=\"true\"";
5494         if (tok->isSplittedVarDeclEq())
5495             out << " isSplittedVarDeclEq=\"true\"";
5496         if (tok->isImplicitInt())
5497             out << " isImplicitInt=\"true\"";
5498         if (tok->link())
5499             out << " link=\"" << tok->link() << '\"';
5500         if (tok->varId() > 0)
5501             out << " varId=\"" << MathLib::toString(tok->varId()) << '\"';
5502         if (tok->variable())
5503             out << " variable=\"" << tok->variable() << '\"';
5504         if (tok->function())
5505             out << " function=\"" << tok->function() << '\"';
5506         if (!tok->values().empty())
5507             out << " values=\"" << &tok->values() << '\"';
5508         if (tok->type())
5509             out << " type-scope=\"" << tok->type()->classScope << '\"';
5510         if (tok->astParent())
5511             out << " astParent=\"" << tok->astParent() << '\"';
5512         if (tok->astOperand1())
5513             out << " astOperand1=\"" << tok->astOperand1() << '\"';
5514         if (tok->astOperand2())
5515             out << " astOperand2=\"" << tok->astOperand2() << '\"';
5516         if (!tok->originalName().empty())
5517             out << " originalName=\"" << tok->originalName() << '\"';
5518         if (tok->valueType()) {
5519             const std::string vt = tok->valueType()->dump();
5520             if (!vt.empty())
5521                 out << ' ' << vt;
5522         }
5523         out << "/>" << std::endl;
5524     }
5525     out << "  </tokenlist>" << std::endl;
5526 
5527     mSymbolDatabase->printXml(out);
5528     if (list.front())
5529         list.front()->printValueFlow(true, out);
5530 
5531     if (!mTypedefInfo.empty()) {
5532         out << "  <typedef-info>" << std::endl;
5533         for (const TypedefInfo &typedefInfo: mTypedefInfo) {
5534             out << "    <info"
5535                 << " name=\"" << typedefInfo.name << "\""
5536                 << " file=\"" << typedefInfo.filename << "\""
5537                 << " line=\"" << typedefInfo.lineNumber << "\""
5538                 << " column=\"" << typedefInfo.column << "\""
5539                 << " used=\"" << (typedefInfo.used?1:0) << "\""
5540                 << "/>" << std::endl;
5541         }
5542         out << "  </typedef-info>" << std::endl;
5543     }
5544 }
5545 
simplifyHeadersAndUnusedTemplates()5546 void Tokenizer::simplifyHeadersAndUnusedTemplates()
5547 {
5548     if (mSettings->checkHeaders && mSettings->checkUnusedTemplates)
5549         // Full analysis. All information in the headers are kept.
5550         return;
5551 
5552     const bool checkHeaders = mSettings->checkHeaders;
5553     const bool removeUnusedIncludedFunctions = !mSettings->checkHeaders;
5554     const bool removeUnusedIncludedClasses   = !mSettings->checkHeaders;
5555     const bool removeUnusedIncludedTemplates = !mSettings->checkUnusedTemplates || !mSettings->checkHeaders;
5556     const bool removeUnusedTemplates = !mSettings->checkUnusedTemplates;
5557 
5558     // checkHeaders:
5559     //
5560     // If it is true then keep all code in the headers. It's possible
5561     // to remove unused types/variables if false positives / false
5562     // negatives can be avoided.
5563     //
5564     // If it is false, then we want to remove selected stuff from the
5565     // headers but not *everything*. The intention here is to not damage
5566     // the analysis of the source file. You should get all warnings in
5567     // the source file. You should not get false positives.
5568 
5569     // functions and types to keep
5570     std::set<std::string> keep;
5571     for (const Token *tok = list.front(); tok; tok = tok->next()) {
5572         if (isCPP() && Token::simpleMatch(tok, "template <")) {
5573             const Token *closingBracket = tok->next()->findClosingBracket();
5574             if (Token::Match(closingBracket, "> class|struct %name% {"))
5575                 tok = closingBracket->linkAt(3);
5576         }
5577 
5578         if (!tok->isName() || tok->isKeyword())
5579             continue;
5580 
5581         if (!checkHeaders && tok->fileIndex() != 0)
5582             continue;
5583 
5584         if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
5585             keep.insert(tok->str());
5586             continue;
5587         }
5588 
5589         if (Token::Match(tok, "%name% %name%|::|*|&|<")) {
5590             keep.insert(tok->str());
5591         }
5592     }
5593 
5594     const std::set<std::string> functionStart{"static", "const", "unsigned", "signed", "void", "bool", "char", "short", "int", "long", "float", "*"};
5595 
5596     for (Token *tok = list.front(); tok; tok = tok->next()) {
5597         const bool isIncluded = (tok->fileIndex() != 0);
5598 
5599         // Remove executable code
5600         if (isIncluded && !mSettings->checkHeaders && tok->str() == "{") {
5601             // TODO: We probably need to keep the executable code if this function is called from the source file.
5602             const Token *prev = tok->previous();
5603             while (prev && prev->isName())
5604                 prev = prev->previous();
5605             if (Token::simpleMatch(prev, ")")) {
5606                 // Replace all tokens from { to } with a ";".
5607                 Token::eraseTokens(tok,tok->link()->next());
5608                 tok->str(";");
5609                 tok->link(nullptr);
5610             }
5611         }
5612 
5613         if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
5614             // Remove unused function declarations
5615             if (isIncluded && removeUnusedIncludedFunctions) {
5616                 while (true) {
5617                     Token *start = tok;
5618                     while (start && functionStart.find(start->str()) != functionStart.end())
5619                         start = start->next();
5620                     if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
5621                         Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
5622                         tok->deleteThis();
5623                     } else
5624                         break;
5625                 }
5626             }
5627 
5628             if (isIncluded && removeUnusedIncludedClasses) {
5629                 if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
5630                     // Remove this class/struct
5631                     const Token *endToken = tok->tokAt(2);
5632                     if (endToken->str() == ":") {
5633                         endToken = endToken->next();
5634                         while (Token::Match(endToken, "%name%|,"))
5635                             endToken = endToken->next();
5636                     }
5637                     if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
5638                         Token::eraseTokens(tok, endToken->link()->next());
5639                         tok->deleteThis();
5640                     }
5641                 }
5642             }
5643 
5644             if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
5645                 if (Token::Match(tok, "template < %name%")) {
5646                     const Token *closingBracket = tok->next()->findClosingBracket();
5647                     if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
5648                         const Token *endToken = closingBracket->tokAt(3);
5649                         if (endToken->str() == ":") {
5650                             endToken = endToken->next();
5651                             while (Token::Match(endToken, "%name%|,"))
5652                                 endToken = endToken->next();
5653                         }
5654                         if (endToken && endToken->str() == "{")
5655                             endToken = endToken->link()->next();
5656                         if (endToken && endToken->str() == ";") {
5657                             Token::eraseTokens(tok, endToken);
5658                             tok->deleteThis();
5659                         }
5660                     } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
5661                         const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
5662                         Token::eraseTokens(tok, endToken);
5663                         tok->deleteThis();
5664                     }
5665                 }
5666             }
5667         }
5668     }
5669 }
5670 
removeExtraTemplateKeywords()5671 void Tokenizer::removeExtraTemplateKeywords()
5672 {
5673     if (isCPP()) {
5674         for (Token *tok = list.front(); tok; tok = tok->next()) {
5675             if (Token::Match(tok, "%name%|>|) .|:: template %name%")) {
5676                 tok->next()->deleteNext();
5677                 Token* templateName = tok->tokAt(2);
5678                 while (Token::Match(templateName, "%name%|::")) {
5679                     templateName->isTemplate(true);
5680                     templateName = templateName->next();
5681                 }
5682                 if (Token::Match(templateName->previous(), "operator %op%|(")) {
5683                     templateName->isTemplate(true);
5684                     if (templateName->str() == "(" && templateName->link())
5685                         templateName->link()->isTemplate(true);
5686                 }
5687             }
5688         }
5689     }
5690 }
5691 
getExpression(const Token * tok)5692 static std::string getExpression(const Token *tok)
5693 {
5694     std::string line;
5695     for (const Token *prev = tok->previous(); prev && !Token::Match(prev, "[;{}]"); prev = prev->previous())
5696         line = prev->str() + " " + line;
5697     line += "!!!" + tok->str() + "!!!";
5698     for (const Token *next = tok->next(); next && !Token::Match(next, "[;{}]"); next = next->next())
5699         line = line + " " + next->str();
5700     return line;
5701 }
5702 
splitTemplateRightAngleBrackets(bool check)5703 void Tokenizer::splitTemplateRightAngleBrackets(bool check)
5704 {
5705     std::set<std::string> vars;
5706 
5707     for (Token *tok = list.front(); tok; tok = tok->next()) {
5708         if (Token::Match(tok, "[;{}] %type% %type% [;,=]") && tok->next()->isStandardType())
5709             vars.insert(tok->strAt(2));
5710 
5711         // Ticket #6181: normalize C++11 template parameter list closing syntax
5712         if (tok->previous() && tok->str() == "<" && TemplateSimplifier::templateParameters(tok) && vars.find(tok->previous()->str()) == vars.end()) {
5713             Token *endTok = tok->findClosingBracket();
5714             if (check) {
5715                 if (Token::Match(endTok, ">>|>>="))
5716                     reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
5717                 continue;
5718             }
5719             if (endTok && endTok->str() == ">>") {
5720                 endTok->str(">");
5721                 endTok->insertToken(">");
5722             } else if (endTok && endTok->str() == ">>=") {
5723                 endTok->str(">");
5724                 endTok->insertToken("=");
5725                 endTok->insertToken(">");
5726             }
5727         } else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <") && vars.find(tok->next()->str()) == vars.end()) {
5728             Token *endTok = tok->tokAt(2)->findClosingBracket();
5729             if (check) {
5730                 if (Token::simpleMatch(endTok, ">>"))
5731                     reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
5732                 continue;
5733             }
5734             if (Token::Match(endTok, ">> ;|{|%type%")) {
5735                 endTok->str(">");
5736                 endTok->insertToken(">");
5737             }
5738         }
5739     }
5740 }
5741 
removeMacrosInGlobalScope()5742 void Tokenizer::removeMacrosInGlobalScope()
5743 {
5744     for (Token *tok = list.front(); tok; tok = tok->next()) {
5745         if (tok->str() == "(") {
5746             tok = tok->link();
5747             if (Token::Match(tok, ") %type% {") &&
5748                 !Token::Match(tok->next(), "const|namespace|class|struct|union|noexcept|override|final|volatile"))
5749                 tok->deleteNext();
5750         }
5751 
5752         if (Token::Match(tok, "%type%") && tok->isUpperCaseName() &&
5753             (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) {
5754             const Token *tok2 = tok->next();
5755             if (tok2 && tok2->str() == "(")
5756                 tok2 = tok2->link()->next();
5757 
5758             // Several unknown macros...
5759             while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName())
5760                 tok2 = tok2->linkAt(1)->next();
5761 
5762             if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") && !Token::Match(tok2, "namespace|class|struct|union|private:|protected:|public:"))
5763                 unknownMacroError(tok);
5764 
5765             if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{"))
5766                 unknownMacroError(tok);
5767 
5768             // remove unknown macros before namespace|class|struct|union
5769             if (Token::Match(tok2, "namespace|class|struct|union")) {
5770                 // is there a "{" for?
5771                 const Token *tok3 = tok2;
5772                 while (tok3 && !Token::Match(tok3,"[;{}()]"))
5773                     tok3 = tok3->next();
5774                 if (tok3 && tok3->str() == "{") {
5775                     Token::eraseTokens(tok, tok2);
5776                     tok->deleteThis();
5777                 }
5778                 continue;
5779             }
5780 
5781             // replace unknown macros before foo(
5782             /*
5783                         if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) {
5784                             std::string typeName;
5785                             for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next())
5786                                 typeName += tok3->str();
5787                             Token::eraseTokens(tok, tok2);
5788                             tok->str(typeName);
5789                         }
5790              */
5791             // remove unknown macros before foo::foo(
5792             if (Token::Match(tok2, "%type% :: %type%")) {
5793                 const Token *tok3 = tok2;
5794                 while (Token::Match(tok3, "%type% :: %type% ::"))
5795                     tok3 = tok3->tokAt(2);
5796                 if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) {
5797                     Token::eraseTokens(tok, tok2);
5798                     tok->deleteThis();
5799                 }
5800                 continue;
5801             }
5802         }
5803 
5804         // Skip executable scopes
5805         if (tok->str() == "{") {
5806             const Token *prev = tok->previous();
5807             while (prev && prev->isName())
5808                 prev = prev->previous();
5809             if (prev && prev->str() == ")")
5810                 tok = tok->link();
5811         }
5812     }
5813 }
5814 
5815 //---------------------------------------------------------------------------
5816 
removePragma()5817 void Tokenizer::removePragma()
5818 {
5819     if (isC() && mSettings->standards.c == Standards::C89)
5820         return;
5821     if (isCPP() && mSettings->standards.cpp == Standards::CPP03)
5822         return;
5823     for (Token *tok = list.front(); tok; tok = tok->next()) {
5824         while (Token::simpleMatch(tok, "_Pragma (")) {
5825             Token::eraseTokens(tok, tok->linkAt(1)->next());
5826             tok->deleteThis();
5827         }
5828     }
5829 }
5830 
5831 //---------------------------------------------------------------------------
5832 
removeMacroInClassDef()5833 void Tokenizer::removeMacroInClassDef()
5834 {
5835     for (Token *tok = list.front(); tok; tok = tok->next()) {
5836         if (!Token::Match(tok, "class|struct %name% %name% {|:"))
5837             continue;
5838 
5839         const bool nextIsUppercase = tok->next()->isUpperCaseName();
5840         const bool afterNextIsUppercase = tok->tokAt(2)->isUpperCaseName();
5841         if (nextIsUppercase && !afterNextIsUppercase)
5842             tok->deleteNext();
5843         else if (!nextIsUppercase && afterNextIsUppercase)
5844             tok->next()->deleteNext();
5845     }
5846 }
5847 
5848 //---------------------------------------------------------------------------
5849 
removeMacroInVarDecl()5850 void Tokenizer::removeMacroInVarDecl()
5851 {
5852     for (Token *tok = list.front(); tok; tok = tok->next()) {
5853         if (Token::Match(tok, "[;{}] %name% (") && tok->next()->isUpperCaseName()) {
5854             // goto ')' parentheses
5855             const Token *tok2 = tok;
5856             int parlevel = 0;
5857             while (tok2) {
5858                 if (tok2->str() == "(")
5859                     ++parlevel;
5860                 else if (tok2->str() == ")") {
5861                     if (--parlevel <= 0)
5862                         break;
5863                 }
5864                 tok2 = tok2->next();
5865             }
5866             tok2 = tok2 ? tok2->next() : nullptr;
5867 
5868             // check if this is a variable declaration..
5869             const Token *tok3 = tok2;
5870             while (tok3 && tok3->isUpperCaseName())
5871                 tok3 = tok3->next();
5872             if (tok3 && (tok3->isStandardType() || Token::Match(tok3,"const|static|struct|union|class")))
5873                 Token::eraseTokens(tok,tok2);
5874         }
5875     }
5876 }
5877 //---------------------------------------------------------------------------
5878 
addSemicolonAfterUnknownMacro()5879 void Tokenizer::addSemicolonAfterUnknownMacro()
5880 {
5881     if (!isCPP())
5882         return;
5883     for (Token *tok = list.front(); tok; tok = tok->next()) {
5884         if (tok->str() != ")")
5885             continue;
5886         const Token *macro = tok->link() ? tok->link()->previous() : nullptr;
5887         if (!macro || !macro->isName())
5888             continue;
5889         if (Token::simpleMatch(tok, ") try") && !Token::Match(macro, "if|for|while"))
5890             tok->insertToken(";");
5891         else if (Token::simpleMatch(tok, ") using"))
5892             tok->insertToken(";");
5893     }
5894 }
5895 //---------------------------------------------------------------------------
5896 
removeRedundantAssignment()5897 void Tokenizer::removeRedundantAssignment()
5898 {
5899     for (Token *tok = list.front(); tok; tok = tok->next()) {
5900         if (tok->str() == "{")
5901             tok = tok->link();
5902 
5903         const Token * const start = const_cast<Token *>(startOfExecutableScope(tok));
5904         if (start) {
5905             tok = start->previous();
5906             // parse in this function..
5907             std::set<int> localvars;
5908             const Token * const end = tok->next()->link();
5909             for (Token * tok2 = tok->next(); tok2 && tok2 != end; tok2 = tok2->next()) {
5910                 // skip local class or struct
5911                 if (Token::Match(tok2, "class|struct %type% {|:")) {
5912                     // skip to '{'
5913                     tok2 = tok2->tokAt(2);
5914                     while (tok2 && tok2->str() != "{")
5915                         tok2 = tok2->next();
5916 
5917                     if (tok2)
5918                         tok2 = tok2->link(); // skip local class or struct
5919                     else
5920                         return;
5921                 } else if (Token::Match(tok2, "[;{}] %type% * %name% ;") && tok2->next()->str() != "return") {
5922                     tok2 = tok2->tokAt(3);
5923                     localvars.insert(tok2->varId());
5924                 } else if (Token::Match(tok2, "[;{}] %type% %name% ;") && tok2->next()->isStandardType()) {
5925                     tok2 = tok2->tokAt(2);
5926                     localvars.insert(tok2->varId());
5927                 } else if (tok2->varId() &&
5928                            !Token::Match(tok2->previous(), "[;{}] %name% = %char%|%num%|%name% ;")) {
5929                     localvars.erase(tok2->varId());
5930                 }
5931             }
5932             localvars.erase(0);
5933             if (!localvars.empty()) {
5934                 for (Token *tok2 = tok->next(); tok2 && tok2 != end;) {
5935                     if (Token::Match(tok2, "[;{}] %type% %name% ;") && localvars.find(tok2->tokAt(2)->varId()) != localvars.end()) {
5936                         tok2->deleteNext(3);
5937                     } else if ((Token::Match(tok2, "[;{}] %type% * %name% ;") &&
5938                                 localvars.find(tok2->tokAt(3)->varId()) != localvars.end()) ||
5939                                (Token::Match(tok2, "[;{}] %name% = %any% ;") &&
5940                                 localvars.find(tok2->next()->varId()) != localvars.end())) {
5941                         tok2->deleteNext(4);
5942                     } else
5943                         tok2 = tok2->next();
5944                 }
5945             }
5946         }
5947     }
5948 }
5949 
simplifyRealloc()5950 void Tokenizer::simplifyRealloc()
5951 {
5952     for (Token *tok = list.front(); tok; tok = tok->next()) {
5953         if (Token::Match(tok, "(|[") ||
5954             (tok->str() == "{" && tok->previous() && tok->previous()->str() == "="))
5955             tok = tok->link();
5956         else if (Token::Match(tok, "[;{}] %name% = realloc (")) {
5957             tok = tok->tokAt(3);
5958             if (Token::simpleMatch(tok->next(), "( 0 ,")) {
5959                 //no "x = realloc(0,);"
5960                 if (!Token::simpleMatch(tok->next()->link(), ") ;") || tok->next()->link()->previous() == tok->tokAt(3))
5961                     continue;
5962 
5963                 // delete "0 ,"
5964                 tok->next()->deleteNext(2);
5965 
5966                 // Change function name "realloc" to "malloc"
5967                 tok->str("malloc");
5968                 tok = tok->next()->link();
5969             } else {
5970                 Token *tok2 = tok->next()->link()->tokAt(-2);
5971                 //no "x = realloc(,0);"
5972                 if (!Token::simpleMatch(tok2, ", 0 ) ;") || tok2 == tok->tokAt(2))
5973                     continue;
5974 
5975                 //remove ", 0"
5976                 tok2 = tok2->previous();
5977                 tok2->deleteNext(2);
5978                 //change "realloc" to "free"
5979                 tok->str("free");
5980                 //insert "0" after "var ="
5981                 tok = tok->previous();
5982                 tok->insertToken("0");
5983                 //move "var = 0" between "free(...)" and ";"
5984                 tok2 = tok2->next();
5985                 Token::move(tok->previous(), tok->next(), tok2);
5986                 //add missing ";" after "free(...)"
5987                 tok2->insertToken(";");
5988                 //goto before last ";" and continue
5989                 tok = tok->next();
5990             }
5991         }
5992     }
5993 }
5994 
simplifyEmptyNamespaces()5995 void Tokenizer::simplifyEmptyNamespaces()
5996 {
5997     if (isC())
5998         return;
5999 
6000     bool goback = false;
6001     for (Token *tok = list.front(); tok; tok = tok ? tok->next() : nullptr) {
6002         if (goback) {
6003             tok = tok->previous();
6004             goback = false;
6005         }
6006         if (Token::Match(tok, "(|[|{")) {
6007             tok = tok->link();
6008             continue;
6009         }
6010         if (!Token::Match(tok, "namespace %name%| {"))
6011             continue;
6012         bool isAnonymousNS = tok->strAt(1) == "{";
6013         if (tok->strAt(3 - isAnonymousNS) == "}") {
6014             tok->deleteNext(3 - isAnonymousNS); // remove '%name%| { }'
6015             if (!tok->previous()) {
6016                 // remove 'namespace' or replace it with ';' if isolated
6017                 tok->deleteThis();
6018                 goback = true;
6019             } else {                    // '%any% namespace %any%'
6020                 tok = tok->previous();  // goto previous token
6021                 tok->deleteNext();      // remove next token: 'namespace'
6022                 if (tok->str() == "{") {
6023                     // Go back in case we were within a namespace that's empty now
6024                     tok = tok->tokAt(-2) ? tok->tokAt(-2) : tok->previous();
6025                     goback = true;
6026                 }
6027             }
6028         } else {
6029             tok = tok->tokAt(2 - isAnonymousNS);
6030         }
6031     }
6032 }
6033 
simplifyFlowControl()6034 void Tokenizer::simplifyFlowControl()
6035 {
6036     for (Token *begin = list.front(); begin; begin = begin->next()) {
6037 
6038         if (Token::Match(begin, "(|[") ||
6039             (begin->str() == "{" && begin->previous() && begin->strAt(-1) == "="))
6040             begin = begin->link();
6041 
6042         //function scope
6043         if (!Token::simpleMatch(begin, ") {") && !Token::Match(begin, ") %name% {"))
6044             continue;
6045 
6046         Token* end = begin->linkAt(1+(begin->next()->str() == "{" ? 0 : 1));
6047         int indentLevel = 0;
6048         bool stilldead = false;
6049 
6050         for (Token *tok = begin; tok && tok != end; tok = tok->next()) {
6051             if (Token::Match(tok, "(|[")) {
6052                 tok = tok->link();
6053                 continue;
6054             }
6055 
6056             if (tok->str() == "{") {
6057                 if (tok->previous() && tok->previous()->str() == "=") {
6058                     tok = tok->link();
6059                     continue;
6060                 }
6061                 ++indentLevel;
6062             } else if (tok->str() == "}") {
6063                 if (indentLevel == 0)
6064                     break;
6065                 --indentLevel;
6066                 if (stilldead) {
6067                     eraseDeadCode(tok, nullptr);
6068                     if (indentLevel == 1 || tok->next()->str() != "}" || !Token::Match(tok->next()->link()->previous(), ";|{|}|do {"))
6069                         stilldead = false;
6070                     continue;
6071                 }
6072             }
6073 
6074             if (indentLevel == 0)
6075                 continue;
6076 
6077             if (Token::Match(tok,"continue|break ;")) {
6078                 tok = tok->next();
6079                 eraseDeadCode(tok, nullptr);
6080 
6081             } else if (Token::Match(tok,"return|goto") ||
6082                        (Token::Match(tok->previous(), "[;{}] %name% (") &&
6083                         mSettings->library.isnoreturn(tok)) ||
6084                        (isCPP() && tok->str() == "throw")) {
6085                 if (tok->next()->str() == "}")
6086                     syntaxError(tok->next()); // invalid code like in #6731
6087                 //TODO: ensure that we exclude user-defined 'exit|abort|throw', except for 'noreturn'
6088                 //catch the first ';'
6089                 for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
6090                     if (Token::Match(tok2, "(|[")) {
6091                         tok2 = tok2->link();
6092                     } else if (tok2->str() == ";") {
6093                         tok = tok2;
6094                         eraseDeadCode(tok, nullptr);
6095                         break;
6096                     } else if (Token::Match(tok2, "[{}]"))
6097                         break;
6098                 }
6099                 //if everything is removed, then remove also the code after an inferior scope
6100                 //only if the actual scope is not special
6101                 if (indentLevel > 1 && tok->next()->str() == "}" && Token::Match(tok->next()->link()->previous(), ";|{|}|do {"))
6102                     stilldead = true;
6103             }
6104         }
6105         begin = end;
6106     }
6107 }
6108 
6109 
removeRedundantConditions()6110 bool Tokenizer::removeRedundantConditions()
6111 {
6112     // Return value for function. Set to true if there are any simplifications
6113     bool ret = false;
6114 
6115     for (Token *tok = list.front(); tok; tok = tok->next()) {
6116         if (!Token::Match(tok, "if ( %bool% ) {"))
6117             continue;
6118 
6119         // Find matching else
6120         Token *elseTag = tok->linkAt(4)->next();
6121 
6122         const bool boolValue = (tok->strAt(2) == "true");
6123 
6124         // Handle if with else
6125         if (Token::simpleMatch(elseTag, "else {")) {
6126             // Handle else
6127             if (!boolValue) {
6128                 // Convert "if( false ) {aaa;} else {bbb;}" => "{bbb;}"
6129 
6130                 //remove '(false)'
6131                 tok->deleteNext(3);
6132                 //delete dead code inside scope
6133                 eraseDeadCode(tok, elseTag);
6134                 //remove 'else'
6135                 elseTag->deleteThis();
6136                 //remove 'if'
6137                 tok->deleteThis();
6138             } else {
6139                 // Convert "if( true ) {aaa;} else {bbb;}" => "{aaa;}"
6140                 const Token *end = elseTag->next()->link()->next();
6141 
6142                 // Remove "else { bbb; }"
6143                 elseTag = elseTag->previous();
6144                 eraseDeadCode(elseTag, end);
6145 
6146                 // Remove "if( true )"
6147                 tok->deleteNext(3);
6148                 tok->deleteThis();
6149             }
6150 
6151             ret = true;
6152         }
6153 
6154         // Handle if without else
6155         else {
6156             if (!boolValue) {
6157                 //remove '(false)'
6158                 tok->deleteNext(3);
6159                 //delete dead code inside scope
6160                 eraseDeadCode(tok, elseTag);
6161                 //remove 'if'
6162                 tok->deleteThis();
6163             } else {
6164                 // convert "if( true ) {aaa;}" => "{aaa;}"
6165                 tok->deleteNext(3);
6166                 tok->deleteThis();
6167             }
6168 
6169             ret = true;
6170         }
6171     }
6172 
6173     return ret;
6174 }
6175 
removeRedundantFor()6176 void Tokenizer::removeRedundantFor()
6177 {
6178     for (Token *tok = list.front(); tok; tok = tok->next()) {
6179         if (Token::Match(tok, "[;{}] for ( %name% = %num% ; %name% < %num% ; ++| %name% ++| ) {") ||
6180             Token::Match(tok, "[;{}] for ( %type% %name% = %num% ; %name% < %num% ; ++| %name% ++| ) {")) {
6181             // Same variable name..
6182             const Token* varTok = tok->tokAt(3);
6183             const bool type = varTok->next()->isName();
6184             if (type)
6185                 varTok = varTok->next();
6186             const std::string varname(varTok->str());
6187             const int varid(varTok->varId());
6188             if (varname != varTok->strAt(4))
6189                 continue;
6190             const Token *vartok2 = tok->linkAt(2)->previous();
6191             if (vartok2->str() == "++")
6192                 vartok2 = vartok2->previous();
6193             else if (vartok2->strAt(-1) != "++")
6194                 continue;
6195             if (varname != vartok2->str())
6196                 continue;
6197 
6198             // Check that the difference of the numeric values is 1
6199             const MathLib::bigint num1(MathLib::toLongNumber(varTok->strAt(2)));
6200             const MathLib::bigint num2(MathLib::toLongNumber(varTok->strAt(6)));
6201             if (num1 + 1 != num2)
6202                 continue;
6203 
6204             // check how loop variable is used in loop..
6205             bool read = false;
6206             bool write = false;
6207             const Token* end = tok->linkAt(2)->next()->link();
6208             for (const Token *tok2 = tok->linkAt(2); tok2 != end; tok2 = tok2->next()) {
6209                 if (tok2->str() == varname) {
6210                     if (tok2->previous()->isArithmeticalOp() &&
6211                         tok2->next() &&
6212                         (tok2->next()->isArithmeticalOp() || tok2->next()->str() == ";")) {
6213                         read = true;
6214                     } else {
6215                         read = write = true;
6216                         break;
6217                     }
6218                 }
6219             }
6220 
6221             // Simplify loop if loop variable isn't written
6222             if (!write) {
6223                 Token* bodyBegin = tok->linkAt(2)->next();
6224                 // remove "for ("
6225                 tok->deleteNext(2);
6226 
6227                 // If loop variable is read then keep assignment before
6228                 // loop body..
6229                 if (type) {
6230                     tok->insertToken("{");
6231                     Token::createMutualLinks(tok->next(), bodyBegin->link());
6232                     bodyBegin->deleteThis();
6233                     tok = tok->tokAt(6);
6234                 } else if (read) {
6235                     // goto ";"
6236                     tok = tok->tokAt(4);
6237                 } else {
6238                     // remove "x = 0 ;"
6239                     tok->deleteNext(4);
6240                 }
6241 
6242                 // remove "x < 1 ; x ++ )"
6243                 tok->deleteNext(7);
6244 
6245                 if (!type) {
6246                     // Add assignment after the loop body so the loop variable
6247                     // get the correct end value
6248                     Token *tok2 = tok->next()->link();
6249                     tok2->insertToken(";");
6250                     tok2->insertToken(MathLib::toString(num2));
6251                     tok2->insertToken("=");
6252                     tok2->insertToken(varname);
6253                     tok2->next()->varId(varid);
6254                 }
6255             }
6256         }
6257     }
6258 }
6259 
6260 
removeRedundantSemicolons()6261 void Tokenizer::removeRedundantSemicolons()
6262 {
6263     for (Token *tok = list.front(); tok; tok = tok->next()) {
6264         if (tok->link() && tok->str() == "(") {
6265             tok = tok->link();
6266             continue;
6267         }
6268         for (;;) {
6269             if (Token::simpleMatch(tok, "; ;")) {
6270                 tok->deleteNext();
6271             } else if (Token::simpleMatch(tok, "; { ; }")) {
6272                 tok->deleteNext(3);
6273             } else {
6274                 break;
6275             }
6276         }
6277     }
6278 }
6279 
6280 
simplifyAddBraces()6281 bool Tokenizer::simplifyAddBraces()
6282 {
6283     for (Token *tok = list.front(); tok; tok = tok->next()) {
6284         Token const * tokRet=simplifyAddBracesToCommand(tok);
6285         if (!tokRet)
6286             return false;
6287     }
6288     return true;
6289 }
6290 
simplifyAddBracesToCommand(Token * tok)6291 Token *Tokenizer::simplifyAddBracesToCommand(Token *tok)
6292 {
6293     Token * tokEnd=tok;
6294     if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6295         tokEnd=simplifyAddBracesPair(tok,true);
6296     } else if (tok->str()=="while") {
6297         Token *tokPossibleDo=tok->previous();
6298         if (Token::simpleMatch(tok->previous(), "{"))
6299             tokPossibleDo = nullptr;
6300         else if (Token::simpleMatch(tokPossibleDo,"}"))
6301             tokPossibleDo = tokPossibleDo->link();
6302         if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6303             tokEnd=simplifyAddBracesPair(tok,true);
6304     } else if (tok->str()=="do") {
6305         tokEnd=simplifyAddBracesPair(tok,false);
6306         if (tokEnd!=tok) {
6307             // walk on to next token, i.e. "while"
6308             // such that simplifyAddBracesPair does not close other braces
6309             // before the "while"
6310             if (tokEnd) {
6311                 tokEnd=tokEnd->next();
6312                 if (!tokEnd || tokEnd->str()!="while") // no while
6313                     syntaxError(tok);
6314             }
6315         }
6316     } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6317         tokEnd=simplifyAddBracesPair(tok,true);
6318         if (!tokEnd)
6319             return nullptr;
6320         if (tokEnd->strAt(1) == "else") {
6321             Token * tokEndNextNext= tokEnd->tokAt(2);
6322             if (!tokEndNextNext || tokEndNextNext->str() == "}")
6323                 syntaxError(tokEndNextNext);
6324             if (tokEndNextNext->str() == "if")
6325                 // do not change "else if ..." to "else { if ... }"
6326                 tokEnd=simplifyAddBracesToCommand(tokEndNextNext);
6327             else
6328                 tokEnd=simplifyAddBracesPair(tokEnd->next(),false);
6329         }
6330     }
6331 
6332     return tokEnd;
6333 }
6334 
simplifyAddBracesPair(Token * tok,bool commandWithCondition)6335 Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition)
6336 {
6337     Token * tokCondition=tok->next();
6338     if (!tokCondition) // Missing condition
6339         return tok;
6340 
6341     Token *tokAfterCondition=tokCondition;
6342     if (commandWithCondition) {
6343         if (tokCondition->str()=="(")
6344             tokAfterCondition=tokCondition->link();
6345         else
6346             syntaxError(tok); // Bad condition
6347 
6348         if (!tokAfterCondition || tokAfterCondition->strAt(1) == "]")
6349             syntaxError(tok); // Bad condition
6350 
6351         tokAfterCondition=tokAfterCondition->next();
6352         if (!tokAfterCondition || Token::Match(tokAfterCondition, ")|}|,")) {
6353             // No tokens left where to add braces around
6354             return tok;
6355         }
6356     }
6357     // Skip labels
6358     Token * tokStatement = tokAfterCondition;
6359     while (true) {
6360         if (Token::Match(tokStatement, "%name% :"))
6361             tokStatement = tokStatement->tokAt(2);
6362         else if (tokStatement->str() == "case") {
6363             tokStatement = skipCaseLabel(tokStatement);
6364             if (!tokStatement)
6365                 return tok;
6366             if (tokStatement->str() != ":")
6367                 syntaxError(tokStatement);
6368             tokStatement = tokStatement->next();
6369         } else
6370             break;
6371         if (!tokStatement)
6372             return tok;
6373     }
6374     Token * tokBracesEnd=nullptr;
6375     if (tokStatement->str() == "{") {
6376         // already surrounded by braces
6377         if (tokStatement != tokAfterCondition) {
6378             // Move the opening brace before labels
6379             Token::move(tokStatement, tokStatement, tokAfterCondition->previous());
6380         }
6381         tokBracesEnd = tokStatement->link();
6382     } else if (Token::simpleMatch(tokStatement, "try {") &&
6383                Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) {
6384         tokAfterCondition->previous()->insertToken("{");
6385         Token * tokOpenBrace = tokAfterCondition->previous();
6386         Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1);
6387         if (!tokEnd) {
6388             syntaxError(tokStatement);
6389         }
6390         tokEnd->insertToken("}");
6391         Token * tokCloseBrace = tokEnd->next();
6392 
6393         Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
6394         tokBracesEnd = tokCloseBrace;
6395     } else {
6396         Token * tokEnd = simplifyAddBracesToCommand(tokStatement);
6397         if (!tokEnd) // Ticket #4887
6398             return tok;
6399         if (tokEnd->str()!="}") {
6400             // Token does not end with brace
6401             // Look for ; to add own closing brace after it
6402             while (tokEnd && !Token::Match(tokEnd, ";|)|}")) {
6403                 if (tokEnd->tokType()==Token::eBracket || tokEnd->str() == "(") {
6404                     tokEnd = tokEnd->link();
6405                     if (!tokEnd) {
6406                         // Inner bracket does not close
6407                         return tok;
6408                     }
6409                 }
6410                 tokEnd=tokEnd->next();
6411             }
6412             if (!tokEnd || tokEnd->str() != ";") {
6413                 // No trailing ;
6414                 return tok;
6415             }
6416         }
6417 
6418         tokAfterCondition->previous()->insertToken("{");
6419         Token * tokOpenBrace=tokAfterCondition->previous();
6420 
6421         tokEnd->insertToken("}");
6422         Token * tokCloseBrace=tokEnd->next();
6423 
6424         Token::createMutualLinks(tokOpenBrace,tokCloseBrace);
6425         tokBracesEnd=tokCloseBrace;
6426     }
6427 
6428     return tokBracesEnd;
6429 }
6430 
simplifyCompoundAssignment()6431 void Tokenizer::simplifyCompoundAssignment()
6432 {
6433     // Simplify compound assignments:
6434     // "a+=b" => "a = a + b"
6435     for (Token *tok = list.front(); tok; tok = tok->next()) {
6436         if (!Token::Match(tok, "[;{}] (| *| (| %name%"))
6437             continue;
6438         if (tok->next()->str() == "return")
6439             continue;
6440         // backup current token..
6441         Token * const tok1 = tok;
6442 
6443         if (tok->next()->str() == "*")
6444             tok = tok->next();
6445 
6446         if (tok->next() && tok->next()->str() == "(") {
6447             tok = tok->next()->link()->next();
6448         } else {
6449             // variable..
6450             tok = tok->tokAt(2);
6451             while (Token::Match(tok, ". %name%") ||
6452                    Token::Match(tok, "[|(")) {
6453                 if (tok->str() == ".")
6454                     tok = tok->tokAt(2);
6455                 else {
6456                     // goto "]" or ")"
6457                     tok = tok->link();
6458 
6459                     // goto next token..
6460                     tok = tok ? tok->next() : nullptr;
6461                 }
6462             }
6463         }
6464         if (!tok)
6465             break;
6466 
6467         // Is current token at a compound assignment: +=|-=|.. ?
6468         const std::string &str = tok->str();
6469         std::string op;  // operator used in assignment
6470         if (tok->isAssignmentOp() && str.size() == 2)
6471             op = str.substr(0, 1);
6472         else if (tok->isAssignmentOp() && str.size() == 3)
6473             op = str.substr(0, 2);
6474         else {
6475             tok = tok1;
6476             continue;
6477         }
6478 
6479         // Remove the whole statement if it says: "+=0;", "-=0;", "*=1;" or "/=1;"
6480         if (Token::Match(tok, "+=|-= 0 ;") ||
6481             Token::simpleMatch(tok, "|= 0 ;") ||
6482             Token::Match(tok, "*=|/= 1 ;")) {
6483             tok = tok1;
6484             while (tok->next()->str() != ";")
6485                 tok->deleteNext();
6486         } else {
6487             // Enclose the rhs in parentheses..
6488             if (!Token::Match(tok->tokAt(2), "[;)]")) {
6489                 // Only enclose rhs in parentheses if there is some operator
6490                 bool someOperator = false;
6491                 for (Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
6492                     if (tok2->link() && Token::Match(tok2, "{|[|("))
6493                         tok2 = tok2->link();
6494 
6495                     if (Token::Match(tok2->next(), "[;)]")) {
6496                         if (someOperator) {
6497                             tok->insertToken("(");
6498                             tok2->insertToken(")");
6499                             Token::createMutualLinks(tok->next(), tok2->next());
6500                         }
6501                         break;
6502                     }
6503 
6504                     someOperator |= (tok2->isOp() || tok2->str() == "?");
6505                 }
6506             }
6507 
6508             // simplify the compound assignment..
6509             tok->str("=");
6510             tok->insertToken(op);
6511 
6512             std::stack<Token *> tokend;
6513             for (Token *tok2 = tok->previous(); tok2 && tok2 != tok1; tok2 = tok2->previous()) {
6514                 // Don't duplicate ++ and --. Put preincrement in lhs. Put
6515                 // postincrement in rhs.
6516                 if (tok2->tokType() == Token::eIncDecOp) {
6517                     // pre increment/decrement => don't copy
6518                     if (tok2->next()->isName()) {
6519                         continue;
6520                     }
6521 
6522                     // post increment/decrement => move from lhs to rhs
6523                     tok->insertToken(tok2->str());
6524                     tok2->deleteThis();
6525                     continue;
6526                 }
6527 
6528                 // Copy token from lhs to rhs
6529                 tok->insertToken(tok2->str());
6530                 tok->next()->varId(tok2->varId());
6531                 if (Token::Match(tok->next(), "]|)|}"))
6532                     tokend.push(tok->next());
6533                 else if (Token::Match(tok->next(), "(|[|{")) {
6534                     Token::createMutualLinks(tok->next(), tokend.top());
6535                     tokend.pop();
6536                 }
6537             }
6538         }
6539     }
6540 }
6541 
simplifyConditions()6542 bool Tokenizer::simplifyConditions()
6543 {
6544     bool ret = false;
6545 
6546     for (Token *tok = list.front(); tok; tok = tok->next()) {
6547         if (Token::Match(tok, "! %bool%|%num%")) {
6548             tok->deleteThis();
6549             if (Token::Match(tok, "0|false"))
6550                 tok->str("true");
6551             else
6552                 tok->str("false");
6553 
6554             ret = true;
6555         }
6556 
6557         if (Token::simpleMatch(tok, "&& true &&")) {
6558             tok->deleteNext(2);
6559             ret = true;
6560         }
6561 
6562         else if (Token::simpleMatch(tok, "|| false ||")) {
6563             tok->deleteNext(2);
6564             ret = true;
6565         }
6566 
6567         else if (Token::Match(tok, "(|&& true && true &&|)")) {
6568             tok->deleteNext(2);
6569             ret = true;
6570         }
6571 
6572         else if (Token::Match(tok, "%oror%|( false %oror% false %oror%|)")) {
6573             tok->deleteNext(2);
6574             ret = true;
6575         }
6576 
6577         else if (Token::simpleMatch(tok, "( true ||") ||
6578                  Token::simpleMatch(tok, "( false &&")) {
6579             Token::eraseTokens(tok->next(), tok->link());
6580             ret = true;
6581         }
6582 
6583         else if (Token::simpleMatch(tok, "|| true )") ||
6584                  Token::simpleMatch(tok, "&& false )")) {
6585             tok = tok->next();
6586             Token::eraseTokens(tok->next()->link(), tok);
6587             ret = true;
6588         }
6589 
6590         else if (Token::simpleMatch(tok, "&& false &&") ||
6591                  Token::simpleMatch(tok, "|| true ||")) {
6592             //goto '('
6593             Token *tok2 = tok;
6594             while (tok2 && tok2->previous()) {
6595                 if (tok2->previous()->str() == ")")
6596                     tok2 = tok2->previous()->link();
6597                 else {
6598                     tok2 = tok2->previous();
6599                     if (tok2->str() == "(")
6600                         break;
6601                 }
6602             }
6603             if (!tok2)
6604                 continue;
6605             //move tok to 'true|false' position
6606             tok = tok->next();
6607             //remove everything before 'true|false'
6608             Token::eraseTokens(tok2, tok);
6609             //remove everything after 'true|false'
6610             Token::eraseTokens(tok, tok2->link());
6611             ret = true;
6612         }
6613 
6614         // Change numeric constant in condition to "true" or "false"
6615         if (Token::Match(tok, "if|while ( %num% )|%oror%|&&")) {
6616             tok->tokAt(2)->str((tok->strAt(2) != "0") ? "true" : "false");
6617             ret = true;
6618         }
6619         if (Token::Match(tok, "&&|%oror% %num% )|%oror%|&&")) {
6620             tok->next()->str((tok->next()->str() != "0") ? "true" : "false");
6621             ret = true;
6622         }
6623 
6624         // Reduce "(%num% == %num%)" => "(true)"/"(false)"
6625         if (Token::Match(tok, "&&|%oror%|(") &&
6626             (Token::Match(tok->next(), "%num% %any% %num%") ||
6627              Token::Match(tok->next(), "%bool% %any% %bool%")) &&
6628             Token::Match(tok->tokAt(4), "&&|%oror%|)|?")) {
6629             std::string cmp = tok->strAt(2);
6630             bool result = false;
6631             if (tok->next()->isNumber()) {
6632                 // Compare numbers
6633 
6634                 if (cmp == "==" || cmp == "!=") {
6635                     const std::string& op1(tok->next()->str());
6636                     const std::string& op2(tok->strAt(3));
6637 
6638                     bool eq = false;
6639                     if (MathLib::isInt(op1) && MathLib::isInt(op2))
6640                         eq = (MathLib::toLongNumber(op1) == MathLib::toLongNumber(op2));
6641                     else {
6642                         eq = (op1 == op2);
6643 
6644                         // It is inconclusive whether two unequal float representations are numerically equal
6645                         if (!eq && MathLib::isFloat(op1))
6646                             cmp.clear();
6647                     }
6648 
6649                     if (cmp == "==")
6650                         result = eq;
6651                     else
6652                         result = !eq;
6653                 } else {
6654                     const double op1 = MathLib::toDoubleNumber(tok->next()->str());
6655                     const double op2 = MathLib::toDoubleNumber(tok->strAt(3));
6656                     if (cmp == ">=")
6657                         result = (op1 >= op2);
6658                     else if (cmp == ">")
6659                         result = (op1 > op2);
6660                     else if (cmp == "<=")
6661                         result = (op1 <= op2);
6662                     else if (cmp == "<")
6663                         result = (op1 < op2);
6664                     else
6665                         cmp.clear();
6666                 }
6667             } else {
6668                 // Compare boolean
6669                 const bool op1 = (tok->next()->str() == std::string("true"));
6670                 const bool op2 = (tok->strAt(3) == std::string("true"));
6671 
6672                 if (cmp == "==")
6673                     result = (op1 == op2);
6674                 else if (cmp == "!=")
6675                     result = (op1 != op2);
6676                 else if (cmp == ">=")
6677                     result = (op1 >= op2);
6678                 else if (cmp == ">")
6679                     result = (op1 > op2);
6680                 else if (cmp == "<=")
6681                     result = (op1 <= op2);
6682                 else if (cmp == "<")
6683                     result = (op1 < op2);
6684                 else
6685                     cmp.clear();
6686             }
6687 
6688             if (!cmp.empty()) {
6689                 tok = tok->next();
6690                 tok->deleteNext(2);
6691 
6692                 tok->str(result ? "true" : "false");
6693                 ret = true;
6694             }
6695         }
6696     }
6697 
6698     return ret;
6699 }
6700 
simplifyConstTernaryOp()6701 bool Tokenizer::simplifyConstTernaryOp()
6702 {
6703     bool ret = false;
6704     const Token *templateParameterEnd = nullptr; // The end of the current template parameter list, if any
6705     for (Token *tok = list.front(); tok; tok = tok->next()) {
6706         if (tok->str() == "<" && TemplateSimplifier::templateParameters(tok))
6707             templateParameterEnd = tok->findClosingBracket();
6708         if (tok == templateParameterEnd)
6709             templateParameterEnd = nullptr; // End of the current template parameter list
6710         if (tok->str() != "?")
6711             continue;
6712 
6713         if (!Token::Match(tok->tokAt(-2), "<|=|,|(|[|{|}|;|case|return %bool%|%num%") &&
6714             !Token::Match(tok->tokAt(-4), "<|=|,|(|[|{|}|;|case|return ( %bool%|%num% )"))
6715             continue;
6716 
6717         const int offset = (tok->previous()->str() == ")") ? 2 : 1;
6718 
6719         if (tok->strAt(-2*offset) == "<") {
6720             if (isC() || !TemplateSimplifier::templateParameters(tok->tokAt(-2*offset)))
6721                 continue; // '<' is less than; the condition is not a constant
6722         }
6723 
6724         // Find the token ":" then go to the next token
6725         Token *colon = skipTernaryOp(tok);
6726         if (!colon || colon->previous()->str() != ":" || !colon->next())
6727             continue;
6728 
6729         //handle the GNU extension: "x ? : y" <-> "x ? x : y"
6730         if (colon->previous() == tok->next())
6731             tok->insertToken(tok->strAt(-offset));
6732 
6733         // go back before the condition, if possible
6734         tok = tok->tokAt(-2);
6735         if (offset == 2) {
6736             // go further back before the "("
6737             tok = tok->tokAt(-2);
6738             //simplify the parentheses
6739             tok->deleteNext();
6740             tok->next()->deleteNext();
6741         }
6742 
6743         if (Token::Match(tok->next(), "false|0")) {
6744             // Use code after colon, remove code before it.
6745             Token::eraseTokens(tok, colon);
6746 
6747             tok = tok->next();
6748             ret = true;
6749         }
6750 
6751         // The condition is true. Delete the operator after the ":"..
6752         else {
6753             // delete the condition token and the "?"
6754             tok->deleteNext(2);
6755 
6756             int ternaryOplevel = 0;
6757             for (const Token *endTok = colon; endTok; endTok = endTok->next()) {
6758                 if (Token::Match(endTok, "(|[|{"))
6759                     endTok = endTok->link();
6760                 else if (endTok->str() == "<" && (endTok->strAt(1) == ">" || TemplateSimplifier::templateParameters(endTok)))
6761                     endTok = endTok->findClosingBracket();
6762                 else if (endTok->str() == "?")
6763                     ++ternaryOplevel;
6764                 else if (Token::Match(endTok, ")|}|]|;|,|:|>")) {
6765                     if (endTok->str() == ":" && ternaryOplevel)
6766                         --ternaryOplevel;
6767                     else if (endTok->str() == ">" && !templateParameterEnd)
6768                         ;
6769                     else {
6770                         Token::eraseTokens(colon->tokAt(-2), endTok);
6771                         ret = true;
6772                         break;
6773                     }
6774                 }
6775             }
6776         }
6777     }
6778     return ret;
6779 }
6780 
simplifyUndefinedSizeArray()6781 void Tokenizer::simplifyUndefinedSizeArray()
6782 {
6783     for (Token *tok = list.front(); tok; tok = tok->next()) {
6784         if (Token::Match(tok, "%type%")) {
6785             Token *tok2 = tok->next();
6786             while (tok2 && tok2->str() == "*")
6787                 tok2 = tok2->next();
6788             if (!Token::Match(tok2, "%name% [ ] ;|["))
6789                 continue;
6790 
6791             tok = tok2->previous();
6792             Token *end = tok2->next();
6793             int count = 0;
6794             do {
6795                 end = end->tokAt(2);
6796                 ++count;
6797             } while (Token::Match(end, "[ ] [;=[]"));
6798             if (Token::Match(end, "[;=]")) {
6799                 do {
6800                     tok2->deleteNext(2);
6801                     tok->insertToken("*");
6802                 } while (--count);
6803                 tok = end;
6804             } else
6805                 tok = tok->tokAt(3);
6806         }
6807     }
6808 }
6809 
simplifyCasts()6810 void Tokenizer::simplifyCasts()
6811 {
6812     for (Token *tok = list.front(); tok; tok = tok->next()) {
6813         // Don't remove cast in such cases:
6814         // *((char *)a + 1) = 0;
6815         // Remove cast when casting a function pointer:
6816         // (*(void (*)(char *))fp)(x);
6817         if (!tok->isName() &&
6818             Token::simpleMatch(tok->next(), "* (") &&
6819             !Token::Match(tok->linkAt(2), ") %name%|&")) {
6820             tok = tok->linkAt(2);
6821             continue;
6822         }
6823         // #3935 : don't remove cast in such cases:
6824         // ((char *)a)[1] = 0;
6825         if (tok->str() == "(" && Token::simpleMatch(tok->link(), ") [")) {
6826             tok = tok->link();
6827             continue;
6828         }
6829         // #4164 : ((unsigned char)1) => (1)
6830         if (Token::Match(tok->next(), "( %type% ) %num%") && tok->next()->link()->previous()->isStandardType()) {
6831             const MathLib::bigint value = MathLib::toLongNumber(tok->next()->link()->next()->str());
6832             int bits = mSettings->char_bit * mTypeSize[tok->next()->link()->previous()->str()];
6833             if (!tok->tokAt(2)->isUnsigned() && bits > 0)
6834                 bits--;
6835             if (bits < 31 && value >= 0 && value < (1LL << bits)) {
6836                 tok->linkAt(1)->next()->isCast(true);
6837                 Token::eraseTokens(tok, tok->next()->link()->next());
6838             }
6839             continue;
6840         }
6841 
6842         while ((Token::Match(tok->next(), "( %type% *| *| *|&| ) *|&| %name%") && (tok->str() != ")" || tok->tokAt(2)->isStandardType())) ||
6843                Token::Match(tok->next(), "( const| %type% * *| *|&| ) *|&| %name%") ||
6844                Token::Match(tok->next(), "( const| %type% %type% *| *| *|&| ) *|&| %name%") ||
6845                (!tok->isName() && (Token::Match(tok->next(), "( %type% * *| *|&| ) (") ||
6846                                    Token::Match(tok->next(), "( const| %type% %type% * *| *|&| ) (")))) {
6847             if (tok->isName() && tok->str() != "return")
6848                 break;
6849 
6850             if (isCPP() && tok->strAt(-1) == "operator")
6851                 break;
6852 
6853             // Remove cast..
6854             Token::eraseTokens(tok, tok->next()->link()->next());
6855 
6856             // Set isCasted flag.
6857             Token *tok2 = tok->next();
6858             if (!Token::Match(tok2, "%name% [|."))
6859                 tok2->isCast(true);
6860             else {
6861                 // TODO: handle more complex expressions
6862                 tok2->next()->isCast(true);
6863             }
6864 
6865             // Remove '* &'
6866             if (Token::simpleMatch(tok, "* &")) {
6867                 tok->deleteNext();
6868                 tok->deleteThis();
6869             }
6870 
6871             if (tok->str() == ")" && tok->link()->previous()) {
6872                 // If there was another cast before this, go back
6873                 // there to check it also. e.g. "(int)(char)x"
6874                 tok = tok->link()->previous();
6875             }
6876         }
6877 
6878         // Replace pointer casts of 0.. "(char *)0" => "0"
6879         while (Token::Match(tok->next(), "( %type% %type%| * *| ) 0")) {
6880             tok->linkAt(1)->next()->isCast(true);
6881             Token::eraseTokens(tok, tok->next()->link()->next());
6882             if (tok->str() == ")" && tok->link()->previous()) {
6883                 // If there was another cast before this, go back
6884                 // there to check it also. e.g. "(char*)(char*)0"
6885                 tok = tok->link()->previous();
6886             }
6887         }
6888 
6889         if (Token::Match(tok->next(), "dynamic_cast|reinterpret_cast|const_cast|static_cast <")) {
6890             Token *tok2 = tok->linkAt(2);
6891             if (!Token::simpleMatch(tok2, "> ("))
6892                 break;
6893 
6894             tok2->tokAt(2)->isCast(true);
6895             Token::eraseTokens(tok, tok2->next());
6896         }
6897     }
6898 }
6899 
6900 
simplifyFunctionParameters()6901 void Tokenizer::simplifyFunctionParameters()
6902 {
6903     for (Token *tok = list.front(); tok; tok = tok->next()) {
6904         if (tok->link() && Token::Match(tok, "{|[|(")) {
6905             tok = tok->link();
6906         }
6907 
6908         // Find the function e.g. foo( x ) or foo( x, y )
6909         else if (Token::Match(tok, "%name% ( %name% [,)]") &&
6910                  !(tok->strAt(-1) == ":" || tok->strAt(-1) == "," || tok->strAt(-1) == "::")) {
6911             // We have found old style function, now we need to change it
6912 
6913             // First step: Get list of argument names in parentheses
6914             std::map<std::string, Token *> argumentNames;
6915             bool bailOut = false;
6916             Token * tokparam = nullptr;
6917 
6918             //take count of the function name..
6919             const std::string& funcName(tok->str());
6920 
6921             //floating token used to check for parameters
6922             Token *tok1 = tok;
6923 
6924             while (nullptr != (tok1 = tok1->tokAt(2))) {
6925                 if (!Token::Match(tok1, "%name% [,)]")) {
6926                     bailOut = true;
6927                     break;
6928                 }
6929 
6930                 //same parameters: take note of the parameter
6931                 if (argumentNames.find(tok1->str()) != argumentNames.end())
6932                     tokparam = tok1;
6933                 else if (tok1->str() != funcName)
6934                     argumentNames[tok1->str()] = tok1;
6935                 else {
6936                     if (tok1->next()->str() == ")") {
6937                         if (tok1->previous()->str() == ",") {
6938                             tok1 = tok1->tokAt(-2);
6939                             tok1->deleteNext(2);
6940                         } else {
6941                             tok1 = tok1->previous();
6942                             tok1->deleteNext();
6943                             bailOut = true;
6944                             break;
6945                         }
6946                     } else {
6947                         tok1 = tok1->tokAt(-2);
6948                         tok1->next()->deleteNext(2);
6949                     }
6950                 }
6951 
6952                 if (tok1->next()->str() == ")") {
6953                     tok1 = tok1->tokAt(2);
6954                     //expect at least a type name after round brace..
6955                     if (!tok1 || !tok1->isName())
6956                         bailOut = true;
6957                     break;
6958                 }
6959             }
6960 
6961             //goto '('
6962             tok = tok->next();
6963 
6964             if (bailOut) {
6965                 tok = tok->link();
6966                 continue;
6967             }
6968 
6969             tok1 = tok->link()->next();
6970 
6971             // there should be the sequence '; {' after the round parentheses
6972             for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) {
6973                 if (Token::simpleMatch(tok2, "; {"))
6974                     break;
6975                 else if (tok2->str() == "{") {
6976                     bailOut = true;
6977                     break;
6978                 }
6979             }
6980 
6981             if (bailOut) {
6982                 tok = tok->link();
6983                 continue;
6984             }
6985 
6986             // Last step: check out if the declarations between ')' and '{' match the parameters list
6987             std::map<std::string, Token *> argumentNames2;
6988 
6989             while (tok1 && tok1->str() != "{") {
6990                 if (Token::Match(tok1, "(|)")) {
6991                     bailOut = true;
6992                     break;
6993                 }
6994                 if (tok1->str() == ";") {
6995                     if (tokparam) {
6996                         syntaxError(tokparam);
6997                     }
6998                     Token *tok2 = tok1->previous();
6999                     while (tok2->str() == "]")
7000                         tok2 = tok2->link()->previous();
7001 
7002                     //it should be a name..
7003                     if (!tok2->isName()) {
7004                         bailOut = true;
7005                         break;
7006                     }
7007 
7008                     if (argumentNames2.find(tok2->str()) != argumentNames2.end()) {
7009                         //same parameter names...
7010                         syntaxError(tok1);
7011                     } else
7012                         argumentNames2[tok2->str()] = tok2;
7013 
7014                     if (argumentNames.find(tok2->str()) == argumentNames.end()) {
7015                         //non-matching parameter... bailout
7016                         bailOut = true;
7017                         break;
7018                     }
7019                 }
7020                 tok1 = tok1->next();
7021             }
7022 
7023             if (bailOut || !tok1) {
7024                 tok = tok->link();
7025                 continue;
7026             }
7027 
7028             //the two containers may not hold the same size...
7029             //in that case, the missing parameters are defined as 'int'
7030             if (argumentNames.size() != argumentNames2.size()) {
7031                 //move back 'tok1' to the last ';'
7032                 tok1 = tok1->previous();
7033                 for (std::pair<const std::string, Token *>& argumentName : argumentNames) {
7034                     if (argumentNames2.find(argumentName.first) == argumentNames2.end()) {
7035                         //add the missing parameter argument declaration
7036                         tok1->insertToken(";");
7037                         tok1->insertToken(argumentName.first);
7038                         //register the change inside argumentNames2
7039                         argumentNames2[argumentName.first] = tok1->next();
7040                         tok1->insertToken("int");
7041                     }
7042                 }
7043             }
7044 
7045             while (tok->str() != ")") {
7046                 //initialize start and end tokens to be moved
7047                 Token *declStart = argumentNames2[tok->next()->str()];
7048                 Token *declEnd = declStart;
7049                 while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")")
7050                     declStart = declStart->previous();
7051                 while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{")
7052                     declEnd = declEnd->next();
7053 
7054                 //remove ';' after declaration
7055                 declEnd->deleteNext();
7056 
7057                 //replace the parameter name in the parentheses with all the declaration
7058                 Token::replace(tok->next(), declStart, declEnd);
7059 
7060                 //since there are changes to tokens, put tok where tok1 is
7061                 tok = declEnd->next();
7062 
7063                 //fix up line number
7064                 if (tok->str() == ",")
7065                     tok->linenr(tok->previous()->linenr());
7066             }
7067             //goto forward and continue
7068             tok = tok->next()->link();
7069         }
7070     }
7071 }
7072 
simplifyPointerToStandardType()7073 void Tokenizer::simplifyPointerToStandardType()
7074 {
7075     if (!isC())
7076         return;
7077 
7078     for (Token *tok = list.front(); tok; tok = tok->next()) {
7079         if (!Token::Match(tok, "& %name% [ 0 ] !!["))
7080             continue;
7081 
7082         if (!Token::Match(tok->previous(), "[,(=]"))
7083             continue;
7084 
7085         // Remove '[ 0 ]' suffix
7086         Token::eraseTokens(tok->next(), tok->tokAt(5));
7087         // Remove '&' prefix
7088         tok = tok->previous();
7089         if (!tok)
7090             break;
7091         tok->deleteNext();
7092     }
7093 }
7094 
simplifyFunctionPointers()7095 void Tokenizer::simplifyFunctionPointers()
7096 {
7097     for (Token *tok = list.front(); tok; tok = tok->next()) {
7098         // #2873 - do not simplify function pointer usage here:
7099         // (void)(xy(*p)(0));
7100         if (Token::simpleMatch(tok, ") (")) {
7101             tok = tok->next()->link();
7102             continue;
7103         }
7104 
7105         // check for function pointer cast
7106         if (Token::Match(tok, "( %type% %type%| *| *| ( * ) (") ||
7107             Token::Match(tok, "static_cast < %type% %type%| *| *| ( * ) (")) {
7108             Token *tok1 = tok;
7109 
7110             if (isCPP() && tok1->str() == "static_cast")
7111                 tok1 = tok1->next();
7112 
7113             tok1 = tok1->next();
7114 
7115             if (Token::Match(tok1->next(), "%type%"))
7116                 tok1 = tok1->next();
7117 
7118             while (tok1->next()->str() == "*")
7119                 tok1 = tok1->next();
7120 
7121             // check that the cast ends
7122             if (!Token::Match(tok1->linkAt(4), ") )|>"))
7123                 continue;
7124 
7125             // ok simplify this function pointer cast to an ordinary pointer cast
7126             tok1->deleteNext();
7127             tok1->next()->deleteNext();
7128             Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next());
7129             continue;
7130         }
7131 
7132         // check for start of statement
7133         else if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
7134             continue;
7135 
7136         if (Token::Match(tok, "delete|else|return|throw|typedef"))
7137             continue;
7138 
7139         while (Token::Match(tok, "%type%|:: %type%|::"))
7140             tok = tok->next();
7141 
7142         Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
7143         while (Token::Match(tok2, "*|&"))
7144             tok2 = tok2->next();
7145         if (!tok2 || tok2->str() != "(")
7146             continue;
7147         while (Token::Match(tok2, "(|:: %type%"))
7148             tok2 = tok2->tokAt(2);
7149         if (!Token::Match(tok2, "(|:: * *| %name%"))
7150             continue;
7151         tok2 = tok2->tokAt(2);
7152         if (tok2->str() == "*")
7153             tok2 = tok2->next();
7154         while (Token::Match(tok2, "%type%|:: %type%|::"))
7155             tok2 = tok2->next();
7156 
7157         if (!Token::Match(tok2, "%name% ) (") &&
7158             !Token::Match(tok2, "%name% [ ] ) (") &&
7159             !(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
7160             continue;
7161 
7162         while (tok && tok->str() != "(")
7163             tok = tok->next();
7164 
7165         // check that the declaration ends
7166         if (!tok || !tok->link() || !tok->link()->next()) {
7167             syntaxError(nullptr);
7168         }
7169         Token *endTok = tok->link()->next()->link();
7170         if (Token::simpleMatch(endTok, ") throw ("))
7171             endTok = endTok->linkAt(2);
7172         if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
7173             continue;
7174 
7175         while (Token::Match(endTok->next(), "const|volatile"))
7176             endTok->deleteNext();
7177 
7178         // ok simplify this function pointer to an ordinary pointer
7179         Token::eraseTokens(tok->link(), endTok->next());
7180         if (Token::simpleMatch(tok->link()->previous(), ") )")) {
7181             // Function returning function pointer
7182             // void (*dostuff(void))(void) {}
7183             tok->link()->deleteThis();
7184             tok->deleteThis();
7185         } else {
7186             // Function pointer variable
7187             // void (*p)(void) {}
7188             tok->link()->insertToken("(");
7189             Token *par1 = tok->link()->next();
7190             par1->insertToken(")");
7191             par1->link(par1->next());
7192             par1->next()->link(par1);
7193             while (Token::Match(tok, "( %type% ::"))
7194                 tok->deleteNext(2);
7195         }
7196     }
7197 }
7198 
7199 
simplifyFunctionReturn()7200 bool Tokenizer::simplifyFunctionReturn()
7201 {
7202     std::map<std::string, const Token*> functions;
7203 
7204     for (const Token *tok = tokens(); tok; tok = tok->next()) {
7205         if (tok->str() == "{")
7206             tok = tok->link();
7207 
7208         else if (Token::Match(tok, "%name% ( ) { return %bool%|%char%|%num%|%str% ; }") && tok->strAt(-1) != "::") {
7209             const Token* const any = tok->tokAt(5);
7210             functions[tok->str()] = any;
7211             tok = any;
7212         }
7213     }
7214 
7215     if (functions.empty())
7216         return false;
7217 
7218     bool ret = false;
7219     for (Token *tok = list.front(); tok; tok = tok->next()) {
7220         if (Token::Match(tok, "(|[|=|return|%op% %name% ( ) ;|]|)|%cop%")) {
7221             tok = tok->next();
7222             auto it = functions.find(tok->str());
7223             if (it != functions.cend()) {
7224                 tok->str(it->second->str());
7225                 tok->deleteNext(2);
7226                 ret = true;
7227             }
7228         }
7229     }
7230 
7231     return ret;
7232 }
7233 
simplifyVarDecl(const bool only_k_r_fpar)7234 void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
7235 {
7236     simplifyVarDecl(list.front(), nullptr, only_k_r_fpar);
7237 }
7238 
simplifyVarDecl(Token * tokBegin,const Token * const tokEnd,const bool only_k_r_fpar)7239 void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
7240 {
7241     const bool isCPP11  = mSettings->standards.cpp >= Standards::CPP11;
7242 
7243     // Split up variable declarations..
7244     // "int a=4;" => "int a; a=4;"
7245     bool finishedwithkr = true;
7246     bool scopeDecl = false;
7247     for (Token *tok = tokBegin; tok != tokEnd; tok = tok->next()) {
7248         if (Token::Match(tok, "{|;"))
7249             scopeDecl = false;
7250         if (isCPP()) {
7251             if (Token::Match(tok, "class|struct|namespace|union"))
7252                 scopeDecl = true;
7253             if (Token::Match(tok, "decltype|noexcept (")) {
7254                 tok = tok->next()->link();
7255                 // skip decltype(...){...}
7256                 if (tok && Token::simpleMatch(tok->previous(), ") {"))
7257                     tok = tok->link();
7258             } else if (Token::simpleMatch(tok, "= {") ||
7259                        (!scopeDecl && Token::Match(tok, "%name%|> {") &&
7260                         !Token::Match(tok, "else|try|do|const|constexpr|override|volatile|noexcept"))) {
7261                 if (!tok->next()->link())
7262                     syntaxError(tokBegin);
7263                 // Check for lambdas before skipping
7264                 for (Token* tok2 = tok->next(); tok2 != tok->next()->link(); tok2 = tok2->next()) {
7265                     Token* lambdaEnd = findLambdaEndScope(tok2);
7266                     if (!lambdaEnd)
7267                         continue;
7268                     simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7269                 }
7270                 tok = tok->next()->link();
7271             }
7272 
7273         } else if (Token::simpleMatch(tok, "= {")) {
7274             tok = tok->next()->link();
7275         }
7276         if (!tok) {
7277             syntaxError(tokBegin);
7278         }
7279         if (only_k_r_fpar && finishedwithkr) {
7280             if (Token::Match(tok, "(|[|{")) {
7281                 tok = tok->link();
7282                 if (tok->next() && Token::Match(tok, ") !!{"))
7283                     tok = tok->next();
7284                 else
7285                     continue;
7286             } else
7287                 continue;
7288         } else if (tok->str() == "(") {
7289             if (isCPP()) {
7290                 for (Token * tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
7291                     if (Token::Match(tok2, "[(,] [")) {
7292                         // lambda function at tok2->next()
7293                         // find start of lambda body
7294                         Token * lambdaBody = tok2;
7295                         while (lambdaBody && lambdaBody != tok2->link() && lambdaBody->str() != "{")
7296                             lambdaBody = lambdaBody->next();
7297                         if (lambdaBody && lambdaBody != tok2->link() && lambdaBody->link())
7298                             simplifyVarDecl(lambdaBody, lambdaBody->link()->next(), only_k_r_fpar);
7299                     }
7300                 }
7301             }
7302             tok = tok->link();
7303         }
7304 
7305         if (!tok)
7306             syntaxError(nullptr); // #7043 invalid code
7307         if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:"))
7308             continue;
7309         if (Token::simpleMatch(tok, "template <"))
7310             continue;
7311 
7312         Token *type0 = tok;
7313         if (!Token::Match(type0, "::|extern| %type%"))
7314             continue;
7315         if (Token::Match(type0, "else|return|public:|protected:|private:"))
7316             continue;
7317         if (isCPP11 && type0->str() == "using")
7318             continue;
7319         if (isCPP() && type0->str() == "namespace")
7320             continue;
7321 
7322         bool isconst = false;
7323         bool isstatic = false;
7324         Token *tok2 = type0;
7325         int typelen = 1;
7326 
7327         if (Token::Match(tok2, "::|extern")) {
7328             tok2 = tok2->next();
7329             typelen++;
7330         }
7331 
7332         //check if variable is declared 'const' or 'static' or both
7333         while (tok2) {
7334             if (!Token::Match(tok2, "const|static|constexpr") && Token::Match(tok2, "%type% const|static")) {
7335                 tok2 = tok2->next();
7336                 ++typelen;
7337             }
7338 
7339             if (Token::Match(tok2, "const|constexpr"))
7340                 isconst = true;
7341 
7342             else if (Token::Match(tok2, "static|constexpr"))
7343                 isstatic = true;
7344 
7345             else if (Token::Match(tok2, "%type% :: %type%")) {
7346                 tok2 = tok2->next();
7347                 ++typelen;
7348             }
7349 
7350             else
7351                 break;
7352 
7353             if (tok2->strAt(1) == "*")
7354                 break;
7355 
7356             if (Token::Match(tok2->next(), "& %name% ,"))
7357                 break;
7358 
7359             tok2 = tok2->next();
7360             ++typelen;
7361         }
7362 
7363         // strange looking variable declaration => don't split up.
7364         if (Token::Match(tok2, "%type% *|&| %name% , %type% *|&| %name%"))
7365             continue;
7366 
7367         if (Token::Match(tok2, "struct|union|class %type%")) {
7368             tok2 = tok2->next();
7369             ++typelen;
7370         }
7371 
7372         // check for qualification..
7373         if (Token::Match(tok2,  ":: %type%")) {
7374             ++typelen;
7375             tok2 = tok2->next();
7376         }
7377 
7378         //skip combinations of templates and namespaces
7379         while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
7380             if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
7381                 tok2 = nullptr;
7382                 break;
7383             }
7384             typelen += 2;
7385             tok2 = tok2->tokAt(2);
7386             if (tok2 && tok2->previous()->str() == "::")
7387                 continue;
7388             int indentlevel = 0;
7389             int parens = 0;
7390 
7391             for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
7392                 ++typelen;
7393 
7394                 if (!parens && tok3->str() == "<") {
7395                     ++indentlevel;
7396                 } else if (!parens && tok3->str() == ">") {
7397                     if (indentlevel == 0) {
7398                         tok2 = tok3->next();
7399                         break;
7400                     }
7401                     --indentlevel;
7402                 } else if (!parens && tok3->str() == ">>") {
7403                     if (indentlevel <= 1) {
7404                         tok2 = tok3->next();
7405                         break;
7406                     }
7407                     indentlevel -= 2;
7408                 } else if (tok3->str() == "(") {
7409                     ++parens;
7410                 } else if (tok3->str() == ")") {
7411                     if (!parens) {
7412                         tok2 = nullptr;
7413                         break;
7414                     }
7415                     --parens;
7416                 } else if (tok3->str() == ";") {
7417                     break;
7418                 }
7419             }
7420 
7421             if (Token::Match(tok2,  ":: %type%")) {
7422                 ++typelen;
7423                 tok2 = tok2->next();
7424             }
7425         }
7426 
7427         //pattern: "%type% *| ... *| const| %name% ,|="
7428         if (Token::Match(tok2, "%type%") ||
7429             (tok2 && tok2->previous() && tok2->previous()->str() == ">")) {
7430             Token *varName = tok2;
7431             if (!tok2->previous() || tok2->previous()->str() != ">")
7432                 varName = varName->next();
7433             else
7434                 --typelen;
7435             //skip all the pointer part
7436             bool isPointerOrRef = false;
7437             while (Token::simpleMatch(varName, "*") || Token::Match(varName, "& %name% ,")) {
7438                 isPointerOrRef = true;
7439                 varName = varName->next();
7440             }
7441 
7442             while (Token::Match(varName, "%type% %type%")) {
7443                 if (varName->str() != "const") {
7444                     ++typelen;
7445                 }
7446                 varName = varName->next();
7447             }
7448             // Function pointer
7449             if (Token::simpleMatch(varName, "( *") && Token::Match(varName->link()->previous(), "%name% ) ( ) =")) {
7450                 Token *endDecl = varName->link()->tokAt(2);
7451                 varName = varName->link()->previous();
7452                 endDecl->insertToken(";");
7453                 endDecl = endDecl->next();
7454                 endDecl->insertToken(varName->str());
7455                 continue;
7456             }
7457             //non-VLA case
7458             else if (Token::Match(varName, "%name% ,|=")) {
7459                 if (varName->str() != "operator") {
7460                     tok2 = varName->next(); // The ',' or '=' token
7461 
7462                     if (tok2->str() == "=" && (isstatic || (isconst && !isPointerOrRef))) {
7463                         //do not split const non-pointer variables..
7464                         while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7465                             if (Token::Match(tok2, "{|(|["))
7466                                 tok2 = tok2->link();
7467                             const Token *tok3 = tok2;
7468                             if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
7469                                 tok2 = tok2->findClosingBracket();
7470                             }
7471                             if (!tok2)
7472                                 syntaxError(tok3); // #6881 invalid code
7473                             tok2 = tok2->next();
7474                         }
7475                         if (tok2 && tok2->str() == ";")
7476                             tok2 = nullptr;
7477                     }
7478                 } else
7479                     tok2 = nullptr;
7480             }
7481 
7482             //VLA case
7483             else if (Token::Match(varName, "%name% [")) {
7484                 tok2 = varName->next();
7485 
7486                 while (Token::Match(tok2->link(), "] ,|=|["))
7487                     tok2 = tok2->link()->next();
7488                 if (!Token::Match(tok2, "=|,"))
7489                     tok2 = nullptr;
7490                 if (tok2 && tok2->str() == "=") {
7491                     while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7492                         if (Token::Match(tok2, "{|(|["))
7493                             tok2 = tok2->link();
7494                         tok2 = tok2->next();
7495                     }
7496                     if (tok2 && tok2->str() == ";")
7497                         tok2 = nullptr;
7498                 }
7499             }
7500 
7501             // brace initialization
7502             else if (Token::Match(varName, "%name% {")) {
7503                 tok2 = varName->next();
7504                 tok2 = tok2->link();
7505                 if (tok2)
7506                     tok2 = tok2->next();
7507                 if (tok2 && tok2->str() != ",")
7508                     tok2 = nullptr;
7509             }
7510 
7511             // parenthesis, functions can't be declared like:
7512             // int f1(a,b), f2(c,d);
7513             // so if there is a comma assume this is a variable declaration
7514             else if (Token::Match(varName, "%name% (") && Token::simpleMatch(varName->linkAt(1), ") ,")) {
7515                 tok2 = varName->linkAt(1)->next();
7516             }
7517 
7518             else
7519                 tok2 = nullptr;
7520         } else {
7521             tok2 = nullptr;
7522         }
7523 
7524         if (!tok2) {
7525             if (only_k_r_fpar)
7526                 finishedwithkr = false;
7527             continue;
7528         }
7529 
7530         if (tok2->str() == ",") {
7531             tok2->str(";");
7532             tok2->isSplittedVarDeclComma(true);
7533             //TODO: should we have to add also template '<>' links?
7534             TokenList::insertTokens(tok2, type0, typelen);
7535         }
7536 
7537         else {
7538             Token *eq = tok2;
7539 
7540             while (tok2) {
7541                 if (Token::Match(tok2, "{|(|["))
7542                     tok2 = tok2->link();
7543 
7544                 else if (!isC() && tok2->str() == "<" && tok2->previous()->isName() && !tok2->previous()->varId())
7545                     tok2 = tok2->findClosingBracket();
7546 
7547                 else if (std::strchr(";,", tok2->str()[0])) {
7548                     // "type var ="   =>   "type var; var ="
7549                     const Token *varTok = type0->tokAt(typelen);
7550                     while (Token::Match(varTok, "%name%|*|& %name%|*|&"))
7551                         varTok = varTok->next();
7552                     if (!varTok)
7553                         syntaxError(tok2); // invalid code
7554                     TokenList::insertTokens(eq, varTok, 2);
7555                     eq->str(";");
7556                     eq->isSplittedVarDeclEq(true);
7557 
7558                     // "= x, "   =>   "= x; type "
7559                     if (tok2->str() == ",") {
7560                         tok2->str(";");
7561                         tok2->isSplittedVarDeclComma(true);
7562                         TokenList::insertTokens(tok2, type0, typelen);
7563                     }
7564                     break;
7565                 }
7566                 if (tok2)
7567                     tok2 = tok2->next();
7568             }
7569         }
7570         finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{");
7571     }
7572 }
7573 
simplifyStaticConst()7574 void Tokenizer::simplifyStaticConst()
7575 {
7576     // This function will simplify the token list so that the qualifiers "extern", "static"
7577     // and "const" appear in the same order as in the array below.
7578     const std::string qualifiers[] = {"extern", "static", "const"};
7579 
7580     // Move 'const' before all other qualifiers and types and then
7581     // move 'static' before all other qualifiers and types, ...
7582     for (Token *tok = list.front(); tok; tok = tok->next()) {
7583         bool continue2 = false;
7584         for (int i = 0; i < sizeof(qualifiers)/sizeof(qualifiers[0]); i++) {
7585 
7586             // Keep searching for a qualifier
7587             if (!tok->next() || tok->next()->str() != qualifiers[i])
7588                 continue;
7589 
7590             // Look backwards to find the beginning of the declaration
7591             Token* leftTok = tok;
7592             bool behindOther = false;
7593             for (; leftTok; leftTok = leftTok->previous()) {
7594                 for (int j = 0; j <= i; j++) {
7595                     if (leftTok->str() == qualifiers[j]) {
7596                         behindOther = true;
7597                         break;
7598                     }
7599                 }
7600                 if (behindOther)
7601                     break;
7602                 if (!Token::Match(leftTok, "%type%|struct|::") ||
7603                     (isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator|template"))) {
7604                     break;
7605                 }
7606             }
7607 
7608             // The token preceding the declaration should indicate the start of a declaration
7609             if (leftTok == tok)
7610                 continue;
7611 
7612             if (leftTok && !behindOther && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:")) {
7613                 continue2 = true;
7614                 break;
7615             }
7616 
7617             // Move the qualifier to the left-most position in the declaration
7618             tok->deleteNext();
7619             if (!leftTok) {
7620                 list.front()->insertToken(qualifiers[i], emptyString, false);
7621                 list.front()->swapWithNext();
7622                 tok = list.front();
7623             } else if (leftTok->next()) {
7624                 leftTok->next()->insertToken(qualifiers[i], emptyString, true);
7625                 tok = leftTok->next();
7626             } else {
7627                 leftTok->insertToken(qualifiers[i]);
7628                 tok = leftTok;
7629             }
7630         }
7631         if (continue2)
7632             continue;
7633     }
7634 }
7635 
simplifyIfAndWhileAssign()7636 void Tokenizer::simplifyIfAndWhileAssign()
7637 {
7638     for (Token *tok = list.front(); tok; tok = tok->next()) {
7639         if (!Token::Match(tok->next(), "if|while ("))
7640             continue;
7641 
7642         const Token* tokAt3 = tok->tokAt(3);
7643         if (!Token::Match(tokAt3, "!| (| %name% =") &&
7644             !Token::Match(tokAt3, "!| (| %name% . %name% =") &&
7645             !Token::Match(tokAt3, "0 == (| %name% =") &&
7646             !Token::Match(tokAt3, "0 == (| %name% . %name% ="))
7647             continue;
7648 
7649         // simplifying a "while(cond) { }" condition ?
7650         const bool iswhile(tok->next()->str() == "while");
7651 
7652         // simplifying a "do { } while(cond);" condition ?
7653         const bool isDoWhile = iswhile && Token::simpleMatch(tok, "}") && Token::simpleMatch(tok->link()->previous(), "do");
7654         Token* openBraceTok = tok->link();
7655 
7656         // delete the "if|while"
7657         tok->deleteNext();
7658 
7659         // Remember if there is a "!" or not. And delete it if there are.
7660         const bool isNot(Token::Match(tok->tokAt(2), "!|0"));
7661         if (isNot)
7662             tok->next()->deleteNext((tok->strAt(2) == "0") ? 2 : 1);
7663 
7664         // Delete parentheses.. and remember how many there are with
7665         // their links.
7666         std::stack<Token *> braces;
7667         while (tok->next()->str() == "(") {
7668             braces.push(tok->next()->link());
7669             tok->deleteNext();
7670         }
7671 
7672         // Skip the "%name% = ..."
7673         Token *tok2;
7674         for (tok2 = tok->next(); tok2; tok2 = tok2->next()) {
7675             if (tok2->str() == "(")
7676                 tok2 = tok2->link();
7677             else if (tok2->str() == ")")
7678                 break;
7679         }
7680 
7681         // Insert "; if|while ( .."
7682         tok2 = tok2->previous();
7683         if (tok->strAt(2) == ".") {
7684             tok2->insertToken(tok->strAt(3));
7685             tok2->next()->varId(tok->tokAt(3)->varId());
7686             tok2->insertToken(".");
7687         }
7688         tok2->insertToken(tok->next()->str());
7689         tok2->next()->varId(tok->next()->varId());
7690 
7691         while (!braces.empty()) {
7692             tok2->insertToken("(");
7693             Token::createMutualLinks(tok2->next(), braces.top());
7694             braces.pop();
7695         }
7696 
7697         if (isNot)
7698             tok2->next()->insertToken("!");
7699         tok2->insertToken(iswhile ? "while" : "if");
7700         if (isDoWhile) {
7701             tok2->insertToken("}");
7702             Token::createMutualLinks(openBraceTok, tok2->next());
7703         }
7704 
7705         tok2->insertToken(";");
7706 
7707         // delete the extra "}"
7708         if (isDoWhile)
7709             tok->deleteThis();
7710 
7711         // If it's a while loop, insert the assignment in the loop
7712         if (iswhile && !isDoWhile) {
7713             int indentlevel = 0;
7714             Token *tok3 = tok2;
7715 
7716             for (; tok3; tok3 = tok3->next()) {
7717                 if (tok3->str() == "{")
7718                     ++indentlevel;
7719                 else if (tok3->str() == "}") {
7720                     if (indentlevel <= 1)
7721                         break;
7722                     --indentlevel;
7723                 }
7724             }
7725 
7726             if (tok3 && indentlevel == 1) {
7727                 tok3 = tok3->previous();
7728                 std::stack<Token *> braces2;
7729 
7730                 for (tok2 = tok2->next(); tok2 && tok2 != tok; tok2 = tok2->previous()) {
7731                     tok3->insertToken(tok2->str());
7732                     Token *newTok = tok3->next();
7733 
7734                     newTok->varId(tok2->varId());
7735                     newTok->fileIndex(tok2->fileIndex());
7736                     newTok->linenr(tok2->linenr());
7737 
7738                     // link() new tokens manually
7739                     if (tok2->link()) {
7740                         if (Token::Match(newTok, "}|)|]|>")) {
7741                             braces2.push(newTok);
7742                         } else {
7743                             Token::createMutualLinks(newTok, braces2.top());
7744                             braces2.pop();
7745                         }
7746                     }
7747                 }
7748             }
7749         }
7750     }
7751 }
7752 
simplifyVariableMultipleAssign()7753 void Tokenizer::simplifyVariableMultipleAssign()
7754 {
7755     for (Token *tok = list.front(); tok; tok = tok->next()) {
7756         if (Token::Match(tok, "%name% = %name% = %num%|%name% ;")) {
7757             // skip intermediate assignments
7758             Token *tok2 = tok->previous();
7759             while (tok2 &&
7760                    tok2->str() == "=" &&
7761                    Token::Match(tok2->previous(), "%name%")) {
7762                 tok2 = tok2->tokAt(-2);
7763             }
7764 
7765             if (!tok2 || tok2->str() != ";") {
7766                 continue;
7767             }
7768 
7769             Token *stopAt = tok->tokAt(2);
7770             const Token *valueTok = stopAt->tokAt(2);
7771             const std::string& value(valueTok->str());
7772             tok2 = tok2->next();
7773 
7774             while (tok2 != stopAt) {
7775                 tok2->next()->insertToken(";");
7776                 tok2->next()->insertToken(value);
7777                 tok2 = tok2->tokAt(4);
7778             }
7779         }
7780     }
7781 }
7782 
7783 // Binary operators simplification map
7784 static const std::unordered_map<std::string, std::string> cAlternativeTokens = {
7785     std::make_pair("and", "&&")
7786     , std::make_pair("and_eq", "&=")
7787     , std::make_pair("bitand", "&")
7788     , std::make_pair("bitor", "|")
7789     , std::make_pair("not_eq", "!=")
7790     , std::make_pair("or", "||")
7791     , std::make_pair("or_eq", "|=")
7792     , std::make_pair("xor", "^")
7793     , std::make_pair("xor_eq", "^=")
7794 };
7795 
7796 // Simplify the C alternative tokens:
7797 //  and      =>     &&
7798 //  and_eq   =>     &=
7799 //  bitand   =>     &
7800 //  bitor    =>     |
7801 //  compl    =>     ~
7802 //  not      =>     !
7803 //  not_eq   =>     !=
7804 //  or       =>     ||
7805 //  or_eq    =>     |=
7806 //  xor      =>     ^
7807 //  xor_eq   =>     ^=
simplifyCAlternativeTokens()7808 bool Tokenizer::simplifyCAlternativeTokens()
7809 {
7810     /* executable scope level */
7811     int executableScopeLevel = 0;
7812 
7813     std::vector<Token *> alt;
7814     bool replaceAll = false;  // replace all or none
7815 
7816     for (Token *tok = list.front(); tok; tok = tok->next()) {
7817         if (tok->str() == ")") {
7818             if (const Token *end = isFunctionHead(tok, "{")) {
7819                 ++executableScopeLevel;
7820                 tok = const_cast<Token *>(end);
7821                 continue;
7822             }
7823         }
7824 
7825         if (tok->str() == "{") {
7826             if (executableScopeLevel > 0)
7827                 ++executableScopeLevel;
7828             continue;
7829         }
7830 
7831         if (tok->str() == "}") {
7832             if (executableScopeLevel > 0)
7833                 --executableScopeLevel;
7834             continue;
7835         }
7836 
7837         if (!tok->isName())
7838             continue;
7839 
7840         const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7841         if (cOpIt != cAlternativeTokens.end()) {
7842             alt.push_back(tok);
7843 
7844             // Is this a variable declaration..
7845             if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]"))
7846                 return false;
7847 
7848             if (!Token::Match(tok->previous(), "%name%|%num%|%char%|)|]|> %name% %name%|%num%|%char%|%op%|("))
7849                 continue;
7850             if (Token::Match(tok->next(), "%assign%|%or%|%oror%|&&|*|/|%|^") && !Token::Match(tok->previous(), "%num%|%char%|) %name% *"))
7851                 continue;
7852             if (executableScopeLevel == 0 && Token::Match(tok, "%name% (")) {
7853                 const Token *start = tok;
7854                 while (Token::Match(start, "%name%|*"))
7855                     start = start->previous();
7856                 if (!start || Token::Match(start, "[;}]"))
7857                     continue;
7858             }
7859             replaceAll = true;
7860         } else if (Token::Match(tok, "not|compl")) {
7861             alt.push_back(tok);
7862 
7863             if (Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) {
7864                 replaceAll = true;
7865                 continue;
7866             }
7867 
7868             // Don't simplify 'not p;' (in case 'not' is a type)
7869             if (!Token::Match(tok->next(), "%name%|(") ||
7870                 Token::Match(tok->previous(), "[;{}]") ||
7871                 (executableScopeLevel == 0U && tok->strAt(-1) == "("))
7872                 continue;
7873 
7874             replaceAll = true;
7875         }
7876     }
7877 
7878     if (!replaceAll)
7879         return false;
7880 
7881     for (Token *tok: alt) {
7882         const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7883         if (cOpIt != cAlternativeTokens.end())
7884             tok->str(cOpIt->second);
7885         else if (tok->str() == "not")
7886             tok->str("!");
7887         else
7888             tok->str("~");
7889     }
7890 
7891     return !alt.empty();
7892 }
7893 
7894 // int i(0); => int i; i = 0;
7895 // int i(0), j; => int i; i = 0; int j;
simplifyInitVar()7896 void Tokenizer::simplifyInitVar()
7897 {
7898     if (isC())
7899         return;
7900 
7901     for (Token *tok = list.front(); tok; tok = tok->next()) {
7902         if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]")))
7903             continue;
7904 
7905         if (tok->str() == "return")
7906             continue;
7907 
7908         if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ;")) {
7909             tok = initVar(tok);
7910         } else if (Token::Match(tok, "%type% *| %name% ( %type% (")) {
7911             const Token* tok2 = tok->tokAt(2);
7912             if (!tok2->link())
7913                 tok2 = tok2->next();
7914             if (!tok2->link() || (tok2->link()->strAt(1) == ";" && !Token::simpleMatch(tok2->linkAt(2), ") (")))
7915                 tok = initVar(tok);
7916         } else if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ,")) {
7917             Token *tok1 = tok->tokAt(5);
7918             while (tok1->str() != ",")
7919                 tok1 = tok1->next();
7920             tok1->str(";");
7921 
7922             const int numTokens = (Token::Match(tok, "class|struct|union")) ? 2U : 1U;
7923             TokenList::insertTokens(tok1, tok, numTokens);
7924             tok = initVar(tok);
7925         }
7926     }
7927 }
7928 
initVar(Token * tok)7929 Token * Tokenizer::initVar(Token * tok)
7930 {
7931     // call constructor of class => no simplification
7932     if (Token::Match(tok, "class|struct|union")) {
7933         if (tok->strAt(2) != "*")
7934             return tok;
7935 
7936         tok = tok->next();
7937     } else if (!tok->isStandardType() && tok->str() != "auto" && tok->next()->str() != "*")
7938         return tok;
7939 
7940     // goto variable name..
7941     tok = tok->next();
7942     if (tok->str() == "*")
7943         tok = tok->next();
7944 
7945     // sizeof is not a variable name..
7946     if (tok->str() == "sizeof")
7947         return tok;
7948 
7949     // check initializer..
7950     if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void")
7951         return tok;
7952     else if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0)
7953         return tok;
7954 
7955     // insert '; var ='
7956     tok->insertToken(";");
7957     tok->next()->insertToken(tok->str());
7958     tok->tokAt(2)->varId(tok->varId());
7959     tok = tok->tokAt(2);
7960     tok->insertToken("=");
7961 
7962     // goto '('..
7963     tok = tok->tokAt(2);
7964 
7965     // delete ')'
7966     tok->link()->deleteThis();
7967 
7968     // delete this
7969     tok->deleteThis();
7970 
7971     return tok;
7972 }
7973 
7974 
simplifyKnownVariables()7975 bool Tokenizer::simplifyKnownVariables()
7976 {
7977     // return value for function. Set to true if any simplifications are made
7978     bool ret = false;
7979 
7980     // constants..
7981     {
7982         std::unordered_map<int, std::string> constantValues;
7983         std::map<int, Token*> constantVars;
7984         std::unordered_map<int, std::list<Token*>> constantValueUsages;
7985         for (Token *tok = list.front(); tok; tok = tok->next()) {
7986             // Reference to variable
7987             if (Token::Match(tok, "%type%|* & %name% = %name% ;")) {
7988                 Token *start = tok->previous();
7989                 while (Token::Match(start,"%type%|*|&"))
7990                     start = start->previous();
7991                 if (!Token::Match(start,"[;{}]"))
7992                     continue;
7993                 const Token *reftok = tok->tokAt(2);
7994                 const Token *vartok = reftok->tokAt(2);
7995                 int level = 0;
7996                 for (Token *tok2 = tok->tokAt(6); tok2; tok2 = tok2->next()) {
7997                     if (tok2->str() == "{") {
7998                         ++level;
7999                     } else if (tok2->str() == "}") {
8000                         if (level <= 0)
8001                             break;
8002                         --level;
8003                     } else if (tok2->varId() == reftok->varId()) {
8004                         tok2->str(vartok->str());
8005                         tok2->varId(vartok->varId());
8006                     }
8007                 }
8008                 Token::eraseTokens(start, tok->tokAt(6));
8009                 tok = start;
8010             }
8011 
8012             if (tok->isName() && (Token::Match(tok, "static| const| static| %type% const| %name% = %any% ;") ||
8013                                   Token::Match(tok, "static| const| static| %type% const| %name% ( %any% ) ;"))) {
8014                 bool isconst = false;
8015                 for (const Token *tok2 = tok; (tok2->str() != "=") && (tok2->str() != "("); tok2 = tok2->next()) {
8016                     if (tok2->str() == "const") {
8017                         isconst = true;
8018                         break;
8019                     }
8020                 }
8021                 if (!isconst)
8022                     continue;
8023 
8024                 Token *tok1 = tok;
8025 
8026                 // start of statement
8027                 if (tok != list.front() && !Token::Match(tok->previous(),";|{|}|private:|protected:|public:"))
8028                     continue;
8029                 // skip "const" and "static"
8030                 while (Token::Match(tok, "const|static"))
8031                     tok = tok->next();
8032                 // pod type
8033                 if (!tok->isStandardType())
8034                     continue;
8035 
8036                 Token * const vartok = (tok->next() && tok->next()->str() == "const") ? tok->tokAt(2) : tok->next();
8037                 const Token * const valuetok = vartok->tokAt(2);
8038                 if (Token::Match(valuetok, "%bool%|%char%|%num%|%str% )| ;")) {
8039                     // record a constant value for this variable
8040                     constantValues[vartok->varId()] = valuetok->str();
8041                     constantVars[vartok->varId()] = tok1;
8042                 }
8043             } else if (tok->varId()) {
8044                 // find the entry for the known variable, if any.  Exclude the location where the variable is assigned with next == "="
8045                 if (constantValues.find(tok->varId()) != constantValues.end() && tok->next()->str() != "=") {
8046                     constantValueUsages[tok->varId()].push_back(tok);
8047                 }
8048             }
8049         }
8050 
8051         for (auto constantVar = constantVars.rbegin(); constantVar != constantVars.rend(); constantVar++) {
8052             bool referenceFound = false;
8053             std::list<Token*> usageList = constantValueUsages[constantVar->first];
8054             for (Token* usage : usageList) {
8055                 // check if any usages of each known variable are a reference
8056                 if (Token::Match(usage->tokAt(-2), "(|[|,|{|return|%op% & %varid%", constantVar->first)) {
8057                     referenceFound = true;
8058                     break;
8059                 }
8060             }
8061 
8062             if (!referenceFound) {
8063                 // replace all usages of non-referenced known variables with their value
8064                 for (Token* usage : usageList) {
8065                     usage->str(constantValues[constantVar->first]);
8066                 }
8067 
8068                 Token* startTok = constantVar->second;
8069                 // remove variable assignment statement
8070                 while (startTok->next()->str() != ";")
8071                     startTok->deleteNext();
8072                 startTok->deleteNext();
8073 
8074                 // #8579 if we can we want another token to delete startTok. if we can't it doesn't matter
8075                 if (startTok->previous()) {
8076                     startTok->previous()->deleteNext();
8077                 } else if (startTok->next()) {
8078                     startTok->next()->deletePrevious();
8079                 } else {
8080                     startTok->deleteThis();
8081                 }
8082                 startTok = nullptr;
8083 
8084                 constantVar->second = nullptr;
8085                 ret = true;
8086             }
8087         }
8088     }
8089 
8090     // variable id for local, float/double, array variables
8091     std::set<int> localvars;
8092     std::set<int> floatvars;
8093     std::set<int> arrays;
8094 
8095     // auto variables..
8096     for (Token *tok = list.front(); tok; tok = tok->next()) {
8097         // Search for a block of code
8098         Token * const start = const_cast<Token *>(startOfExecutableScope(tok));
8099         if (!start)
8100             continue;
8101 
8102         for (const Token *tok2 = start->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
8103             if (tok2->varId() != 0)
8104                 localvars.insert(tok2->varId());
8105         }
8106 
8107         tok = start;
8108         // parse the block of code..
8109         int indentlevel = 0;
8110         Token *tok2 = tok;
8111         for (; tok2; tok2 = tok2->next()) {
8112             if (Token::Match(tok2, "[;{}] %type% %name%|*")) {
8113                 bool isfloat = false;
8114                 bool ispointer = false;
8115                 const Token *vartok = tok2->next();
8116                 while (Token::Match(vartok, "%name%|* %name%|*")) {
8117                     if (Token::Match(vartok, "float|double"))
8118                         isfloat = true;
8119                     if (vartok->str() == "*")
8120                         ispointer = true;
8121                     vartok = vartok->next();
8122                 }
8123                 if (Token::Match(vartok, "%var% ;|["))
8124                     localvars.insert(vartok->varId());
8125                 if (isfloat && !ispointer && Token::Match(vartok, "%var% ;"))
8126                     floatvars.insert(vartok->varId());
8127                 if (Token::Match(vartok, "%var% ["))
8128                     arrays.insert(vartok->varId());
8129             }
8130 
8131             if (tok2->str() == "{")
8132                 ++indentlevel;
8133 
8134             else if (tok2->str() == "}") {
8135                 --indentlevel;
8136                 if (indentlevel <= 0)
8137                     break;
8138             }
8139 
8140             else if (Token::simpleMatch(tok2, "for ("))
8141                 tok2 = tok2->next()->link();
8142 
8143             else if (tok2->previous()->str() != "*" && !Token::Match(tok2->tokAt(-2), "* --|++") &&
8144                      (Token::Match(tok2, "%name% = %bool%|%char%|%num%|%str%|%name% ;") ||
8145                       Token::Match(tok2, "%name% [ %num%| ] = %str% ;") ||
8146                       Token::Match(tok2, "%name% = & %name% ;") ||
8147                       (Token::Match(tok2, "%name% = & %name% [ 0 ] ;") && arrays.find(tok2->tokAt(3)->varId()) != arrays.end()))) {
8148                 const int varid = tok2->varId();
8149                 if (varid == 0)
8150                     continue;
8151 
8152                 if (Token::Match(tok2->previous(), "[;{}]") && localvars.find(varid) == localvars.end())
8153                     continue;
8154 
8155                 // initialization of static variable => the value is not *known*
8156                 {
8157                     bool isstatic = false;
8158                     const Token *decl = tok2->previous();
8159                     while (decl && (decl->isName() || decl->str() == "*")) {
8160                         if (decl->str() == "static") {
8161                             isstatic = true;
8162                             break;
8163                         }
8164                         decl = decl->previous();
8165                     }
8166                     if (isstatic)
8167                         continue;
8168                 }
8169 
8170                 // skip loop variable
8171                 if (Token::Match(tok2->tokAt(-2), "(|:: %type%")) {
8172                     const Token *tok3 = tok2->previous();
8173                     do {
8174                         tok3 = tok3->tokAt(-2);
8175                     } while (Token::Match(tok3->previous(), ":: %type%"));
8176                     if (Token::Match(tok3->tokAt(-2), "for ( %type%"))
8177                         continue;
8178                 }
8179 
8180                 // struct name..
8181                 if (Token::Match(tok2, "%varid% = &| %varid%", tok2->varId()))
8182                     continue;
8183 
8184                 const std::string structname = Token::Match(tok2->tokAt(-3), "[;{}] %name% .") ?
8185                                                std::string(tok2->strAt(-2) + " .") :
8186                                                std::string();
8187 
8188                 const Token * const valueToken = tok2->tokAt(2);
8189 
8190                 std::string value;
8191                 nonneg int valueVarId = 0;
8192 
8193                 Token *tok3 = nullptr;
8194                 bool valueIsPointer = false;
8195 
8196                 // there could be a hang here if tok2 is moved back by the function calls below for some reason
8197                 if (Settings::terminated())
8198                     return false;
8199 
8200                 if (!simplifyKnownVariablesGetData(varid, &tok2, &tok3, value, valueVarId, valueIsPointer, floatvars.find(tok2->varId()) != floatvars.end()))
8201                     continue;
8202 
8203                 if (valueVarId > 0 && arrays.find(valueVarId) != arrays.end())
8204                     continue;
8205 
8206                 ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, structname, value, valueVarId, valueIsPointer, valueToken, indentlevel);
8207             }
8208 
8209             else if (Token::Match(tok2, "strcpy|sprintf ( %name% , %str% ) ;")) {
8210                 const int varid(tok2->tokAt(2)->varId());
8211                 if (varid == 0)
8212                     continue;
8213 
8214                 const Token * const valueToken = tok2->tokAt(4);
8215                 std::string value(valueToken->str());
8216                 if (tok2->str() == "sprintf") {
8217                     std::string::size_type n = 0;
8218                     while ((n = value.find("%%", n)) != std::string::npos) {
8219                         // Replace "%%" with "%" - erase the first '%' and continue past the second '%'
8220                         value.erase(n, 1);
8221                         ++n;
8222                     }
8223                 }
8224                 const int valueVarId(0);
8225                 const bool valueIsPointer(false);
8226                 Token *tok3 = tok2->tokAt(6);
8227                 ret |= simplifyKnownVariablesSimplify(&tok2, tok3, varid, emptyString, value, valueVarId, valueIsPointer, valueToken, indentlevel);
8228 
8229                 // there could be a hang here if tok2 was moved back by the function call above for some reason
8230                 if (Settings::terminated())
8231                     return false;
8232             }
8233         }
8234 
8235         if (tok2)
8236             tok = tok2->previous();
8237     }
8238 
8239     return ret;
8240 }
8241 
simplifyKnownVariablesGetData(nonneg int varid,Token ** _tok2,Token ** _tok3,std::string & value,nonneg int & valueVarId,bool & valueIsPointer,bool floatvar)8242 bool Tokenizer::simplifyKnownVariablesGetData(nonneg int varid, Token **_tok2, Token **_tok3, std::string &value, nonneg int &valueVarId, bool &valueIsPointer, bool floatvar)
8243 {
8244     Token *tok2 = *_tok2;
8245     Token *tok3 = nullptr;
8246 
8247     if (Token::simpleMatch(tok2->tokAt(-2), "for (")) {
8248         // only specific for loops is handled
8249         if (!Token::Match(tok2, "%varid% = %num% ; %varid% <|<= %num% ; ++| %varid% ++| ) {", varid))
8250             return false;
8251 
8252         // is there a "break" in the for loop?
8253         bool hasbreak = false;
8254         const Token* end4 = tok2->linkAt(-1)->linkAt(1);
8255         for (const Token *tok4 = tok2->previous()->link(); tok4 != end4; tok4 = tok4->next()) {
8256             if (tok4->str() == "break") {
8257                 hasbreak = true;
8258                 break;
8259             }
8260         }
8261         if (hasbreak)
8262             return false;
8263 
8264         // no break => the value of the counter value is known after the for loop..
8265         const Token* compareTok = tok2->tokAt(5);
8266         if (compareTok->str() == "<") {
8267             value = compareTok->next()->str();
8268             valueVarId = compareTok->next()->varId();
8269         } else
8270             value = MathLib::toString(MathLib::toLongNumber(compareTok->next()->str()) + 1);
8271 
8272         // Skip for-body..
8273         tok3 = tok2->previous()->link()->next()->link()->next();
8274     } else {
8275         value = tok2->strAt(2);
8276         valueVarId = tok2->tokAt(2)->varId();
8277         if (tok2->strAt(1) == "[") {
8278             value = tok2->next()->link()->strAt(2);
8279             valueVarId = 0;
8280         } else if (value == "&") {
8281             value = tok2->strAt(3);
8282             valueVarId = tok2->tokAt(3)->varId();
8283 
8284             // *ptr = &var; *ptr = 5;
8285             // equals
8286             // var = 5; not *var = 5;
8287             if (tok2->strAt(4) == ";")
8288                 valueIsPointer = true;
8289         }
8290 
8291         // Add a '.0' to a decimal value and therefore convert it to an floating point number.
8292         else if (MathLib::isDec(tok2->strAt(2)) && floatvar) {
8293             value += ".0";
8294         }
8295 
8296         // float variable: convert true/false to 1.0 / 0.0
8297         else if (tok2->tokAt(2)->isBoolean() && floatvar) {
8298             value = (value == "true") ? "1.0" : "0.0";
8299         }
8300 
8301         if (Token::simpleMatch(tok2->next(), "= &"))
8302             tok2 = tok2->tokAt(3);
8303 
8304         tok3 = tok2->next();
8305     }
8306     *_tok2 = tok2;
8307     *_tok3 = tok3;
8308     return true;
8309 }
8310 
simplifyKnownVariablesSimplify(Token ** tok2,Token * tok3,nonneg int varid,const std::string & structname,std::string & value,nonneg int valueVarId,bool valueIsPointer,const Token * const valueToken,int indentlevel) const8311 bool Tokenizer::simplifyKnownVariablesSimplify(Token **tok2, Token *tok3, nonneg int varid, const std::string &structname, std::string &value, nonneg int valueVarId, bool valueIsPointer, const Token * const valueToken, int indentlevel) const
8312 {
8313     const bool pointeralias(valueToken->isName() || Token::Match(valueToken, "& %name% ["));
8314     const bool varIsGlobal = (indentlevel == 0);
8315     const bool printDebug = mSettings->debugwarnings;
8316 
8317     if (mErrorLogger && !list.getFiles().empty())
8318         mErrorLogger->reportProgress(list.getFiles()[0], "Tokenize (simplifyKnownVariables)", tok3->progressValue());
8319 
8320     if (isMaxTime())
8321         return false;
8322 
8323     bool ret = false;
8324 
8325     Token* bailOutFromLoop = nullptr;
8326     int indentlevel3 = indentlevel;
8327     bool ret3 = false;
8328     for (; tok3; tok3 = tok3->next()) {
8329         if (tok3->str() == "{") {
8330             ++indentlevel3;
8331         } else if (tok3->str() == "}") {
8332             --indentlevel3;
8333             if (indentlevel3 < indentlevel) {
8334                 if (Token::Match((*tok2)->tokAt(-7), "%type% * %name% ; %name% = & %name% ;") &&
8335                     (*tok2)->strAt(-5) == (*tok2)->strAt(-3)) {
8336                     (*tok2) = (*tok2)->tokAt(-4);
8337                     Token::eraseTokens((*tok2), (*tok2)->tokAt(6));
8338                 }
8339                 break;
8340             }
8341         }
8342 
8343         // Stop if there is a pointer alias and a shadow variable is
8344         // declared in an inner scope (#3058)
8345         if (valueIsPointer && tok3->varId() > 0 &&
8346             tok3->previous() && (tok3->previous()->isName() || tok3->previous()->str() == "*") &&
8347             valueToken->str() == "&" &&
8348             valueToken->next() &&
8349             valueToken->next()->isName() &&
8350             tok3->str() == valueToken->next()->str() &&
8351             tok3->varId() > valueToken->next()->varId()) {
8352             // more checking if this is a variable declaration
8353             bool decl = true;
8354             for (const Token *tok4 = tok3->previous(); tok4; tok4 = tok4->previous()) {
8355                 if (Token::Match(tok4, "[;{}]"))
8356                     break;
8357 
8358                 else if (tok4->isName()) {
8359                     if (tok4->varId() > 0) {
8360                         decl = false;
8361                         break;
8362                     }
8363                 }
8364 
8365                 else if (!Token::Match(tok4, "[&*]")) {
8366                     decl = false;
8367                     break;
8368                 }
8369             }
8370             if (decl)
8371                 break;
8372         }
8373 
8374         // Stop if label is found
8375         if (Token::Match(tok3, "; %type% : ;"))
8376             break;
8377 
8378         // Stop if break/continue is found ..
8379         if (Token::Match(tok3, "break|continue"))
8380             break;
8381         if ((indentlevel3 > 1 || !Token::simpleMatch(Token::findsimplematch(tok3,";"), "; }")) && tok3->str() == "return")
8382             ret3 = true;
8383         if (ret3 && tok3->str() == ";")
8384             break;
8385 
8386         if (pointeralias && Token::Match(tok3, ("!!= " + value).c_str()))
8387             break;
8388 
8389         // Stop if a loop is found
8390         if (pointeralias && Token::Match(tok3, "do|for|while"))
8391             break;
8392 
8393         // Stop if unknown function call is seen and the variable is global: it might be
8394         // changed by the function call
8395         if (varIsGlobal && tok3->str() == ")" && tok3->link() &&
8396             Token::Match(tok3->link()->tokAt(-2), "[;{}] %name% (") &&
8397             !Token::Match(tok3->link()->previous(), "if|for|while|switch|BOOST_FOREACH"))
8398             break;
8399 
8400         // Stop if something like 'while (--var)' is found
8401         if (Token::Match(tok3, "for|while|do")) {
8402             const Token *endpar = tok3->next()->link();
8403             if (Token::simpleMatch(endpar, ") {"))
8404                 endpar = endpar->next()->link();
8405             bool bailout = false;
8406             for (const Token *tok4 = tok3; tok4 && tok4 != endpar; tok4 = tok4->next()) {
8407                 if (Token::Match(tok4, "++|-- %varid%", varid) ||
8408                     Token::Match(tok4, "%varid% ++|--|=", varid)) {
8409                     bailout = true;
8410                     break;
8411                 }
8412             }
8413             if (bailout)
8414                 break;
8415         }
8416 
8417         if (bailOutFromLoop) {
8418             // This could be a loop, skip it, but only if it doesn't contain
8419             // the variable we are checking for. If it contains the variable
8420             // we will bail out.
8421             if (tok3->varId() == varid) {
8422                 // Continue
8423                 //tok2 = bailOutFromLoop;
8424                 break;
8425             } else if (tok3 == bailOutFromLoop) {
8426                 // We have skipped the loop
8427                 bailOutFromLoop = nullptr;
8428                 continue;
8429             }
8430 
8431             continue;
8432         } else if (tok3->str() == "{" && tok3->previous()->str() == ")") {
8433             // There is a possible loop after the assignment. Try to skip it.
8434             if (tok3->previous()->link() &&
8435                 tok3->previous()->link()->strAt(-1) != "if")
8436                 bailOutFromLoop = tok3->link();
8437             continue;
8438         }
8439 
8440         // Variable used in realloc (see Ticket #1649)
8441         if (Token::Match(tok3, "%name% = realloc ( %name% ,") &&
8442             tok3->varId() == varid &&
8443             tok3->tokAt(4)->varId() == varid) {
8444             tok3->tokAt(4)->str(value);
8445             ret = true;
8446         }
8447 
8448         // condition "(|&&|%OROR% %varid% )|&&|%OROR%|;
8449         if (!Token::Match(tok3->previous(), "( %name% )") &&
8450             Token::Match(tok3->previous(), "&&|(|%oror% %varid% &&|%oror%|)|;", varid)) {
8451             tok3->str(value);
8452             tok3->varId(valueVarId);
8453             ret = true;
8454         }
8455 
8456         // parameter in function call..
8457         if (tok3->varId() == varid && Token::Match(tok3->previous(), "[(,] %name% [,)]")) {
8458             // If the parameter is passed by value then simplify it
8459             if (isFunctionParameterPassedByValue(tok3)) {
8460                 tok3->str(value);
8461                 tok3->varId(valueVarId);
8462                 ret = true;
8463             }
8464         }
8465 
8466         // Variable is used somehow in a non-defined pattern => bail out
8467         if (tok3->varId() == varid) {
8468             // This is a really generic bailout so let's try to avoid this.
8469             // There might be lots of false negatives.
8470             if (printDebug) {
8471                 // FIXME: Fix all the debug warnings for values and then
8472                 // remove this bailout
8473                 if (pointeralias)
8474                     break;
8475 
8476                 // suppress debug-warning when calling member function
8477                 if (Token::Match(tok3->next(), ". %name% ("))
8478                     break;
8479 
8480                 // suppress debug-warning when assignment
8481                 if (tok3->strAt(1) == "=")
8482                     break;
8483 
8484                 // taking address of variable..
8485                 if (Token::Match(tok3->tokAt(-2), "return|= & %name% ;"))
8486                     break;
8487 
8488                 // parameter in function call..
8489                 if (Token::Match(tok3->tokAt(-2), "%name% ( %name% ,|)") ||
8490                     Token::Match(tok3->previous(), ", %name% ,|)"))
8491                     break;
8492 
8493                 // conditional increment
8494                 if (Token::Match(tok3->tokAt(-3), ") { ++|--") ||
8495                     Token::Match(tok3->tokAt(-2), ") { %name% ++|--"))
8496                     break;
8497 
8498                 reportError(tok3, Severity::debug, "debug",
8499                             "simplifyKnownVariables: bailing out (variable="+tok3->str()+", value="+value+")");
8500             }
8501 
8502             break;
8503         }
8504 
8505         // Using the variable in condition..
8506         if (Token::Match(tok3->previous(), ("if ( " + structname + " %varid% %cop%|)").c_str(), varid) ||
8507             Token::Match(tok3, ("( " + structname + " %varid% %comp%").c_str(), varid) ||
8508             Token::Match(tok3, ("%comp%|!|= " + structname + " %varid% %cop%|)|;").c_str(), varid) ||
8509             Token::Match(tok3->previous(), "strlen|free ( %varid% )", varid)) {
8510             if (value[0] == '\"' && tok3->previous()->str() != "strlen") {
8511                 // bail out if value is a string unless if it's just given
8512                 // as parameter to strlen
8513                 break;
8514             }
8515             if (!structname.empty()) {
8516                 tok3->deleteNext(2);
8517             }
8518             if (Token::Match(valueToken, "& %name% ;")) {
8519                 tok3->insertToken("&");
8520                 tok3 = tok3->next();
8521             }
8522             tok3 = tok3->next();
8523             tok3->str(value);
8524             tok3->varId(valueVarId);
8525             ret = true;
8526         }
8527 
8528         // pointer alias used in condition..
8529         if (Token::Match(valueToken,"& %name% ;") && Token::Match(tok3, ("( * " + structname + " %varid% %cop%").c_str(), varid)) {
8530             tok3->deleteNext();
8531             if (!structname.empty())
8532                 tok3->deleteNext(2);
8533             tok3 = tok3->next();
8534             tok3->str(value);
8535             tok3->varId(valueVarId);
8536             ret = true;
8537         }
8538 
8539         // Delete pointer alias
8540         if (isCPP() && pointeralias && (tok3->str() == "delete") && tok3->next() &&
8541             (Token::Match(tok3->next(), "%varid% ;", varid) ||
8542              Token::Match(tok3->next(), "[ ] %varid%", varid))) {
8543             tok3 = (tok3->next()->str() == "[") ? tok3->tokAt(3) : tok3->next();
8544             tok3->str(value);
8545             tok3->varId(valueVarId);
8546             ret = true;
8547         }
8548 
8549         // Variable is used in function call..
8550         if (Token::Match(tok3, ("%name% ( " + structname + " %varid% ,").c_str(), varid)) {
8551             static const char * const functionName[] = {
8552                 // always simplify
8553                 "strcmp", "strdup",
8554                 // don't simplify buffer value
8555                 "memcmp","memcpy","memmove","memset","strcpy","strncmp","strncpy"
8556             };
8557             for (int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) {
8558                 if (valueVarId == 0U && i >= 2)
8559                     break;
8560                 if (tok3->str() == functionName[i]) {
8561                     Token *par1 = tok3->tokAt(2);
8562                     if (!structname.empty()) {
8563                         par1->deleteNext();
8564                         par1->deleteThis();
8565                     }
8566                     par1->str(value);
8567                     par1->varId(valueVarId);
8568                     break;
8569                 }
8570             }
8571         }
8572 
8573         // Variable is used as 2nd parameter in function call..
8574         if (Token::Match(tok3, ("%name% ( %any% , " + structname + " %varid% ,|)").c_str(), varid)) {
8575             static const char * const functionName[] = {
8576                 // always simplify
8577                 "strcmp","strcpy","strncmp","strncpy",
8578                 // don't simplify buffer value
8579                 "memcmp","memcpy","memmove"
8580             };
8581             for (int i = 0; i < (sizeof(functionName) / sizeof(*functionName)); ++i) {
8582                 if (valueVarId == 0U && i >= 4)
8583                     break;
8584                 if (tok3->str() == functionName[i]) {
8585                     Token *par = tok3->tokAt(4);
8586                     if (!structname.empty()) {
8587                         par->deleteNext();
8588                         par->deleteThis();
8589                     }
8590                     par->str(value);
8591                     par->varId(valueVarId);
8592                     break;
8593                 }
8594             }
8595         }
8596 
8597         // array usage
8598         if (value[0] != '\"' && Token::Match(tok3, ("[(,] " + structname + " %varid% [|%cop%").c_str(), varid)) {
8599             if (!structname.empty()) {
8600                 tok3->deleteNext(2);
8601             }
8602             tok3 = tok3->next();
8603             tok3->str(value);
8604             tok3->varId(valueVarId);
8605             ret = true;
8606         }
8607 
8608         // The >> operator is sometimes used to assign a variable in C++
8609         if (isCPP() && Token::Match(tok3, (">> " + structname + " %varid%").c_str(), varid)) {
8610             // bailout for such code:   ; std :: cin >> i ;
8611             const Token *prev = tok3->previous();
8612             while (prev && prev->str() != "return" && Token::Match(prev, "%name%|::|*"))
8613                 prev = prev->previous();
8614             if (Token::Match(prev, ";|{|}|>>"))
8615                 break;
8616         }
8617 
8618         // Variable is used in calculation..
8619         if (((tok3->previous()->varId() > 0) && Token::Match(tok3, ("& " + structname + " %varid%").c_str(), varid)) ||
8620             (Token::Match(tok3, ("[=+-*/%^|[] " + structname + " %varid% [=?+-*/%^|;])]").c_str(), varid) && !Token::Match(tok3, ("= " + structname + " %name% =").c_str())) ||
8621             Token::Match(tok3, ("[(=+-*/%^|[] " + structname + " %varid% <<|>>").c_str(), varid) ||
8622             Token::Match(tok3, ("<<|>> " + structname + " %varid% %cop%|;|]|)").c_str(), varid) ||
8623             Token::Match(tok3->previous(), ("[=+-*/%^|[] ( " + structname + " %varid% !!=").c_str(), varid)) {
8624             if (value[0] == '\"')
8625                 break;
8626             if (!structname.empty()) {
8627                 tok3->deleteNext(2);
8628                 ret = true;
8629             }
8630             tok3 = tok3->next();
8631             if (tok3->str() != value)
8632                 ret = true;
8633             tok3->str(value);
8634             tok3->varId(valueVarId);
8635             if (tok3->previous()->str() == "*" && (valueIsPointer || Token::Match(valueToken, "& %name% ;"))) {
8636                 tok3 = tok3->previous();
8637                 tok3->deleteThis();
8638                 ret = true;
8639             } else if (Token::Match(valueToken, "& %name% ;"))
8640                 tok3->insertToken("&", emptyString, true);
8641         }
8642 
8643         if (Token::simpleMatch(tok3, "= {")) {
8644             const Token* const end4 = tok3->linkAt(1);
8645             for (const Token *tok4 = tok3; tok4 != end4; tok4 = tok4->next()) {
8646                 if (Token::Match(tok4, "{|, %varid% ,|}", varid)) {
8647                     tok4->next()->str(value);
8648                     tok4->next()->varId(valueVarId);
8649                     ret = true;
8650                 }
8651             }
8652         }
8653 
8654         // Using the variable in for-condition..
8655         if (Token::simpleMatch(tok3, "for (")) {
8656             for (Token *tok4 = tok3->tokAt(2); tok4; tok4 = tok4->next()) {
8657                 if (Token::Match(tok4, "(|)"))
8658                     break;
8659 
8660                 // Replace variable used in condition..
8661                 if (Token::Match(tok4, "; %name% <|<=|!= %name% ; ++| %name% ++| )")) {
8662                     const Token *inctok = tok4->tokAt(5);
8663                     if (inctok->str() == "++")
8664                         inctok = inctok->next();
8665                     if (inctok->varId() == varid)
8666                         break;
8667 
8668                     if (tok4->next()->varId() == varid) {
8669                         tok4->next()->str(value);
8670                         tok4->next()->varId(valueVarId);
8671                         ret = true;
8672                     }
8673                     if (tok4->tokAt(3)->varId() == varid) {
8674                         tok4->tokAt(3)->str(value);
8675                         tok4->tokAt(3)->varId(valueVarId);
8676                         ret = true;
8677                     }
8678                 }
8679             }
8680         }
8681 
8682         if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "%varid% ++|--", varid) && MathLib::isInt(value)) {
8683             const std::string op(tok3->strAt(2));
8684             if (Token::Match(tok3, "[{};] %any% %any% ;")) {
8685                 tok3->deleteNext(3);
8686             } else {
8687                 tok3 = tok3->next();
8688                 tok3->str(value);
8689                 tok3->varId(valueVarId);
8690                 tok3->deleteNext();
8691             }
8692             value = MathLib::incdec(value, op);
8693             if (!Token::simpleMatch((*tok2)->tokAt(-2), "for (")) {
8694                 (*tok2)->tokAt(2)->str(value);
8695                 (*tok2)->tokAt(2)->varId(valueVarId);
8696             }
8697             ret = true;
8698         }
8699 
8700         if (indentlevel == indentlevel3 && Token::Match(tok3->next(), "++|-- %varid%", varid) && MathLib::isInt(value) &&
8701             !Token::Match(tok3->tokAt(3), "[.[]")) {
8702             value = MathLib::incdec(value, tok3->next()->str());
8703             (*tok2)->tokAt(2)->str(value);
8704             (*tok2)->tokAt(2)->varId(valueVarId);
8705             if (Token::Match(tok3, "[;{}] %any% %any% ;")) {
8706                 tok3->deleteNext(3);
8707             } else {
8708                 tok3->deleteNext();
8709                 tok3->next()->str(value);
8710                 tok3->next()->varId(valueVarId);
8711             }
8712             tok3 = tok3->next();
8713             ret = true;
8714         }
8715 
8716         // return variable..
8717         if (Token::Match(tok3, "return %varid% %any%", varid) &&
8718             valueToken->str() != "&" &&
8719             (tok3->tokAt(2)->isExtendedOp() || tok3->strAt(2) == ";") &&
8720             value[0] != '\"') {
8721             tok3->next()->str(value);
8722             tok3->next()->varId(valueVarId);
8723         }
8724 
8725         else if (pointeralias && Token::Match(tok3, "return * %varid% ;", varid) && value[0] != '\"') {
8726             tok3->deleteNext();
8727             tok3->next()->str(value);
8728             tok3->next()->varId(valueVarId);
8729         }
8730     }
8731     return ret;
8732 }
8733 
8734 
elseif()8735 void Tokenizer::elseif()
8736 {
8737     for (Token *tok = list.front(); tok; tok = tok->next()) {
8738         if (!Token::simpleMatch(tok, "else if"))
8739             continue;
8740 
8741         for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
8742             if (Token::Match(tok2, "(|{|["))
8743                 tok2 = tok2->link();
8744 
8745             if (Token::Match(tok2, "}|;")) {
8746                 if (tok2->next() && tok2->next()->str() != "else") {
8747                     tok->insertToken("{");
8748                     tok2->insertToken("}");
8749                     Token::createMutualLinks(tok->next(), tok2->next());
8750                     break;
8751                 }
8752             }
8753         }
8754     }
8755 }
8756 
8757 
simplifyIfSwitchForInit()8758 void Tokenizer::simplifyIfSwitchForInit()
8759 {
8760     if (!isCPP() || mSettings->standards.cpp < Standards::CPP17)
8761         return;
8762 
8763     const bool forInit = (mSettings->standards.cpp >= Standards::CPP20);
8764 
8765     for (Token *tok = list.front(); tok; tok = tok->next()) {
8766         if (!Token::Match(tok, "if|switch|for ("))
8767             continue;
8768 
8769         Token *semicolon = tok->tokAt(2);
8770         while (!Token::Match(semicolon, "[;)]")) {
8771             if (semicolon->str() == "(")
8772                 semicolon = semicolon->link();
8773             semicolon = semicolon->next();
8774         }
8775         if (semicolon->str() != ";")
8776             continue;
8777 
8778         if (tok->str() ==  "for") {
8779             if (!forInit)
8780                 continue;
8781 
8782             // Is it a for range..
8783             const Token *tok2 = semicolon->next();
8784             bool rangeFor = false;
8785             while (!Token::Match(tok2, "[;)]")) {
8786                 if (tok2->str() == "(")
8787                     tok2 = tok2->link();
8788                 else if (!rangeFor && tok2->str() == "?")
8789                     break;
8790                 else if (tok2->str() == ":")
8791                     rangeFor = true;
8792                 tok2 = tok2->next();
8793             }
8794             if (!rangeFor || tok2->str() != ")")
8795                 continue;
8796         }
8797 
8798         Token *endpar = tok->linkAt(1);
8799         if (!Token::simpleMatch(endpar, ") {"))
8800             continue;
8801 
8802         Token *endscope = endpar->linkAt(1);
8803         if (Token::simpleMatch(endscope, "} else {"))
8804             endscope = endscope->linkAt(2);
8805 
8806         // Simplify, the initialization expression is broken out..
8807         semicolon->insertToken(tok->str());
8808         semicolon->next()->insertToken("(");
8809         Token::createMutualLinks(semicolon->next()->next(), endpar);
8810         tok->deleteNext();
8811         tok->str("{");
8812         endscope->insertToken("}");
8813         Token::createMutualLinks(tok, endscope->next());
8814     }
8815 }
8816 
8817 
simplifyRedundantParentheses()8818 bool Tokenizer::simplifyRedundantParentheses()
8819 {
8820     bool ret = false;
8821     for (Token *tok = list.front(); tok; tok = tok->next()) {
8822         if (tok->str() != "(")
8823             continue;
8824 
8825         if (isCPP() && Token::simpleMatch(tok->previous(), "} (") &&
8826             Token::Match(tok->previous()->link()->previous(), "%name%|> {"))
8827             continue;
8828 
8829         if (Token::simpleMatch(tok, "( {"))
8830             continue;
8831 
8832         if (Token::Match(tok->link(), ") %num%")) {
8833             tok = tok->link();
8834             continue;
8835         }
8836 
8837         // Do not simplify if there is comma inside parentheses..
8838         if (Token::Match(tok->previous(), "%op% (") || Token::Match(tok->link(), ") %op%")) {
8839             bool innerComma = false;
8840             for (const Token *inner = tok->link()->previous(); inner != tok; inner = inner->previous()) {
8841                 if (inner->str() == ")")
8842                     inner = inner->link();
8843                 if (inner->str() == ",") {
8844                     innerComma = true;
8845                     break;
8846                 }
8847             }
8848             if (innerComma)
8849                 continue;
8850         }
8851 
8852         // !!operator = ( x ) ;
8853         if (tok->strAt(-2) != "operator" &&
8854             tok->previous() && tok->previous()->str() == "=" &&
8855             tok->next() && tok->next()->str() != "{" &&
8856             Token::simpleMatch(tok->link(), ") ;")) {
8857             tok->link()->deleteThis();
8858             tok->deleteThis();
8859             continue;
8860         }
8861 
8862         while (Token::simpleMatch(tok, "( (") &&
8863                tok->link() && tok->link()->previous() == tok->next()->link()) {
8864             // We have "(( *something* ))", remove the inner
8865             // parentheses
8866             tok->deleteNext();
8867             tok->link()->tokAt(-2)->deleteNext();
8868             ret = true;
8869         }
8870 
8871         if (isCPP() && Token::Match(tok->tokAt(-2), "[;{}=(] new (") && Token::Match(tok->link(), ") [;,{}[]")) {
8872             // Remove the parentheses in "new (type)" constructs
8873             tok->link()->deleteThis();
8874             tok->deleteThis();
8875             ret = true;
8876         }
8877 
8878         if (Token::Match(tok->previous(), "! ( %name% )")) {
8879             // Remove the parentheses
8880             tok->deleteThis();
8881             tok->deleteNext();
8882             ret = true;
8883         }
8884 
8885         if (Token::Match(tok->previous(), "[(,;{}] ( %name% ) .")) {
8886             // Remove the parentheses
8887             tok->deleteThis();
8888             tok->deleteNext();
8889             ret = true;
8890         }
8891 
8892         if (Token::Match(tok->previous(), "[(,;{}] ( %name% (") &&
8893             tok->link()->previous() == tok->linkAt(2)) {
8894             // We have "( func ( *something* ))", remove the outer
8895             // parentheses
8896             tok->link()->deleteThis();
8897             tok->deleteThis();
8898             ret = true;
8899         }
8900 
8901         if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %name% ) ;")) {
8902             // We have "( delete [| ]| var )", remove the outer
8903             // parentheses
8904             tok->link()->deleteThis();
8905             tok->deleteThis();
8906             ret = true;
8907         }
8908 
8909         if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
8910             Token::Match(tok->previous(), "delete|; (") &&
8911             (tok->previous()->str() != "delete" || tok->next()->varId() > 0) &&
8912             Token::Match(tok->link(), ") ;|,")) {
8913             tok->link()->deleteThis();
8914             tok->deleteThis();
8915             ret = true;
8916         }
8917 
8918         if (Token::Match(tok->previous(), "[(!*;{}] ( %name% )") &&
8919             (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]")) && !tok->next()->isStandardType()) {
8920             // We have "( var )", remove the parentheses
8921             tok->deleteThis();
8922             tok->deleteNext();
8923             ret = true;
8924         }
8925 
8926         while (Token::Match(tok->previous(), "[;{}[(,!*] ( %name% .")) {
8927             Token *tok2 = tok->tokAt(2);
8928             while (Token::Match(tok2, ". %name%")) {
8929                 tok2 = tok2->tokAt(2);
8930             }
8931             if (tok2 != tok->link())
8932                 break;
8933             // We have "( var . var . ... . var )", remove the parentheses
8934             tok = tok->previous();
8935             tok->deleteNext();
8936             tok2->deleteThis();
8937             ret = true;
8938         }
8939 
8940         if (Token::simpleMatch(tok->previous(), "? (") && Token::simpleMatch(tok->link(), ") :")) {
8941             const Token *tok2 = tok->next();
8942             while (tok2 && (Token::Match(tok2,"%bool%|%num%|%name%") || tok2->isArithmeticalOp()))
8943                 tok2 = tok2->next();
8944             if (tok2 && tok2->str() == ")") {
8945                 tok->link()->deleteThis();
8946                 tok->deleteThis();
8947                 ret = true;
8948                 continue;
8949             }
8950         }
8951 
8952         while (Token::Match(tok->previous(), "[{([,] ( !!{") &&
8953                Token::Match(tok->link(), ") [;,])]") &&
8954                !Token::simpleMatch(tok->tokAt(-2), "operator ,") && // Ticket #5709
8955                !Token::findsimplematch(tok, ",", tok->link())) {
8956             // We have "( ... )", remove the parentheses
8957             tok->link()->deleteThis();
8958             tok->deleteThis();
8959             ret = true;
8960         }
8961 
8962         if (Token::simpleMatch(tok->previous(), ", (") &&
8963             Token::simpleMatch(tok->link(), ") =")) {
8964             tok->link()->deleteThis();
8965             tok->deleteThis();
8966             ret = true;
8967         }
8968 
8969         // Simplify "!!operator !!%name%|)|]|>|>> ( %num%|%bool% ) %op%|;|,|)"
8970         if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") &&
8971             tok->strAt(-2) != "operator" &&
8972             tok->previous() &&
8973             !Token::Match(tok->previous(), "%name%|)|]") &&
8974             (!(isCPP() && Token::Match(tok->previous(),">|>>")))) {
8975             tok->link()->deleteThis();
8976             tok->deleteThis();
8977             ret = true;
8978         }
8979 
8980         if (Token::Match(tok->previous(), "*|& ( %name% )")) {
8981             // We may have a variable declaration looking like "type_name *(var_name)"
8982             Token *tok2 = tok->tokAt(-2);
8983             while (Token::Match(tok2, "%type%|static|const|extern") && tok2->str() != "operator") {
8984                 tok2 = tok2->previous();
8985             }
8986             if (tok2 && !Token::Match(tok2, "[;,{]")) {
8987                 // Not a variable declaration
8988             } else {
8989                 tok->deleteThis();
8990                 tok->deleteNext();
8991             }
8992         }
8993     }
8994     return ret;
8995 }
8996 
simplifyTypeIntrinsics()8997 void Tokenizer::simplifyTypeIntrinsics()
8998 {
8999     static const std::unordered_map<std::string, std::string> intrinsics = {
9000         { "__has_nothrow_assign", "has_nothrow_assign" },
9001         { "__has_nothrow_constructor", "has_nothrow_constructor" },
9002         { "__has_nothrow_copy", "has_nothrow_copy" },
9003         { "__has_trivial_assign", "has_trivial_assign" },
9004         { "__has_trivial_constructor", "has_trivial_constructor" },
9005         { "__has_trivial_copy", "has_trivial_copy" },
9006         { "__has_trivial_destructor", "has_trivial_destructor" },
9007         { "__has_virtual_destructor", "has_virtual_destructor" },
9008         { "__is_abstract", "is_abstract" },
9009         { "__is_aggregate", "is_aggregate" },
9010         { "__is_assignable", "is_assignable" },
9011         { "__is_base_of", "is_base_of" },
9012         { "__is_class", "is_class" },
9013         { "__is_constructible", "is_constructible" },
9014         { "__is_convertible_to", "is_convertible_to" },
9015         { "__is_destructible", "is_destructible" },
9016         { "__is_empty", "is_empty" },
9017         { "__is_enum", "is_enum" },
9018         { "__is_final", "is_final" },
9019         { "__is_nothrow_assignable", "is_nothrow_assignable" },
9020         { "__is_nothrow_constructible", "is_nothrow_constructible" },
9021         { "__is_nothrow_destructible", "is_nothrow_destructible" },
9022         { "__is_pod", "is_pod" },
9023         { "__is_polymorphic", "is_polymorphic" },
9024         { "__is_trivially_assignable", "is_trivially_assignable" },
9025         { "__is_trivially_constructible", "is_trivially_constructible" },
9026         { "__is_union", "is_union" },
9027     };
9028     for (Token *tok = list.front(); tok; tok = tok->next()) {
9029         if (!Token::Match(tok, "%name% ("))
9030             continue;
9031         auto p = intrinsics.find(tok->str());
9032         if (p == intrinsics.end())
9033             continue;
9034         Token * end = tok->next()->link();
9035         Token * prev = tok->previous();
9036         tok->str(p->second);
9037         prev->insertToken("::");
9038         prev->insertToken("std");
9039         tok->next()->str("<");
9040         end->str(">");
9041         end->insertToken("}");
9042         end->insertToken("{");
9043         Token::createMutualLinks(end->tokAt(1), end->tokAt(2));
9044     }
9045 }
9046 
simplifyCharAt()9047 void Tokenizer::simplifyCharAt()
9048 {
9049     // Replace "string"[0] with 's'
9050     for (Token *tok = list.front(); tok; tok = tok->next()) {
9051         if (Token::Match(tok, "%str% [ %num% ]")) {
9052             const MathLib::bigint index = MathLib::toLongNumber(tok->strAt(2));
9053             // Check within range
9054             if (index >= 0 && index <= Token::getStrLength(tok)) {
9055                 tok->str("'" + Token::getCharAt(tok, index) + "'");
9056                 tok->deleteNext(3);
9057             }
9058         }
9059     }
9060 }
9061 
simplifyReference()9062 void Tokenizer::simplifyReference()
9063 {
9064     if (isC())
9065         return;
9066 
9067     for (Token *tok = list.front(); tok; tok = tok->next()) {
9068         // starting executable scope..
9069         Token *start = const_cast<Token *>(startOfExecutableScope(tok));
9070         if (start) {
9071             tok = start;
9072             // replace references in this scope..
9073             Token * const end = tok->link();
9074             for (Token *tok2 = tok; tok2 && tok2 != end; tok2 = tok2->next()) {
9075                 // found a reference..
9076                 if (Token::Match(tok2, "[;{}] %type% & %name% (|= %name% )| ;")) {
9077                     const int refId = tok2->tokAt(3)->varId();
9078                     if (!refId)
9079                         continue;
9080 
9081                     // replace reference in the code..
9082                     for (Token *tok3 = tok2->tokAt(7); tok3 && tok3 != end; tok3 = tok3->next()) {
9083                         if (tok3->varId() == refId) {
9084                             tok3->str(tok2->strAt(5));
9085                             tok3->varId(tok2->tokAt(5)->varId());
9086                         }
9087                     }
9088 
9089                     tok2->deleteNext(6+(tok2->strAt(6)==")" ? 1 : 0));
9090                 }
9091             }
9092             tok = end;
9093         }
9094     }
9095 }
9096 
simplifyCalculations()9097 bool Tokenizer::simplifyCalculations()
9098 {
9099     return mTemplateSimplifier->simplifyCalculations(nullptr, nullptr, false);
9100 }
9101 
simplifyOffsetPointerDereference()9102 void Tokenizer::simplifyOffsetPointerDereference()
9103 {
9104     // Replace "*(str + num)" => "str[num]" and
9105     // Replace "*(str - num)" => "str[-num]"
9106     for (Token *tok = list.front(); tok; tok = tok->next()) {
9107         if (!tok->isName() && !tok->isLiteral()
9108             && !Token::Match(tok, "]|)|++|--")
9109             && Token::Match(tok->next(), "* ( %name% +|- %num%|%name% )")) {
9110 
9111             // remove '* ('
9112             tok->deleteNext(2);
9113 
9114             // '+'->'['
9115             tok = tok->tokAt(2);
9116             Token* const openBraceTok = tok;
9117             const bool isNegativeIndex = (tok->str() == "-");
9118             tok->str("[");
9119 
9120             // Insert a "-" in front of the number or variable
9121             if (isNegativeIndex) {
9122                 if (tok->next()->isName()) {
9123                     tok->insertToken("-");
9124                     tok = tok->next();
9125                 } else
9126                     tok->next()->str(std::string("-") + tok->next()->str());
9127             }
9128 
9129             tok = tok->tokAt(2);
9130             tok->str("]");
9131             Token::createMutualLinks(openBraceTok, tok);
9132         }
9133     }
9134 }
9135 
simplifyOffsetPointerReference()9136 void Tokenizer::simplifyOffsetPointerReference()
9137 {
9138     std::set<int> pod;
9139     for (const Token *tok = list.front(); tok; tok = tok->next()) {
9140         if (tok->isStandardType()) {
9141             tok = tok->next();
9142             while (tok && (tok->str() == "*" || tok->isName())) {
9143                 if (tok->varId() > 0) {
9144                     pod.insert(tok->varId());
9145                     break;
9146                 }
9147                 tok = tok->next();
9148             }
9149             if (!tok)
9150                 break;
9151         }
9152     }
9153 
9154     for (Token *tok = list.front(); tok; tok = tok->next()) {
9155         if (!Token::Match(tok, "%num%|%name%|]|)") &&
9156             (Token::Match(tok->next(), "& %name% [ %num%|%name% ] !!["))) {
9157             tok = tok->next();
9158 
9159             if (tok->next()->varId()) {
9160                 if (pod.find(tok->next()->varId()) == pod.end()) {
9161                     tok = tok->tokAt(5);
9162                     if (!tok)
9163                         syntaxError(tok);
9164                     continue;
9165                 }
9166             }
9167 
9168             // '&' => '('
9169             tok->str("(");
9170 
9171             tok = tok->next();
9172             // '[' => '+'
9173             tok->deleteNext();
9174             tok->insertToken("+");
9175 
9176             tok = tok->tokAt(3);
9177             //remove ']'
9178             tok->str(")");
9179             Token::createMutualLinks(tok->tokAt(-4), tok);
9180         }
9181     }
9182 }
9183 
simplifyNestedStrcat()9184 void Tokenizer::simplifyNestedStrcat()
9185 {
9186     for (Token *tok = list.front(); tok; tok = tok->next()) {
9187         if (!Token::Match(tok, "[;{}] strcat ( strcat (")) {
9188             continue;
9189         }
9190 
9191         // find inner strcat call
9192         Token *tok2 = tok->tokAt(3);
9193         while (Token::simpleMatch(tok2, "strcat ( strcat"))
9194             tok2 = tok2->tokAt(2);
9195 
9196         if (tok2->strAt(3) != ",")
9197             continue;
9198 
9199         // If we have this code:
9200         //   strcat(strcat(dst, foo), bar);
9201         // We move this part of code before all strcat() calls: strcat(dst, foo)
9202         // And place "dst" token where the code was.
9203         Token *prevTok = tok2->previous();
9204 
9205         // Move tokens to new place
9206         Token::move(tok2, tok2->next()->link(), tok);
9207         tok = tok2->next()->link();
9208 
9209         // Insert the "dst" token
9210         prevTok->insertToken(tok2->strAt(2));
9211         prevTok->next()->varId(tok2->tokAt(2)->varId());
9212 
9213         // Insert semicolon after the moved strcat()
9214         tok->insertToken(";");
9215     }
9216 }
9217 
9218 // Check if this statement is a duplicate definition.  A duplicate
9219 // definition will hide the enumerator within it's scope so just
9220 // skip the entire scope of the duplicate.
duplicateDefinition(Token ** tokPtr)9221 bool Tokenizer::duplicateDefinition(Token ** tokPtr)
9222 {
9223     // check for an end of definition
9224     const Token * tok = *tokPtr;
9225     if (tok && Token::Match(tok->next(), ";|,|[|=|)|>")) {
9226         const Token * end = tok->next();
9227 
9228         if (end->str() == "[") {
9229             end = end->link()->next();
9230         } else if (end->str() == ",") {
9231             // check for function argument
9232             if (Token::Match(tok->previous(), "(|,"))
9233                 return false;
9234 
9235             // find end of definition
9236             int level = 0;
9237             while (end->next() && (!Token::Match(end->next(), ";|)|>") ||
9238                                    (end->next()->str() == ")" && level == 0))) {
9239                 if (end->next()->str() == "(")
9240                     ++level;
9241                 else if (end->next()->str() == ")")
9242                     --level;
9243 
9244                 end = end->next();
9245             }
9246         } else if (end->str() == ")") {
9247             // check for function argument
9248             if (tok->previous()->str() == ",")
9249                 return false;
9250         }
9251 
9252         if (end) {
9253             if (Token::simpleMatch(end, ") {")) { // function parameter ?
9254                 // make sure it's not a conditional
9255                 if (Token::Match(end->link()->previous(), "if|for|while|switch|BOOST_FOREACH") || Token::Match(end->link()->tokAt(-2), ":|,"))
9256                     return false;
9257 
9258                 // look backwards
9259                 if (tok->previous()->str() == "enum" ||
9260                     (Token::Match(tok->previous(), "%type%") &&
9261                      tok->previous()->str() != "return") ||
9262                     Token::Match(tok->tokAt(-2), "%type% &|*")) {
9263                     // duplicate definition so skip entire function
9264                     *tokPtr = end->next()->link();
9265                     return true;
9266                 }
9267             } else if (end->str() == ">") { // template parameter ?
9268                 // look backwards
9269                 if (tok->previous()->str() == "enum" ||
9270                     (Token::Match(tok->previous(), "%type%") &&
9271                      tok->previous()->str() != "return")) {
9272                     // duplicate definition so skip entire template
9273                     while (end && end->str() != "{")
9274                         end = end->next();
9275                     if (end) {
9276                         *tokPtr = end->link();
9277                         return true;
9278                     }
9279                 }
9280             } else {
9281                 if (Token::Match(tok->previous(), "enum|,"))
9282                     return true;
9283                 else if (Token::Match(tok->previous(), "%type%")) {
9284                     // look backwards
9285                     const Token *back = tok;
9286                     while (back && back->isName())
9287                         back = back->previous();
9288                     if (!back || (Token::Match(back, "[(,;{}]") && !Token::Match(back->next(),"return|throw")))
9289                         return true;
9290                 }
9291             }
9292         }
9293     }
9294     return false;
9295 }
9296 
9297 static const std::set<std::string> stdFunctionsPresentInC = {
9298     "strcat",
9299     "strcpy",
9300     "strncat",
9301     "strncpy",
9302     "free",
9303     "malloc",
9304     "strdup"
9305 };
9306 
simplifyStd()9307 void Tokenizer::simplifyStd()
9308 {
9309     if (isC())
9310         return;
9311 
9312     for (Token *tok = list.front(); tok; tok = tok->next()) {
9313         if (tok->str() != "std")
9314             continue;
9315 
9316         if (Token::Match(tok->previous(), "[(,{};] std :: %name% (") &&
9317             stdFunctionsPresentInC.find(tok->strAt(2)) != stdFunctionsPresentInC.end()) {
9318             tok->deleteNext();
9319             tok->deleteThis();
9320         }
9321     }
9322 }
9323 
9324 //---------------------------------------------------------------------------
9325 // Helper functions for handling the tokens list
9326 //---------------------------------------------------------------------------
9327 
9328 //---------------------------------------------------------------------------
9329 
isScopeNoReturn(const Token * endScopeToken,bool * unknown) const9330 bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
9331 {
9332     std::string unknownFunc;
9333     const bool ret = mSettings->library.isScopeNoReturn(endScopeToken,&unknownFunc);
9334     if (!unknownFunc.empty() && mSettings->summaryReturn.find(unknownFunc) != mSettings->summaryReturn.end()) {
9335         return false;
9336     }
9337     if (unknown)
9338         *unknown = !unknownFunc.empty();
9339     if (!unknownFunc.empty() && mSettings->checkLibrary && mSettings->severity.isEnabled(Severity::information)) {
9340         // Is function global?
9341         bool globalFunction = true;
9342         if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
9343             const Token * const ftok = endScopeToken->linkAt(-2)->previous();
9344             if (ftok &&
9345                 ftok->isName() &&
9346                 ftok->function() &&
9347                 ftok->function()->nestedIn &&
9348                 ftok->function()->nestedIn->type != Scope::eGlobal) {
9349                 globalFunction = false;
9350             }
9351         }
9352 
9353         // don't warn for nonglobal functions (class methods, functions hidden in namespaces) since they can't be configured yet
9354         // FIXME: when methods and namespaces can be configured properly, remove the "globalFunction" check
9355         if (globalFunction) {
9356             reportError(endScopeToken->previous(),
9357                         Severity::information,
9358                         "checkLibraryNoReturn",
9359                         "--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
9360         }
9361     }
9362     return ret;
9363 }
9364 
9365 //---------------------------------------------------------------------------
9366 
isFunctionParameterPassedByValue(const Token * fpar) const9367 bool Tokenizer::isFunctionParameterPassedByValue(const Token *fpar) const
9368 {
9369     // TODO: If symbol database is available, use it.
9370     const Token *ftok;
9371 
9372     // Look at function call, what parameter number is it?
9373     int parameter = 1;
9374     for (ftok = fpar->previous(); ftok; ftok = ftok->previous()) {
9375         if (ftok->str() == "(")
9376             break;
9377         else if (ftok->str() == ")")
9378             ftok = ftok->link();
9379         else if (ftok->str() == ",")
9380             ++parameter;
9381         else if (Token::Match(ftok, "[;{}]"))
9382             break;
9383     }
9384 
9385     // Is this a function call?
9386     if (ftok && Token::Match(ftok->tokAt(-2), "[;{}=] %name% (")) {
9387         const std::string& functionName(ftok->previous()->str());
9388 
9389         if (functionName == "return")
9390             return true;
9391 
9392         // Locate function declaration..
9393         for (const Token *tok = tokens(); tok; tok = tok->next()) {
9394             if (tok->str() == "{")
9395                 tok = tok->link();
9396             else if (Token::Match(tok, "%type% (") && tok->str() == functionName) {
9397                 // Goto parameter
9398                 tok = tok->tokAt(2);
9399                 int par = 1;
9400                 while (tok && par < parameter) {
9401                     if (tok->str() == ")")
9402                         break;
9403                     if (tok->str() == ",")
9404                         ++par;
9405                     tok = tok->next();
9406                 }
9407                 if (!tok)
9408                     return false;
9409 
9410                 // If parameter was found, determine if it's passed by value
9411                 if (par == parameter) {
9412                     bool knowntype = false;
9413                     while (tok && tok->isName()) {
9414                         knowntype |= tok->isStandardType();
9415                         knowntype |= (tok->str() == "struct");
9416                         tok = tok->next();
9417                     }
9418                     if (!tok || !knowntype)
9419                         return false;
9420                     if (tok->str() != "," && tok->str() != ")")
9421                         return false;
9422                     return true;
9423                 }
9424             }
9425         }
9426     }
9427     return false;
9428 }
9429 
9430 //---------------------------------------------------------------------------
9431 
eraseDeadCode(Token * begin,const Token * end)9432 void Tokenizer::eraseDeadCode(Token *begin, const Token *end)
9433 {
9434     if (!begin)
9435         return;
9436     const bool isgoto = Token::Match(begin->tokAt(-2), "goto %name% ;");
9437     int indentlevel = 1;
9438     int indentcase = 0;
9439     int indentswitch = 0;
9440     int indentlabel = 0;
9441     int roundbraces = 0;
9442     int indentcheck = 0;
9443     std::vector<int> switchindents;
9444     bool checklabel = false;
9445     Token *tok = begin;
9446     Token *tokcheck = nullptr;
9447     while (tok->next() && tok->next() != end) {
9448         if (tok->next()->str() == "(") {
9449             ++roundbraces;
9450             tok->deleteNext();
9451             continue;
9452         } else if (tok->next()->str() == ")") {
9453             if (!roundbraces)
9454                 break;  //too many ending round parentheses
9455             --roundbraces;
9456             tok->deleteNext();
9457             continue;
9458         }
9459 
9460         if (roundbraces) {
9461             tok->deleteNext();
9462             continue;
9463         }
9464 
9465         if (Token::Match(tok, "[{};] switch (")) {
9466             if (!checklabel) {
9467                 if (!indentlabel) {
9468                     //remove 'switch ( ... )'
9469                     Token::eraseTokens(tok, tok->linkAt(2)->next());
9470                 } else {
9471                     tok = tok->linkAt(2);
9472                 }
9473                 if (tok->next()->str() == "{") {
9474                     ++indentswitch;
9475                     indentcase = indentlevel + 1;
9476                     switchindents.push_back(indentcase);
9477                 }
9478             } else {
9479                 tok = tok->linkAt(2);
9480                 if (Token::simpleMatch(tok, ") {")) {
9481                     ++indentswitch;
9482                     indentcase = indentlevel + 1;
9483                     switchindents.push_back(indentcase);
9484                 }
9485             }
9486         } else if (tok->next()->str() == "{") {
9487             ++indentlevel;
9488             if (!checklabel) {
9489                 checklabel = true;
9490                 tokcheck = tok;
9491                 indentcheck = indentlevel;
9492                 indentlabel = 0;
9493             }
9494             tok = tok->next();
9495         } else if (tok->next()->str() == "}") {
9496             --indentlevel;
9497             if (!indentlevel)
9498                 break;
9499 
9500             if (!checklabel) {
9501                 tok->deleteNext();
9502             } else {
9503                 if (indentswitch && indentlevel == indentcase)
9504                     --indentlevel;
9505                 if (indentlevel < indentcheck) {
9506                     const Token *end2 = tok->next();
9507                     tok = end2->link()->previous();  //return to initial '{'
9508                     if (indentswitch && Token::simpleMatch(tok, ") {") && Token::Match(tok->link()->tokAt(-2), "[{};] switch ("))
9509                         tok = tok->link()->tokAt(-2);       //remove also 'switch ( ... )'
9510                     Token::eraseTokens(tok, end2->next());
9511                     checklabel = false;
9512                     tokcheck = nullptr;
9513                     indentcheck = 0;
9514                 } else {
9515                     tok = tok->next();
9516                 }
9517             }
9518             if (indentswitch && indentlevel <= indentcase) {
9519                 --indentswitch;
9520                 switchindents.pop_back();
9521                 if (!indentswitch)
9522                     indentcase = 0;
9523                 else
9524                     indentcase = switchindents[indentswitch-1];
9525             }
9526         } else if (Token::Match(tok, "[{};:] case")) {
9527             const Token *tok2 = Token::findsimplematch(tok->next(), ": ;", end);
9528             if (!tok2) {
9529                 tok->deleteNext();
9530                 continue;
9531             }
9532             if (indentlevel == 1)
9533                 break;      //it seems like the function was called inside a case-default block.
9534             if (indentlevel == indentcase)
9535                 ++indentlevel;
9536             tok2 = tok2->next();
9537             if (!checklabel || !indentswitch) {
9538                 Token::eraseTokens(tok, tok2->next());
9539             } else {
9540                 tok = const_cast<Token *>(tok2);
9541             }
9542         } else if (Token::Match(tok, "[{};] default : ;")) {
9543             if (indentlevel == 1)
9544                 break;      //it seems like the function was called inside a case-default block.
9545             if (indentlevel == indentcase)
9546                 ++indentlevel;
9547             if (!checklabel || !indentswitch) {
9548                 tok->deleteNext(3);
9549             } else {
9550                 tok = tok->tokAt(3);
9551             }
9552         } else if (Token::Match(tok, "[{};] %name% : ;") && tok->next()->str() != "default") {
9553             if (checklabel) {
9554                 indentlabel = indentlevel;
9555                 tok = tokcheck->next();
9556                 checklabel = false;
9557                 indentlevel = indentcheck;
9558             } else {
9559                 if (indentswitch) {
9560                     //Before stopping the function, since the 'switch()'
9561                     //instruction is removed, there's no sense to keep the
9562                     //case instructions. Remove them, if there are any.
9563                     Token *tok2 = tok->tokAt(3);
9564                     int indentlevel2 = indentlevel;
9565                     while (tok2->next() && tok2->next() != end) {
9566                         if (Token::Match(tok2->next(), "{|[|(")) {
9567                             tok2 = tok2->next()->link();
9568                         } else if (Token::Match(tok2, "[{};:] case")) {
9569                             const Token *tok3 = Token::findsimplematch(tok2->next(), ": ;", end);
9570                             if (!tok3) {
9571                                 tok2 = tok2->next();
9572                                 continue;
9573                             }
9574                             Token::eraseTokens(tok2, tok3->next());
9575                         } else if (Token::Match(tok2, "[{};] default : ;")) {
9576                             tok2->deleteNext(3);
9577                         } else if (tok2->next()->str() == "}") {
9578                             --indentlevel2;
9579                             if (indentlevel2 <= indentcase)
9580                                 break;
9581                             tok2 = tok2->next();
9582                         } else {
9583                             tok2 = tok2->next();
9584                         }
9585                     }
9586                 }
9587                 break;  //stop removing tokens, we arrived to the label.
9588             }
9589         } else if (isgoto && Token::Match(tok, "[{};] do|while|for|BOOST_FOREACH")) {
9590             //it's possible that code inside loop is not dead,
9591             //because of the possible presence of the label pointed by 'goto'
9592             const Token *start = tok->tokAt(2);
9593             if (start && start->str() == "(")
9594                 start = start->link()->next();
9595             if (start && start->str() == "{") {
9596                 std::string labelpattern = "[{};] " + begin->previous()->str() + " : ;";
9597                 bool simplify = true;
9598                 for (Token *tok2 = start->next(); tok2 != start->link(); tok2 = tok2->next()) {
9599                     if (Token::Match(tok2, labelpattern.c_str())) {
9600                         simplify = false;
9601                         break;
9602                     }
9603                 }
9604                 //bailout for now
9605                 if (!simplify)
9606                     break;
9607             }
9608             tok->deleteNext();
9609         } else {
9610             // no need to keep the other strings, remove them.
9611             if (tok->strAt(1) == "while") {
9612                 if (tok->str() == "}" && tok->link()->strAt(-1) == "do")
9613                     tok->link()->previous()->deleteThis();
9614             }
9615             tok->deleteNext();
9616         }
9617     }
9618 }
9619 
9620 //---------------------------------------------------------------------------
9621 
syntaxError(const Token * tok,const std::string & code) const9622 void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
9623 {
9624     printDebugOutput(0);
9625     throw InternalError(tok, code.empty() ? "syntax error" : "syntax error: " + code, InternalError::SYNTAX);
9626 }
9627 
unmatchedToken(const Token * tok) const9628 void Tokenizer::unmatchedToken(const Token *tok) const
9629 {
9630     printDebugOutput(0);
9631     throw InternalError(tok,
9632                         "Unmatched '" + tok->str() + "'. Configuration: '" + mConfiguration + "'.",
9633                         InternalError::SYNTAX);
9634 }
9635 
syntaxErrorC(const Token * tok,const std::string & what) const9636 void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
9637 {
9638     printDebugOutput(0);
9639     throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
9640 }
9641 
unknownMacroError(const Token * tok1) const9642 void Tokenizer::unknownMacroError(const Token *tok1) const
9643 {
9644     printDebugOutput(0);
9645     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);
9646 }
9647 
unhandled_macro_class_x_y(const Token * tok) const9648 void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const
9649 {
9650     reportError(tok,
9651                 Severity::information,
9652                 "class_X_Y",
9653                 "The code '" +
9654                 tok->str() + " " +
9655                 tok->strAt(1) + " " +
9656                 tok->strAt(2) + " " +
9657                 tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
9658 }
9659 
macroWithSemicolonError(const Token * tok,const std::string & macroName) const9660 void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string &macroName) const
9661 {
9662     reportError(tok,
9663                 Severity::information,
9664                 "macroWithSemicolon",
9665                 "Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
9666 }
9667 
cppcheckError(const Token * tok) const9668 void Tokenizer::cppcheckError(const Token *tok) const
9669 {
9670     printDebugOutput(0);
9671     throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL);
9672 }
9673 
unhandledCharLiteral(const Token * tok,const std::string & msg) const9674 void Tokenizer::unhandledCharLiteral(const Token *tok, const std::string& msg) const
9675 {
9676     std::string s = tok ? (" " + tok->str()) : "";
9677     for (int i = 0; i < s.size(); ++i) {
9678         if ((unsigned char)s[i] >= 0x80)
9679             s.clear();
9680     }
9681 
9682     reportError(tok,
9683                 Severity::portability,
9684                 "nonStandardCharLiteral",
9685                 "Non-standard character literal" + s + ". " + msg);
9686 }
9687 
9688 /**
9689  * Helper function to check whether number is equal to integer constant X
9690  * or floating point pattern X.0
9691  * @param s the string to check
9692  * @param intConstant the integer constant to check against
9693  * @param floatConstant the string with stringified float constant to check against
9694  * @return true in case s is equal to X or X.0 and false otherwise.
9695  */
isNumberOneOf(const std::string & s,const MathLib::bigint & intConstant,const char * floatConstant)9696 static bool isNumberOneOf(const std::string &s, const MathLib::bigint& intConstant, const char* floatConstant)
9697 {
9698     if (MathLib::isInt(s)) {
9699         if (MathLib::toLongNumber(s) == intConstant)
9700             return true;
9701     } else if (MathLib::isFloat(s)) {
9702         if (MathLib::toString(MathLib::toDoubleNumber(s)) == floatConstant)
9703             return true;
9704     }
9705     return false;
9706 }
9707 
9708 // ------------------------------------------------------------------------
9709 // Helper function to check whether number is zero (0 or 0.0 or 0E+0) or not?
9710 // @param s the string to check
9711 // @return true in case s is zero and false otherwise.
9712 // ------------------------------------------------------------------------
isZeroNumber(const std::string & s)9713 bool Tokenizer::isZeroNumber(const std::string &s)
9714 {
9715     return isNumberOneOf(s, 0L, "0.0");
9716 }
9717 
9718 // ------------------------------------------------------------------------
9719 // Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
9720 // @param s the string to check
9721 // @return true in case s is one and false otherwise.
9722 // ------------------------------------------------------------------------
isOneNumber(const std::string & s)9723 bool Tokenizer::isOneNumber(const std::string &s)
9724 {
9725     if (!MathLib::isPositive(s))
9726         return false;
9727     return isNumberOneOf(s, 1L, "1.0");
9728 }
9729 
9730 // ------------------------------------------------------------------------
9731 // Helper function to check whether number is two (2 or 0.2E+1 or 2E+0) or not?
9732 // @param s the string to check
9733 // @return true in case s is two and false otherwise.
9734 // ------------------------------------------------------------------------
isTwoNumber(const std::string & s)9735 bool Tokenizer::isTwoNumber(const std::string &s)
9736 {
9737     if (!MathLib::isPositive(s))
9738         return false;
9739     return isNumberOneOf(s, 2L, "2.0");
9740 }
9741 
9742 // ------------------------------------------------------
9743 // Simplify math functions.
9744 // It simplifies the following functions: atol(), fmin(),
9745 // fminl(), fminf(), fmax(), fmaxl(), fmaxf(), pow(),
9746 // powf(), powl(), cbrt(), cbrtl(), cbtrf(), sqrt(),
9747 // sqrtf(), sqrtl(), exp(), expf(), expl(), exp2(),
9748 // exp2f(), exp2l(), log2(), log2f(), log2l(), log1p(),
9749 // log1pf(), log1pl(), log10(), log10l(), log10f(),
9750 // log(), logf(), logl(), logb(), logbf(), logbl(), acosh()
9751 // acoshf(), acoshl(), acos(), acosf(), acosl(), cosh()
9752 // coshf(), coshf(), cos(), cosf(), cosl(), erfc(),
9753 // erfcf(), erfcl(), ilogb(), ilogbf(), ilogbf(), erf(),
9754 // erfl(), erff(), asin(), asinf(), asinf(), asinh(),
9755 // asinhf(), asinhl(), tan(), tanf(), tanl(), tanh(),
9756 // tanhf(), tanhl(), atan(), atanf(), atanl(), atanh(),
9757 // atanhf(), atanhl(), expm1(), expm1l(), expm1f(), sin(),
9758 // sinf(), sinl(), sinh(), sinhf(), sinhl()
9759 // in the tokenlist.
9760 //
9761 // Reference:
9762 // - http://www.cplusplus.com/reference/cmath/
9763 // ------------------------------------------------------
simplifyMathFunctions()9764 void Tokenizer::simplifyMathFunctions()
9765 {
9766     for (Token *tok = list.front(); tok; tok = tok->next()) {
9767         if (tok->isName() && !tok->varId() && tok->strAt(1) == "(") { // precondition for function
9768             bool simplifcationMade = false;
9769             if (Token::Match(tok, "atol ( %str% )")) { //@todo Add support for atoll()
9770                 if (Token::simpleMatch(tok->tokAt(-2), "std ::")) {
9771                     tok = tok->tokAt(-2);// set token index two steps back
9772                     tok->deleteNext(2);  // delete "std ::"
9773                 }
9774                 const std::string& strNumber = tok->tokAt(2)->strValue(); // get number
9775                 const bool isNotAnInteger = (!MathLib::isInt(strNumber));// check: is not an integer
9776                 if (strNumber.empty() || isNotAnInteger) {
9777                     // Ignore strings which we can't convert
9778                     continue;
9779                 }
9780                 // Convert string into a number and insert into token list
9781                 tok->str(MathLib::toString(MathLib::toLongNumber(strNumber)));
9782                 // remove ( %num% )
9783                 tok->deleteNext(3);
9784                 simplifcationMade = true;
9785             } else if (Token::Match(tok, "sqrt|sqrtf|sqrtl|cbrt|cbrtf|cbrtl ( %num% )")) {
9786                 // Simplify: sqrt(0) = 0 and cbrt(0) == 0
9787                 //           sqrt(1) = 1 and cbrt(1) == 1
9788                 // get number string
9789                 const std::string& parameter(tok->strAt(2));
9790                 // is parameter 0 ?
9791                 if (isZeroNumber(parameter)) {
9792                     tok->deleteNext(3);  // delete tokens
9793                     tok->str("0"); // insert result into token list
9794                     simplifcationMade = true;
9795                 } else if (isOneNumber(parameter)) {
9796                     tok->deleteNext(3);  // delete tokens
9797                     tok->str("1"); // insert result into token list
9798                     simplifcationMade = true;
9799                 }
9800             } else if (Token::Match(tok, "exp|expf|expl|exp2|exp2f|exp2l|cos|cosf|cosl|cosh|coshf|coshl|erfc|erfcf|erfcl ( %num% )")) {
9801                 // Simplify: exp[f|l](0)  = 1 and exp2[f|l](0) = 1
9802                 //           cosh[f|l](0) = 1 and cos[f|l](0)  = 1
9803                 //           erfc[f|l](0) = 1
9804                 // get number string
9805                 const std::string& parameter(tok->strAt(2));
9806                 // is parameter 0 ?
9807                 if (isZeroNumber(parameter)) {
9808                     tok->deleteNext(3);  // delete tokens
9809                     tok->str("1"); // insert result into token list
9810                     simplifcationMade = true;
9811                 }
9812             } else if (Token::Match(tok, "log1p|log1pf|log1pl|sin|sinf|sinl|sinh|sinhf|sinhl|erf|erff|erfl|asin|asinf|asinl|asinh|asinhf|asinhl|tan|tanf|tanl|tanh|tanhf|tanhl|atan|atanf|atanl|atanh|atanhf|atanhl|expm1|expm1f|expm1l ( %num% )")) {
9813                 // Simplify: log1p[f|l](0) = 0 and sin[f|l](0)  = 0
9814                 //           sinh[f|l](0)  = 0 and erf[f|l](0)  = 0
9815                 //           asin[f|l](0)  = 0 and sinh[f|l](0) = 0
9816                 //           tan[f|l](0)   = 0 and tanh[f|l](0) = 0
9817                 //           atan[f|l](0)  = 0 and atanh[f|l](0)= 0
9818                 //           expm1[f|l](0) = 0
9819                 // get number string
9820                 const std::string& parameter(tok->strAt(2));
9821                 // is parameter 0 ?
9822                 if (isZeroNumber(parameter)) {
9823                     tok->deleteNext(3);  // delete tokens
9824                     tok->str("0"); // insert result into token list
9825                     simplifcationMade = true;
9826                 }
9827             } else if (Token::Match(tok, "log2|log2f|log2l|log|logf|logl|log10|log10f|log10l|logb|logbf|logbl|acosh|acoshf|acoshl|acos|acosf|acosl|ilogb|ilogbf|ilogbl ( %num% )")) {
9828                 // Simplify: log2[f|l](1)  = 0 , log10[f|l](1)  = 0
9829                 //           log[f|l](1)   = 0 , logb10[f|l](1) = 0
9830                 //           acosh[f|l](1) = 0 , acos[f|l](1)   = 0
9831                 //           ilogb[f|l](1) = 0
9832                 // get number string
9833                 const std::string& parameter(tok->strAt(2));
9834                 // is parameter 1 ?
9835                 if (isOneNumber(parameter)) {
9836                     tok->deleteNext(3);  // delete tokens
9837                     tok->str("0"); // insert result into token list
9838                     simplifcationMade = true;
9839                 }
9840             } else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) {
9841                 // @todo if one of the parameters is NaN the other is returned
9842                 // e.g. printf ("fmin (NaN, -1.0) = %f\n", fmin(NaN,-1.0));
9843                 // e.g. printf ("fmin (-1.0, NaN) = %f\n", fmin(-1.0,NaN));
9844                 const std::string& strLeftNumber(tok->strAt(2));
9845                 const std::string& strRightNumber(tok->strAt(4));
9846                 const bool isLessEqual =  MathLib::isLessEqual(strLeftNumber, strRightNumber);
9847                 // case: left <= right ==> insert left
9848                 if (isLessEqual) {
9849                     tok->str(strLeftNumber); // insert e.g. -1.0
9850                     tok->deleteNext(5);      // delete e.g. fmin ( -1.0, 1.0 )
9851                     simplifcationMade = true;
9852                 } else { // case left > right ==> insert right
9853                     tok->str(strRightNumber); // insert e.g. 0.0
9854                     tok->deleteNext(5);       // delete e.g. fmin ( 1.0, 0.0 )
9855                     simplifcationMade = true;
9856                 }
9857             } else if (Token::Match(tok, "fmax|fmaxl|fmaxf ( %num% , %num% )")) {
9858                 // @todo if one of the parameters is NaN the other is returned
9859                 // e.g. printf ("fmax (NaN, -1.0) = %f\n", fmax(NaN,-1.0));
9860                 // e.g. printf ("fmax (-1.0, NaN) = %f\n", fmax(-1.0,NaN));
9861                 const std::string& strLeftNumber(tok->strAt(2));
9862                 const std::string& strRightNumber(tok->strAt(4));
9863                 const bool isLessEqual =  MathLib::isLessEqual(strLeftNumber, strRightNumber);
9864                 // case: left <= right ==> insert right
9865                 if (isLessEqual) {
9866                     tok->str(strRightNumber);// insert e.g. 1.0
9867                     tok->deleteNext(5);      // delete e.g. fmax ( -1.0, 1.0 )
9868                     simplifcationMade = true;
9869                 } else { // case left > right ==> insert left
9870                     tok->str(strLeftNumber);  // insert e.g. 1.0
9871                     tok->deleteNext(5);       // delete e.g. fmax ( 1.0, 0.0 )
9872                     simplifcationMade = true;
9873                 }
9874             } else if (Token::Match(tok, "pow|powf|powl (")) {
9875                 if (Token::Match(tok->tokAt(2), "%num% , %num% )")) {
9876                     // In case of pow ( 0 , anyNumber > 0): It can be simplified to 0
9877                     // In case of pow ( 0 , 0 ): It simplified to 1
9878                     // In case of pow ( 1 , anyNumber ): It simplified to 1
9879                     const std::string& leftNumber(tok->strAt(2)); // get the left parameter
9880                     const std::string& rightNumber(tok->strAt(4)); // get the right parameter
9881                     const bool isLeftNumberZero = isZeroNumber(leftNumber);
9882                     const bool isLeftNumberOne = isOneNumber(leftNumber);
9883                     const bool isRightNumberZero = isZeroNumber(rightNumber);
9884                     if (isLeftNumberZero && !isRightNumberZero && MathLib::isPositive(rightNumber)) { // case: 0^(y) = 0 and y > 0
9885                         tok->deleteNext(5); // delete tokens
9886                         tok->str("0");  // insert simplified result
9887                         simplifcationMade = true;
9888                     } else if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1
9889                         tok->deleteNext(5); // delete tokens
9890                         tok->str("1");  // insert simplified result
9891                         simplifcationMade = true;
9892                     } else if (isLeftNumberOne) { // case 1^(y) = 1
9893                         tok->deleteNext(5); // delete tokens
9894                         tok->str("1");  // insert simplified result
9895                         simplifcationMade = true;
9896                     }
9897                 }
9898                 if (Token::Match(tok->tokAt(2), "%any% , %num% )")) {
9899                     // In case of pow( x , 1 ): It can be simplified to x.
9900                     const std::string& leftParameter(tok->strAt(2)); // get the left parameter
9901                     const std::string& rightNumber(tok->strAt(4)); // get right number
9902                     if (isOneNumber(rightNumber)) { // case: x^(1) = x
9903                         tok->str(leftParameter);  // insert simplified result
9904                         tok->deleteNext(5); // delete tokens
9905                         simplifcationMade = true;
9906                     } else if (isZeroNumber(rightNumber)) { // case: x^(0) = 1
9907                         tok->deleteNext(5); // delete tokens
9908                         tok->str("1");  // insert simplified result
9909                         simplifcationMade = true;
9910                     }
9911                 }
9912             }
9913             // Jump back to begin of statement if a simplification was performed
9914             if (simplifcationMade) {
9915                 while (tok->previous() && tok->str() != ";") {
9916                     tok = tok->previous();
9917                 }
9918             }
9919         }
9920     }
9921 }
9922 
simplifyComma()9923 void Tokenizer::simplifyComma()
9924 {
9925     bool inReturn = false;
9926 
9927     for (Token *tok = list.front(); tok; tok = tok->next()) {
9928 
9929         // skip enums
9930         if (Token::Match(tok, "enum class|struct| %name%| :|{")) {
9931             skipEnumBody(&tok);
9932         }
9933         if (!tok)
9934             syntaxError(nullptr); // invalid code like in #4195
9935 
9936         if (Token::Match(tok, "(|[") || Token::Match(tok->previous(), "%name%|= {")) {
9937             tok = tok->link();
9938             continue;
9939         }
9940 
9941         if (Token::simpleMatch(tok, "= (") && Token::simpleMatch(tok->linkAt(1), ") {")) {
9942             tok = tok->linkAt(1)->linkAt(1);
9943             continue;
9944         }
9945 
9946         // Skip unhandled template specifiers..
9947         if (tok->link() && tok->str() == "<")
9948             tok = tok->link();
9949 
9950         if (tok->str() == "return" && Token::Match(tok->previous(), "[;{}]"))
9951             inReturn = true;
9952 
9953         if (inReturn && Token::Match(tok, "[;{}?:]"))
9954             inReturn = false;
9955 
9956         if (!tok->next() || tok->str() != ",")
9957             continue;
9958 
9959         // We must not accept just any keyword, e.g. accepting int
9960         // would cause function parameters to corrupt.
9961         if (isCPP() && tok->strAt(1) == "delete") {
9962             // Handle "delete a, delete b;"
9963             tok->str(";");
9964         }
9965 
9966         if (isCPP() && Token::Match(tok->tokAt(-2), "delete %name% , %name% ;") &&
9967             tok->next()->varId() != 0) {
9968             // Handle "delete a, b;" - convert to delete a; b;
9969             tok->str(";");
9970         } else if (!inReturn && tok->tokAt(-2)) {
9971             bool replace = false;
9972             for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) {
9973                 if (tok2->str() == "=") {
9974                     // Handle "a = 0, b = 0;"
9975                     replace = true;
9976                 } else if (isCPP() && (Token::Match(tok2, "delete %name%") ||
9977                                        Token::Match(tok2, "delete [ ] %name%"))) {
9978                     // Handle "delete a, a = 0;"
9979                     replace = true;
9980                 } else if (Token::Match(tok2, "[?:;,{}()]")) {
9981                     if (replace && Token::Match(tok2, "[;{}]"))
9982                         tok->str(";");
9983                     break;
9984                 }
9985             }
9986         }
9987 
9988         // find token where return ends and also count commas
9989         if (inReturn) {
9990             Token *startFrom = nullptr;    // "[;{}]" token before "return"
9991             Token *endAt = nullptr;        // first ";" token after "[;{}] return"
9992 
9993             // find "; return" pattern before comma
9994             for (Token *tok2 = tok->previous(); tok2; tok2 = tok2->previous()) {
9995                 if (tok2->str() == "return") {
9996                     startFrom = tok2->previous();
9997                     break;
9998                 }
9999             }
10000             if (!startFrom)
10001                 // to be very sure...
10002                 return;
10003             int commaCounter = 0;
10004             for (Token *tok2 = startFrom->next(); tok2; tok2 = tok2->next()) {
10005                 if (tok2->str() == ";") {
10006                     endAt = tok2;
10007                     break;
10008 
10009                 } else if (Token::Match(tok2, "(|[") ||
10010                            (tok2->str() == "{" && tok2->previous() && tok2->previous()->str() == "=")) {
10011                     tok2 = tok2->link();
10012 
10013                 } else if (tok2->str() == ",") {
10014                     ++commaCounter;
10015                 }
10016             }
10017 
10018             if (!endAt)
10019                 //probably a syntax error
10020                 return;
10021 
10022             if (commaCounter) {
10023                 // change tokens:
10024                 // "; return a ( ) , b ( ) , c ;"
10025                 // to
10026                 // "; a ( ) ; b ( ) ; return c ;"
10027 
10028                 // remove "return"
10029                 startFrom->deleteNext();
10030                 for (Token *tok2 = startFrom->next(); tok2 != endAt; tok2 = tok2->next()) {
10031                     if (Token::Match(tok2, "(|[") ||
10032                         (tok2->str() == "{" && tok2->previous() && tok2->previous()->str() == "=")) {
10033                         tok2 = tok2->link();
10034 
10035                     } else if (tok2->str() == ",") {
10036                         tok2->str(";");
10037                         --commaCounter;
10038                         if (commaCounter == 0) {
10039                             tok2->insertToken("return");
10040                         }
10041                     }
10042                 }
10043                 tok = endAt;
10044             }
10045         }
10046     }
10047 }
10048 
checkConfiguration() const10049 void Tokenizer::checkConfiguration() const
10050 {
10051     if (!mSettings->checkConfiguration)
10052         return;
10053     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10054         if (!Token::Match(tok, "%name% ("))
10055             continue;
10056         if (tok->isControlFlowKeyword())
10057             continue;
10058         for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
10059             if (tok2->str() == ";") {
10060                 macroWithSemicolonError(tok, tok->str());
10061                 break;
10062             }
10063             if (Token::Match(tok2, "(|{"))
10064                 tok2 = tok2->link();
10065         }
10066     }
10067 }
10068 
validateC() const10069 void Tokenizer::validateC() const
10070 {
10071     if (isCPP())
10072         return;
10073     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10074         // That might trigger false positives, but it's much faster to have this truncated pattern
10075         if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
10076             syntaxErrorC(tok, "C++ cast <...");
10077         // Template function..
10078         if (Token::Match(tok, "%name% < %name% > (")) {
10079             const Token *tok2 = tok->tokAt(5);
10080             while (tok2 && !Token::Match(tok2, "[()]"))
10081                 tok2 = tok2->next();
10082             if (Token::simpleMatch(tok2, ") {"))
10083                 syntaxErrorC(tok, tok->str() + '<' + tok->strAt(2) + ">() {}");
10084         }
10085         if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
10086             continue;
10087         if (Token::Match(tok, "using namespace %name% ;"))
10088             syntaxErrorC(tok, "using namespace " + tok->strAt(2));
10089         if (Token::Match(tok, "template < class|typename %name% [,>]"))
10090             syntaxErrorC(tok, "template<...");
10091         if (Token::Match(tok, "%name% :: %name%"))
10092             syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
10093         if (Token::Match(tok, "class|namespace %name% [:{]"))
10094             syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
10095     }
10096 }
10097 
validate() const10098 void Tokenizer::validate() const
10099 {
10100     std::stack<const Token *> linkTokens;
10101     const Token *lastTok = nullptr;
10102     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10103         lastTok = tok;
10104         if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) {
10105             if (tok->link() == nullptr)
10106                 cppcheckError(tok);
10107 
10108             linkTokens.push(tok);
10109         }
10110 
10111         else if (Token::Match(tok, "[})]]") || (Token::Match(tok, ">|>>") && tok->link())) {
10112             if (tok->link() == nullptr)
10113                 cppcheckError(tok);
10114 
10115             if (linkTokens.empty() == true)
10116                 cppcheckError(tok);
10117 
10118             if (tok->link() != linkTokens.top())
10119                 cppcheckError(tok);
10120 
10121             if (tok != tok->link()->link())
10122                 cppcheckError(tok);
10123 
10124             linkTokens.pop();
10125         }
10126 
10127         else if (tok->link() != nullptr)
10128             cppcheckError(tok);
10129     }
10130 
10131     if (!linkTokens.empty())
10132         cppcheckError(linkTokens.top());
10133 
10134     // Validate that the Tokenizer::list.back() is updated correctly during simplifications
10135     if (lastTok != list.back())
10136         cppcheckError(lastTok);
10137 }
10138 
findUnmatchedTernaryOp(const Token * const begin,const Token * const end,int depth=0)10139 static const Token *findUnmatchedTernaryOp(const Token * const begin, const Token * const end, int depth = 0)
10140 {
10141     std::stack<const Token *> ternaryOp;
10142     for (const Token *tok = begin; tok != end && tok->str() != ";"; tok = tok->next()) {
10143         if (tok->str() == "?")
10144             ternaryOp.push(tok);
10145         else if (!ternaryOp.empty() && tok->str() == ":")
10146             ternaryOp.pop();
10147         else if (depth < 100 && Token::Match(tok,"(|[")) {
10148             const Token *inner = findUnmatchedTernaryOp(tok->next(), tok->link(), depth+1);
10149             if (inner)
10150                 return inner;
10151             tok = tok->link();
10152         }
10153     }
10154     return ternaryOp.empty() ? nullptr : ternaryOp.top();
10155 }
10156 
isCPPAttribute(const Token * tok)10157 static bool isCPPAttribute(const Token * tok)
10158 {
10159     return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
10160 }
10161 
isAlignAttribute(const Token * tok)10162 static bool isAlignAttribute(const Token * tok)
10163 {
10164     return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
10165 }
10166 
skipCPPOrAlignAttribute(const Token * tok)10167 static const Token* skipCPPOrAlignAttribute(const Token * tok)
10168 {
10169     if (isCPPAttribute(tok)) {
10170         return tok->link();
10171     } else if (isAlignAttribute(tok)) {
10172         return tok->next()->link();
10173     }
10174     return tok;
10175 }
10176 
reportUnknownMacros() const10177 void Tokenizer::reportUnknownMacros() const
10178 {
10179     // Report unknown macros used in expressions "%name% %num%"
10180     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10181         if (Token::Match(tok, "%name% %num%")) {
10182             // A keyword is not an unknown macro
10183             if (tok->isKeyword())
10184                 continue;
10185 
10186             if (Token::Match(tok->previous(), "%op%|("))
10187                 unknownMacroError(tok);
10188         }
10189     }
10190 
10191     // Report unknown macros that contain several statements "MACRO(a;b;c)"
10192     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10193         if (!Token::Match(tok, "%name% ("))
10194             continue;
10195         if (!tok->isUpperCaseName())
10196             continue;
10197         const Token *endTok = tok->linkAt(1);
10198         for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
10199             if (Token::Match(inner, "[[({]"))
10200                 inner = inner->link();
10201             else if (inner->str() == ";")
10202                 unknownMacroError(inner);
10203         }
10204     }
10205 
10206     // Report unknown macros that contain struct initialization "MACRO(a, .b=3)"
10207     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10208         if (!Token::Match(tok, "%name% ("))
10209             continue;
10210         const Token *endTok = tok->linkAt(1);
10211         for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
10212             if (Token::Match(inner, "[[({]"))
10213                 inner = inner->link();
10214             else if (Token::Match(inner->previous(), "[,(] . %name% =|{"))
10215                 unknownMacroError(tok);
10216         }
10217     }
10218 
10219     // Report unknown macros in non-executable scopes..
10220     std::set<std::string> possible;
10221     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10222         // Skip executable scopes..
10223         if (tok->str() == "{") {
10224             const Token *prev = tok->previous();
10225             while (prev && prev->isName())
10226                 prev = prev->previous();
10227             if (prev && prev->str() == ")")
10228                 tok = tok->link();
10229             else
10230                 possible.clear();
10231         } else if (tok->str() == "}")
10232             possible.clear();
10233 
10234         if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
10235             // A keyword is not an unknown macro
10236             if (tok->isKeyword())
10237                 continue;
10238 
10239             const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
10240             const Token *bodyEnd = tok->link();
10241             for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) {
10242                 if (Token::Match(tok2, "if|switch|for|while|return"))
10243                     unknownMacroError(tok);
10244             }
10245         } else if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::Match(tok->linkAt(1), ") %name% (") && Token::Match(tok->linkAt(1)->linkAt(2), ") [;{]")) {
10246             if (possible.count(tok->str()) == 0)
10247                 possible.insert(tok->str());
10248             else
10249                 unknownMacroError(tok);
10250         }
10251     }
10252 
10253     // String concatenation with unknown macros
10254     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10255         if (Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) {
10256             if (tok->next()->isKeyword())
10257                 continue;
10258             unknownMacroError(tok->next());
10259         }
10260         if (Token::Match(tok, "[(,] %name% (") && Token::Match(tok->linkAt(2), ") %name% %name%|,|)")) {
10261             if (tok->next()->isKeyword() || tok->linkAt(2)->next()->isKeyword())
10262                 continue;
10263             if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
10264                 continue;
10265             if (tok->next()->str().compare(0, 2, "__") == 0) // attribute/annotation
10266                 continue;
10267             unknownMacroError(tok->next());
10268         }
10269     }
10270 }
10271 
findGarbageCode() const10272 void Tokenizer::findGarbageCode() const
10273 {
10274     const bool isCPP11 = isCPP() && mSettings->standards.cpp >= Standards::CPP11;
10275 
10276     static const std::unordered_set<std::string> nonConsecutiveKeywords{ "break",
10277                                                                          "continue",
10278                                                                          "for",
10279                                                                          "goto",
10280                                                                          "if",
10281                                                                          "return",
10282                                                                          "switch",
10283                                                                          "throw",
10284                                                                          "typedef",
10285                                                                          "while" };
10286 
10287     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10288         // initialization: = {
10289         if (Token::simpleMatch(tok, "= {") && Token::simpleMatch(tok->linkAt(1), "} ("))
10290             syntaxError(tok->linkAt(1));
10291 
10292         // Inside [] there can't be ; or various keywords
10293         else if (tok->str() == "[") {
10294             for (const Token* inner = tok->next(); inner != tok->link(); inner = inner->next()) {
10295                 if (Token::Match(inner, "(|[|{"))
10296                     inner = inner->link();
10297                 else if (Token::Match(inner, ";|goto|return|typedef"))
10298                     syntaxError(inner);
10299             }
10300         }
10301 
10302         // array assignment
10303         else if (Token::Match(tok, "%assign% [") && Token::simpleMatch(tok->linkAt(1), "] ;"))
10304             syntaxError(tok, tok->str() + "[...];");
10305 
10306         // UNKNOWN_MACRO(return)
10307         if (tok->isKeyword() && Token::Match(tok, "throw|return )") && Token::Match(tok->linkAt(1)->previous(), "%name% ("))
10308             unknownMacroError(tok->linkAt(1)->previous());
10309 
10310         // UNKNOWN_MACRO(return)
10311         else if (Token::Match(tok, "%name% throw|return") && std::isupper(tok->str()[0]))
10312             unknownMacroError(tok);
10313 
10314         // Assign/increment/decrement literal
10315         else if (Token::Match(tok, "!!) %num%|%str%|%char% %assign%|++|--"))
10316             syntaxError(tok, tok->next()->str() + " " + tok->strAt(2));
10317 
10318         if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for|switch")) { // if|while|for|switch (EXPR) { ... }
10319             if (tok->previous() && !Token::Match(tok->previous(), "%name%|:|;|{|}|)")) {
10320                 if (Token::Match(tok->previous(), "[,(]")) {
10321                     const Token *prev = tok->previous();
10322                     while (prev && prev->str() != "(") {
10323                         if (prev->str() == ")")
10324                             prev = prev->link();
10325                         prev = prev->previous();
10326                     }
10327                     if (prev && Token::Match(prev->previous(), "%name% ("))
10328                         unknownMacroError(prev->previous());
10329                 }
10330                 if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if"))
10331                     syntaxError(tok);
10332             }
10333             if (!Token::Match(tok->next(), "( !!)"))
10334                 syntaxError(tok);
10335             if (tok->str() != "for") {
10336                 if (isGarbageExpr(tok->next(), tok->linkAt(1), mSettings->standards.cpp>=Standards::cppstd_t::CPP17))
10337                     syntaxError(tok);
10338             }
10339         }
10340 
10341         // keyword keyword
10342         if (tok->isKeyword() && nonConsecutiveKeywords.count(tok->str()) != 0) {
10343             if (Token::Match(tok, "%name% %name%") && nonConsecutiveKeywords.count(tok->next()->str()) == 1)
10344                 syntaxError(tok);
10345             const Token* prev = tok;
10346             while (prev && prev->isName())
10347                 prev = prev->previous();
10348             if (Token::Match(prev, "%op%|%num%|%str%|%char%")) {
10349                 if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if") &&
10350                     !Token::simpleMatch(tok->tokAt(-2), "extern \"C\""))
10351                     syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str()));
10352             }
10353         }
10354     }
10355 
10356     // invalid struct declaration
10357     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10358         if (Token::Match(tok, "struct|class|enum %name%| {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
10359             const Token *tok2 = tok->linkAt(tok->next()->isName() ? 2 : 1);
10360             if (Token::Match(tok2, "} %op%")) {
10361                 tok2 = tok2->next();
10362                 if (!Token::Match(tok2, "*|&|&&"))
10363                     syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
10364                 while (Token::Match(tok2, "*|&|&&"))
10365                     tok2 = tok2->next();
10366                 if (!Token::Match(tok2, "%name%"))
10367                     syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
10368             }
10369         }
10370     }
10371 
10372     // Keywords in global scope
10373     static const std::unordered_set<std::string> nonGlobalKeywords{"break",
10374                                                                    "continue",
10375                                                                    "for",
10376                                                                    "goto",
10377                                                                    "if",
10378                                                                    "return",
10379                                                                    "switch",
10380                                                                    "while",
10381                                                                    "try",
10382                                                                    "catch"};
10383     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10384         if (tok->str() == "{")
10385             tok = tok->link();
10386         else if (tok->isKeyword() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
10387             syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
10388     }
10389 
10390     // case keyword must be inside switch
10391     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10392         if (Token::simpleMatch(tok, "switch (")) {
10393             if (Token::simpleMatch(tok->linkAt(1), ") {")) {
10394                 tok = tok->linkAt(1)->linkAt(1);
10395                 continue;
10396             }
10397             const Token *switchToken = tok;
10398             tok = tok->linkAt(1);
10399             if (!tok)
10400                 syntaxError(switchToken);
10401             // Look for the end of the switch statement, i.e. the first semi-colon or '}'
10402             for (; tok; tok = tok->next()) {
10403                 if (tok->str() == "{") {
10404                     tok = tok->link();
10405                 }
10406                 if (Token::Match(tok, ";|}")) {
10407                     // We're at the end of the switch block
10408                     if (tok->str() == "}" && tok->strAt(-1) == ":") // Invalid case
10409                         syntaxError(switchToken);
10410                     break;
10411                 }
10412             }
10413             if (!tok)
10414                 break;
10415         } else if (tok->str() == "(") {
10416             tok = tok->link();
10417         } else if (tok->str() == "case") {
10418             syntaxError(tok);
10419         }
10420     }
10421 
10422     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10423         if (!Token::simpleMatch(tok, "for (")) // find for loops
10424             continue;
10425         // count number of semicolons
10426         int semicolons = 0;
10427         const Token* const startTok = tok;
10428         tok = tok->next()->link()->previous(); // find ")" of the for-loop
10429         // walk backwards until we find the beginning (startTok) of the for() again
10430         for (; tok != startTok; tok = tok->previous()) {
10431             if (tok->str() == ";") { // do the counting
10432                 semicolons++;
10433             } else if (tok->str() == ")") { // skip pairs of ( )
10434                 tok = tok->link();
10435             }
10436         }
10437         // if we have an invalid number of semicolons inside for( ), assume syntax error
10438         if (semicolons > 2)
10439             syntaxError(tok);
10440         if (semicolons == 1 && !(isCPP() && mSettings->standards.cpp >= Standards::CPP20))
10441             syntaxError(tok);
10442     }
10443 
10444     // Operators without operands..
10445     const Token *templateEndToken = nullptr;
10446     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10447         if (!templateEndToken) {
10448             if (tok->str() == "<" && isCPP())
10449                 templateEndToken = tok->findClosingBracket();
10450         } else {
10451             if (templateEndToken == tok)
10452                 templateEndToken = nullptr;
10453             if (Token::Match(tok, "> %cop%"))
10454                 continue;
10455         }
10456         // skip C++ attributes [[...]]
10457         if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok))) {
10458             tok = skipCPPOrAlignAttribute(tok);
10459             continue;
10460         }
10461         {
10462             bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
10463             bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
10464             if (isCPP()) {
10465                 match1 = match1 || Token::Match(tok, "::|throw|decltype|typeof");
10466                 match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
10467             }
10468             if (match1 && match2)
10469                 syntaxError(tok);
10470         }
10471         if (Token::Match(tok, "%or%|%oror%|~|^|!|%comp%|+|-|/|%")) {
10472             std::string code;
10473             if (Token::Match(tok->next(), ")|]|}"))
10474                 code = tok->str() + tok->next()->str();
10475             if (Token::simpleMatch(tok->next(), "( )"))
10476                 code = tok->str() + "()";
10477             if (!code.empty()) {
10478                 if (isC() || (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")))
10479                     syntaxError(tok, code);
10480             }
10481         }
10482         if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
10483             syntaxError(tok);
10484         if (Token::Match(tok, "%assign% typename|class %assign%"))
10485             syntaxError(tok);
10486         if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%"))
10487             syntaxError(tok);
10488         if (Token::Match(tok, ";|(|[ %comp%"))
10489             syntaxError(tok);
10490         if (Token::Match(tok, "%cop%|= ]") && !(isCPP() && Token::Match(tok->previous(), "[|,|%num% &|=|> ]")))
10491             syntaxError(tok);
10492         if (Token::Match(tok, "[+-] [;,)]}]") && !(isCPP() && Token::Match(tok->previous(), "operator [+-] ;")))
10493             syntaxError(tok);
10494         if (Token::simpleMatch(tok, ",") &&
10495             !Token::Match(tok->tokAt(-2), "[ = , &|%name%")) {
10496             if (Token::Match(tok->previous(), "(|[|{|<|%assign%|%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|::|sizeof"))
10497                 syntaxError(tok);
10498             if (isCPP() && Token::Match(tok->previous(), "throw|decltype|typeof"))
10499                 syntaxError(tok);
10500             if (Token::Match(tok->next(), ")|]|>|%assign%|%or%|%oror%|==|!=|/|>=|<=|&&"))
10501                 syntaxError(tok);
10502         }
10503         if (Token::simpleMatch(tok, ".") &&
10504             !Token::simpleMatch(tok->previous(), ".") &&
10505             !Token::simpleMatch(tok->next(), ".") &&
10506             !Token::Match(tok->previous(), "{|, . %name% =|.|[|{") &&
10507             !Token::Match(tok->previous(), ", . %name%")) {
10508             if (!Token::Match(tok->previous(), "%name%|)|]|>|}"))
10509                 syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
10510             if (!Token::Match(tok->next(), "%name%|*|~"))
10511                 syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
10512         }
10513         if (Token::Match(tok, "[!|+-/%^~] )|]"))
10514             syntaxError(tok);
10515         if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
10516             syntaxError(tok, tok->str() + " " + tok->strAt(1));
10517     }
10518 
10519     // ternary operator without :
10520     if (const Token *ternaryOp = findUnmatchedTernaryOp(tokens(), nullptr))
10521         syntaxError(ternaryOp);
10522 
10523     // Code must not start with an arithmetical operand
10524     if (Token::Match(list.front(), "%cop%"))
10525         syntaxError(list.front());
10526 
10527     // Code must end with } ; ) NAME
10528     if (!Token::Match(list.back(), "%name%|;|}|)"))
10529         syntaxError(list.back());
10530     if (list.back()->str() == ")" && !Token::Match(list.back()->link()->previous(), "%name%|> ("))
10531         syntaxError(list.back());
10532     for (const Token *end = list.back(); end && end->isName(); end = end->previous()) {
10533         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"))
10534             syntaxError(list.back());
10535     }
10536     if ((list.back()->str()==")" || list.back()->str()=="}") && list.back()->previous() && list.back()->previous()->isControlFlowKeyword())
10537         syntaxError(list.back()->previous());
10538 
10539     // Garbage templates..
10540     if (isCPP()) {
10541         for (const Token *tok = tokens(); tok; tok = tok->next()) {
10542             if (!Token::simpleMatch(tok, "template <"))
10543                 continue;
10544             if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) {
10545                 if (tok->previous()->isUpperCaseName())
10546                     unknownMacroError(tok->previous());
10547                 else
10548                     syntaxError(tok);
10549             }
10550             const Token * const tok1 = tok;
10551             tok = tok->next()->findClosingBracket();
10552             if (!tok)
10553                 syntaxError(tok1);
10554             if (!Token::Match(tok, ">|>> ::|...| %name%") &&
10555                 !Token::Match(tok, ">|>> [ [ %name%") &&
10556                 !Token::Match(tok, "> >|*"))
10557                 syntaxError(tok->next() ? tok->next() : tok1);
10558         }
10559     }
10560 
10561     // Objective C/C++
10562     for (const Token *tok = tokens(); tok; tok = tok->next()) {
10563         if (Token::Match(tok, "[;{}] [ %name% %name% ] ;"))
10564             syntaxError(tok->next());
10565     }
10566 }
10567 
10568 
isGarbageExpr(const Token * start,const Token * end,bool allowSemicolon)10569 bool Tokenizer::isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
10570 {
10571     for (const Token *tok = start; tok != end; tok = tok->next()) {
10572         if (tok->isControlFlowKeyword())
10573             return true;
10574         if (!allowSemicolon && tok->str() == ";")
10575             return true;
10576         if (tok->str() == "{")
10577             tok = tok->link();
10578     }
10579     return false;
10580 }
10581 
simplifyString(const std::string & source)10582 std::string Tokenizer::simplifyString(const std::string &source)
10583 {
10584     std::string str = source;
10585 
10586     for (std::string::size_type i = 0; i + 1U < str.size(); ++i) {
10587         if (str[i] != '\\')
10588             continue;
10589 
10590         int c = 'a';   // char
10591         int sz = 0;    // size of stringdata
10592         if (str[i+1] == 'x') {
10593             sz = 2;
10594             while (sz < 4 && std::isxdigit((unsigned char)str[i+sz]))
10595                 sz++;
10596             if (sz > 2) {
10597                 std::istringstream istr(str.substr(i+2, sz-2));
10598                 istr >> std::hex >> c;
10599             }
10600         } else if (MathLib::isOctalDigit(str[i+1])) {
10601             sz = 2;
10602             while (sz < 4 && MathLib::isOctalDigit(str[i+sz]))
10603                 sz++;
10604             std::istringstream istr(str.substr(i+1, sz-1));
10605             istr >> std::oct >> c;
10606             str = str.substr(0,i) + (char)c + str.substr(i+sz);
10607             continue;
10608         }
10609 
10610         if (sz <= 2)
10611             i++;
10612         else if (i+sz < str.size())
10613             str.replace(i, sz, std::string(1U, (char)c));
10614         else
10615             str.replace(i, str.size() - i - 1U, "a");
10616     }
10617 
10618     return str;
10619 }
10620 
simplifyWhile0()10621 void Tokenizer::simplifyWhile0()
10622 {
10623     for (Token *tok = list.front(); tok; tok = tok->next()) {
10624         // while (0)
10625         const bool while0(Token::Match(tok->previous(), "[{};] while ( 0|false )"));
10626 
10627         // for (0) - not banal, ticket #3140
10628         const bool for0((Token::Match(tok->previous(), "[{};] for ( %name% = %num% ; %name% < %num% ;") &&
10629                          tok->strAt(2) == tok->strAt(6) && tok->strAt(4) == tok->strAt(8)) ||
10630                         (Token::Match(tok->previous(), "[{};] for ( %type% %name% = %num% ; %name% < %num% ;") &&
10631                          tok->strAt(3) == tok->strAt(7) && tok->strAt(5) == tok->strAt(9)));
10632 
10633         if (!while0 && !for0)
10634             continue;
10635 
10636         if (while0 && tok->previous()->str() == "}") {
10637             // find "do"
10638             Token *tok2 = tok->previous()->link();
10639             tok2 = tok2->previous();
10640             if (tok2 && tok2->str() == "do") {
10641                 const bool flowmatch = Token::findmatch(tok2, "continue|break", tok) != nullptr;
10642                 // delete "do ({)"
10643                 tok2->deleteThis();
10644                 if (!flowmatch)
10645                     tok2->deleteThis();
10646 
10647                 // delete "(}) while ( 0 ) (;)"
10648                 tok = tok->previous();
10649                 tok->deleteNext(4);  // while ( 0 )
10650                 if (tok->next() && tok->next()->str() == ";")
10651                     tok->deleteNext(); // ;
10652                 if (!flowmatch)
10653                     tok->deleteThis(); // }
10654 
10655                 continue;
10656             }
10657         }
10658 
10659         // remove "while (0) { .. }"
10660         if (Token::simpleMatch(tok->next()->link(), ") {")) {
10661             Token *end = tok->next()->link(), *old_prev = tok->previous();
10662             end = end->next()->link();
10663             if (Token::Match(tok, "for ( %name% ="))
10664                 old_prev = end->link();
10665             eraseDeadCode(old_prev, end->next());
10666             if (old_prev && old_prev->next())
10667                 tok = old_prev->next();
10668             else
10669                 break;
10670         }
10671     }
10672 }
10673 
simplifyFunctionTryCatch()10674 void Tokenizer::simplifyFunctionTryCatch()
10675 {
10676     if (!isCPP())
10677         return;
10678 
10679     for (Token * tok = list.front(); tok; tok = tok->next()) {
10680         if (!Token::simpleMatch(tok, "try {"))
10681             continue;
10682         if (!isFunctionHead(tok->previous(), "try"))
10683             continue;
10684 
10685         // find the end of the last catch block
10686         Token * const tryEndToken = tok->linkAt(1);
10687         Token * endToken = tryEndToken;
10688         while (Token::simpleMatch(endToken, "} catch (")) {
10689             endToken = endToken->linkAt(2)->next();
10690             if (!endToken)
10691                 break;
10692             if (endToken->str() != "{") {
10693                 endToken = nullptr;
10694                 break;
10695             }
10696             endToken = endToken->link();
10697         }
10698         if (!endToken || endToken == tryEndToken)
10699             continue;
10700 
10701         tok->previous()->insertToken("{");
10702         endToken->insertToken("}");
10703         Token::createMutualLinks(tok->previous(), endToken->next());
10704     }
10705 }
10706 
simplifyErrNoInWhile()10707 void Tokenizer::simplifyErrNoInWhile()
10708 {
10709     for (Token *tok = list.front(); tok; tok = tok->next()) {
10710         if (tok->str() != "errno")
10711             continue;
10712 
10713         Token *endpar = nullptr;
10714         if (Token::Match(tok->previous(), "&& errno == EINTR ) { ;| }"))
10715             endpar = tok->tokAt(3);
10716         else if (Token::Match(tok->tokAt(-2), "&& ( errno == EINTR ) ) { ;| }"))
10717             endpar = tok->tokAt(4);
10718         else
10719             continue;
10720 
10721         if (Token::simpleMatch(endpar->link()->previous(), "while (")) {
10722             Token *tok1 = tok->previous();
10723             if (tok1->str() == "(")
10724                 tok1 = tok1->previous();
10725 
10726             // erase "&& errno == EINTR"
10727             tok1 = tok1->previous();
10728             Token::eraseTokens(tok1, endpar);
10729 
10730             // tok is invalid.. move to endpar
10731             tok = endpar;
10732         }
10733     }
10734 }
10735 
10736 
simplifyFuncInWhile()10737 void Tokenizer::simplifyFuncInWhile()
10738 {
10739     int count = 0;
10740     for (Token *tok = list.front(); tok; tok = tok->next()) {
10741         if (!Token::Match(tok, "while ( %name% ( %name% ) ) {"))
10742             continue;
10743 
10744         Token *func = tok->tokAt(2);
10745         const Token * const var = tok->tokAt(4);
10746         Token * const end = tok->next()->link()->next()->link();
10747 
10748         const int varid = ++mVarId; // Create new variable
10749         const std::string varname("cppcheck:r" + MathLib::toString(++count));
10750         tok->str("int");
10751         tok->next()->insertToken(varname);
10752         tok->tokAt(2)->varId(varid);
10753         tok->insertToken("while");
10754         tok->insertToken(";");
10755         tok->insertToken(")");
10756         tok->insertToken(var->str());
10757         tok->next()->varId(var->varId());
10758         tok->insertToken("(");
10759         tok->insertToken(func->str());
10760         tok->insertToken("=");
10761         tok->insertToken(varname);
10762         tok->next()->varId(varid);
10763         Token::createMutualLinks(tok->tokAt(4), tok->tokAt(6));
10764         end->previous()->insertToken(varname);
10765         end->previous()->varId(varid);
10766         end->previous()->insertToken("=");
10767         Token::move(func, func->tokAt(3), end->previous());
10768         end->previous()->insertToken(";");
10769 
10770         tok = end;
10771     }
10772 }
10773 
simplifyStructDecl()10774 void Tokenizer::simplifyStructDecl()
10775 {
10776     const bool cpp = isCPP();
10777 
10778     // A counter that is used when giving unique names for anonymous structs.
10779     int count = 0;
10780 
10781     // Skip simplification of unions in class definition
10782     std::stack<bool> skip; // true = in function, false = not in function
10783     skip.push(false);
10784 
10785     // Add names for anonymous structs
10786     for (Token *tok = list.front(); tok; tok = tok->next()) {
10787         if (!tok->isName())
10788             continue;
10789         // check for anonymous struct/union
10790         if (Token::Match(tok, "struct|union {")) {
10791             if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) {
10792                 tok->insertToken("Anonymous" + MathLib::toString(count++));
10793             }
10794         }
10795         // check for derived anonymous class/struct
10796         else if (cpp && Token::Match(tok, "class|struct :")) {
10797             const Token *tok1 = Token::findsimplematch(tok, "{");
10798             if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) {
10799                 tok->insertToken("Anonymous" + MathLib::toString(count++));
10800             }
10801         }
10802         // check for anonymous enum
10803         else if ((Token::simpleMatch(tok, "enum {") &&
10804                   !Token::Match(tok->tokAt(-3), "using %name% =") &&
10805                   Token::Match(tok->next()->link(), "} (| %type%| )| ,|;|[|(|{")) ||
10806                  (Token::Match(tok, "enum : %type% {") && Token::Match(tok->linkAt(3), "} (| %type%| )| ,|;|[|(|{"))) {
10807             Token *start = tok->strAt(1) == ":" ? tok->linkAt(3) : tok->linkAt(1);
10808             if (start && Token::Match(start->next(), "( %type% )")) {
10809                 start->next()->link()->deleteThis();
10810                 start->next()->deleteThis();
10811             }
10812             tok->insertToken("Anonymous" + MathLib::toString(count++));
10813         }
10814     }
10815 
10816     for (Token *tok = list.front(); tok; tok = tok->next()) {
10817 
10818         // check for start of scope and determine if it is in a function
10819         if (tok->str() == "{")
10820             skip.push(Token::Match(tok->previous(), "const|)"));
10821 
10822         // end of scope
10823         else if (tok->str() == "}" && !skip.empty())
10824             skip.pop();
10825 
10826         // check for named struct/union
10827         else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
10828             Token *start = tok;
10829             while (Token::Match(start->previous(), "%type%"))
10830                 start = start->previous();
10831             const Token * const type = tok->next();
10832             Token *next = tok->tokAt(2);
10833 
10834             while (next && next->str() != "{")
10835                 next = next->next();
10836             if (!next)
10837                 continue;
10838             skip.push(false);
10839             tok = next->link();
10840             if (!tok)
10841                 break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
10842             Token *restart = next;
10843 
10844             // check for named type
10845             if (Token::Match(tok->next(), "const| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
10846                 tok->insertToken(";");
10847                 tok = tok->next();
10848                 while (!Token::Match(start, "struct|class|union|enum")) {
10849                     tok->insertToken(start->str());
10850                     tok = tok->next();
10851                     start->deleteThis();
10852                 }
10853                 if (!tok)
10854                     break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
10855                 tok->insertToken(type->str());
10856                 if (start->str() != "class") {
10857                     tok->insertToken(start->str());
10858                     tok = tok->next();
10859                 }
10860 
10861                 tok = tok->tokAt(2);
10862 
10863                 if (Token::Match(tok, "( %type% )")) {
10864                     tok->link()->deleteThis();
10865                     tok->deleteThis();
10866                 }
10867 
10868                 // check for initialization
10869                 if (tok && (tok->next()->str() == "(" || tok->next()->str() == "{")) {
10870                     tok->insertToken("=");
10871                     tok = tok->next();
10872 
10873                     if (start->str() == "enum") {
10874                         if (tok->next()->str() == "{") {
10875                             tok->next()->str("(");
10876                             tok->linkAt(1)->str(")");
10877                         }
10878                     }
10879                 }
10880             }
10881 
10882             tok = restart;
10883         }
10884 
10885         // check for anonymous struct/union
10886         else if (Token::Match(tok, "struct|union {")) {
10887             const bool inFunction = skip.top();
10888             skip.push(false);
10889             Token *tok1 = tok;
10890 
10891             Token *restart = tok->next();
10892             tok = tok->next()->link();
10893 
10894             // unnamed anonymous struct/union so possibly remove it
10895             if (tok && tok->next() && tok->next()->str() == ";") {
10896                 if (inFunction && tok1->str() == "union") {
10897                     // Try to create references in the union..
10898                     Token *tok2 = tok1->tokAt(2);
10899                     while (tok2) {
10900                         if (Token::Match(tok2, "%type% %name% ;"))
10901                             tok2 = tok2->tokAt(3);
10902                         else
10903                             break;
10904                     }
10905                     if (!Token::simpleMatch(tok2, "} ;"))
10906                         continue;
10907                     Token *vartok = nullptr;
10908                     tok2 = tok1->tokAt(2);
10909                     while (Token::Match(tok2, "%type% %name% ;")) {
10910                         if (!vartok) {
10911                             vartok = tok2->next();
10912                             tok2 = tok2->tokAt(3);
10913                         } else {
10914                             tok2->insertToken("&");
10915                             tok2 = tok2->tokAt(2);
10916                             tok2->insertToken(vartok->str());
10917                             tok2->next()->varId(vartok->varId());
10918                             tok2->insertToken("=");
10919                             tok2 = tok2->tokAt(4);
10920                         }
10921                     }
10922                 }
10923 
10924                 // don't remove unnamed anonymous unions from a class, struct or union
10925                 if (!(!inFunction && tok1->str() == "union") && !Token::Match(tok1->tokAt(-3), "using %name% =")) {
10926                     skip.pop();
10927                     tok1->deleteThis();
10928                     if (tok1->next() == tok) {
10929                         tok1->deleteThis();
10930                         tok = tok1;
10931                     } else
10932                         tok1->deleteThis();
10933                     restart = tok1->previous();
10934                     tok->deleteThis();
10935                     if (tok->next())
10936                         tok->deleteThis();
10937                 }
10938             }
10939 
10940             if (!restart) {
10941                 simplifyStructDecl();
10942                 return;
10943             } else if (!restart->next())
10944                 return;
10945 
10946             tok = restart;
10947         }
10948     }
10949 }
10950 
simplifyCallingConvention()10951 void Tokenizer::simplifyCallingConvention()
10952 {
10953     const bool windows = mSettings->isWindowsPlatform();
10954 
10955     for (Token *tok = list.front(); tok; tok = tok->next()) {
10956         while (Token::Match(tok, "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near") || (windows && Token::Match(tok, "WINAPI|APIENTRY|CALLBACK"))) {
10957             tok->deleteThis();
10958         }
10959     }
10960 }
10961 
simplifyDeclspec()10962 void Tokenizer::simplifyDeclspec()
10963 {
10964     for (Token *tok = list.front(); tok; tok = tok->next()) {
10965         while (Token::Match(tok, "__declspec|_declspec (") && tok->next()->link() && tok->next()->link()->next()) {
10966             if (Token::Match(tok->tokAt(2), "noreturn|nothrow")) {
10967                 Token *tok1 = tok->next()->link()->next();
10968                 while (tok1 && !Token::Match(tok1, "%name%")) {
10969                     tok1 = tok1->next();
10970                 }
10971                 if (tok1) {
10972                     if (tok->strAt(2) == "noreturn")
10973                         tok1->isAttributeNoreturn(true);
10974                     else
10975                         tok1->isAttributeNothrow(true);
10976                 }
10977             } else if (tok->strAt(2) == "property")
10978                 tok->next()->link()->insertToken("__property");
10979 
10980             Token::eraseTokens(tok, tok->next()->link()->next());
10981             tok->deleteThis();
10982         }
10983     }
10984 }
10985 
simplifyAttribute()10986 void Tokenizer::simplifyAttribute()
10987 {
10988     for (Token *tok = list.front(); tok; tok = tok->next()) {
10989         if (Token::Match(tok, "%type% (") && !mSettings->library.isNotLibraryFunction(tok)) {
10990             if (mSettings->library.isFunctionConst(tok->str(), true))
10991                 tok->isAttributePure(true);
10992             if (mSettings->library.isFunctionConst(tok->str(), false))
10993                 tok->isAttributeConst(true);
10994         }
10995         while (Token::Match(tok, "__attribute__|__attribute (")) {
10996             Token *after = tok;
10997             while (Token::Match(after, "__attribute__|__attribute ("))
10998                 after = after->linkAt(1)->next();
10999             if (!after)
11000                 syntaxError(tok);
11001 
11002             Token *functok = nullptr;
11003             if (Token::Match(after, "%name%|*")) {
11004                 Token *ftok = after;
11005                 while (Token::Match(ftok, "%name%|* !!("))
11006                     ftok = ftok->next();
11007                 if (Token::Match(ftok, "%name% ("))
11008                     functok = ftok;
11009             } else if (Token::Match(after, "[;{=:]")) {
11010                 Token *prev = tok->previous();
11011                 while (Token::Match(prev, "%name%"))
11012                     prev = prev->previous();
11013                 if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->previous(), "%name% ("))
11014                     functok = prev->link()->previous();
11015                 else if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
11016                     functok = tok->previous();
11017             }
11018 
11019             for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
11020                 if (Token::Match(attr, "%name% ("))
11021                     attr = attr->linkAt(1);
11022 
11023                 if (Token::Match(attr, "[(,] constructor|__constructor__ [,()]")) {
11024                     if (!functok)
11025                         syntaxError(tok);
11026                     functok->isAttributeConstructor(true);
11027                 }
11028 
11029                 else if (Token::Match(attr, "[(,] destructor|__destructor__ [,()]")) {
11030                     if (!functok)
11031                         syntaxError(tok);
11032                     functok->isAttributeDestructor(true);
11033                 }
11034 
11035                 else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
11036                     Token *vartok = nullptr;
11037 
11038                     // check if after variable name
11039                     if (Token::Match(after, ";|=")) {
11040                         if (Token::Match(tok->previous(), "%type%"))
11041                             vartok = tok->previous();
11042                     }
11043 
11044                     // check if before variable name
11045                     else if (Token::Match(after, "%type%"))
11046                         vartok = after;
11047 
11048                     if (vartok) {
11049                         const std::string &attribute(attr->next()->str());
11050                         if (attribute.find("unused") != std::string::npos)
11051                             vartok->isAttributeUnused(true);
11052                         else
11053                             vartok->isAttributeUsed(true);
11054                     }
11055                 }
11056 
11057                 else if (Token::Match(attr, "[(,] pure|__pure__|const|__const__|noreturn|__noreturn__|nothrow|__nothrow__|warn_unused_result [,)]")) {
11058                     if (!functok)
11059                         syntaxError(tok);
11060 
11061                     const std::string &attribute(attr->next()->str());
11062                     if (attribute.find("pure") != std::string::npos)
11063                         functok->isAttributePure(true);
11064                     else if (attribute.find("const") != std::string::npos)
11065                         functok->isAttributeConst(true);
11066                     else if (attribute.find("noreturn") != std::string::npos)
11067                         functok->isAttributeNoreturn(true);
11068                     else if (attribute.find("nothrow") != std::string::npos)
11069                         functok->isAttributeNothrow(true);
11070                     else if (attribute.find("warn_unused_result") != std::string::npos)
11071                         functok->isAttributeNodiscard(true);
11072                 }
11073 
11074                 else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
11075                     tok->previous()->isAttributePacked(true);
11076             }
11077 
11078             Token::eraseTokens(tok, tok->linkAt(1)->next());
11079             tok->deleteThis();
11080         }
11081     }
11082 }
11083 
simplifyCppcheckAttribute()11084 void Tokenizer::simplifyCppcheckAttribute()
11085 {
11086     for (Token *tok = list.front(); tok; tok = tok->next()) {
11087         if (tok->str() != "(")
11088             continue;
11089         if (!tok->previous())
11090             continue;
11091         const std::string &attr = tok->previous()->str();
11092         if (attr.compare(0, 11, "__cppcheck_") != 0) // TODO: starts_with("__cppcheck_")
11093             continue;
11094         if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
11095             continue;
11096 
11097         Token *vartok = tok->link();
11098         while (Token::Match(vartok->next(), "%name%|*|&|::")) {
11099             vartok = vartok->next();
11100             if (Token::Match(vartok, "%name% (") && vartok->str().compare(0,11,"__cppcheck_") == 0)
11101                 vartok = vartok->linkAt(1);
11102         }
11103 
11104         if (vartok->isName()) {
11105             if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
11106                 vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(tok->next()->str()));
11107             else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
11108                 vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(tok->next()->str()));
11109         }
11110 
11111         // Delete cppcheck attribute..
11112         if (tok->tokAt(-2)) {
11113             tok = tok->tokAt(-2);
11114             Token::eraseTokens(tok, tok->linkAt(2)->next());
11115         } else {
11116             tok = tok->previous();
11117             Token::eraseTokens(tok, tok->linkAt(1)->next());
11118             tok->str(";");
11119         }
11120     }
11121 }
11122 
simplifyCPPAttribute()11123 void Tokenizer::simplifyCPPAttribute()
11124 {
11125     if (mSettings->standards.cpp < Standards::CPP11 || isC())
11126         return;
11127 
11128     for (Token *tok = list.front(); tok; tok = tok->next()) {
11129         if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
11130             continue;
11131         }
11132         if (isCPPAttribute(tok)) {
11133             if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
11134                 const Token * head = skipCPPOrAlignAttribute(tok);
11135                 while (isCPPAttribute(head) || isAlignAttribute(head))
11136                     head = skipCPPOrAlignAttribute(head);
11137                 head = head->next();
11138                 while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
11139                     head = head->next();
11140                 if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
11141                     head->previous()->isAttributeNoreturn(true);
11142                 }
11143             } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
11144                 const Token * head = skipCPPOrAlignAttribute(tok);
11145                 while (isCPPAttribute(head) || isAlignAttribute(head))
11146                     head = skipCPPOrAlignAttribute(head);
11147                 head = head->next();
11148                 while (Token::Match(head, "%name%|::|*|&|<|>|,"))
11149                     head = head->next();
11150                 if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
11151                     head->previous()->isAttributeNodiscard(true);
11152                 }
11153             } else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
11154                 const Token* head = skipCPPOrAlignAttribute(tok);
11155                 while (isCPPAttribute(head) || isAlignAttribute(head))
11156                     head = skipCPPOrAlignAttribute(head);
11157                 head->next()->isAttributeMaybeUnused(true);
11158             } else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
11159                 const Token *vartok = tok->tokAt(4);
11160                 if (vartok->str() == ":")
11161                     vartok = vartok->next();
11162                 Token *argtok = tok->tokAt(-2);
11163                 while (argtok && argtok->str() != "(") {
11164                     if (argtok->str() == vartok->str())
11165                         break;
11166                     if (argtok->str() == ")")
11167                         argtok = argtok->link();
11168                     argtok = argtok->previous();
11169                 }
11170                 if (argtok && argtok->str() == vartok->str()) {
11171                     if (vartok->next()->str() == ">=")
11172                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2)));
11173                     else if (vartok->next()->str() == ">")
11174                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW, MathLib::toLongNumber(vartok->strAt(2))+1);
11175                     else if (vartok->next()->str() == "<=")
11176                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2)));
11177                     else if (vartok->next()->str() == "<")
11178                         argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH, MathLib::toLongNumber(vartok->strAt(2))-1);
11179                 }
11180             }
11181         } else {
11182             if (Token::simpleMatch(tok, "alignas (")) {
11183                 // alignment requirements could be checked here
11184             }
11185         }
11186         Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
11187         // fix iterator after removing
11188         if (tok->previous()) {
11189             tok = tok->previous();
11190             tok->next()->deleteThis();
11191         } else {
11192             tok->deleteThis();
11193             tok = list.front();
11194         }
11195     }
11196 }
11197 
removeAlignas()11198 void Tokenizer::removeAlignas()
11199 {
11200     if (!isCPP() || mSettings->standards.cpp < Standards::CPP11)
11201         return;
11202 
11203     for (Token *tok = list.front(); tok; tok = tok->next()) {
11204         if (Token::Match(tok, "[;{}] alignas (") && Token::Match(tok->linkAt(2), ") %name%"))
11205             Token::eraseTokens(tok, tok->linkAt(2)->next());
11206     }
11207 }
11208 
simplifySpaceshipOperator()11209 void Tokenizer::simplifySpaceshipOperator()
11210 {
11211     if (isCPP() && mSettings->standards.cpp >= Standards::CPP20) {
11212         for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
11213             if (Token::simpleMatch(tok, "<= >")) {
11214                 tok->str("<=>");
11215                 tok->deleteNext();
11216             }
11217         }
11218     }
11219 }
11220 
11221 static const std::unordered_set<std::string> keywords = {
11222     "inline"
11223     , "_inline"
11224     , "__inline"
11225     , "__forceinline"
11226     , "register"
11227     , "__restrict"
11228     , "__restrict__"
11229     , "__thread"
11230 };
11231 // Remove "inline", "register", "restrict", "override", "static" and "constexpr"
11232 // "restrict" keyword
11233 //   - New to 1999 ANSI/ISO C standard
11234 //   - Not in C++ standard yet
simplifyKeyword()11235 void Tokenizer::simplifyKeyword()
11236 {
11237     // FIXME: There is a risk that "keywords" are removed by mistake. This
11238     // code should be fixed so it doesn't remove variables etc. Nonstandard
11239     // keywords should be defined with a library instead. For instance the
11240     // linux kernel code at least uses "_inline" as struct member name at some
11241     // places.
11242 
11243     const bool c99 = isC() && mSettings->standards.c >= Standards::C99;
11244     const bool cpp11 = isCPP() && mSettings->standards.cpp >= Standards::CPP11;
11245 
11246     for (Token *tok = list.front(); tok; tok = tok->next()) {
11247         if (keywords.find(tok->str()) != keywords.end()) {
11248             // Don't remove struct members
11249             if (!Token::simpleMatch(tok->previous(), ".")) {
11250                 if (tok->str().find("inline") != std::string::npos && Token::Match(tok->next(), "%name%"))
11251                     tok->next()->isInline(true);
11252                 tok->deleteThis(); // Simplify..
11253             }
11254         }
11255 
11256         if (isC() || mSettings->standards.cpp == Standards::CPP03) {
11257             if (tok->str() == "auto")
11258                 tok->deleteThis();
11259         }
11260 
11261         // simplify static keyword:
11262         // void foo( int [ static 5 ] ); ==> void foo( int [ 5 ] );
11263         if (Token::Match(tok, "[ static %num%"))
11264             tok->deleteNext();
11265 
11266         if (c99) {
11267             while (tok->str() == "restrict")
11268                 tok->deleteThis();
11269 
11270             if (mSettings->standards.c >= Standards::C11) {
11271                 while (tok->str() == "_Atomic")
11272                     tok->deleteThis();
11273             }
11274         }
11275 
11276         else if (cpp11) {
11277             // final:
11278             // 1) struct name final { };   <- struct is final
11279             if (Token::Match(tok->previous(), "struct|class|union %type% final [:{]")) {
11280                 tok->deleteNext();
11281             }
11282 
11283             // noexcept -> noexcept(true)
11284             // 2) void f() noexcept; -> void f() noexcept(true);
11285             else if (Token::Match(tok, ") noexcept :|{|;|const|override|final")) {
11286                 // Insertion is done in inverse order
11287                 // The brackets are linked together accordingly afterwards
11288                 Token * tokNoExcept = tok->next();
11289                 tokNoExcept->insertToken(")");
11290                 Token * braceEnd = tokNoExcept->next();
11291                 tokNoExcept->insertToken("true");
11292                 tokNoExcept->insertToken("(");
11293                 Token * braceStart = tokNoExcept->next();
11294                 tok = tok->tokAt(3);
11295                 Token::createMutualLinks(braceStart, braceEnd);
11296             }
11297 
11298             // 3) thread_local -> static
11299             //    on single thread thread_local has the effect of static
11300             else if (tok->str() == "thread_local") {
11301                 tok->originalName(tok->str());
11302                 tok->str("static");
11303             }
11304         }
11305     }
11306 }
11307 
simplifyAssignmentInFunctionCall()11308 void Tokenizer::simplifyAssignmentInFunctionCall()
11309 {
11310     for (Token *tok = list.front(); tok; tok = tok->next()) {
11311         if (tok->str() == "(")
11312             tok = tok->link();
11313 
11314         // Find 'foo(var='. Exclude 'assert(var=' to allow tests to check that assert(...) does not contain side-effects
11315         else if (Token::Match(tok, "[;{}] %name% ( %name% =") &&
11316                  Token::simpleMatch(tok->linkAt(2), ") ;") &&
11317                  !Token::Match(tok->next(), "assert|while")) {
11318             const std::string& funcname(tok->next()->str());
11319             Token* const vartok = tok->tokAt(3);
11320 
11321             // Goto ',' or ')'..
11322             for (Token *tok2 = vartok->tokAt(2); tok2; tok2 = tok2->next()) {
11323                 if (tok2->link() && Token::Match(tok2, "(|[|{"))
11324                     tok2 = tok2->link();
11325                 else if (tok2->str() == ";")
11326                     break;
11327                 else if (Token::Match(tok2, ")|,")) {
11328                     tok2 = tok2->previous();
11329 
11330                     tok2->insertToken(vartok->str());
11331                     tok2->next()->varId(vartok->varId());
11332 
11333                     tok2->insertToken("(");
11334                     Token::createMutualLinks(tok2->next(), tok->linkAt(2));
11335 
11336                     tok2->insertToken(funcname);
11337                     tok2->insertToken(";");
11338 
11339                     Token::eraseTokens(tok, vartok);
11340                     break;
11341                 }
11342             }
11343         }
11344     }
11345 }
11346 
simplifyAssignmentBlock()11347 void Tokenizer::simplifyAssignmentBlock()
11348 {
11349     for (Token *tok = list.front(); tok; tok = tok->next()) {
11350         if (Token::Match(tok, "[;{}] %name% = ( {")) {
11351             const std::string &varname = tok->next()->str();
11352 
11353             // goto the "} )"
11354             int indentlevel = 0;
11355             Token *tok2 = tok;
11356             while (nullptr != (tok2 = tok2->next())) {
11357                 if (Token::Match(tok2, "(|{"))
11358                     ++indentlevel;
11359                 else if (Token::Match(tok2, ")|}")) {
11360                     if (indentlevel <= 2)
11361                         break;
11362                     --indentlevel;
11363                 } else if (indentlevel == 2 && tok2->str() == varname && Token::Match(tok2->previous(), "%type%|*"))
11364                     // declaring variable in inner scope with same name as lhs variable
11365                     break;
11366             }
11367             if (indentlevel == 2 && Token::simpleMatch(tok2, "} )")) {
11368                 tok2 = tok2->tokAt(-3);
11369                 if (Token::Match(tok2, "[;{}] %num%|%name% ;")) {
11370                     tok2->insertToken("=");
11371                     tok2->insertToken(tok->next()->str());
11372                     tok2->next()->varId(tok->next()->varId());
11373                     tok->deleteNext(3);
11374                     tok2->tokAt(5)->deleteNext();
11375                 }
11376             }
11377         }
11378     }
11379 }
11380 
11381 // Remove __asm..
simplifyAsm()11382 void Tokenizer::simplifyAsm()
11383 {
11384     std::string instruction;
11385     for (Token *tok = list.front(); tok; tok = tok->next()) {
11386         if (Token::Match(tok, "__asm|_asm|asm {") &&
11387             tok->next()->link()->next()) {
11388             instruction = tok->tokAt(2)->stringifyList(tok->next()->link());
11389             Token::eraseTokens(tok, tok->next()->link()->next());
11390         }
11391 
11392         else if (Token::Match(tok, "asm|__asm|__asm__ volatile|__volatile|__volatile__| (")) {
11393             // Goto "("
11394             Token *partok = tok->next();
11395             if (partok->str() != "(")
11396                 partok = partok->next();
11397             instruction = partok->next()->stringifyList(partok->link());
11398             Token::eraseTokens(tok, partok->link()->next());
11399         }
11400 
11401         else if (Token::Match(tok, "_asm|__asm")) {
11402             Token *endasm = tok->next();
11403             const Token *firstSemiColon = nullptr;
11404             int comment = 0;
11405             while (Token::Match(endasm, "%num%|%name%|,|:|;") || (endasm && endasm->linenr() == comment)) {
11406                 if (Token::Match(endasm, "_asm|__asm|__endasm"))
11407                     break;
11408                 if (endasm->str() == ";") {
11409                     comment = endasm->linenr();
11410                     if (!firstSemiColon)
11411                         firstSemiColon = endasm;
11412                 }
11413                 endasm = endasm->next();
11414             }
11415             if (Token::simpleMatch(endasm, "__endasm")) {
11416                 instruction = tok->next()->stringifyList(endasm);
11417                 Token::eraseTokens(tok, endasm->next());
11418                 if (!Token::simpleMatch(tok->next(), ";"))
11419                     tok->insertToken(";");
11420             } else if (firstSemiColon) {
11421                 instruction = tok->next()->stringifyList(firstSemiColon);
11422                 Token::eraseTokens(tok, firstSemiColon);
11423             } else if (!endasm) {
11424                 instruction = tok->next()->stringifyList(endasm);
11425                 Token::eraseTokens(tok, endasm);
11426                 tok->insertToken(";");
11427             } else
11428                 continue;
11429         }
11430 
11431         else
11432             continue;
11433 
11434         // insert "asm ( "instruction" )"
11435         tok->str("asm");
11436         if (tok->strAt(1) != ";" && tok->strAt(1) != "{")
11437             tok->insertToken(";");
11438         tok->insertToken(")");
11439         tok->insertToken("\"" + instruction + "\"");
11440         tok->insertToken("(");
11441 
11442         tok = tok->next();
11443         Token::createMutualLinks(tok, tok->tokAt(2));
11444 
11445         //move the new tokens in the same line as ";" if available
11446         tok = tok->tokAt(2);
11447         if (tok->next() && tok->next()->str() == ";" &&
11448             tok->next()->linenr() != tok->linenr()) {
11449             const int endposition = tok->next()->linenr();
11450             tok = tok->tokAt(-3);
11451             for (int i = 0; i < 4; ++i) {
11452                 tok = tok->next();
11453                 tok->linenr(endposition);
11454             }
11455         }
11456     }
11457 }
11458 
simplifyAsm2()11459 void Tokenizer::simplifyAsm2()
11460 {
11461     // Block declarations: ^{}
11462     // A C extension used to create lambda like closures.
11463 
11464     // Put ^{} statements in asm()
11465     for (Token *tok = list.front(); tok; tok = tok->next()) {
11466         if (tok->str() != "^")
11467             continue;
11468 
11469         if (Token::simpleMatch(tok, "^ {") || (Token::simpleMatch(tok->linkAt(1), ") {") && tok->strAt(-1) != "operator")) {
11470             Token * start = tok;
11471             while (start && !Token::Match(start, "[,(;{}=]")) {
11472                 if (start->link() && Token::Match(start, ")|]|>"))
11473                     start = start->link();
11474                 start = start->previous();
11475             }
11476 
11477             const Token *last = tok->next()->link();
11478             if (Token::simpleMatch(last, ") {"))
11479                 last = last->linkAt(1);
11480             last = last->next();
11481             while (last && !Token::Match(last, "%cop%|,|;|{|}|)")) {
11482                 if (Token::Match(last, "(|["))
11483                     last = last->link();
11484                 last = last->next();
11485             }
11486 
11487             if (start && last) {
11488                 std::string asmcode;
11489                 while (start->next() != last) {
11490                     asmcode += start->next()->str();
11491                     start->deleteNext();
11492                 }
11493                 if (last->str() == "}")
11494                     start->insertToken(";");
11495                 start->insertToken(")");
11496                 start->insertToken("\"" + asmcode + "\"");
11497                 start->insertToken("(");
11498                 start->insertToken("asm");
11499                 start->tokAt(2)->link(start->tokAt(4));
11500                 start->tokAt(4)->link(start->tokAt(2));
11501                 tok = start->tokAt(4);
11502             }
11503         }
11504     }
11505 }
11506 
simplifyAt()11507 void Tokenizer::simplifyAt()
11508 {
11509     std::set<std::string> var;
11510 
11511     for (Token *tok = list.front(); tok; tok = tok->next()) {
11512         if (Token::Match(tok, "%name%|] @ %num%|%name%|(")) {
11513             const Token *end = tok->tokAt(2);
11514             if (end->isNumber())
11515                 end = end->next();
11516             else if (end->str() == "(") {
11517                 int par = 0;
11518                 while ((end = end->next()) != nullptr) {
11519                     if (end->str() == "(")
11520                         par++;
11521                     else if (end->str() == ")") {
11522                         if (--par < 0)
11523                             break;
11524                     }
11525                 }
11526                 end = end ? end->next() : nullptr;
11527             } else if (var.find(end->str()) != var.end())
11528                 end = end->next();
11529             else
11530                 continue;
11531 
11532             if (Token::Match(end, ": %num% ;"))
11533                 end = end->tokAt(2);
11534 
11535             if (end && end->str() == ";") {
11536                 if (tok->isName())
11537                     var.insert(tok->str());
11538                 tok->isAtAddress(true);
11539                 Token::eraseTokens(tok, end);
11540             }
11541         }
11542 
11543         // keywords in compiler from cosmic software for STM8
11544         // TODO: Should use platform configuration.
11545         if (Token::Match(tok, "@ builtin|eeprom|far|inline|interrupt|near|noprd|nostack|nosvf|packed|stack|svlreg|tiny|vector")) {
11546             tok->str(tok->next()->str() + "@");
11547             tok->deleteNext();
11548         }
11549     }
11550 }
11551 
11552 // Simplify bitfields
simplifyBitfields()11553 void Tokenizer::simplifyBitfields()
11554 {
11555     bool goback = false;
11556     for (Token *tok = list.front(); tok; tok = tok->next()) {
11557         if (goback) {
11558             goback = false;
11559             tok = tok->previous();
11560         }
11561         Token *last = nullptr;
11562 
11563         if (Token::simpleMatch(tok, "for ("))
11564             tok = tok->linkAt(1);
11565 
11566         if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
11567             continue;
11568 
11569         bool isEnum = false;
11570         if (tok->str() == "}") {
11571             const Token *type = tok->link()->previous();
11572             while (type && type->isName()) {
11573                 if (type->str() == "enum") {
11574                     isEnum = true;
11575                     break;
11576                 }
11577                 type = type->previous();
11578             }
11579         }
11580 
11581         if (Token::Match(tok->next(), "const| %type% %name% :") &&
11582             !Token::Match(tok->next(), "case|public|protected|private|class|struct") &&
11583             !Token::simpleMatch(tok->tokAt(2), "default :")) {
11584             Token *tok1 = (tok->next()->str() == "const") ? tok->tokAt(3) : tok->tokAt(2);
11585             if (Token::Match(tok1, "%name% : %num% ;"))
11586                 tok1->setBits(MathLib::toLongNumber(tok1->strAt(2)));
11587             if (tok1 && tok1->tokAt(2) &&
11588                 (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
11589                  !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
11590                 while (tok1->next() && !Token::Match(tok1->next(), "[;,)]{}]")) {
11591                     if (Token::Match(tok1->next(), "[([]"))
11592                         Token::eraseTokens(tok1, tok1->next()->link());
11593                     tok1->deleteNext();
11594                 }
11595 
11596                 last = tok1->next();
11597             }
11598         } else if (isEnum && Token::Match(tok, "} %name%| : %num% ;")) {
11599             if (tok->next()->str() == ":") {
11600                 tok->deleteNext(2);
11601                 tok->insertToken("Anonymous");
11602             } else {
11603                 tok->next()->deleteNext(2);
11604             }
11605         } else if (Token::Match(tok->next(), "const| %type% : %num%|%bool% ;") &&
11606                    tok->next()->str() != "default") {
11607             const int offset = (tok->next()->str() == "const") ? 1 : 0;
11608             if (!Token::Match(tok->tokAt(3 + offset), "[{};()]")) {
11609                 tok->deleteNext(4 + offset);
11610                 goback = true;
11611             }
11612         }
11613 
11614         if (last && last->str() == ",") {
11615             Token * tok1 = last;
11616             tok1->str(";");
11617 
11618             const Token *const tok2 = tok->next();
11619             tok1->insertToken(tok2->str());
11620             tok1 = tok1->next();
11621             tok1->isSigned(tok2->isSigned());
11622             tok1->isUnsigned(tok2->isUnsigned());
11623             tok1->isLong(tok2->isLong());
11624         }
11625     }
11626 }
11627 
11628 
11629 // Types and objects in std namespace that are neither functions nor templates
11630 static const std::set<std::string> stdTypes = {
11631     "string", "wstring", "u16string", "u32string",
11632     "iostream", "ostream", "ofstream", "ostringstream",
11633     "istream", "ifstream", "istringstream", "fstream", "stringstream",
11634     "wstringstream", "wistringstream", "wostringstream", "wstringbuf",
11635     "stringbuf", "streambuf", "ios", "filebuf", "ios_base",
11636     "exception", "bad_exception", "bad_alloc",
11637     "logic_error", "domain_error", "invalid_argument_", "length_error",
11638     "out_of_range", "runtime_error", "range_error", "overflow_error", "underflow_error",
11639     "locale",
11640     "cout", "cerr", "clog", "cin",
11641     "wcerr", "wcin", "wclog", "wcout",
11642     "endl", "ends", "flush",
11643     "boolalpha", "noboolalpha", "showbase", "noshowbase",
11644     "showpoint", "noshowpoint", "showpos", "noshowpos",
11645     "skipws", "noskipws", "unitbuf", "nounitbuf", "uppercase", "nouppercase",
11646     "dec", "hex", "oct",
11647     "fixed", "scientific",
11648     "internal", "left", "right",
11649     "fpos", "streamoff", "streampos", "streamsize"
11650 };
11651 
11652 static const std::set<std::string> stdTemplates = {
11653     "array", "basic_string", "bitset", "deque", "list", "map", "multimap",
11654     "priority_queue", "queue", "set", "multiset", "stack", "vector", "pair",
11655     "iterator", "iterator_traits",
11656     "unordered_map", "unordered_multimap", "unordered_set", "unordered_multiset",
11657     "tuple", "function"
11658 };
11659 static const std::set<std::string> stdFunctions = {
11660     "getline",
11661     "for_each", "find", "find_if", "find_end", "find_first_of",
11662     "adjacent_find", "count", "count_if", "mismatch", "equal", "search", "search_n",
11663     "copy", "copy_backward", "swap", "swap_ranges", "iter_swap", "transform", "replace",
11664     "replace_if", "replace_copy", "replace_copy_if", "fill", "fill_n", "generate", "generate_n", "remove",
11665     "remove_if", "remove_copy", "remove_copy_if",
11666     "unique", "unique_copy", "reverse", "reverse_copy",
11667     "rotate", "rotate_copy", "random_shuffle", "partition", "stable_partition",
11668     "sort", "stable_sort", "partial_sort", "partial_sort_copy", "nth_element",
11669     "lower_bound", "upper_bound", "equal_range", "binary_search", "merge", "inplace_merge", "includes",
11670     "set_union", "set_intersection", "set_difference",
11671     "set_symmetric_difference", "push_heap", "pop_heap", "make_heap", "sort_heap",
11672     "min", "max", "min_element", "max_element", "lexicographical_compare", "next_permutation", "prev_permutation",
11673     "advance", "back_inserter", "distance", "front_inserter", "inserter",
11674     "make_pair", "make_shared", "make_tuple"
11675 };
11676 
11677 
11678 // Add std:: in front of std classes, when using namespace std; was given
simplifyNamespaceStd()11679 void Tokenizer::simplifyNamespaceStd()
11680 {
11681     if (!isCPP())
11682         return;
11683 
11684     const bool isCPP11  = mSettings->standards.cpp == Standards::CPP11;
11685 
11686     std::set<std::string> userFunctions;
11687 
11688     for (const Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
11689         bool insert = false;
11690         if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
11691             skipEnumBody(&tok);
11692         }
11693         if (!Token::Match(tok->previous(), ".|::")) {
11694             if (Token::Match(tok, "%name% (")) {
11695                 if (isFunctionHead(tok->next(), "{"))
11696                     userFunctions.insert(tok->str());
11697                 else if (isFunctionHead(tok->next(), ";")) {
11698                     const Token *start = tok;
11699                     while (Token::Match(start->previous(), "%type%|*|&"))
11700                         start = start->previous();
11701                     if (start != tok && start->isName() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
11702                         userFunctions.insert(tok->str());
11703                 }
11704                 if (userFunctions.find(tok->str()) == userFunctions.end() && stdFunctions.find(tok->str()) != stdFunctions.end())
11705                     insert = true;
11706             } else if (Token::Match(tok, "%name% <") && stdTemplates.find(tok->str()) != stdTemplates.end())
11707                 insert = true;
11708             else if (tok->isName() && !tok->varId() && !Token::Match(tok->next(), "(|<") && stdTypes.find(tok->str()) != stdTypes.end())
11709                 insert = true;
11710         }
11711 
11712         if (insert) {
11713             tok->previous()->insertToken("std");
11714             tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
11715             tok->previous()->fileIndex(tok->fileIndex());
11716             tok->previous()->insertToken("::");
11717         } else if (isCPP11 && Token::Match(tok, "!!:: tr1 ::"))
11718             tok->next()->str("std");
11719     }
11720 
11721     for (Token* tok = list.front(); tok; tok = tok->next()) {
11722         if (isCPP11 && Token::simpleMatch(tok, "std :: tr1 ::"))
11723             Token::eraseTokens(tok, tok->tokAt(3));
11724 
11725         else if (Token::simpleMatch(tok, "using namespace std ;")) {
11726             Token::eraseTokens(tok, tok->tokAt(4));
11727             tok->deleteThis();
11728         }
11729     }
11730 }
11731 
11732 
simplifyMicrosoftMemoryFunctions()11733 void Tokenizer::simplifyMicrosoftMemoryFunctions()
11734 {
11735     // skip if not Windows
11736     if (!mSettings->isWindowsPlatform())
11737         return;
11738 
11739     for (Token *tok = list.front(); tok; tok = tok->next()) {
11740         if (tok->strAt(1) != "(")
11741             continue;
11742 
11743         if (Token::Match(tok, "CopyMemory|RtlCopyMemory|RtlCopyBytes")) {
11744             tok->str("memcpy");
11745         } else if (Token::Match(tok, "MoveMemory|RtlMoveMemory")) {
11746             tok->str("memmove");
11747         } else if (Token::Match(tok, "FillMemory|RtlFillMemory|RtlFillBytes")) {
11748             // FillMemory(dst, len, val) -> memset(dst, val, len)
11749             tok->str("memset");
11750 
11751             Token *tok1 = tok->tokAt(2);
11752             if (tok1)
11753                 tok1 = tok1->nextArgument(); // Second argument
11754             if (tok1) {
11755                 Token *tok2 = tok1->nextArgument(); // Third argument
11756 
11757                 if (tok2)
11758                     Token::move(tok1->previous(), tok2->tokAt(-2), tok->next()->link()->previous()); // Swap third with second argument
11759             }
11760         } else if (Token::Match(tok, "ZeroMemory|RtlZeroMemory|RtlZeroBytes|RtlSecureZeroMemory")) {
11761             // ZeroMemory(dst, len) -> memset(dst, 0, len)
11762             tok->str("memset");
11763 
11764             Token *tok1 = tok->tokAt(2);
11765             if (tok1)
11766                 tok1 = tok1->nextArgument(); // Second argument
11767 
11768             if (tok1) {
11769                 tok1 = tok1->previous();
11770                 tok1->insertToken("0");
11771                 tok1 = tok1->next();
11772                 tok1->insertToken(",");
11773             }
11774         } else if (Token::simpleMatch(tok, "RtlCompareMemory")) {
11775             // RtlCompareMemory(src1, src2, len) -> memcmp(src1, src2, len)
11776             tok->str("memcmp");
11777             // For the record, when memcmp returns 0, both strings are equal.
11778             // When RtlCompareMemory returns len, both strings are equal.
11779             // It might be needed to improve this replacement by something
11780             // like ((len - memcmp(src1, src2, len)) % (len + 1)) to
11781             // respect execution path (if required)
11782         }
11783     }
11784 }
11785 
11786 namespace {
11787     struct triplet {
triplet__anon5685b77f0511::triplet11788         triplet(const char* m, const char* u) :  mbcs(m), unicode(u) {}
11789         std::string mbcs, unicode;
11790     };
11791 
11792     const std::map<std::string, triplet> apis = {
11793         std::make_pair("_topen", triplet("open", "_wopen")),
11794         std::make_pair("_tsopen_s", triplet("_sopen_s", "_wsopen_s")),
11795         std::make_pair("_tfopen", triplet("fopen", "_wfopen")),
11796         std::make_pair("_tfopen_s", triplet("fopen_s", "_wfopen_s")),
11797         std::make_pair("_tfreopen", triplet("freopen", "_wfreopen")),
11798         std::make_pair("_tfreopen_s", triplet("freopen_s", "_wfreopen_s")),
11799         std::make_pair("_tcscat", triplet("strcat", "wcscat")),
11800         std::make_pair("_tcschr", triplet("strchr", "wcschr")),
11801         std::make_pair("_tcscmp", triplet("strcmp", "wcscmp")),
11802         std::make_pair("_tcsdup", triplet("strdup", "wcsdup")),
11803         std::make_pair("_tcscpy", triplet("strcpy", "wcscpy")),
11804         std::make_pair("_tcslen", triplet("strlen", "wcslen")),
11805         std::make_pair("_tcsncat", triplet("strncat", "wcsncat")),
11806         std::make_pair("_tcsncpy", triplet("strncpy", "wcsncpy")),
11807         std::make_pair("_tcsnlen", triplet("strnlen", "wcsnlen")),
11808         std::make_pair("_tcsrchr", triplet("strrchr", "wcsrchr")),
11809         std::make_pair("_tcsstr", triplet("strstr", "wcsstr")),
11810         std::make_pair("_tcstok", triplet("strtok", "wcstok")),
11811         std::make_pair("_ftprintf", triplet("fprintf", "fwprintf")),
11812         std::make_pair("_tprintf", triplet("printf", "wprintf")),
11813         std::make_pair("_stprintf", triplet("sprintf", "swprintf")),
11814         std::make_pair("_sntprintf", triplet("_snprintf", "_snwprintf")),
11815         std::make_pair("_ftscanf", triplet("fscanf", "fwscanf")),
11816         std::make_pair("_tscanf", triplet("scanf", "wscanf")),
11817         std::make_pair("_stscanf", triplet("sscanf", "swscanf")),
11818         std::make_pair("_ftprintf_s", triplet("fprintf_s", "fwprintf_s")),
11819         std::make_pair("_tprintf_s", triplet("printf_s", "wprintf_s")),
11820         std::make_pair("_stprintf_s", triplet("sprintf_s", "swprintf_s")),
11821         std::make_pair("_sntprintf_s", triplet("_snprintf_s", "_snwprintf_s")),
11822         std::make_pair("_ftscanf_s", triplet("fscanf_s", "fwscanf_s")),
11823         std::make_pair("_tscanf_s", triplet("scanf_s", "wscanf_s")),
11824         std::make_pair("_stscanf_s", triplet("sscanf_s", "swscanf_s"))
11825     };
11826 }
11827 
simplifyMicrosoftStringFunctions()11828 void Tokenizer::simplifyMicrosoftStringFunctions()
11829 {
11830     // skip if not Windows
11831     if (!mSettings->isWindowsPlatform())
11832         return;
11833 
11834     const bool ansi = mSettings->platformType == Settings::Win32A;
11835     for (Token *tok = list.front(); tok; tok = tok->next()) {
11836         if (tok->strAt(1) != "(")
11837             continue;
11838 
11839         const std::map<std::string, triplet>::const_iterator match = apis.find(tok->str());
11840         if (match!=apis.end()) {
11841             tok->str(ansi ? match->second.mbcs : match->second.unicode);
11842             tok->originalName(match->first);
11843         } else if (Token::Match(tok, "_T|_TEXT|TEXT ( %char%|%str% )")) {
11844             tok->deleteNext();
11845             tok->deleteThis();
11846             tok->deleteNext();
11847             if (!ansi) {
11848                 tok->isLong(true);
11849                 if (tok->str()[0] != 'L')
11850                     tok->str("L" + tok->str());
11851             }
11852             while (Token::Match(tok->next(), "_T|_TEXT|TEXT ( %char%|%str% )")) {
11853                 tok->next()->deleteNext();
11854                 tok->next()->deleteThis();
11855                 tok->next()->deleteNext();
11856                 tok->concatStr(tok->next()->str());
11857                 tok->deleteNext();
11858             }
11859         }
11860     }
11861 }
11862 
11863 // Remove Borland code
simplifyBorland()11864 void Tokenizer::simplifyBorland()
11865 {
11866     // skip if not Windows
11867     if (!mSettings->isWindowsPlatform())
11868         return;
11869     if (isC())
11870         return;
11871     for (Token *tok = list.front(); tok; tok = tok->next()) {
11872         if (Token::Match(tok, "( __closure * %name% )")) {
11873             tok->deleteNext();
11874         }
11875     }
11876 
11877     // I think that these classes are always declared at the outer scope
11878     // I save some time by ignoring inner classes.
11879     for (Token *tok = list.front(); tok; tok = tok->next()) {
11880         if (tok->str() == "{" && !Token::Match(tok->tokAt(-2), "namespace %type%")) {
11881             tok = tok->link();
11882             if (!tok)
11883                 break;
11884         } else if (Token::Match(tok, "class %name% :|{")) {
11885             while (tok && tok->str() != "{" && tok->str() != ";")
11886                 tok = tok->next();
11887             if (!tok)
11888                 break;
11889             if (tok->str() == ";")
11890                 continue;
11891 
11892             const Token* end = tok->link()->next();
11893             for (Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
11894                 if (tok2->str() == "__property" &&
11895                     Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) {
11896                     while (tok2->next() && !Token::Match(tok2->next(), "{|;"))
11897                         tok2->deleteNext();
11898                     tok2->deleteThis();
11899                     if (tok2->str() == "{") {
11900                         Token::eraseTokens(tok2, tok2->link());
11901                         tok2->deleteNext();
11902                         tok2->deleteThis();
11903 
11904                         // insert "; __property ;"
11905                         tok2->previous()->insertToken(";");
11906                         tok2->previous()->insertToken("__property");
11907                         tok2->previous()->insertToken(";");
11908                     }
11909                 }
11910             }
11911         }
11912     }
11913 }
11914 
11915 // Remove Qt signals and slots
simplifyQtSignalsSlots()11916 void Tokenizer::simplifyQtSignalsSlots()
11917 {
11918     if (isC())
11919         return;
11920     for (Token *tok = list.front(); tok; tok = tok->next()) {
11921         // check for emit which can be outside of class
11922         if (Token::Match(tok, "emit|Q_EMIT %name% (") &&
11923             Token::simpleMatch(tok->linkAt(2), ") ;")) {
11924             tok->deleteThis();
11925         } else if (!Token::Match(tok, "class %name% :|::|{"))
11926             continue;
11927 
11928         if (tok->previous() && tok->previous()->str() == "enum") {
11929             tok = tok->tokAt(2);
11930             continue;
11931         }
11932 
11933         // count { and } for tok2
11934         int indentlevel = 0;
11935         for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
11936             if (tok2->str() == "{") {
11937                 ++indentlevel;
11938                 if (indentlevel == 1)
11939                     tok = tok2;
11940                 else
11941                     tok2 = tok2->link();
11942             } else if (tok2->str() == "}") {
11943                 if (indentlevel<2)
11944                     break;
11945                 else
11946                     --indentlevel;
11947             } else if (tok2->str() == ";" && indentlevel == 0)
11948                 break;
11949 
11950             if (tok2->strAt(1) == "Q_OBJECT")
11951                 tok2->deleteNext();
11952 
11953             if (Token::Match(tok2->next(), "public|protected|private slots|Q_SLOTS :")) {
11954                 tok2 = tok2->next();
11955                 tok2->str(tok2->str() + ":");
11956                 tok2->deleteNext(2);
11957                 tok2 = tok2->previous();
11958             } else if (Token::Match(tok2->next(), "signals|Q_SIGNALS :")) {
11959                 tok2 = tok2->next();
11960                 tok2->str("protected:");
11961                 tok2->deleteNext();
11962             } else if (Token::Match(tok2->next(), "emit|Q_EMIT %name% (") &&
11963                        Token::simpleMatch(tok2->linkAt(3), ") ;")) {
11964                 tok2->deleteNext();
11965             }
11966         }
11967     }
11968 }
11969 
createSymbolDatabase()11970 void Tokenizer::createSymbolDatabase()
11971 {
11972     if (!mSymbolDatabase)
11973         mSymbolDatabase = new SymbolDatabase(this, mSettings, mErrorLogger);
11974     mSymbolDatabase->validate();
11975 }
11976 
deleteSymbolDatabase()11977 void Tokenizer::deleteSymbolDatabase()
11978 {
11979     delete mSymbolDatabase;
11980     mSymbolDatabase = nullptr;
11981 }
11982 
operatorEnd(const Token * tok) const11983 bool Tokenizer::operatorEnd(const Token * tok) const
11984 {
11985     if (tok && tok->str() == ")") {
11986         if (isFunctionHead(tok, "{|;|?|:|["))
11987             return true;
11988 
11989         tok = tok->next();
11990         while (tok && !Token::Match(tok, "[=;{),]")) {
11991             if (Token::Match(tok, "const|volatile|override")) {
11992                 tok = tok->next();
11993             } else if (tok->str() == "noexcept") {
11994                 tok = tok->next();
11995                 if (tok && tok->str() == "(") {
11996                     tok = tok->link()->next();
11997                 }
11998             } else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
11999                 tok = tok->next()->link()->next();
12000             }
12001             // unknown macros ") MACRO {" and ") MACRO(...) {"
12002             else if (tok->isUpperCaseName()) {
12003                 tok = tok->next();
12004                 if (tok && tok->str() == "(") {
12005                     tok = tok->link()->next();
12006                 }
12007             } else if (Token::Match(tok, "%op% !!(") ||
12008                        (Token::Match(tok, "%op% (") && !isFunctionHead(tok->next(), "{")))
12009                 break;
12010             else
12011                 return false;
12012         }
12013 
12014         return true;
12015     }
12016 
12017     return false;
12018 }
12019 
simplifyOperatorName()12020 void Tokenizer::simplifyOperatorName()
12021 {
12022     if (isC())
12023         return;
12024 
12025     for (Token *tok = list.front(); tok; tok = tok->next()) {
12026         if (Token::Match(tok, "using|:: operator %op%|%name% ;")) {
12027             tok->next()->str("operator" + tok->strAt(2));
12028             tok->next()->deleteNext();
12029             continue;
12030         }
12031 
12032         if (tok->str() != "operator")
12033             continue;
12034         // operator op
12035         if (Token::Match(tok, "operator %op% (") && !operatorEnd(tok->linkAt(2))) {
12036             tok->str(tok->str() + tok->next()->str());
12037             tok->deleteNext();
12038             continue;
12039         }
12040         std::string op;
12041         Token *par = tok->next();
12042         bool done = false;
12043         while (!done && par) {
12044             done = true;
12045             if (par->isName()) {
12046                 op += par->str();
12047                 par = par->next();
12048                 // merge namespaces eg. 'operator std :: string () const {'
12049                 if (Token::Match(par, ":: %name%|%op%|.")) {
12050                     op += par->str();
12051                     par = par->next();
12052                 }
12053                 done = false;
12054             } else if (Token::Match(par, ".|%op%|,")) {
12055                 // check for operator in template
12056                 if (par->str() == "," && !op.empty())
12057                     break;
12058                 if (!(Token::Match(par, "<|>") && !op.empty())) {
12059                     op += par->str();
12060                     par = par->next();
12061                     done = false;
12062                 }
12063             } else if (Token::simpleMatch(par, "[ ]")) {
12064                 op += "[]";
12065                 par = par->tokAt(2);
12066                 done = false;
12067             } else if (Token::Match(par, "( *| )")) {
12068                 // break out and simplify..
12069                 if (operatorEnd(par->next()))
12070                     break;
12071 
12072                 while (par->str() != ")") {
12073                     op += par->str();
12074                     par = par->next();
12075                 }
12076                 op += ")";
12077                 par = par->next();
12078                 if (Token::simpleMatch(par, "...")) {
12079                     op.clear();
12080                     par = nullptr;
12081                     break;
12082                 }
12083                 done = false;
12084             } else if (Token::Match(par, "\"\" %name% (|;|<")) {
12085                 op += "\"\"";
12086                 op += par->strAt(1);
12087                 par = par->tokAt(2);
12088                 done = true;
12089             } else if (par->str() == "::") {
12090                 op += par->str();
12091                 par = par->next();
12092                 done = false;
12093             } else if (par->str() == ";" || par->str() == ")") {
12094                 done = true;
12095             } else if (par->str() != "(") {
12096                 syntaxError(par, "operator");
12097             }
12098         }
12099 
12100         if (par && !op.empty()) {
12101             tok->str("operator" + op);
12102             Token::eraseTokens(tok, par);
12103         }
12104 
12105         if (!op.empty())
12106             tok->isOperatorKeyword(true);
12107     }
12108 
12109     for (Token *tok = list.front(); tok; tok = tok->next()) {
12110         if (Token::Match(tok, "%op% %str% %name%")) {
12111             std::string name = tok->strAt(2);
12112             Token * const str = tok->next();
12113             str->deleteNext();
12114             tok->insertToken("operator\"\"" + name);
12115             tok = tok->next();
12116             tok->isOperatorKeyword(true);
12117             tok->insertToken("(");
12118             str->insertToken(")");
12119             Token::createMutualLinks(tok->next(), str->next());
12120             str->insertToken(MathLib::toString(Token::getStrLength(str)));
12121             str->insertToken(",");
12122         }
12123     }
12124 
12125     if (mSettings->debugwarnings) {
12126         const Token *tok = list.front();
12127 
12128         while ((tok = Token::findsimplematch(tok, "operator")) != nullptr) {
12129             reportError(tok, Severity::debug, "debug",
12130                         "simplifyOperatorName: found unsimplified operator name");
12131             tok = tok->next();
12132         }
12133     }
12134 }
12135 
simplifyOverloadedOperators()12136 void Tokenizer::simplifyOverloadedOperators()
12137 {
12138     if (isC())
12139         return;
12140     std::set<std::string> classNames;
12141     std::set<nonneg int> classVars;
12142     for (Token *tok = list.front(); tok; tok = tok->next()) {
12143         if (!tok->isName())
12144             continue;
12145 
12146         if (Token::simpleMatch(tok, "this ) (") && Token::simpleMatch(tok->tokAt(-2), "( *")) {
12147             tok = tok->next();
12148             tok->insertToken("operator()");
12149             tok->insertToken(".");
12150             continue;
12151         }
12152 
12153         // Get classes that have operator() member
12154         if (Token::Match(tok, "class|struct %name% [:{]")) {
12155             int indent = 0;
12156             for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
12157                 if (tok2->str() == "}")
12158                     break;
12159                 else if (indent == 0 && tok2->str() == ";")
12160                     break;
12161                 else if (tok2->str() == "{") {
12162                     if (indent == 0)
12163                         ++indent;
12164                     else
12165                         tok2 = tok2->link();
12166                 } else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
12167                     classNames.insert(tok->strAt(1));
12168                     break;
12169                 }
12170             }
12171         }
12172 
12173         // Get variables that have operator() member
12174         if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
12175             tok = tok->next();
12176             while (!tok->isName())
12177                 tok = tok->next();
12178             classVars.insert(tok->varId());
12179         }
12180 
12181         // Simplify operator() calls
12182         if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
12183             // constructor init list..
12184             if (Token::Match(tok->previous(), "[:,]")) {
12185                 const Token *start = tok->previous();
12186                 while (Token::simpleMatch(start, ",")) {
12187                     if (Token::simpleMatch(start->previous(), ")"))
12188                         start = start->linkAt(-1);
12189                     else
12190                         break;
12191                     if (Token::Match(start->previous(), "%name%"))
12192                         start = start->tokAt(-2);
12193                     else
12194                         break;
12195                 }
12196                 const Token *after = tok->linkAt(1);
12197                 while (Token::Match(after, ")|} , %name% (|{"))
12198                     after = after->linkAt(3);
12199 
12200                 // Do not simplify initlist
12201                 if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
12202                     continue;
12203             }
12204 
12205             tok->insertToken("operator()");
12206             tok->insertToken(".");
12207         }
12208     }
12209 }
12210 
12211 // remove unnecessary member qualification..
removeUnnecessaryQualification()12212 void Tokenizer::removeUnnecessaryQualification()
12213 {
12214     if (isC())
12215         return;
12216 
12217     std::vector<Space> classInfo;
12218     for (Token *tok = list.front(); tok; tok = tok->next()) {
12219         if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
12220             (!tok->previous() || tok->previous()->str() != "enum")) {
12221             Space info;
12222             info.isNamespace = tok->str() == "namespace";
12223             tok = tok->next();
12224             info.className = tok->str();
12225             tok = tok->next();
12226             while (tok && tok->str() != "{")
12227                 tok = tok->next();
12228             if (!tok)
12229                 return;
12230             info.bodyEnd = tok->link();
12231             classInfo.push_back(info);
12232         } else if (!classInfo.empty()) {
12233             if (tok == classInfo.back().bodyEnd)
12234                 classInfo.pop_back();
12235             else if (tok->str() == classInfo.back().className &&
12236                      !classInfo.back().isNamespace && tok->previous()->str() != ":" &&
12237                      (Token::Match(tok, "%type% :: ~| %type% (") ||
12238                       Token::Match(tok, "%type% :: operator"))) {
12239                 const Token *tok1 = tok->tokAt(3);
12240                 if (tok->strAt(2) == "operator") {
12241                     // check for operator ()
12242                     if (tok1->str() == "(")
12243                         tok1 = tok1->next();
12244 
12245                     while (tok1 && tok1->str() != "(") {
12246                         if (tok1->str() == ";")
12247                             break;
12248                         tok1 = tok1->next();
12249                     }
12250                     if (!tok1 || tok1->str() != "(")
12251                         continue;
12252                 } else if (tok->strAt(2) == "~")
12253                     tok1 = tok1->next();
12254 
12255                 if (!tok1 || !Token::Match(tok1->link(), ") const| {|;|:")) {
12256                     continue;
12257                 }
12258 
12259                 const bool isConstructorOrDestructor =
12260                     Token::Match(tok, "%type% :: ~| %type%") && (tok->strAt(2) == tok->str() || (tok->strAt(2) == "~" && tok->strAt(3) == tok->str()));
12261                 if (!isConstructorOrDestructor) {
12262                     bool isPrependedByType = Token::Match(tok->previous(), "%type%");
12263                     if (!isPrependedByType) {
12264                         const Token* tok2 = tok->tokAt(-2);
12265                         isPrependedByType = Token::Match(tok2, "%type% *|&");
12266                     }
12267                     if (!isPrependedByType) {
12268                         const Token* tok3 = tok->tokAt(-3);
12269                         isPrependedByType = Token::Match(tok3, "%type% * *|&");
12270                     }
12271                     if (!isPrependedByType) {
12272                         // It's not a constructor declaration and it's not a function declaration so
12273                         // this is a function call which can have all the qualifiers just fine - skip.
12274                         continue;
12275                     }
12276                 }
12277             }
12278         }
12279     }
12280 }
12281 
simplifyReturnStrncat()12282 void Tokenizer::simplifyReturnStrncat()
12283 {
12284     for (Token *tok = list.front(); tok; tok = tok->next()) {
12285         if (Token::simpleMatch(tok, "return strncat (") &&
12286             Token::simpleMatch(tok->linkAt(2), ") ;") &&
12287             tok->strAt(3) != ")" && tok->strAt(3) != ",") {
12288 
12289             //first argument
12290             Token *tok2 = tok->tokAt(3);
12291 
12292             //check if there are at least three arguments
12293             for (int i = 0; i < 2; ++i) {
12294                 tok2 = tok2->nextArgument();
12295                 if (!tok2) {
12296                     tok = tok->linkAt(2)->next();
12297                     break;
12298                 }
12299             }
12300             if (!tok2)
12301                 continue;
12302 
12303             tok2 = tok2->nextArgument();
12304             //we want only three arguments
12305             if (tok2) {
12306                 tok = tok->linkAt(2)->next();
12307                 continue;
12308             }
12309 
12310             // Remove 'return'
12311             tok->deleteThis();
12312 
12313             // Add 'return arg1 ;' after 'strncat(arg1, arg2, arg3);'
12314             tok = tok->next();
12315 
12316             tok2 = tok->link()->next();
12317             tok2->insertToken(";");
12318 
12319             //the last token of the first argument before ','
12320             const Token * const end = tok->next()->nextArgument()->tokAt(-2);
12321 
12322             //all the first argument is copied
12323             TokenList::copyTokens(tok2, tok->next(), end);
12324             tok2->insertToken("return");
12325         }
12326     }
12327 }
12328 
printUnknownTypes() const12329 void Tokenizer::printUnknownTypes() const
12330 {
12331     if (!mSymbolDatabase)
12332         return;
12333 
12334     std::multimap<std::string, const Token *> unknowns;
12335 
12336     for (int i = 1; i <= mVarId; ++i) {
12337         const Variable *var = mSymbolDatabase->getVariableFromVarId(i);
12338         if (!var)
12339             continue;
12340         // is unknown type?
12341         if (var->type() || var->typeStartToken()->isStandardType())
12342             continue;
12343 
12344         std::string name;
12345         const Token * nameTok;
12346 
12347         // single token type?
12348         if (var->typeStartToken() == var->typeEndToken()) {
12349             nameTok = var->typeStartToken();
12350             name = nameTok->str();
12351         }
12352 
12353         // complicated type
12354         else {
12355             const Token *tok = var->typeStartToken();
12356             int level = 0;
12357 
12358             nameTok =  tok;
12359 
12360             while (tok) {
12361                 // skip pointer and reference part of type
12362                 if (level == 0 && Token::Match(tok, "*|&"))
12363                     break;
12364 
12365                 name += tok->str();
12366 
12367                 if (Token::Match(tok, "struct|union|enum"))
12368                     name += " ";
12369 
12370                 // pointers and references are OK in template
12371                 else if (tok->str() == "<")
12372                     ++level;
12373                 else if (tok->str() == ">")
12374                     --level;
12375 
12376                 if (tok == var->typeEndToken())
12377                     break;
12378 
12379                 tok = tok->next();
12380             }
12381         }
12382 
12383         unknowns.insert(std::pair<std::string, const Token *>(name, nameTok));
12384     }
12385 
12386     if (!unknowns.empty()) {
12387         std::string last;
12388         int count = 0;
12389 
12390         for (std::multimap<std::string, const Token *>::const_iterator it = unknowns.begin(); it != unknowns.end(); ++it) {
12391             // skip types is std namespace because they are not interesting
12392             if (it->first.find("std::") != 0) {
12393                 if (it->first != last) {
12394                     last = it->first;
12395                     count = 1;
12396                     reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
12397                 } else {
12398                     if (count < 3) // limit same type to 3
12399                         reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
12400                     count++;
12401                 }
12402             }
12403         }
12404     }
12405 }
12406 
simplifyMathExpressions()12407 void Tokenizer::simplifyMathExpressions()
12408 {
12409     for (Token *tok = list.front(); tok; tok = tok->next()) {
12410 
12411         //simplify Pythagorean trigonometric identity: pow(sin(x),2)+pow(cos(x),2) = 1
12412         //                                             pow(cos(x),2)+pow(sin(x),2) = 1
12413         // @todo: sin(x) * sin(x) + cos(x) * cos(x) = 1
12414         //        cos(x) * cos(x) + sin(x) * sin(x) = 1
12415         //simplify Hyperbolic identity: pow(sinh(x),2)-pow(cosh(x),2) = -1
12416         //                              pow(cosh(x),2)-pow(sinh(x),2) = -1
12417         // @todo: sinh(x) * sinh(x) - cosh(x) * cosh(x) = -1
12418         //        cosh(x) * cosh(x) - sinh(x) * sinh(x) = -1
12419         if (Token::Match(tok, "pow|powf|powl (")) {
12420             if (Token::Match(tok->tokAt(2), "sin|sinf|sinl (")) {
12421                 Token * const tok2 = tok->linkAt(3);
12422                 if (!Token::Match(tok2, ") , %num% ) + pow|powf|powl ( cos|cosf|cosl ("))
12423                     continue;
12424                 const std::string& leftExponent = tok2->strAt(2);
12425                 if (!isTwoNumber(leftExponent))
12426                     continue; // left exponent is not 2
12427                 const Token * const tok3 = tok2->tokAt(8);
12428                 Token * const tok4 = tok3->link();
12429                 if (!Token::Match(tok4, ") , %num% )"))
12430                     continue;
12431                 const std::string& rightExponent = tok4->strAt(2);
12432                 if (!isTwoNumber(rightExponent))
12433                     continue; // right exponent is not 2
12434                 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok4->next())) {
12435                     Token::eraseTokens(tok, tok4->tokAt(4));
12436                     tok->str("1");
12437                 }
12438             } else if (Token::Match(tok->tokAt(2), "cos|cosf|cosl (")) {
12439                 Token * const tok2 = tok->linkAt(3);
12440                 if (!Token::Match(tok2, ") , %num% ) + pow|powf|powl ( sin|sinf|sinl ("))
12441                     continue;
12442                 const std::string& leftExponent = tok2->strAt(2);
12443                 if (!isTwoNumber(leftExponent))
12444                     continue; // left exponent is not 2
12445                 const Token * const tok3 = tok2->tokAt(8);
12446                 Token * const tok4 = tok3->link();
12447                 if (!Token::Match(tok4, ") , %num% )"))
12448                     continue;
12449                 const std::string& rightExponent = tok4->strAt(2);
12450                 if (!isTwoNumber(rightExponent))
12451                     continue; // right exponent is not 2
12452                 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok4->next())) {
12453                     Token::eraseTokens(tok, tok4->tokAt(4));
12454                     tok->str("1");
12455                 }
12456             } else if (Token::Match(tok->tokAt(2), "sinh|sinhf|sinhl (")) {
12457                 Token * const tok2 = tok->linkAt(3);
12458                 if (!Token::Match(tok2, ") , %num% ) - pow|powf|powl ( cosh|coshf|coshl ("))
12459                     continue;
12460                 const std::string& leftExponent = tok2->strAt(2);
12461                 if (!isTwoNumber(leftExponent))
12462                     continue; // left exponent is not 2
12463                 const Token * const tok3 = tok2->tokAt(8);
12464                 Token * const tok4 = tok3->link();
12465                 if (!Token::Match(tok4, ") , %num% )"))
12466                     continue;
12467                 const std::string& rightExponent = tok4->strAt(2);
12468                 if (!isTwoNumber(rightExponent))
12469                     continue; // right exponent is not 2
12470                 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok4->next())) {
12471                     Token::eraseTokens(tok, tok4->tokAt(4));
12472                     tok->str("-1");
12473                 }
12474             } else if (Token::Match(tok->tokAt(2), "cosh|coshf|coshl (")) {
12475                 Token * const tok2 = tok->linkAt(3);
12476                 if (!Token::Match(tok2, ") , %num% ) - pow|powf|powl ( sinh|sinhf|sinhl ("))
12477                     continue;
12478                 const std::string& leftExponent = tok2->strAt(2);
12479                 if (!isTwoNumber(leftExponent))
12480                     continue; // left exponent is not 2
12481                 const Token * const tok3 = tok2->tokAt(8);
12482                 Token * const tok4 = tok3->link();
12483                 if (!Token::Match(tok4, ") , %num% )"))
12484                     continue;
12485                 const std::string& rightExponent = tok4->strAt(2);
12486                 if (!isTwoNumber(rightExponent))
12487                     continue; // right exponent is not 2
12488                 if (tok->tokAt(3)->stringifyList(tok2->next()) == tok3->stringifyList(tok4->next())) {
12489                     Token::eraseTokens(tok, tok4->tokAt(4));
12490                     tok->str("-1");
12491                 }
12492             }
12493         }
12494     }
12495 }
12496 
simplifyStrlen()12497 bool Tokenizer::simplifyStrlen()
12498 {
12499     // replace strlen(str)
12500     bool modified=false;
12501     for (Token *tok = list.front(); tok; tok = tok->next()) {
12502         if (Token::Match(tok, "strlen ( %str% )")) {
12503             tok->str(MathLib::toString(Token::getStrLength(tok->tokAt(2))));
12504             tok->deleteNext(3);
12505             modified=true;
12506         }
12507     }
12508     return modified;
12509 }
12510 
prepareTernaryOpForAST()12511 void Tokenizer::prepareTernaryOpForAST()
12512 {
12513     // http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
12514     //       "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
12515     // The AST parser relies on this function to add such parentheses where necessary.
12516     for (Token* tok = list.front(); tok; tok = tok->next()) {
12517         if (tok->str() == "?") {
12518             bool parenthesesNeeded = false;
12519             int depth = 0;
12520             Token* tok2 = tok->next();
12521             for (; tok2; tok2 = tok2->next()) {
12522                 if (tok2->link() && Token::Match(tok2, "[|(|<"))
12523                     tok2 = tok2->link();
12524                 else if (tok2->str() == ":") {
12525                     if (depth == 0)
12526                         break;
12527                     depth--;
12528                 } else if (tok2->str() == ";" || (tok2->link() && tok2->str() != "{" && tok2->str() != "}"))
12529                     break;
12530                 else if (tok2->str() == ",")
12531                     parenthesesNeeded = true;
12532                 else if (tok2->str() == "<")
12533                     parenthesesNeeded = true;
12534                 else if (tok2->str() == "?") {
12535                     depth++;
12536                     parenthesesNeeded = true;
12537                 }
12538             }
12539             if (parenthesesNeeded && tok2 && tok2->str() == ":") {
12540                 tok->insertToken("(");
12541                 tok2->insertToken(")", emptyString, true);
12542                 Token::createMutualLinks(tok->next(), tok2->previous());
12543             }
12544         }
12545     }
12546 }
12547 
reportError(const Token * tok,const Severity::SeverityType severity,const std::string & id,const std::string & msg,bool inconclusive) const12548 void Tokenizer::reportError(const Token* tok, const Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive) const
12549 {
12550     const std::list<const Token*> callstack(1, tok);
12551     reportError(callstack, severity, id, msg, inconclusive);
12552 }
12553 
reportError(const std::list<const Token * > & callstack,Severity::SeverityType severity,const std::string & id,const std::string & msg,bool inconclusive) const12554 void Tokenizer::reportError(const std::list<const Token*>& callstack, Severity::SeverityType severity, const std::string& id, const std::string& msg, bool inconclusive) const
12555 {
12556     const ErrorMessage errmsg(callstack, &list, severity, id, msg, inconclusive ? Certainty::inconclusive : Certainty::normal);
12557     if (mErrorLogger)
12558         mErrorLogger->reportErr(errmsg);
12559     else
12560         Check::reportError(errmsg);
12561 }
12562 
setPodTypes()12563 void Tokenizer::setPodTypes()
12564 {
12565     if (!mSettings)
12566         return;
12567     for (Token *tok = list.front(); tok; tok = tok->next()) {
12568         if (!tok->isName())
12569             continue;
12570 
12571         // pod type
12572         const struct Library::PodType *podType = mSettings->library.podtype(tok->str());
12573         if (podType) {
12574             const Token *prev = tok->previous();
12575             while (prev && prev->isName())
12576                 prev = prev->previous();
12577             if (prev && !Token::Match(prev, ";|{|}|,|("))
12578                 continue;
12579             tok->isStandardType(true);
12580         }
12581     }
12582 }
12583 
findSQLBlockEnd(const Token * tokSQLStart)12584 const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
12585 {
12586     const Token *tokLastEnd = nullptr;
12587     for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr; tok = tok->next()) {
12588         if (tokLastEnd == nullptr && tok->str() == ";")
12589             tokLastEnd = tok;
12590         else if (tok->str() == "__CPPCHECK_EMBEDDED_SQL_EXEC__") {
12591             if (Token::simpleMatch(tok->tokAt(-2), "END - __CPPCHECK_EMBEDDED_SQL_EXEC__ ;"))
12592                 return tok->next();
12593             return tokLastEnd;
12594         } else if (Token::Match(tok, "{|}|==|&&|!|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|~"))
12595             break; // We are obviously outside the SQL block
12596     }
12597 
12598     return tokLastEnd;
12599 }
12600 
simplifyNestedNamespace()12601 void Tokenizer::simplifyNestedNamespace()
12602 {
12603     if (!isCPP())
12604         return;
12605 
12606     for (Token *tok = list.front(); tok; tok = tok->next()) {
12607         if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
12608             Token * tok2 = tok->tokAt(2);
12609 
12610             // validate syntax
12611             while (Token::Match(tok2, ":: %name%"))
12612                 tok2 = tok2->tokAt(2);
12613 
12614             if (!tok2 || tok2->str() != "{")
12615                 return; // syntax error
12616 
12617             std::stack<Token *> links;
12618             tok2 = tok->tokAt(2);
12619 
12620             while (tok2->str() == "::") {
12621                 links.push(tok2);
12622                 tok2->str("{");
12623                 tok2->insertToken("namespace");
12624                 tok2 = tok2->tokAt(3);
12625             }
12626 
12627             tok = tok2;
12628 
12629             if (!links.empty() && tok2->str() == "{") {
12630                 tok2 = tok2->link();
12631                 while (!links.empty()) {
12632                     tok2->insertToken("}");
12633                     tok2 = tok2->next();
12634                     Token::createMutualLinks(links.top(), tok2);
12635                     links.pop();
12636                 }
12637             }
12638         }
12639     }
12640 }
12641 
simplifyCoroutines()12642 void Tokenizer::simplifyCoroutines()
12643 {
12644     if (!isCPP() || mSettings->standards.cpp < Standards::CPP20)
12645         return;
12646     for (Token *tok = list.front(); tok; tok = tok->next()) {
12647         if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await"))
12648             continue;
12649         Token *end = tok->next();
12650         while (end && end->str() != ";") {
12651             if (Token::Match(end, "[({[]"))
12652                 end = end->link();
12653             else if (Token::Match(end, "[)]}]"))
12654                 break;
12655             end = end->next();
12656         }
12657         if (Token::simpleMatch(end, ";")) {
12658             tok->insertToken("(");
12659             end->previous()->insertToken(")");
12660             Token::createMutualLinks(tok->next(), end->previous());
12661         }
12662     }
12663 }
12664 
sameTokens(const Token * first,const Token * last,const Token * other)12665 static bool sameTokens(const Token *first, const Token *last, const Token *other)
12666 {
12667     while (other && first->str() == other->str()) {
12668         if (first == last)
12669             return true;
12670         first = first->next();
12671         other = other->next();
12672     }
12673 
12674     return false;
12675 }
12676 
alreadyHasNamespace(const Token * first,const Token * last,const Token * end)12677 static bool alreadyHasNamespace(const Token *first, const Token *last, const Token *end)
12678 {
12679     while (end && last->str() == end->str()) {
12680         if (first == last)
12681             return true;
12682         last = last->previous();
12683         end = end->previous();
12684     }
12685 
12686     return false;
12687 }
12688 
deleteAlias(Token * tok)12689 static Token * deleteAlias(Token * tok)
12690 {
12691     Token::eraseTokens(tok, Token::findsimplematch(tok, ";"));
12692 
12693     // delete first token
12694     tok->deleteThis();
12695 
12696     // delete ';' if not last token
12697     tok->deleteThis();
12698 
12699     return tok;
12700 }
12701 
simplifyNamespaceAliases()12702 void Tokenizer::simplifyNamespaceAliases()
12703 {
12704     if (!isCPP())
12705         return;
12706 
12707     int scope = 0;
12708 
12709     for (Token *tok = list.front(); tok; tok = tok->next()) {
12710         if (tok->str() == "{")
12711             scope++;
12712         else if (tok->str() == "}")
12713             scope--;
12714         else if (Token::Match(tok, "namespace %name% =")) {
12715             const std::string name(tok->next()->str());
12716             Token * tokNameStart = tok->tokAt(3);
12717             Token * tokNameEnd = tokNameStart;
12718 
12719             while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";")
12720                 tokNameEnd = tokNameEnd->next();
12721 
12722             if (!tokNameEnd)
12723                 return; // syntax error
12724 
12725             int endScope = scope;
12726             Token * tokLast = tokNameEnd->next();
12727             Token * tokNext = tokLast->next();
12728             Token * tok2 = tokNext;
12729 
12730             while (tok2 && endScope >= scope) {
12731                 if (Token::simpleMatch(tok2, "{"))
12732                     endScope++;
12733                 else if (Token::simpleMatch(tok2, "}"))
12734                     endScope--;
12735                 else if (tok2->str() == name) {
12736                     if (Token::Match(tok2->previous(), "namespace %name% =")) {
12737                         // check for possible duplicate aliases
12738                         if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
12739                             // delete duplicate
12740                             tok2 = deleteAlias(tok2->previous());
12741                             continue;
12742                         } else {
12743                             // conflicting declaration (syntax error)
12744                             // cppcheck-suppress duplicateBranch - remove when TODO below is addressed
12745                             if (endScope == scope) {
12746                                 // delete conflicting declaration
12747                                 tok2 = deleteAlias(tok2->previous());
12748                             }
12749 
12750                             // new declaration
12751                             else {
12752                                 // TODO: use the new alias in this scope
12753                                 tok2 = deleteAlias(tok2->previous());
12754                             }
12755                             continue;
12756                         }
12757                     }
12758 
12759                     if (tok2->strAt(1) == "::" && !alreadyHasNamespace(tokNameStart, tokNameEnd, tok2)) {
12760                         tok2->str(tokNameStart->str());
12761                         Token * tok3 = tokNameStart;
12762                         while (tok3 != tokNameEnd) {
12763                             tok2->insertToken(tok3->next()->str());
12764                             tok2 = tok2->next();
12765                             tok3 = tok3->next();
12766                         }
12767                     }
12768                 }
12769                 tok2 = tok2->next();
12770             }
12771 
12772             if (tok->previous() && tokNext) {
12773                 Token::eraseTokens(tok->previous(), tokNext);
12774                 tok = tokNext->previous();
12775             } else if (tok->previous()) {
12776                 Token::eraseTokens(tok->previous(), tokLast);
12777                 tok = tokLast;
12778             } else if (tokNext) {
12779                 Token::eraseTokens(tok, tokNext);
12780                 tok->deleteThis();
12781             } else {
12782                 Token::eraseTokens(tok, tokLast);
12783                 tok->deleteThis();
12784             }
12785         }
12786     }
12787 }
12788 
12789 
VariableMap()12790 Tokenizer::VariableMap::VariableMap() : mVarId(0) {}
12791 
enterScope()12792 void Tokenizer::VariableMap::enterScope()
12793 {
12794     mScopeInfo.push(std::list<std::pair<std::string, int>>());
12795 }
12796 
leaveScope()12797 bool Tokenizer::VariableMap::leaveScope()
12798 {
12799     if (mScopeInfo.empty())
12800         return false;
12801 
12802     for (const std::pair<std::string, int> &outerVariable : mScopeInfo.top()) {
12803         if (outerVariable.second != 0)
12804             mVariableId[outerVariable.first] = outerVariable.second;
12805         else
12806             mVariableId.erase(outerVariable.first);
12807     }
12808     mScopeInfo.pop();
12809     return true;
12810 }
12811 
addVariable(const std::string & varname)12812 void Tokenizer::VariableMap::addVariable(const std::string &varname)
12813 {
12814     if (mScopeInfo.empty()) {
12815         mVariableId[varname] = ++mVarId;
12816         return;
12817     }
12818     std::map<std::string, int>::iterator it = mVariableId.find(varname);
12819     if (it == mVariableId.end()) {
12820         mScopeInfo.top().push_back(std::pair<std::string, int>(varname, 0));
12821         mVariableId[varname] = ++mVarId;
12822         return;
12823     }
12824     mScopeInfo.top().push_back(std::pair<std::string, int>(varname, it->second));
12825     it->second = ++mVarId;
12826 }
12827 
hasVariable(const std::string & varname) const12828 bool Tokenizer::VariableMap::hasVariable(const std::string &varname) const
12829 {
12830     return mVariableId.find(varname) != mVariableId.end();
12831 }
12832 
hasIfdef(const Token * start,const Token * end) const12833 bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
12834 {
12835     if (!mPreprocessor)
12836         return false;
12837     for (const Directive &d: mPreprocessor->getDirectives()) {
12838         if (d.str.compare(0,3,"#if") == 0 &&
12839             d.linenr >= start->linenr() &&
12840             d.linenr <= end->linenr() &&
12841             start->fileIndex() < list.getFiles().size() &&
12842             d.file == list.getFiles()[start->fileIndex()])
12843             return true;
12844     }
12845     return false;
12846 }
12847