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, ¤tScope, 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, ¤tScope1, 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 ¯oName) 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