Line data Source code
1 : /*
2 : * Cppcheck - A tool for static C/C++ code analysis
3 : * Copyright (C) 2007-2024 Cppcheck team.
4 : *
5 : * This program is free software: you can redistribute it and/or modify
6 : * it under the terms of the GNU General Public License as published by
7 : * the Free Software Foundation, either version 3 of the License, or
8 : * (at your option) any later version.
9 : *
10 : * This program is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 : * GNU General Public License for more details.
14 : *
15 : * You should have received a copy of the GNU General Public License
16 : * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 : */
18 :
19 : //---------------------------------------------------------------------------
20 : #include "tokenize.h"
21 :
22 : #include "errorlogger.h"
23 : #include "errortypes.h"
24 : #include "library.h"
25 : #include "mathlib.h"
26 : #include "path.h"
27 : #include "platform.h"
28 : #include "preprocessor.h"
29 : #include "settings.h"
30 : #include "standards.h"
31 : #include "summaries.h"
32 : #include "symboldatabase.h"
33 : #include "templatesimplifier.h"
34 : #include "timer.h"
35 : #include "token.h"
36 : #include "utils.h"
37 : #include "valueflow.h"
38 : #include "vfvalue.h"
39 :
40 : #include <algorithm>
41 : #include <cassert>
42 : #include <cctype>
43 : #include <cstdlib>
44 : #include <cstring>
45 : #include <ctime>
46 : #include <iostream>
47 : #include <iterator>
48 : #include <exception>
49 : #include <memory>
50 : #include <set>
51 : #include <sstream>
52 : #include <stack>
53 : #include <stdexcept>
54 : #include <unordered_map>
55 : #include <unordered_set>
56 : #include <utility>
57 : #include <vector>
58 :
59 : #include <simplecpp.h>
60 :
61 : //---------------------------------------------------------------------------
62 :
63 : namespace {
64 : // local struct used in setVarId
65 : // in order to store information about the scope
66 : struct VarIdScopeInfo {
67 22632 : VarIdScopeInfo() = default;
68 50521 : VarIdScopeInfo(bool isExecutable, bool isStructInit, bool isEnum, nonneg int startVarid)
69 50521 : : isExecutable(isExecutable), isStructInit(isStructInit), isEnum(isEnum), startVarid(startVarid) {}
70 :
71 : const bool isExecutable{};
72 : const bool isStructInit{};
73 : const bool isEnum{};
74 : const nonneg int startVarid{};
75 : };
76 : }
77 :
78 : /** Return whether tok is the "{" that starts an enumerator list */
79 14858 : static bool isEnumStart(const Token* tok)
80 : {
81 14858 : if (!tok || tok->str() != "{")
82 0 : return false;
83 14859 : return (tok->strAt(-1) == "enum") || (tok->strAt(-2) == "enum") || Token::Match(tok->tokAt(-3), "enum class %name%");
84 : }
85 :
86 : template<typename T>
87 8 : static void skipEnumBody(T *&tok)
88 : {
89 8 : T *defStart = tok;
90 34 : while (Token::Match(defStart, "%name%|::|:"))
91 26 : defStart = defStart->next();
92 8 : if (defStart && defStart->str() == "{")
93 7 : tok = defStart->link()->next();
94 8 : }
95 :
96 496336 : const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &endsWith)
97 : {
98 496336 : if (!tok)
99 1 : return nullptr;
100 496335 : if (tok->str() == "(")
101 272519 : tok = tok->link();
102 496334 : if (tok->str() != ")")
103 130 : return nullptr;
104 496201 : if (!tok->isCpp() && !Token::Match(tok->link()->previous(), "%name%|)"))
105 11682 : return nullptr;
106 484519 : if (Token::Match(tok, ") ;|{|[")) {
107 375663 : tok = tok->next();
108 376114 : while (tok && tok->str() == "[" && tok->link()) {
109 458 : if (endsWith.find(tok->str()) != std::string::npos)
110 1 : return tok;
111 457 : tok = tok->link()->next();
112 : }
113 375655 : return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
114 : }
115 108853 : if (tok->isCpp() && tok->str() == ")") {
116 107660 : tok = tok->next();
117 343344 : while (Token::Match(tok, "const|noexcept|override|final|volatile|mutable|&|&& !!(") ||
118 167810 : (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
119 67875 : tok = tok->next();
120 107661 : if (tok && tok->str() == ")")
121 67410 : tok = tok->next();
122 107716 : while (tok && tok->str() == "[")
123 56 : tok = tok->link()->next();
124 107660 : if (Token::Match(tok, "throw|noexcept ("))
125 1167 : tok = tok->linkAt(1)->next();
126 107660 : if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
127 73 : tok = tok->linkAt(1)->next();
128 107662 : if (tok && tok->originalName() == "->") { // trailing return type
129 3387 : for (tok = tok->next(); tok && !Token::Match(tok, ";|{|override|final"); tok = tok->next())
130 2457 : if (tok->link() && Token::Match(tok, "<|[|("))
131 319 : tok = tok->link();
132 : }
133 335384 : while (Token::Match(tok, "override|final !!(") ||
134 167661 : (Token::Match(tok, "%name% !!(") && tok->isUpperCaseName()))
135 60061 : tok = tok->next();
136 107663 : if (Token::Match(tok, "= 0|default|delete ;"))
137 1244 : tok = tok->tokAt(2);
138 107662 : if (tok && tok->str() == ":" && !Token::Match(tok->next(), "%name%|::"))
139 126 : return nullptr;
140 107536 : return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
141 : }
142 1192 : return nullptr;
143 : }
144 :
145 : /**
146 : * is tok the start brace { of a class, struct, union, or enum
147 : */
148 4416 : static bool isClassStructUnionEnumStart(const Token * tok)
149 : {
150 4416 : if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {"))
151 947 : return false;
152 3466 : const Token * tok2 = tok->previous();
153 8401 : while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|;"))
154 4935 : tok2 = tok2->previous();
155 3466 : return Token::Match(tok2, "class|struct|union|enum");
156 : }
157 :
158 : //---------------------------------------------------------------------------
159 :
160 23898 : Tokenizer::Tokenizer(const Settings &settings, ErrorLogger &errorLogger) :
161 : list(&settings),
162 : mSettings(settings),
163 : mErrorLogger(errorLogger),
164 23898 : mTemplateSimplifier(new TemplateSimplifier(*this))
165 23898 : {}
166 :
167 23897 : Tokenizer::~Tokenizer()
168 : {
169 23898 : delete mSymbolDatabase;
170 23898 : delete mTemplateSimplifier;
171 23898 : }
172 :
173 :
174 : //---------------------------------------------------------------------------
175 : // SizeOfType - gives the size of a type
176 : //---------------------------------------------------------------------------
177 :
178 722 : nonneg int Tokenizer::sizeOfType(const std::string& type) const
179 : {
180 722 : const std::map<std::string, int>::const_iterator it = mTypeSize.find(type);
181 722 : if (it == mTypeSize.end()) {
182 696 : const Library::PodType* podtype = mSettings.library.podtype(type);
183 696 : if (!podtype)
184 696 : return 0;
185 :
186 0 : return podtype->size;
187 : }
188 26 : return it->second;
189 : }
190 :
191 35 : nonneg int Tokenizer::sizeOfType(const Token *type) const
192 : {
193 35 : if (!type || type->str().empty())
194 0 : return 0;
195 :
196 35 : if (type->tokType() == Token::eString)
197 0 : return Token::getStrLength(type) + 1U;
198 :
199 35 : const std::map<std::string, int>::const_iterator it = mTypeSize.find(type->str());
200 35 : if (it == mTypeSize.end()) {
201 4 : const Library::PodType* podtype = mSettings.library.podtype(type->str());
202 4 : if (!podtype)
203 4 : return 0;
204 :
205 0 : return podtype->size;
206 : }
207 31 : if (type->isLong()) {
208 0 : if (type->str() == "double")
209 0 : return mSettings.platform.sizeof_long_double;
210 0 : if (type->str() == "long")
211 0 : return mSettings.platform.sizeof_long_long;
212 : }
213 :
214 31 : return it->second;
215 : }
216 : //---------------------------------------------------------------------------
217 :
218 : // check if this statement is a duplicate definition
219 341 : bool Tokenizer::duplicateTypedef(Token *&tokPtr, const Token *name, const Token *typeDef) const
220 : {
221 : // check for an end of definition
222 341 : Token * tok = tokPtr;
223 341 : if (tok && Token::Match(tok->next(), ";|,|[|=|)|>|(|{")) {
224 58 : Token * end = tok->next();
225 :
226 58 : if (end->str() == "[") {
227 0 : if (!end->link())
228 0 : syntaxError(end); // invalid code
229 0 : end = end->link()->next();
230 58 : } else if (end->str() == ",") {
231 : // check for derived class
232 4 : if (Token::Match(tok->previous(), "public|private|protected"))
233 0 : return false;
234 :
235 : // find end of definition
236 8 : while (end && end->next() && !Token::Match(end->next(), ";|)|>")) {
237 4 : if (end->next()->str() == "(")
238 0 : end = end->linkAt(1);
239 :
240 4 : end = (end)?end->next():nullptr;
241 : }
242 4 : if (end)
243 4 : end = end->next();
244 54 : } else if (end->str() == "(") {
245 19 : if (startsWith(tok->previous()->str(), "operator"))
246 : // conversion operator
247 9 : return false;
248 10 : if (tok->previous()->str() == "typedef")
249 : // typedef of function returning this type
250 0 : return false;
251 10 : if (Token::Match(tok->previous(), "public:|private:|protected:"))
252 0 : return false;
253 10 : if (tok->previous()->str() == ">") {
254 2 : if (!Token::Match(tok->tokAt(-2), "%type%"))
255 1 : return false;
256 :
257 1 : if (!Token::Match(tok->tokAt(-3), ",|<"))
258 1 : return false;
259 :
260 0 : tokPtr = end->link();
261 0 : return true;
262 : }
263 : }
264 :
265 47 : if (end) {
266 47 : if (Token::simpleMatch(end, ") {")) { // function parameter ?
267 : // look backwards
268 0 : if (Token::Match(tok->previous(), "%type%") &&
269 0 : !Token::Match(tok->previous(), "return|new|const|struct")) {
270 : // duplicate definition so skip entire function
271 0 : tokPtr = end->next()->link();
272 0 : return true;
273 : }
274 47 : } else if (end->str() == ">") { // template parameter ?
275 : // look backwards
276 18 : if (Token::Match(tok->previous(), "%type%") &&
277 0 : !Token::Match(tok->previous(), "return|new|const|volatile")) {
278 : // duplicate definition so skip entire template
279 0 : while (end && end->str() != "{")
280 0 : end = end->next();
281 0 : if (end) {
282 0 : tokPtr = end->link();
283 0 : return true;
284 : }
285 : }
286 : } else {
287 : // look backwards
288 55 : if (Token::Match(tok->previous(), "typedef|}|>") ||
289 56 : (end->str() == ";" && tok->previous()->str() == ",") ||
290 82 : (tok->previous()->str() == "*" && tok->next()->str() != "(") ||
291 26 : (Token::Match(tok->previous(), "%type%") &&
292 8 : (!Token::Match(tok->previous(), "return|new|const|friend|public|private|protected|throw|extern") &&
293 4 : !Token::simpleMatch(tok->tokAt(-2), "friend class")))) {
294 : // scan backwards for the end of the previous statement
295 17 : while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{")) {
296 16 : if (tok->previous()->str() == "}") {
297 3 : tok = tok->previous()->link();
298 13 : } else if (tok->previous()->str() == "typedef") {
299 4 : return true;
300 9 : } else if (tok->previous()->str() == "enum") {
301 0 : return true;
302 9 : } else if (tok->previous()->str() == "struct") {
303 4 : if (tok->strAt(-2) == "typedef" &&
304 4 : tok->next()->str() == "{" &&
305 2 : typeDef->strAt(3) != "{") {
306 : // declaration after forward declaration
307 2 : return true;
308 : }
309 0 : if (tok->next()->str() == "{")
310 0 : return true;
311 0 : if (Token::Match(tok->next(), ")|*"))
312 0 : return true;
313 0 : if (tok->next()->str() == name->str())
314 0 : return true;
315 0 : if (tok->next()->str() != ";")
316 0 : return true;
317 0 : return false;
318 7 : } else if (tok->previous()->str() == "union") {
319 0 : return tok->next()->str() != ";";
320 7 : } else if (tok->isCpp() && tok->previous()->str() == "class") {
321 0 : return tok->next()->str() != ";";
322 : }
323 10 : if (tok)
324 10 : tok = tok->previous();
325 : }
326 :
327 1 : if (tokPtr->strAt(1) != "(" || !Token::Match(tokPtr->linkAt(1), ") .|(|["))
328 0 : return true;
329 : }
330 : }
331 : }
332 : }
333 :
334 324 : return false;
335 : }
336 :
337 4 : void Tokenizer::unsupportedTypedef(const Token *tok) const
338 : {
339 4 : if (!mSettings.debugwarnings)
340 1 : return;
341 :
342 3 : std::ostringstream str;
343 3 : const Token *tok1 = tok;
344 3 : int level = 0;
345 17 : while (tok) {
346 17 : if (level == 0 && tok->str() == ";")
347 3 : break;
348 14 : if (tok->str() == "{")
349 0 : ++level;
350 14 : else if (tok->str() == "}") {
351 0 : if (level == 0)
352 0 : break;
353 0 : --level;
354 : }
355 :
356 14 : if (tok != tok1)
357 11 : str << " ";
358 14 : str << tok->str();
359 14 : tok = tok->next();
360 : }
361 3 : if (tok)
362 3 : str << " ;";
363 :
364 3 : reportError(tok1, Severity::debug, "simplifyTypedef",
365 6 : "Failed to parse \'" + str.str() + "\'. The checking continues anyway.");
366 : }
367 :
368 4 : Token * Tokenizer::deleteInvalidTypedef(Token *typeDef)
369 : {
370 4 : Token *tok = nullptr;
371 :
372 : // remove typedef but leave ;
373 19 : while (typeDef->next()) {
374 19 : if (typeDef->next()->str() == ";") {
375 4 : typeDef->deleteNext();
376 4 : break;
377 : }
378 15 : if (typeDef->next()->str() == "{")
379 1 : Token::eraseTokens(typeDef, typeDef->linkAt(1));
380 14 : else if (typeDef->next()->str() == "}")
381 0 : break;
382 15 : typeDef->deleteNext();
383 : }
384 :
385 4 : if (typeDef != list.front()) {
386 1 : tok = typeDef->previous();
387 1 : tok->deleteNext();
388 : } else {
389 3 : list.front()->deleteThis();
390 3 : tok = list.front();
391 : }
392 :
393 4 : return tok;
394 : }
395 :
396 : namespace {
397 : struct Space {
398 : std::string className;
399 : const Token* bodyEnd{}; // for body contains typedef define
400 : const Token* bodyEnd2{}; // for body contains typedef using
401 : bool isNamespace{};
402 : std::set<std::string> recordTypes;
403 : };
404 : }
405 :
406 31 : static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
407 : {
408 62 : std::string name;
409 62 : std::set<std::string> qualifiers;
410 :
411 32 : while (Token::Match(tok->next(), "const|volatile")) {
412 1 : qualifiers.insert(tok->next()->str());
413 1 : tok->deleteNext();
414 : }
415 :
416 : // skip "class|struct|union|enum"
417 31 : Token *tok1 = tok->tokAt(2);
418 :
419 31 : const bool hasName = Token::Match(tok1, "%name%");
420 :
421 : // skip name
422 31 : if (hasName) {
423 27 : name = tok1->str();
424 27 : tok1 = tok1->next();
425 : }
426 :
427 : // skip base classes if present
428 31 : if (tok1->str() == ":") {
429 3 : tok1 = tok1->next();
430 9 : while (tok1 && tok1->str() != "{")
431 6 : tok1 = tok1->next();
432 3 : if (!tok1)
433 0 : return nullptr;
434 : }
435 :
436 : // skip to end
437 31 : tok1 = tok1->link();
438 :
439 31 : if (!hasName) { // unnamed
440 4 : if (tok1->next()) {
441 : // use typedef name if available
442 4 : if (Token::Match(tok1->next(), "%type%"))
443 3 : name = tok1->next()->str();
444 : else // create a unique name
445 1 : name = "Unnamed" + std::to_string((*unnamedCount)++);
446 4 : tok->next()->insertToken(name);
447 : } else
448 0 : return nullptr;
449 : }
450 :
451 31 : tok1->insertToken(";");
452 31 : tok1 = tok1->next();
453 :
454 31 : if (tok1->next() && tok1->next()->str() == ";" && tok1->previous()->str() == "}") {
455 1 : tok->deleteThis();
456 1 : tok1->deleteThis();
457 1 : return nullptr;
458 : }
459 30 : tok1->insertToken("typedef");
460 30 : tok1 = tok1->next();
461 30 : Token * tok3 = tok1;
462 31 : for (const std::string &qualifier : qualifiers) {
463 1 : tok1->insertToken(qualifier);
464 1 : tok1 = tok1->next();
465 : }
466 30 : tok1->insertToken(tok->next()->str()); // struct, union or enum
467 30 : tok1 = tok1->next();
468 30 : tok1->insertToken(name);
469 30 : tok->deleteThis();
470 30 : tok = tok3;
471 :
472 30 : return tok;
473 : }
474 :
475 : /* This function is called when processing function related typedefs.
476 : * If simplifyTypedef generates an "Internal Error" message and the
477 : * code that generated it deals in some way with functions, then this
478 : * function will probably need to be extended to handle a new function
479 : * related pattern */
480 113 : const Token *Tokenizer::processFunc(const Token *tok2, bool inOperator) const
481 : {
482 226 : if (tok2->next() && tok2->next()->str() != ")" &&
483 113 : tok2->next()->str() != ",") {
484 : // skip over tokens for some types of canonicalization
485 112 : if (Token::Match(tok2->next(), "( * %type% ) ("))
486 0 : tok2 = tok2->linkAt(5);
487 112 : else if (Token::Match(tok2->next(), "* ( * %type% ) ("))
488 0 : tok2 = tok2->linkAt(6);
489 112 : else if (Token::Match(tok2->next(), "* ( * %type% ) ;"))
490 1 : tok2 = tok2->tokAt(5);
491 111 : else if (Token::Match(tok2->next(), "* ( %type% [") &&
492 0 : Token::Match(tok2->linkAt(4), "] ) ;|="))
493 0 : tok2 = tok2->linkAt(4)->next();
494 111 : else if (Token::Match(tok2->next(), "* ( * %type% ("))
495 0 : tok2 = tok2->linkAt(5)->next();
496 112 : else if (Token::simpleMatch(tok2->next(), "* [") &&
497 1 : Token::simpleMatch(tok2->linkAt(2), "] ;"))
498 1 : tok2 = tok2->next();
499 : else {
500 110 : if (tok2->next()->str() == "(")
501 2 : tok2 = tok2->next()->link();
502 108 : else if (!inOperator && !Token::Match(tok2->next(), "[|>|;")) {
503 107 : tok2 = tok2->next();
504 :
505 121 : while (Token::Match(tok2, "*|&") &&
506 12 : !Token::Match(tok2->next(), ")|>"))
507 2 : tok2 = tok2->next();
508 :
509 : // skip over namespace
510 113 : while (Token::Match(tok2, "%name% ::"))
511 6 : tok2 = tok2->tokAt(2);
512 :
513 107 : if (!tok2)
514 0 : return nullptr;
515 :
516 107 : if (tok2->str() == "(" &&
517 107 : tok2->link()->next() &&
518 0 : tok2->link()->next()->str() == "(") {
519 0 : tok2 = tok2->link();
520 :
521 0 : if (tok2->next()->str() == "(")
522 0 : tok2 = tok2->next()->link();
523 : }
524 :
525 : // skip over typedef parameter
526 107 : if (tok2->next() && tok2->next()->str() == "(") {
527 15 : tok2 = tok2->next()->link();
528 15 : if (!tok2->next())
529 0 : syntaxError(tok2);
530 :
531 15 : if (tok2->next()->str() == "(")
532 0 : tok2 = tok2->next()->link();
533 : }
534 : }
535 : }
536 : }
537 113 : return tok2;
538 : }
539 :
540 113 : Token *Tokenizer::processFunc(Token *tok2, bool inOperator)
541 : {
542 113 : return const_cast<Token*>(processFunc(const_cast<const Token*>(tok2), inOperator));
543 : }
544 :
545 22683 : void Tokenizer::simplifyUsingToTypedef()
546 : {
547 22683 : if (!isCPP() || mSettings.standards.cpp < Standards::CPP11)
548 6009 : return;
549 :
550 753246 : for (Token *tok = list.front(); tok; tok = tok->next()) {
551 : // using a::b; => typedef a::b b;
552 1473150 : if ((Token::Match(tok, "[;{}] using %name% :: %name% ::|;") && !tok->tokAt(2)->isKeyword()) ||
553 736574 : (Token::Match(tok, "[;{}] using :: %name% :: %name% ::|;") && !tok->tokAt(3)->isKeyword())) {
554 7 : Token *endtok = tok->tokAt(5);
555 7 : if (Token::Match(endtok, "%name%"))
556 3 : endtok = endtok->next();
557 7 : while (Token::Match(endtok, ":: %name%"))
558 0 : endtok = endtok->tokAt(2);
559 7 : if (endtok && endtok->str() == ";") {
560 7 : tok->next()->str("typedef");
561 7 : endtok = endtok->previous();
562 7 : endtok->insertToken(endtok->str());
563 : }
564 : }
565 : }
566 : }
567 :
568 22651 : void Tokenizer::simplifyTypedefLHS()
569 : {
570 22651 : if (!list.front())
571 0 : return;
572 :
573 1001646 : for (Token* tok = list.front()->next(); tok; tok = tok->next()) {
574 978998 : if (tok->str() == "typedef") {
575 355 : bool doSimplify = !Token::Match(tok->previous(), ";|{|}|:|public:|private:|protected:");
576 355 : if (doSimplify && Token::simpleMatch(tok->previous(), ")") && Token::Match(tok->linkAt(-1)->previous(), "if|for|while"))
577 0 : doSimplify = false;
578 355 : bool haveStart = false;
579 355 : Token* start{};
580 355 : if (!doSimplify && Token::simpleMatch(tok->previous(), "}")) {
581 26 : start = tok->linkAt(-1)->previous();
582 39 : while (Token::Match(start, "%name%")) {
583 16 : if (Token::Match(start, "class|struct|union|enum")) {
584 3 : start = start->previous();
585 3 : doSimplify = true;
586 3 : haveStart = true;
587 3 : break;
588 : }
589 13 : start = start->previous();
590 : }
591 : }
592 355 : if (doSimplify) {
593 12 : if (!haveStart) {
594 9 : start = tok;
595 46 : while (start && !Token::Match(start, "[;{}]"))
596 37 : start = start->previous();
597 : }
598 12 : if (start)
599 6 : start = start->next();
600 : else
601 6 : start = list.front();
602 12 : start->insertTokenBefore(tok->str());
603 12 : tok->deleteThis();
604 : }
605 : }
606 : }
607 : }
608 :
609 : namespace {
610 : class TypedefSimplifier {
611 : private:
612 : Token* mTypedefToken; // The "typedef" token
613 : Token* mEndToken{nullptr}; // Semicolon
614 : std::pair<Token*, Token*> mRangeType;
615 : std::pair<Token*, Token*> mRangeTypeQualifiers;
616 : std::pair<Token*, Token*> mRangeAfterVar;
617 : Token* mNameToken{nullptr};
618 : bool mFail = false;
619 : bool mReplaceFailed = false;
620 : bool mUsed = false;
621 :
622 : public:
623 1154 : explicit TypedefSimplifier(Token* typedefToken) : mTypedefToken(typedefToken) {
624 1154 : Token* start = typedefToken->next();
625 1154 : if (Token::simpleMatch(start, "typename"))
626 21 : start = start->next();
627 :
628 : // TODO handle unnamed structs etc
629 1154 : if (Token::Match(start, "const| enum|struct|union|class %name%| {")) {
630 197 : const std::pair<Token*, Token*> rangeBefore(start, Token::findsimplematch(start, "{"));
631 :
632 : // find typedef name token
633 197 : Token* nameToken = rangeBefore.second->link()->next();
634 225 : while (Token::Match(nameToken, "%name%|* %name%|*"))
635 28 : nameToken = nameToken->next();
636 197 : const std::pair<Token*, Token*> rangeQualifiers(rangeBefore.second->link()->next(), nameToken);
637 :
638 197 : if (Token::Match(nameToken, "%name% ;")) {
639 183 : if (Token::Match(rangeBefore.second->previous(), "enum|struct|union|class {"))
640 66 : rangeBefore.second->previous()->insertToken(nameToken->str());
641 183 : mRangeType = rangeBefore;
642 183 : mRangeTypeQualifiers = rangeQualifiers;
643 183 : Token* typeName = rangeBefore.second->previous();
644 183 : if (typeName->isKeyword()) {
645 : // TODO typeName->insertToken("T:" + std::to_string(num++));
646 0 : typeName->insertToken(nameToken->str());
647 : }
648 183 : mNameToken = nameToken;
649 183 : mEndToken = nameToken->next();
650 183 : return;
651 : }
652 : }
653 :
654 2131 : for (Token* type = start; Token::Match(type, "%name%|*|&|&&"); type = type->next()) {
655 1777 : if (type != start && Token::Match(type, "%name% ;") && !type->isStandardType()) {
656 296 : mRangeType.first = start;
657 296 : mRangeType.second = type;
658 296 : mNameToken = type;
659 296 : mEndToken = mNameToken->next();
660 296 : return;
661 : }
662 1481 : if (type != start && Token::Match(type, "%name% [")) {
663 112 : Token* end = type->linkAt(1);
664 120 : while (Token::simpleMatch(end, "] ["))
665 8 : end = end->linkAt(1);
666 112 : if (!Token::simpleMatch(end, "] ;"))
667 0 : break;
668 112 : mRangeType.first = start;
669 112 : mRangeType.second = type;
670 112 : mNameToken = type;
671 112 : mEndToken = end->next();
672 112 : mRangeAfterVar.first = mNameToken->next();
673 112 : mRangeAfterVar.second = mEndToken;
674 112 : return;
675 : }
676 1369 : if (Token::Match(type->next(), "( * const| %name% ) (") && Token::simpleMatch(type->linkAt(1)->linkAt(1), ") ;")) {
677 156 : mNameToken = type->linkAt(1)->previous();
678 156 : mEndToken = type->linkAt(1)->linkAt(1)->next();
679 156 : mRangeType.first = start;
680 156 : mRangeType.second = mNameToken;
681 156 : mRangeAfterVar.first = mNameToken->next();
682 156 : mRangeAfterVar.second = mEndToken;
683 156 : return;
684 : }
685 1213 : if (Token::Match(type, "%name% ( !!(") && Token::simpleMatch(type->linkAt(1), ") ;") && !type->isStandardType()) {
686 53 : mNameToken = type;
687 53 : mEndToken = type->linkAt(1)->next();
688 53 : mRangeType.first = start;
689 53 : mRangeType.second = type;
690 53 : mRangeAfterVar.first = mNameToken->next();
691 53 : mRangeAfterVar.second = mEndToken;
692 53 : return;
693 : }
694 : }
695 : // TODO: handle all typedefs
696 : if ((false))
697 : printTypedef(typedefToken);
698 354 : mFail = true;
699 : }
700 :
701 685 : const Token* getTypedefToken() const {
702 685 : return mTypedefToken;
703 : }
704 :
705 323 : bool isUsed() const {
706 323 : return mUsed;
707 : }
708 :
709 77 : bool isInvalidConstFunctionType(const std::map<std::string, TypedefSimplifier>& m) const {
710 77 : if (!Token::Match(mTypedefToken, "typedef const %name% %name% ;"))
711 76 : return false;
712 1 : const auto it = m.find(mTypedefToken->strAt(2));
713 1 : if (it == m.end())
714 0 : return false;
715 1 : return Token::Match(it->second.mNameToken, "%name% (");
716 : }
717 :
718 1154 : bool fail() const {
719 1154 : return mFail;
720 : }
721 :
722 323 : bool replaceFailed() const {
723 323 : return mReplaceFailed;
724 : }
725 :
726 323 : bool isStructEtc() const {
727 323 : return mRangeType.second && mRangeType.second->str() == "{";
728 : }
729 :
730 1446 : std::string name() const {
731 2892 : return mNameToken ? mNameToken->str() : "";
732 : }
733 :
734 355 : void replace(Token* tok) {
735 355 : if (tok == mNameToken)
736 11 : return;
737 :
738 355 : mUsed = true;
739 :
740 : // Special handling for T() when T is a pointer
741 355 : if (Token::Match(tok, "%name% ( )")) {
742 4 : bool pointerType = false;
743 10 : for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
744 8 : if (type->str() == "*" || type->str() == "&") {
745 2 : pointerType = true;
746 2 : break;
747 : }
748 : }
749 4 : for (const Token* type = mRangeTypeQualifiers.first; type != mRangeTypeQualifiers.second; type = type->next()) {
750 0 : if (type->str() == "*" || type->str() == "&") {
751 0 : pointerType = true;
752 0 : break;
753 : }
754 : }
755 4 : if (pointerType) {
756 2 : tok->deleteThis();
757 2 : tok->next()->insertToken("0");
758 2 : Token* tok2 = insertTokens(tok, mRangeType);
759 2 : insertTokens(tok2, mRangeTypeQualifiers);
760 2 : return;
761 : }
762 : }
763 :
764 : // Special handling of function pointer cast
765 353 : const bool isFunctionPointer = Token::Match(mNameToken, "%name% )");
766 353 : if (isFunctionPointer && isCast(tok->previous())) {
767 3 : tok->insertToken("*");
768 3 : insertTokens(tok, std::pair<Token*, Token*>(mRangeType.first, mNameToken->linkAt(1)));
769 3 : tok->deleteThis();
770 3 : return;
771 : }
772 :
773 : // Inherited type => skip "struct" / "class"
774 350 : if (Token::Match(mRangeType.first, "const| struct|class %name% {") && Token::Match(tok->previous(), "public|protected|private|<")) {
775 4 : tok->originalName(tok->str());
776 4 : tok->str(mRangeType.second->previous()->str());
777 4 : return;
778 : }
779 :
780 346 : if (Token::Match(tok, "%name% ::")) {
781 2 : if (Token::Match(mRangeType.first, "const| struct|class %name% %name% ;")) {
782 2 : tok->originalName(tok->str());
783 2 : tok->str(mRangeType.second->previous()->str());
784 : } else {
785 0 : mReplaceFailed = true;
786 : }
787 2 : return;
788 : }
789 :
790 : // pointer => move "const"
791 344 : if (Token::simpleMatch(tok->previous(), "const")) {
792 24 : bool pointerType = false;
793 58 : for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
794 39 : if (type->str() == "*") {
795 5 : pointerType = true;
796 5 : break;
797 : }
798 : }
799 24 : if (pointerType) {
800 5 : tok->insertToken("const");
801 5 : tok->next()->column(tok->column());
802 5 : tok->next()->setMacroName(tok->previous()->getMacroName());
803 5 : tok->deletePrevious();
804 : }
805 : }
806 :
807 : // Do not duplicate class/struct/enum/union
808 344 : if (Token::Match(tok->previous(), "enum|union|struct|class")) {
809 2 : bool found = false;
810 2 : const std::string &kw = tok->previous()->str();
811 2 : for (const Token* type = mRangeType.first; type != mRangeType.second; type = type->next()) {
812 2 : if (type->str() == kw) {
813 2 : found = true;
814 2 : break;
815 : }
816 : }
817 2 : if (found)
818 2 : tok->deletePrevious();
819 : else {
820 0 : mReplaceFailed = true;
821 0 : return;
822 : }
823 : }
824 :
825 : // don't add class|struct|union in inheritance list
826 344 : auto rangeType = mRangeType;
827 344 : if (Token::Match(tok->previous(), "public|private|protected")) {
828 6 : while (Token::Match(rangeType.first, "const|class|struct|union"))
829 3 : rangeType.first = rangeType.first->next();
830 : }
831 :
832 344 : Token* const tok2 = insertTokens(tok, rangeType);
833 344 : Token* const tok3 = insertTokens(tok2, mRangeTypeQualifiers);
834 :
835 344 : tok2->originalName(tok->str());
836 344 : tok3->originalName(tok->str());
837 344 : Token *after = tok3;
838 1087 : while (Token::Match(after, "%name%|*|&|&&|::"))
839 743 : after = after->next();
840 344 : if (Token::Match(mNameToken, "%name% (") && Token::simpleMatch(tok3->next(), "*")) {
841 18 : while (Token::Match(after, "(|["))
842 6 : after = after->link()->next();
843 12 : if (after) {
844 12 : tok3->insertToken("(");
845 12 : after->previous()->insertToken(")");
846 12 : Token::createMutualLinks(tok3->next(), after->previous());
847 : }
848 : }
849 :
850 344 : bool useAfterVarRange = true;
851 344 : if (Token::simpleMatch(mRangeAfterVar.first, "[")) {
852 67 : if (Token::Match(after->previous(), "%name% ( !!*")) {
853 11 : useAfterVarRange = false;
854 : // Function return type => replace array with "*"
855 27 : for (const Token* a = mRangeAfterVar.first; Token::simpleMatch(a, "["); a = a->link()->next())
856 16 : tok3->insertToken("*");
857 56 : } else if (Token::Match(after->previous(), "%name% ( * %name% ) [")) {
858 0 : after = after->linkAt(4)->next();
859 : } else {
860 56 : Token* prev = after->previous();
861 56 : if (prev->isName() && prev != tok3)
862 48 : prev = prev->previous();
863 56 : if (Token::Match(prev, "*|&|&&") && prev != tok3) {
864 34 : while (Token::Match(prev, "*|&|&&") && prev != tok3)
865 18 : prev = prev->previous();
866 16 : prev->insertToken("(");
867 16 : after->previous()->insertToken(")");
868 : }
869 : }
870 : }
871 :
872 344 : if (isFunctionPointer) {
873 70 : if (Token::Match(after, "( * %name% ) ("))
874 6 : after = after->link()->linkAt(1)->next();
875 64 : else if (after->str() == "(") {
876 9 : useAfterVarRange = false;
877 9 : if (Token::simpleMatch(tok3->previous(), "( *"))
878 9 : tok3->deletePrevious();
879 : }
880 55 : else if (after->str() == "[") {
881 6 : while (after && after->str() == "[")
882 3 : after = after->link()->next();
883 : }
884 : }
885 : else {
886 286 : while (Token::simpleMatch(after, "["))
887 12 : after = after->link()->next();
888 : }
889 :
890 344 : if (!after)
891 0 : throw InternalError(tok, "Failed to simplify typedef. Is the code valid?");
892 :
893 344 : Token* const tok4 = useAfterVarRange ? insertTokens(after->previous(), mRangeAfterVar)->next() : tok3->next();
894 :
895 344 : tok->deleteThis();
896 :
897 : // Unsplit variable declarations
898 385 : if (tok4 && tok4->isSplittedVarDeclEq() &&
899 41 : ((tok4->isCpp() && Token::Match(tok4->tokAt(-2), "&|&& %name% ;")) || Token::Match(tok4->previous(), "] ; %name% = {"))) {
900 5 : tok4->deleteNext();
901 5 : tok4->deleteThis();
902 : }
903 :
904 : // Set links
905 688 : std::stack<Token*> brackets;
906 2068 : for (; tok != tok4; tok = tok->next()) {
907 1724 : if (Token::Match(tok, "[{([]"))
908 266 : brackets.push(tok);
909 1458 : else if (Token::Match(tok, "[})]]")) {
910 266 : Token::createMutualLinks(brackets.top(), tok);
911 266 : brackets.pop();
912 : }
913 : }
914 : }
915 :
916 323 : void removeDeclaration() {
917 323 : if (Token::simpleMatch(mRangeType.second, "{")) {
918 164 : while (Token::Match(mTypedefToken, "typedef|const"))
919 83 : mTypedefToken->deleteThis();
920 81 : Token::eraseTokens(mRangeType.second->link(), mEndToken);
921 : } else {
922 242 : Token::eraseTokens(mTypedefToken, mEndToken);
923 242 : mTypedefToken->deleteThis();
924 : }
925 323 : }
926 :
927 840 : static int canReplaceStatic(const Token* tok) {
928 840 : if (!Token::Match(tok, "%name% %name%|*|&|&&|;|(|)|,|::")) {
929 114 : if (Token::Match(tok->previous(), "( %name% =") && Token::Match(tok->linkAt(-1), ") %name%|{") && !tok->tokAt(-2)->isKeyword())
930 1 : return true;
931 113 : if (Token::Match(tok->previous(), ", %name% ="))
932 3 : return true;
933 110 : if (Token::Match(tok->previous(), "new %name% ["))
934 2 : return true;
935 108 : if (Token::Match(tok->previous(), "< %name%") && tok->previous()->findClosingBracket())
936 24 : return true;
937 84 : if (Token::Match(tok->previous(), ", %name% >|>>")) {
938 30 : for (const Token* prev = tok->previous(); prev; prev = prev->previous()) {
939 30 : if (Token::Match(prev, "[;{}(]"))
940 0 : break;
941 30 : if (prev->str() == "<" && prev->findClosingBracket() == tok->next())
942 5 : return true;
943 25 : if (prev->str() == ")")
944 3 : prev = prev->link();
945 : }
946 0 : return true;
947 : }
948 79 : if (Token::Match(tok->previous(), "public|protected|private"))
949 7 : return true;
950 72 : if (Token::Match(tok->previous(), ", %name% :")) {
951 1 : bool isGeneric = false;
952 4 : for (; tok; tok = tok->previous()) {
953 4 : if (Token::Match(tok, ")|]"))
954 1 : tok = tok->link();
955 3 : else if (Token::Match(tok, "[;{}(]")) {
956 1 : isGeneric = Token::simpleMatch(tok->previous(), "_Generic (");
957 1 : break;
958 : }
959 : }
960 1 : return isGeneric;
961 : }
962 71 : return false;
963 : }
964 726 : return -1;
965 : }
966 :
967 604 : bool canReplace(const Token* tok) {
968 604 : if (mNameToken == tok)
969 81 : return false;
970 523 : if (!Token::Match(tok->previous(), "%name%|;|{|}|(|,|<") && !Token::Match(tok->previous(), "!!. %name% ("))
971 18 : return false;
972 : {
973 505 : const int res = canReplaceStatic(tok);
974 505 : if (res == 0 || res == 1)
975 85 : return res != 0;
976 : }
977 420 : if (Token::Match(tok->previous(), "%name%") && !tok->previous()->isKeyword())
978 5 : return false;
979 415 : if (Token::simpleMatch(tok->next(), "(") && Token::Match(tok->linkAt(1), ") %name%|{"))
980 0 : return false;
981 415 : if (Token::Match(tok->previous(), "struct|union|class|enum %name% %name%") &&
982 451 : Token::simpleMatch(mRangeType.second, "{") &&
983 36 : tok->str() != mRangeType.second->previous()->str())
984 2 : return true;
985 413 : if (Token::Match(tok->previous(), "; %name% ;"))
986 1 : return false;
987 412 : if (Token::Match(tok->previous(), "<|, %name% * ,|>"))
988 5 : return true;
989 920 : for (const Token* after = tok->next(); after; after = after->next()) {
990 920 : if (Token::Match(after, "%name%|::|&|*|&&"))
991 513 : continue;
992 407 : if (after->str() == "<" && after->link())
993 0 : break;
994 407 : if (after->isNumber())
995 1 : return false;
996 406 : if (after->isComparisonOp() || after->isArithmeticalOp())
997 5 : return false;
998 401 : break;
999 : }
1000 453 : for (const Token* before = tok->previous(); before; before = before->previous()) {
1001 453 : if (Token::Match(before, "[+-*/&|~!]"))
1002 0 : return false;
1003 453 : if (Token::Match(before, "struct|union|class|enum") || before->isStandardType())
1004 82 : return false;
1005 371 : if (before->str() == "::")
1006 0 : return false;
1007 371 : if (before->isName())
1008 52 : continue;
1009 319 : break;
1010 : }
1011 319 : return true;
1012 : }
1013 :
1014 242 : Token* endToken() const {
1015 242 : return mEndToken;
1016 : }
1017 :
1018 : private:
1019 73 : static bool isCast(const Token* tok) {
1020 73 : if (Token::Match(tok, "( %name% ) (|%name%"))
1021 2 : return !tok->tokAt(2)->isKeyword();
1022 71 : if (Token::Match(tok, "< %name% > (") && tok->previous() && endsWith(tok->previous()->str(), "_cast", 5))
1023 1 : return true;
1024 70 : return false;
1025 : }
1026 :
1027 1019 : static Token* insertTokens(Token* to, std::pair<Token*,Token*> range) {
1028 2215 : for (const Token* from = range.first; from != range.second; from = from->next()) {
1029 1196 : to->insertToken(from->str());
1030 1196 : to->next()->column(to->column());
1031 1196 : to = to->next();
1032 1196 : to->isSimplifiedTypedef(true);
1033 1196 : to->isExternC(from->isExternC());
1034 : }
1035 1019 : return to;
1036 : }
1037 :
1038 : static void printTypedef(const Token *tok) {
1039 : int indent = 0;
1040 : while (tok && (indent > 0 || tok->str() != ";")) {
1041 : if (tok->str() == "{")
1042 : ++indent;
1043 : else if (tok->str() == "}")
1044 : --indent;
1045 : std::cout << " " << tok->str();
1046 : tok = tok->next();
1047 : }
1048 : std::cout << "\n";
1049 : }
1050 : };
1051 : }
1052 :
1053 22687 : void Tokenizer::simplifyTypedef()
1054 : {
1055 : // Simplify global typedefs that are not redefined with the fast 1-pass simplification.
1056 : // Then use the slower old typedef simplification.
1057 45371 : std::map<std::string, int> numberOfTypedefs;
1058 1025107 : for (Token* tok = list.front(); tok; tok = tok->next()) {
1059 1002420 : if (tok->str() == "typedef") {
1060 652 : TypedefSimplifier ts(tok);
1061 652 : if (!ts.fail())
1062 452 : numberOfTypedefs[ts.name()]++;
1063 652 : continue;
1064 : }
1065 : }
1066 :
1067 22686 : int indentlevel = 0;
1068 45372 : std::map<std::string, TypedefSimplifier> typedefs;
1069 1021568 : for (Token* tok = list.front(); tok; tok = tok->next()) {
1070 998873 : if (!tok->isName()) {
1071 594928 : if (tok->str()[0] == '{')
1072 47805 : ++indentlevel;
1073 547129 : else if (tok->str()[0] == '}')
1074 47802 : --indentlevel;
1075 595427 : continue;
1076 : }
1077 :
1078 403945 : if (indentlevel == 0 && tok->str() == "typedef") {
1079 502 : TypedefSimplifier ts(tok);
1080 1366 : if (!ts.fail() && numberOfTypedefs[ts.name()] == 1 &&
1081 864 : (numberOfTypedefs.find(ts.getTypedefToken()->strAt(1)) == numberOfTypedefs.end() || ts.getTypedefToken()->strAt(2) == "(")) {
1082 323 : if (mSettings.severity.isEnabled(Severity::portability) && ts.isInvalidConstFunctionType(typedefs))
1083 1 : reportError(tok->next(), Severity::portability, "invalidConstFunctionType",
1084 2 : "It is unspecified behavior to const qualify a function type.");
1085 323 : typedefs.emplace(ts.name(), ts);
1086 323 : if (!ts.isStructEtc())
1087 242 : tok = ts.endToken();
1088 : }
1089 502 : continue;
1090 : }
1091 :
1092 403459 : auto it = typedefs.find(tok->str());
1093 403456 : if (it != typedefs.end() && it->second.canReplace(tok)) {
1094 694 : std::set<std::string> r;
1095 702 : while (it != typedefs.end() && r.insert(tok->str()).second) {
1096 355 : it->second.replace(tok);
1097 355 : it = typedefs.find(tok->str());
1098 : }
1099 403109 : } else if (tok->str() == "enum") {
1100 1487 : while (Token::Match(tok, "%name%|:|::"))
1101 1108 : tok = tok->next();
1102 379 : if (!tok)
1103 0 : break;
1104 379 : if (tok->str() == "{")
1105 351 : tok = tok->link();
1106 : }
1107 : }
1108 :
1109 22683 : if (!typedefs.empty())
1110 : {
1111 : // remove typedefs
1112 584 : for (auto &t: typedefs) {
1113 323 : if (!t.second.replaceFailed()) {
1114 323 : const Token* const typedefToken = t.second.getTypedefToken();
1115 646 : TypedefInfo typedefInfo;
1116 323 : typedefInfo.name = t.second.name();
1117 323 : typedefInfo.filename = list.file(typedefToken);
1118 323 : typedefInfo.lineNumber = typedefToken->linenr();
1119 323 : typedefInfo.column = typedefToken->column();
1120 323 : typedefInfo.used = t.second.isUsed();
1121 323 : mTypedefInfo.push_back(std::move(typedefInfo));
1122 :
1123 323 : t.second.removeDeclaration();
1124 : }
1125 : }
1126 :
1127 463 : while (Token::Match(list.front(), "; %any%"))
1128 202 : list.front()->deleteThis();
1129 : }
1130 :
1131 22683 : simplifyTypedefCpp();
1132 22678 : }
1133 :
1134 433 : static bool isEnumScope(const Token* tok)
1135 : {
1136 433 : if (!Token::simpleMatch(tok, "{"))
1137 0 : return false;
1138 433 : tok = tok->previous();
1139 614 : while (tok && !tok->isKeyword() && Token::Match(tok, "%name%|::|:"))
1140 181 : tok = tok->previous();
1141 433 : if (Token::simpleMatch(tok, "class"))
1142 44 : tok = tok->previous();
1143 433 : return Token::simpleMatch(tok, "enum");
1144 : }
1145 :
1146 22687 : void Tokenizer::simplifyTypedefCpp()
1147 : {
1148 22687 : bool isNamespace = false;
1149 22705 : std::string className, fullClassName;
1150 22680 : bool hasClass = false;
1151 22680 : bool goback = false;
1152 :
1153 : // add global namespace
1154 22689 : std::vector<Space> spaceInfo(1);
1155 :
1156 : // Convert "using a::b;" to corresponding typedef statements
1157 22683 : simplifyUsingToTypedef();
1158 :
1159 22681 : const std::time_t maxTime = mSettings.typedefMaxTime > 0 ? std::time(nullptr) + mSettings.typedefMaxTime: 0;
1160 :
1161 1022795 : for (Token *tok = list.front(); tok; tok = tok->next()) {
1162 1000121 : if (!list.getFiles().empty())
1163 1000116 : mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (typedef)", tok->progressValue());
1164 :
1165 1000115 : if (Settings::terminated())
1166 0 : return;
1167 :
1168 1000116 : if (maxTime > 0 && std::time(nullptr) > maxTime) {
1169 0 : if (mSettings.debugwarnings) {
1170 0 : ErrorMessage::FileLocation loc(list.getFiles()[0], 0, 0);
1171 0 : ErrorMessage errmsg({std::move(loc)},
1172 : emptyString,
1173 : Severity::debug,
1174 : "Typedef simplification instantiation maximum time exceeded",
1175 : "typedefMaxTime",
1176 0 : Certainty::normal);
1177 0 : mErrorLogger.reportErr(errmsg);
1178 : }
1179 0 : return;
1180 : }
1181 :
1182 1000116 : if (goback) {
1183 : //jump back once, see the comment at the end of the function
1184 130 : goback = false;
1185 130 : tok = tok->previous();
1186 : }
1187 :
1188 1000116 : if (tok->str() != "typedef") {
1189 999777 : if (Token::simpleMatch(tok, "( typedef")) {
1190 : // Skip typedefs inside parentheses (#2453 and #4002)
1191 0 : tok = tok->next();
1192 1011999 : } else if (Token::Match(tok, "class|struct|namespace %any%") &&
1193 12224 : (!tok->previous() || tok->previous()->str() != "enum")) {
1194 7789 : isNamespace = (tok->str() == "namespace");
1195 7789 : hasClass = true;
1196 7789 : className = tok->next()->str();
1197 7789 : const Token *tok1 = tok->next();
1198 7789 : fullClassName = className;
1199 7894 : while (Token::Match(tok1, "%name% :: %name%")) {
1200 105 : tok1 = tok1->tokAt(2);
1201 105 : fullClassName += " :: " + tok1->str();
1202 : }
1203 992001 : } else if (hasClass && tok->str() == ";") {
1204 1238 : hasClass = false;
1205 990762 : } else if (hasClass && tok->str() == "{") {
1206 6110 : if (!isNamespace)
1207 5619 : spaceInfo.back().recordTypes.insert(fullClassName);
1208 :
1209 6110 : Space info;
1210 6110 : info.isNamespace = isNamespace;
1211 6110 : info.className = className;
1212 6110 : info.bodyEnd = tok->link();
1213 6110 : info.bodyEnd2 = tok->link();
1214 6110 : spaceInfo.push_back(std::move(info));
1215 :
1216 6110 : hasClass = false;
1217 984652 : } else if (spaceInfo.size() > 1 && tok->str() == "}" && spaceInfo.back().bodyEnd == tok) {
1218 6109 : spaceInfo.pop_back();
1219 : }
1220 999796 : continue;
1221 : }
1222 :
1223 : // pull struct, union, enum or class definition out of typedef
1224 : // use typedef name for unnamed struct, union, enum or class
1225 336 : const Token* tokClass = tok->next();
1226 350 : while (Token::Match(tokClass, "const|volatile"))
1227 14 : tokClass = tokClass->next();
1228 336 : if (Token::Match(tokClass, "struct|enum|union|class %type%| {|:")) {
1229 31 : Token *tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
1230 31 : if (!tok1)
1231 1 : continue;
1232 30 : tok = tok1;
1233 : }
1234 :
1235 : /** @todo add support for union */
1236 335 : if (Token::Match(tok->next(), "enum %type% %type% ;") && tok->strAt(2) == tok->strAt(3)) {
1237 2 : tok->deleteNext(3);
1238 2 : tok->deleteThis();
1239 2 : if (tok->next())
1240 2 : tok->deleteThis();
1241 : //now the next token to process is 'tok', not 'tok->next()';
1242 2 : goback = true;
1243 2 : continue;
1244 : }
1245 :
1246 : Token *typeName;
1247 333 : Token *typeStart = nullptr;
1248 333 : Token *typeEnd = nullptr;
1249 333 : Token *argStart = nullptr;
1250 333 : Token *argEnd = nullptr;
1251 333 : Token *arrayStart = nullptr;
1252 333 : Token *arrayEnd = nullptr;
1253 333 : Token *specStart = nullptr;
1254 333 : Token *specEnd = nullptr;
1255 333 : Token *typeDef = tok;
1256 333 : Token *argFuncRetStart = nullptr;
1257 333 : Token *argFuncRetEnd = nullptr;
1258 333 : Token *funcStart = nullptr;
1259 333 : Token *funcEnd = nullptr;
1260 333 : Token *tokOffset = tok->next();
1261 333 : bool function = false;
1262 333 : bool functionPtr = false;
1263 333 : bool functionRetFuncPtr = false;
1264 333 : bool functionPtrRetFuncPtr = false;
1265 333 : bool ptrToArray = false;
1266 333 : bool refToArray = false;
1267 333 : bool ptrMember = false;
1268 333 : bool typeOf = false;
1269 333 : Token *namespaceStart = nullptr;
1270 333 : Token *namespaceEnd = nullptr;
1271 :
1272 : // check for invalid input
1273 333 : if (!tokOffset || tokOffset->isControlFlowKeyword())
1274 0 : syntaxError(tok);
1275 :
1276 333 : if (tokOffset->str() == "::") {
1277 17 : typeStart = tokOffset;
1278 17 : tokOffset = tokOffset->next();
1279 :
1280 33 : while (Token::Match(tokOffset, "%type% ::"))
1281 16 : tokOffset = tokOffset->tokAt(2);
1282 :
1283 17 : typeEnd = tokOffset;
1284 :
1285 17 : if (Token::Match(tokOffset, "%type%"))
1286 17 : tokOffset = tokOffset->next();
1287 316 : } else if (Token::Match(tokOffset, "%type% ::")) {
1288 50 : typeStart = tokOffset;
1289 :
1290 4 : do {
1291 54 : tokOffset = tokOffset->tokAt(2);
1292 54 : } while (Token::Match(tokOffset, "%type% ::"));
1293 :
1294 50 : typeEnd = tokOffset;
1295 :
1296 50 : if (Token::Match(tokOffset, "%type%"))
1297 50 : tokOffset = tokOffset->next();
1298 266 : } else if (Token::Match(tokOffset, "%type%")) {
1299 264 : typeStart = tokOffset;
1300 :
1301 853 : while (Token::Match(tokOffset, "const|struct|enum %type%") ||
1302 545 : (tokOffset->next() && tokOffset->next()->isStandardType() && !Token::Match(tokOffset->next(), "%name% ;")))
1303 44 : tokOffset = tokOffset->next();
1304 :
1305 264 : typeEnd = tokOffset;
1306 264 : if (!Token::Match(tokOffset->next(), "%name% ;"))
1307 190 : tokOffset = tokOffset->next();
1308 :
1309 268 : while (Token::Match(tokOffset, "%type%") &&
1310 323 : (tokOffset->isStandardType() || Token::Match(tokOffset, "unsigned|signed")) &&
1311 55 : !Token::Match(tokOffset->next(), "%name% ;")) {
1312 4 : typeEnd = tokOffset;
1313 4 : tokOffset = tokOffset->next();
1314 : }
1315 :
1316 264 : bool atEnd = false;
1317 634 : while (!atEnd) {
1318 370 : if (tokOffset && tokOffset->str() == "::") {
1319 7 : typeEnd = tokOffset;
1320 7 : tokOffset = tokOffset->next();
1321 : }
1322 :
1323 591 : if (Token::Match(tokOffset, "%type%") &&
1324 591 : tokOffset->next() && !Token::Match(tokOffset->next(), "[|;|,|(")) {
1325 106 : typeEnd = tokOffset;
1326 106 : tokOffset = tokOffset->next();
1327 264 : } else if (Token::simpleMatch(tokOffset, "const (")) {
1328 5 : typeEnd = tokOffset;
1329 5 : tokOffset = tokOffset->next();
1330 5 : atEnd = true;
1331 : } else
1332 259 : atEnd = true;
1333 : }
1334 : } else
1335 2 : continue; // invalid input
1336 :
1337 : // check for invalid input
1338 331 : if (!tokOffset)
1339 1 : syntaxError(tok);
1340 :
1341 : // check for template
1342 330 : if (!isC() && tokOffset->str() == "<") {
1343 59 : typeEnd = tokOffset->findClosingBracket();
1344 :
1345 65 : while (typeEnd && Token::Match(typeEnd->next(), ":: %type%"))
1346 6 : typeEnd = typeEnd->tokAt(2);
1347 :
1348 59 : if (!typeEnd) {
1349 : // internal error
1350 0 : return;
1351 : }
1352 :
1353 61 : while (Token::Match(typeEnd->next(), "const|volatile"))
1354 2 : typeEnd = typeEnd->next();
1355 :
1356 59 : tok = typeEnd;
1357 59 : tokOffset = tok->next();
1358 : }
1359 :
1360 338 : std::list<std::string> pointers;
1361 : // check for pointers and references
1362 374 : while (Token::Match(tokOffset, "*|&|&&|const")) {
1363 44 : pointers.push_back(tokOffset->str());
1364 44 : tokOffset = tokOffset->next();
1365 : }
1366 :
1367 : // check for invalid input
1368 330 : if (!tokOffset)
1369 0 : syntaxError(tok);
1370 :
1371 330 : if (tokOffset->isName() && !tokOffset->isKeyword()) {
1372 : // found the type name
1373 189 : typeName = tokOffset;
1374 189 : tokOffset = tokOffset->next();
1375 :
1376 : // check for array
1377 207 : while (tokOffset && tokOffset->str() == "[") {
1378 18 : if (!arrayStart)
1379 14 : arrayStart = tokOffset;
1380 18 : arrayEnd = tokOffset->link();
1381 18 : tokOffset = arrayEnd->next();
1382 : }
1383 :
1384 : // check for end or another
1385 189 : if (Token::Match(tokOffset, ";|,"))
1386 184 : tok = tokOffset;
1387 :
1388 : // or a function typedef
1389 5 : else if (tokOffset && tokOffset->str() == "(") {
1390 5 : Token *tokOffset2 = nullptr;
1391 5 : if (Token::Match(tokOffset, "( *|%name%")) {
1392 4 : tokOffset2 = tokOffset->next();
1393 4 : if (tokOffset2->str() == "typename")
1394 1 : tokOffset2 = tokOffset2->next();
1395 6 : while (Token::Match(tokOffset2, "%type% ::"))
1396 2 : tokOffset2 = tokOffset2->tokAt(2);
1397 : }
1398 :
1399 : // unhandled typedef, skip it and continue
1400 5 : if (typeName->str() == "void") {
1401 0 : unsupportedTypedef(typeDef);
1402 0 : tok = deleteInvalidTypedef(typeDef);
1403 0 : if (tok == list.front())
1404 : //now the next token to process is 'tok', not 'tok->next()';
1405 0 : goback = true;
1406 0 : continue;
1407 : }
1408 :
1409 : // function pointer
1410 5 : if (Token::Match(tokOffset2, "* %name% ) (")) {
1411 : // name token wasn't a name, it was part of the type
1412 1 : typeEnd = typeEnd->next();
1413 1 : functionPtr = true;
1414 1 : funcStart = funcEnd = tokOffset2; // *
1415 1 : tokOffset = tokOffset2->tokAt(3); // (
1416 1 : typeName = tokOffset->tokAt(-2);
1417 1 : argStart = tokOffset;
1418 1 : argEnd = tokOffset->link();
1419 1 : tok = argEnd->next();
1420 : }
1421 :
1422 : // function
1423 4 : else if (isFunctionHead(tokOffset->link(), ";,")) {
1424 2 : function = true;
1425 2 : if (tokOffset->link()->next()->str() == "const") {
1426 1 : specStart = tokOffset->link()->next();
1427 1 : specEnd = specStart;
1428 : }
1429 2 : argStart = tokOffset;
1430 2 : argEnd = tokOffset->link();
1431 2 : tok = argEnd->next();
1432 2 : if (specStart)
1433 1 : tok = tok->next();
1434 : }
1435 :
1436 : // syntax error
1437 : else
1438 2 : syntaxError(tok);
1439 : }
1440 :
1441 : // unhandled typedef, skip it and continue
1442 : else {
1443 0 : unsupportedTypedef(typeDef);
1444 0 : tok = deleteInvalidTypedef(typeDef);
1445 0 : if (tok == list.front())
1446 : //now the next token to process is 'tok', not 'tok->next()';
1447 0 : goback = true;
1448 0 : continue;
1449 : }
1450 : }
1451 :
1452 : // typeof: typedef typeof ( ... ) type;
1453 142 : else if (Token::simpleMatch(tokOffset->previous(), "typeof (") &&
1454 1 : Token::Match(tokOffset->link(), ") %type% ;")) {
1455 1 : argStart = tokOffset;
1456 1 : argEnd = tokOffset->link();
1457 1 : typeName = tokOffset->link()->next();
1458 1 : tok = typeName->next();
1459 1 : typeOf = true;
1460 : }
1461 :
1462 : // function: typedef ... ( ... type )( ... );
1463 : // typedef ... (( ... type )( ... ));
1464 : // typedef ... ( * ( ... type )( ... ));
1465 414 : else if (tokOffset->str() == "(" && (
1466 274 : (tokOffset->link() && Token::Match(tokOffset->link()->previous(), "%type% ) (") &&
1467 102 : Token::Match(tokOffset->link()->next()->link(), ") const|volatile|;")) ||
1468 37 : (Token::simpleMatch(tokOffset, "( (") &&
1469 4 : tokOffset->next() && Token::Match(tokOffset->next()->link()->previous(), "%type% ) (") &&
1470 2 : Token::Match(tokOffset->next()->link()->next()->link(), ") const|volatile| ) ;|,")) ||
1471 33 : (Token::simpleMatch(tokOffset, "( * (") &&
1472 4 : tokOffset->linkAt(2) && Token::Match(tokOffset->linkAt(2)->previous(), "%type% ) (") &&
1473 4 : Token::Match(tokOffset->linkAt(2)->next()->link(), ") const|volatile| ) ;|,")))) {
1474 104 : if (tokOffset->next()->str() == "(")
1475 4 : tokOffset = tokOffset->next();
1476 100 : else if (Token::simpleMatch(tokOffset, "( * (")) {
1477 0 : pointers.emplace_back("*");
1478 0 : tokOffset = tokOffset->tokAt(2);
1479 : }
1480 :
1481 104 : if (tokOffset->link()->strAt(-2) == "*")
1482 78 : functionPtr = true;
1483 : else
1484 26 : function = true;
1485 104 : funcStart = tokOffset->next();
1486 104 : tokOffset = tokOffset->link();
1487 104 : funcEnd = tokOffset->tokAt(-2);
1488 104 : typeName = tokOffset->previous();
1489 104 : argStart = tokOffset->next();
1490 104 : argEnd = tokOffset->next()->link();
1491 104 : if (!argEnd)
1492 2 : syntaxError(argStart);
1493 :
1494 102 : tok = argEnd->next();
1495 102 : Token *spec = tok;
1496 102 : if (Token::Match(spec, "const|volatile")) {
1497 31 : specStart = spec;
1498 31 : specEnd = spec;
1499 41 : while (Token::Match(spec->next(), "const|volatile")) {
1500 10 : specEnd = spec->next();
1501 10 : spec = specEnd;
1502 : }
1503 31 : tok = specEnd->next();
1504 : }
1505 102 : if (!tok)
1506 0 : syntaxError(specEnd);
1507 :
1508 102 : if (tok->str() == ")")
1509 2 : tok = tok->next();
1510 : }
1511 :
1512 36 : else if (Token::Match(tokOffset, "( %type% (")) {
1513 8 : function = true;
1514 8 : if (tokOffset->link()->next()) {
1515 8 : tok = tokOffset->link()->next();
1516 8 : tokOffset = tokOffset->tokAt(2);
1517 8 : typeName = tokOffset->previous();
1518 8 : argStart = tokOffset;
1519 8 : argEnd = tokOffset->link();
1520 : } else {
1521 : // internal error
1522 0 : continue;
1523 : }
1524 : }
1525 :
1526 : // pointer to function returning pointer to function
1527 28 : else if (Token::Match(tokOffset, "( * ( * %type% ) (") &&
1528 29 : Token::simpleMatch(tokOffset->linkAt(6), ") ) (") &&
1529 1 : Token::Match(tokOffset->linkAt(6)->linkAt(2), ") ;|,")) {
1530 1 : functionPtrRetFuncPtr = true;
1531 :
1532 1 : tokOffset = tokOffset->tokAt(6);
1533 1 : typeName = tokOffset->tokAt(-2);
1534 1 : argStart = tokOffset;
1535 1 : argEnd = tokOffset->link();
1536 1 : if (!argEnd)
1537 0 : syntaxError(arrayStart);
1538 :
1539 1 : argFuncRetStart = argEnd->tokAt(2);
1540 1 : argFuncRetEnd = argFuncRetStart->link();
1541 1 : if (!argFuncRetEnd)
1542 0 : syntaxError(argFuncRetStart);
1543 :
1544 1 : tok = argFuncRetEnd->next();
1545 : }
1546 :
1547 : // function returning pointer to function
1548 27 : else if (Token::Match(tokOffset, "( * %type% (") &&
1549 30 : Token::simpleMatch(tokOffset->linkAt(3), ") ) (") &&
1550 3 : Token::Match(tokOffset->linkAt(3)->linkAt(2), ") ;|,")) {
1551 3 : functionRetFuncPtr = true;
1552 :
1553 3 : tokOffset = tokOffset->tokAt(3);
1554 3 : typeName = tokOffset->previous();
1555 3 : argStart = tokOffset;
1556 3 : argEnd = tokOffset->link();
1557 :
1558 3 : argFuncRetStart = argEnd->tokAt(2);
1559 3 : if (!argFuncRetStart)
1560 0 : syntaxError(tokOffset);
1561 :
1562 3 : argFuncRetEnd = argFuncRetStart->link();
1563 3 : if (!argFuncRetEnd)
1564 0 : syntaxError(tokOffset);
1565 :
1566 3 : tok = argFuncRetEnd->next();
1567 24 : } else if (Token::Match(tokOffset, "( * ( %type% ) (")) {
1568 3 : functionRetFuncPtr = true;
1569 :
1570 3 : tokOffset = tokOffset->tokAt(5);
1571 3 : typeName = tokOffset->tokAt(-2);
1572 3 : argStart = tokOffset;
1573 3 : argEnd = tokOffset->link();
1574 3 : if (!argEnd)
1575 0 : syntaxError(arrayStart);
1576 :
1577 3 : argFuncRetStart = argEnd->tokAt(2);
1578 3 : if (!argFuncRetStart)
1579 0 : syntaxError(tokOffset);
1580 :
1581 3 : argFuncRetEnd = argFuncRetStart->link();
1582 3 : if (!argFuncRetEnd)
1583 2 : syntaxError(tokOffset);
1584 :
1585 1 : tok = argFuncRetEnd->next();
1586 : }
1587 :
1588 : // pointer/reference to array
1589 21 : else if (Token::Match(tokOffset, "( *|& %type% ) [")) {
1590 10 : ptrToArray = (tokOffset->next()->str() == "*");
1591 10 : refToArray = !ptrToArray;
1592 10 : tokOffset = tokOffset->tokAt(2);
1593 10 : typeName = tokOffset;
1594 10 : arrayStart = tokOffset->tokAt(2);
1595 10 : arrayEnd = arrayStart->link();
1596 10 : if (!arrayEnd)
1597 0 : syntaxError(arrayStart);
1598 :
1599 10 : tok = arrayEnd->next();
1600 : }
1601 :
1602 : // pointer to class member
1603 11 : else if (Token::Match(tokOffset, "( %type% :: * %type% ) ;")) {
1604 7 : tokOffset = tokOffset->tokAt(2);
1605 7 : namespaceStart = tokOffset->previous();
1606 7 : namespaceEnd = tokOffset;
1607 7 : ptrMember = true;
1608 7 : tokOffset = tokOffset->tokAt(2);
1609 7 : typeName = tokOffset;
1610 7 : tok = tokOffset->tokAt(2);
1611 : }
1612 :
1613 : // unhandled typedef, skip it and continue
1614 : else {
1615 4 : unsupportedTypedef(typeDef);
1616 4 : tok = deleteInvalidTypedef(typeDef);
1617 4 : if (tok == list.front())
1618 : //now the next token to process is 'tok', not 'tok->next()';
1619 3 : goback = true;
1620 4 : continue;
1621 : }
1622 :
1623 320 : bool done = false;
1624 320 : bool ok = true;
1625 :
1626 322 : TypedefInfo typedefInfo;
1627 320 : typedefInfo.name = typeName->str();
1628 320 : typedefInfo.filename = list.file(typeName);
1629 320 : typedefInfo.lineNumber = typeName->linenr();
1630 320 : typedefInfo.column = typeName->column();
1631 320 : typedefInfo.used = false;
1632 320 : mTypedefInfo.push_back(std::move(typedefInfo));
1633 :
1634 647 : while (!done) {
1635 331 : std::string pattern = typeName->str();
1636 329 : int scope = 0;
1637 329 : bool simplifyType = false;
1638 329 : bool inMemberFunc = false;
1639 329 : int memberScope = 0;
1640 329 : bool globalScope = false;
1641 329 : int classLevel = spaceInfo.size();
1642 329 : bool inTypeDef = false;
1643 329 : bool inEnum = false;
1644 331 : std::string removed;
1645 331 : std::string classPath;
1646 482 : for (size_t i = 1; i < spaceInfo.size(); ++i) {
1647 153 : if (!classPath.empty())
1648 33 : classPath += " :: ";
1649 153 : classPath += spaceInfo[i].className;
1650 : }
1651 :
1652 13930 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
1653 13630 : if (Settings::terminated())
1654 0 : return;
1655 :
1656 13630 : removed.clear();
1657 :
1658 13630 : if (Token::simpleMatch(tok2, "typedef"))
1659 211 : inTypeDef = true;
1660 :
1661 13630 : if (inTypeDef && Token::simpleMatch(tok2, ";"))
1662 209 : inTypeDef = false;
1663 :
1664 : // Check for variable declared with the same name
1665 15871 : if (!inTypeDef && spaceInfo.size() == 1 && Token::Match(tok2->previous(), "%name%") &&
1666 2241 : !tok2->previous()->isKeyword()) {
1667 1798 : Token* varDecl = tok2;
1668 1936 : while (Token::Match(varDecl, "*|&|&&|const"))
1669 138 : varDecl = varDecl->next();
1670 1798 : if (Token::Match(varDecl, "%name% ;|,|)|=") && varDecl->str() == typeName->str()) {
1671 : // Skip to the next closing brace
1672 2 : if (Token::Match(varDecl, "%name% ) {")) { // is argument variable
1673 1 : tok2 = varDecl->linkAt(2)->next();
1674 : } else {
1675 1 : tok2 = varDecl;
1676 11 : while (tok2 && !Token::simpleMatch(tok2, "}")) {
1677 10 : if (Token::Match(tok2, "(|{|["))
1678 0 : tok2 = tok2->link();
1679 10 : tok2 = tok2->next();
1680 : }
1681 : }
1682 2 : if (!tok2)
1683 0 : break;
1684 2 : continue;
1685 : }
1686 : }
1687 :
1688 13628 : if (tok2->link()) { // Pre-check for performance
1689 : // check for end of scope
1690 3398 : if (tok2->str() == "}") {
1691 : // check for end of member function
1692 615 : if (inMemberFunc) {
1693 61 : --memberScope;
1694 61 : if (memberScope == 0)
1695 61 : inMemberFunc = false;
1696 : }
1697 615 : inEnum = false;
1698 :
1699 615 : if (classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd2) {
1700 164 : --classLevel;
1701 164 : pattern.clear();
1702 :
1703 378 : for (int i = classLevel; i < spaceInfo.size(); ++i)
1704 214 : pattern += (spaceInfo[i].className + " :: ");
1705 :
1706 164 : pattern += typeName->str();
1707 : } else {
1708 451 : if (scope == 0 && !(classLevel > 1 && tok2 == spaceInfo[classLevel - 1].bodyEnd))
1709 27 : break;
1710 424 : scope = std::max(scope - 1, 0);
1711 : }
1712 : }
1713 :
1714 : // check for member functions
1715 3921 : else if (tok2->isCpp() && tok2->str() == "(" && isFunctionHead(tok2, "{:")) {
1716 211 : const Token *func = tok2->previous();
1717 :
1718 : /** @todo add support for multi-token operators */
1719 211 : if (func->previous()->str() == "operator")
1720 0 : func = func->previous();
1721 :
1722 211 : if (!func->previous())
1723 0 : syntaxError(func);
1724 :
1725 : // check for qualifier
1726 211 : if (Token::Match(func->tokAt(-2), "%name% ::")) {
1727 80 : int offset = -2;
1728 159 : while (Token::Match(func->tokAt(offset - 2), "%name% ::"))
1729 79 : offset -= 2;
1730 : // check for available and matching class name
1731 150 : if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1732 70 : func->strAt(offset) == spaceInfo[classLevel].className) {
1733 61 : memberScope = 0;
1734 61 : inMemberFunc = true;
1735 : }
1736 : }
1737 : }
1738 :
1739 : // check for entering a new scope
1740 2572 : else if (tok2->str() == "{") {
1741 : // check for entering a new namespace
1742 436 : if (tok2->isCpp()) {
1743 433 : if (tok2->strAt(-2) == "namespace") {
1744 36 : if (classLevel < spaceInfo.size() &&
1745 64 : spaceInfo[classLevel].isNamespace &&
1746 28 : spaceInfo[classLevel].className == tok2->previous()->str()) {
1747 11 : spaceInfo[classLevel].bodyEnd2 = tok2->link();
1748 11 : ++classLevel;
1749 11 : pattern.clear();
1750 15 : for (int i = classLevel; i < spaceInfo.size(); ++i)
1751 4 : pattern += spaceInfo[i].className + " :: ";
1752 :
1753 11 : pattern += typeName->str();
1754 : }
1755 36 : ++scope;
1756 : }
1757 433 : if (isEnumScope(tok2))
1758 32 : inEnum = true;
1759 : }
1760 :
1761 : // keep track of scopes within member function
1762 436 : if (inMemberFunc)
1763 61 : ++memberScope;
1764 :
1765 436 : ++scope;
1766 : }
1767 : }
1768 :
1769 : // check for operator typedef
1770 : /** @todo add support for multi-token operators */
1771 20440 : else if (tok2->isCpp() &&
1772 10228 : tok2->str() == "operator" &&
1773 35 : tok2->next() &&
1774 17 : tok2->next()->str() == typeName->str() &&
1775 22 : tok2->linkAt(2) &&
1776 20450 : tok2->strAt(2) == "(" &&
1777 10 : Token::Match(tok2->linkAt(2), ") const| {")) {
1778 : // check for qualifier
1779 5 : if (tok2->previous()->str() == "::") {
1780 : // check for available and matching class name
1781 2 : if (spaceInfo.size() > 1 && classLevel < spaceInfo.size() &&
1782 1 : tok2->strAt(-2) == spaceInfo[classLevel].className) {
1783 1 : tok2 = tok2->next();
1784 1 : simplifyType = true;
1785 : }
1786 : }
1787 : }
1788 :
1789 10225 : else if (Token::Match(tok2->previous(), "class|struct %name% [:{]")) {
1790 : // don't replace names in struct/class definition
1791 : }
1792 :
1793 : // check for typedef that can be substituted
1794 13638 : else if ((tok2->isNameOnly() || (tok2->isName() && (tok2->isExpandedMacro() || tok2->isInline()))) &&
1795 3534 : (Token::simpleMatch(tok2, pattern.c_str(), pattern.size()) ||
1796 74 : (inMemberFunc && tok2->str() == typeName->str()))) {
1797 : // member function class variables don't need qualification
1798 430 : if (!(inMemberFunc && tok2->str() == typeName->str()) && pattern.find("::") != std::string::npos) { // has a "something ::"
1799 68 : Token *start = tok2;
1800 68 : int count = 0;
1801 68 : int back = classLevel - 1;
1802 68 : bool good = true;
1803 : // check for extra qualification
1804 82 : while (back >= 1) {
1805 21 : Token *qualificationTok = start->tokAt(-2);
1806 21 : if (!Token::Match(qualificationTok, "%type% ::"))
1807 4 : break;
1808 17 : if (qualificationTok->str() == spaceInfo[back].className) {
1809 14 : start = qualificationTok;
1810 14 : back--;
1811 14 : count++;
1812 : } else {
1813 3 : good = false;
1814 3 : break;
1815 : }
1816 : }
1817 : // check global namespace
1818 68 : if (good && back == 1 && start->strAt(-1) == "::")
1819 1 : good = false;
1820 :
1821 68 : if (good) {
1822 : // remove any extra qualification if present
1823 76 : while (count) {
1824 12 : if (!removed.empty())
1825 4 : removed.insert(0, " ");
1826 12 : removed.insert(0, tok2->strAt(-2) + " " + tok2->strAt(-1));
1827 12 : tok2->tokAt(-3)->deleteNext(2);
1828 12 : --count;
1829 : }
1830 :
1831 : // remove global namespace if present
1832 64 : if (tok2->strAt(-1) == "::") {
1833 6 : removed.insert(0, ":: ");
1834 6 : tok2->tokAt(-2)->deleteNext();
1835 6 : globalScope = true;
1836 : }
1837 :
1838 : // remove qualification if present
1839 157 : for (int i = classLevel; i < spaceInfo.size(); ++i) {
1840 93 : if (!removed.empty())
1841 39 : removed += " ";
1842 93 : removed += (tok2->str() + " " + tok2->strAt(1));
1843 93 : tok2->deleteThis();
1844 93 : tok2->deleteThis();
1845 : }
1846 64 : simplifyType = true;
1847 : }
1848 : } else {
1849 362 : if (tok2->strAt(-1) == "::") {
1850 21 : int relativeSpaceInfoSize = spaceInfo.size();
1851 21 : Token * tokBeforeType = tok2->previous();
1852 38 : while (relativeSpaceInfoSize > 1 &&
1853 122 : tokBeforeType && tokBeforeType->str() == "::" &&
1854 32 : tokBeforeType->strAt(-1) == spaceInfo[relativeSpaceInfoSize-1].className) {
1855 31 : tokBeforeType = tokBeforeType->tokAt(-2);
1856 31 : --relativeSpaceInfoSize;
1857 : }
1858 21 : if (tokBeforeType && tokBeforeType->str() != "::") {
1859 17 : Token::eraseTokens(tokBeforeType, tok2);
1860 17 : simplifyType = true;
1861 : }
1862 341 : } else if (Token::Match(tok2->previous(), "case|;|{|} %type% :")) {
1863 0 : tok2 = tok2->next();
1864 341 : } else if (duplicateTypedef(tok2, typeName, typeDef)) {
1865 : // skip to end of scope if not already there
1866 6 : if (tok2->str() != "}") {
1867 76 : while (tok2->next()) {
1868 74 : if (tok2->next()->str() == "{")
1869 1 : tok2 = tok2->linkAt(1)->previous();
1870 73 : else if (tok2->next()->str() == "}")
1871 4 : break;
1872 :
1873 70 : tok2 = tok2->next();
1874 : }
1875 : }
1876 335 : } else if (Token::Match(tok2->tokAt(-2), "%type% *|&")) {
1877 : // Ticket #5868: Don't substitute variable names
1878 335 : } else if (tok2->previous()->str() != ".") {
1879 335 : simplifyType = (TypedefSimplifier::canReplaceStatic(tok2) != 0);
1880 : }
1881 : }
1882 : }
1883 :
1884 13601 : simplifyType = simplifyType && (!inEnum || !Token::simpleMatch(tok2->next(), "="));
1885 13601 : simplifyType = simplifyType && !(Token::simpleMatch(tok2->next(), "<") && Token::simpleMatch(typeEnd, ">"));
1886 :
1887 13601 : if (simplifyType) {
1888 407 : mTypedefInfo.back().used = true;
1889 :
1890 : // can't simplify 'operator functionPtr ()' and 'functionPtr operator ... ()'
1891 591 : if (functionPtr && (tok2->previous()->str() == "operator" ||
1892 184 : (tok2->next() && tok2->next()->str() == "operator"))) {
1893 2 : simplifyType = false;
1894 2 : tok2 = tok2->next();
1895 2 : continue;
1896 : }
1897 :
1898 : // There are 2 categories of typedef substitutions:
1899 : // 1. variable declarations that preserve the variable name like
1900 : // global, local, and function parameters
1901 : // 2. not variable declarations that have no name like derived
1902 : // classes, casts, operators, and template parameters
1903 :
1904 : // try to determine which category this substitution is
1905 405 : bool inCast = false;
1906 405 : bool inTemplate = false;
1907 405 : bool inOperator = false;
1908 405 : bool inSizeof = false;
1909 :
1910 405 : const bool sameStartEnd = (typeStart == typeEnd);
1911 :
1912 : // check for derived class: class A : some_typedef {
1913 405 : const bool isDerived = Token::Match(tok2->previous(), "public|protected|private|: %type% {|,");
1914 :
1915 : // check for cast: (some_typedef) A or static_cast<some_typedef>(A)
1916 : // todo: check for more complicated casts like: (const some_typedef *)A
1917 845 : if ((tok2->previous()->str() == "(" && tok2->next()->str() == ")" && tok2->strAt(-2) != "sizeof") ||
1918 869 : (tok2->previous()->str() == "<" && Token::simpleMatch(tok2->next(), "> (")) ||
1919 380 : Token::Match(tok2->tokAt(-2), "( const %name% )"))
1920 25 : inCast = true;
1921 :
1922 : // check for template parameters: t<some_typedef> t1
1923 413 : else if (Token::Match(tok2->previous(), "<|,") &&
1924 33 : Token::Match(tok2->next(), "&|*| &|*| >|,"))
1925 25 : inTemplate = true;
1926 :
1927 355 : else if (Token::Match(tok2->tokAt(-2), "sizeof ( %type% )"))
1928 0 : inSizeof = true;
1929 :
1930 : // check for operator
1931 799 : if (tok2->strAt(-1) == "operator" ||
1932 394 : Token::simpleMatch(tok2->tokAt(-2), "operator const"))
1933 13 : inOperator = true;
1934 :
1935 405 : if (typeStart->str() == "typename" && tok2->strAt(-1)=="typename") {
1936 : // Remove one typename if it is already contained in the goal
1937 1 : typeStart = typeStart->next();
1938 : }
1939 :
1940 : // skip over class or struct in derived class declaration
1941 405 : bool structRemoved = false;
1942 405 : if ((isDerived || inTemplate) && Token::Match(typeStart, "class|struct")) {
1943 3 : if (typeStart->str() == "struct")
1944 3 : structRemoved = true;
1945 3 : typeStart = typeStart->next();
1946 : }
1947 405 : if (Token::Match(typeStart, "struct|class|union") && Token::Match(tok2, "%name% ::"))
1948 0 : typeStart = typeStart->next();
1949 :
1950 405 : if (sameStartEnd)
1951 225 : typeEnd = typeStart;
1952 :
1953 : // Is this a "T()" expression where T is a pointer type?
1954 405 : const bool isPointerTypeCall = !inOperator && Token::Match(tok2, "%name% ( )") && !pointers.empty();
1955 :
1956 : // start substituting at the typedef name by replacing it with the type
1957 405 : Token* replStart = tok2; // track first replaced token
1958 3189 : for (Token* tok3 = typeStart; tok3 && (tok3->str() != ";"); tok3 = tok3->next())
1959 2784 : tok3->isSimplifiedTypedef(true);
1960 405 : if (isPointerTypeCall) {
1961 0 : tok2->deleteThis();
1962 0 : tok2->insertToken("0");
1963 0 : tok2 = tok2->next();
1964 0 : tok2->next()->insertToken("0");
1965 : }
1966 405 : if (Token::Match(tok2->tokAt(-1), "class|struct|union") && tok2->strAt(-1) == typeStart->str())
1967 3 : tok2->deletePrevious();
1968 405 : tok2->str(typeStart->str());
1969 :
1970 : // restore qualification if it was removed
1971 405 : if (Token::Match(typeStart, "class|struct|union") || structRemoved) {
1972 34 : if (structRemoved)
1973 3 : tok2 = tok2->previous();
1974 :
1975 34 : if (globalScope) {
1976 2 : replStart = tok2->insertToken("::");
1977 2 : tok2 = tok2->next();
1978 : }
1979 :
1980 43 : for (int i = classLevel; i < spaceInfo.size(); ++i) {
1981 9 : tok2->insertToken(spaceInfo[i].className);
1982 9 : tok2 = tok2->next();
1983 9 : tok2->insertToken("::");
1984 9 : tok2 = tok2->next();
1985 : }
1986 : }
1987 :
1988 : // add some qualification back if needed
1989 405 : Token *start = tok2;
1990 407 : std::string removed1 = removed;
1991 405 : std::string::size_type idx = removed1.rfind(" ::");
1992 :
1993 405 : if (idx != std::string::npos)
1994 64 : removed1.resize(idx);
1995 405 : if (removed1 == classPath && !removed1.empty()) {
1996 83 : for (std::vector<Space>::const_reverse_iterator it = spaceInfo.crbegin(); it != spaceInfo.crend(); ++it) {
1997 83 : if (it->recordTypes.find(start->str()) != it->recordTypes.end()) {
1998 8 : std::string::size_type spaceIdx = 0;
1999 8 : std::string::size_type startIdx = 0;
2000 18 : while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
2001 10 : tok2->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
2002 10 : startIdx = spaceIdx + 1;
2003 : }
2004 8 : tok2->previous()->insertToken(removed1.substr(startIdx));
2005 8 : replStart = tok2->previous()->insertToken("::");
2006 8 : break;
2007 : }
2008 75 : idx = removed1.rfind(" ::");
2009 75 : if (idx == std::string::npos)
2010 47 : break;
2011 :
2012 28 : removed1.resize(idx);
2013 : }
2014 : }
2015 405 : replStart->isSimplifiedTypedef(true);
2016 405 : Token* constTok = Token::simpleMatch(tok2->previous(), "const") ? tok2->previous() : nullptr;
2017 : // add remainder of type
2018 405 : tok2 = TokenList::copyTokens(tok2, typeStart->next(), typeEnd);
2019 :
2020 405 : if (!pointers.empty()) {
2021 104 : for (const std::string &p : pointers) {
2022 61 : tok2->insertToken(p);
2023 61 : tok2->isSimplifiedTypedef(true);
2024 61 : tok2 = tok2->next();
2025 : }
2026 43 : if (constTok) {
2027 0 : constTok->deleteThis();
2028 0 : tok2->insertToken("const");
2029 0 : tok2->isSimplifiedTypedef(true);
2030 0 : tok2 = tok2->next();
2031 : }
2032 : }
2033 :
2034 405 : if (funcStart && funcEnd) {
2035 112 : tok2->insertToken("(");
2036 112 : tok2 = tok2->next();
2037 112 : Token *paren = tok2;
2038 112 : tok2 = TokenList::copyTokens(tok2, funcStart, funcEnd);
2039 :
2040 112 : if (!inCast)
2041 105 : tok2 = processFunc(tok2, inOperator);
2042 :
2043 112 : if (!tok2)
2044 0 : break;
2045 :
2046 112 : while (Token::Match(tok2, "%name%|] ["))
2047 0 : tok2 = tok2->linkAt(1);
2048 :
2049 112 : tok2->insertToken(")");
2050 112 : tok2 = tok2->next();
2051 112 : Token::createMutualLinks(tok2, paren);
2052 :
2053 112 : tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2054 :
2055 112 : if (specStart) {
2056 32 : Token *spec = specStart;
2057 32 : tok2->insertToken(spec->str());
2058 32 : tok2 = tok2->next();
2059 42 : while (spec != specEnd) {
2060 10 : spec = spec->next();
2061 10 : tok2->insertToken(spec->str());
2062 10 : tok2 = tok2->next();
2063 : }
2064 112 : }
2065 : }
2066 :
2067 293 : else if (functionPtr || function) {
2068 : // don't add parentheses around function names because it
2069 : // confuses other simplifications
2070 8 : bool needParen = true;
2071 8 : if (!inTemplate && function && tok2->next() && tok2->next()->str() != "*")
2072 1 : needParen = false;
2073 8 : if (needParen) {
2074 7 : tok2->insertToken("(");
2075 7 : tok2 = tok2->next();
2076 : }
2077 8 : Token *tok3 = tok2;
2078 8 : if (namespaceStart) {
2079 0 : const Token *tok4 = namespaceStart;
2080 :
2081 0 : while (tok4 != namespaceEnd) {
2082 0 : tok2->insertToken(tok4->str());
2083 0 : tok2 = tok2->next();
2084 0 : tok4 = tok4->next();
2085 : }
2086 0 : tok2->insertToken(namespaceEnd->str());
2087 0 : tok2 = tok2->next();
2088 : }
2089 8 : if (functionPtr) {
2090 0 : tok2->insertToken("*");
2091 0 : tok2 = tok2->next();
2092 : }
2093 :
2094 8 : if (!inCast)
2095 8 : tok2 = processFunc(tok2, inOperator);
2096 :
2097 8 : if (needParen) {
2098 7 : if (!tok2)
2099 0 : syntaxError(nullptr);
2100 :
2101 7 : tok2->insertToken(")");
2102 7 : tok2 = tok2->next();
2103 7 : Token::createMutualLinks(tok2, tok3);
2104 : }
2105 8 : if (!tok2)
2106 0 : syntaxError(nullptr);
2107 :
2108 8 : tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2109 8 : if (inTemplate) {
2110 5 : if (!tok2)
2111 0 : syntaxError(nullptr);
2112 :
2113 5 : tok2 = tok2->next();
2114 : }
2115 :
2116 8 : if (specStart) {
2117 1 : Token *spec = specStart;
2118 1 : tok2->insertToken(spec->str());
2119 1 : tok2 = tok2->next();
2120 1 : while (spec != specEnd) {
2121 0 : spec = spec->next();
2122 0 : tok2->insertToken(spec->str());
2123 0 : tok2 = tok2->next();
2124 : }
2125 8 : }
2126 285 : } else if (functionRetFuncPtr || functionPtrRetFuncPtr) {
2127 3 : tok2->insertToken("(");
2128 3 : tok2 = tok2->next();
2129 3 : Token *tok3 = tok2;
2130 3 : tok2->insertToken("*");
2131 3 : tok2 = tok2->next();
2132 :
2133 3 : Token * tok4 = nullptr;
2134 3 : if (functionPtrRetFuncPtr) {
2135 1 : tok2->insertToken("(");
2136 1 : tok2 = tok2->next();
2137 1 : tok4 = tok2;
2138 1 : tok2->insertToken("*");
2139 1 : tok2 = tok2->next();
2140 : }
2141 :
2142 : // skip over variable name if there
2143 3 : if (!inCast) {
2144 3 : if (!tok2 || !tok2->next())
2145 0 : syntaxError(nullptr);
2146 :
2147 3 : if (tok2->next()->str() != ")")
2148 3 : tok2 = tok2->next();
2149 : }
2150 :
2151 3 : if (tok4 && functionPtrRetFuncPtr) {
2152 1 : tok2->insertToken(")");
2153 1 : tok2 = tok2->next();
2154 1 : Token::createMutualLinks(tok2, tok4);
2155 : }
2156 :
2157 3 : tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2158 :
2159 3 : tok2->insertToken(")");
2160 3 : tok2 = tok2->next();
2161 3 : Token::createMutualLinks(tok2, tok3);
2162 :
2163 3 : tok2 = TokenList::copyTokens(tok2, argFuncRetStart, argFuncRetEnd);
2164 282 : } else if (ptrToArray || refToArray) {
2165 14 : tok2->insertToken("(");
2166 14 : tok2 = tok2->next();
2167 14 : Token *tok3 = tok2;
2168 :
2169 14 : if (ptrToArray)
2170 5 : tok2->insertToken("*");
2171 : else
2172 9 : tok2->insertToken("&");
2173 14 : tok2 = tok2->next();
2174 :
2175 14 : bool hasName = false;
2176 : // skip over name
2177 27 : if (tok2->next() && tok2->next()->str() != ")" && tok2->next()->str() != "," &&
2178 13 : tok2->next()->str() != ">") {
2179 12 : hasName = true;
2180 12 : if (tok2->next()->str() != "(")
2181 11 : tok2 = tok2->next();
2182 :
2183 : // check for function and skip over args
2184 12 : if (tok2 && tok2->next() && tok2->next()->str() == "(")
2185 2 : tok2 = tok2->next()->link();
2186 :
2187 : // check for array
2188 12 : if (tok2 && tok2->next() && tok2->next()->str() == "[")
2189 1 : tok2 = tok2->next()->link();
2190 : }
2191 :
2192 14 : tok2->insertToken(")");
2193 14 : Token::createMutualLinks(tok2->next(), tok3);
2194 :
2195 14 : if (!hasName)
2196 14 : tok2 = tok2->next();
2197 268 : } else if (ptrMember) {
2198 8 : if (Token::simpleMatch(tok2, "* (")) {
2199 5 : tok2->insertToken("*");
2200 5 : tok2 = tok2->next();
2201 : } else {
2202 : // This is the case of casting operator.
2203 : // Name is not available, and () should not be
2204 : // inserted
2205 3 : const bool castOperator = inOperator && Token::Match(tok2, "%type% (");
2206 3 : Token *openParenthesis = nullptr;
2207 :
2208 3 : if (!castOperator) {
2209 2 : tok2->insertToken("(");
2210 2 : tok2 = tok2->next();
2211 :
2212 2 : openParenthesis = tok2;
2213 : }
2214 :
2215 3 : const Token *tok4 = namespaceStart;
2216 :
2217 6 : while (tok4 != namespaceEnd) {
2218 3 : tok2->insertToken(tok4->str());
2219 3 : tok2 = tok2->next();
2220 3 : tok4 = tok4->next();
2221 : }
2222 3 : tok2->insertToken(namespaceEnd->str());
2223 3 : tok2 = tok2->next();
2224 :
2225 3 : tok2->insertToken("*");
2226 3 : tok2 = tok2->next();
2227 :
2228 3 : if (openParenthesis) {
2229 : // Skip over name, if any
2230 2 : if (Token::Match(tok2->next(), "%name%"))
2231 1 : tok2 = tok2->next();
2232 :
2233 2 : tok2->insertToken(")");
2234 2 : tok2 = tok2->next();
2235 :
2236 2 : Token::createMutualLinks(tok2, openParenthesis);
2237 : }
2238 : }
2239 260 : } else if (typeOf) {
2240 1 : tok2 = TokenList::copyTokens(tok2, argStart, argEnd);
2241 259 : } else if (Token::Match(tok2, "%name% [")) {
2242 0 : while (Token::Match(tok2, "%name%|] [")) {
2243 0 : tok2 = tok2->linkAt(1);
2244 : }
2245 0 : tok2 = tok2->previous();
2246 : }
2247 :
2248 405 : if (arrayStart && arrayEnd) {
2249 0 : do {
2250 34 : if (!tok2->next())
2251 0 : syntaxError(tok2); // can't recover so quit
2252 :
2253 34 : if (!inCast && !inSizeof && !inTemplate)
2254 32 : tok2 = tok2->next();
2255 :
2256 34 : if (tok2->str() == "const")
2257 0 : tok2 = tok2->next();
2258 :
2259 : // reference or pointer to array?
2260 34 : if (Token::Match(tok2, "&|*|&&")) {
2261 10 : tok2 = tok2->previous();
2262 10 : tok2->insertToken("(");
2263 10 : Token *tok3 = tok2->next();
2264 :
2265 : // handle missing variable name
2266 10 : if (Token::Match(tok3, "( *|&|&& *|&|&& %name%"))
2267 0 : tok2 = tok3->tokAt(3);
2268 10 : else if (Token::Match(tok2->tokAt(3), "[(),;]"))
2269 3 : tok2 = tok2->tokAt(2);
2270 7 : else if (Token::simpleMatch(tok2->tokAt(3), ">"))
2271 1 : tok2 = tok2->tokAt(2);
2272 : else
2273 6 : tok2 = tok2->tokAt(3);
2274 10 : if (!tok2)
2275 0 : syntaxError(nullptr);
2276 :
2277 10 : while (tok2->strAt(1) == "::")
2278 0 : tok2 = tok2->tokAt(2);
2279 :
2280 : // skip over function parameters
2281 10 : if (tok2->str() == "(")
2282 0 : tok2 = tok2->link();
2283 :
2284 10 : if (tok2->strAt(1) == "(")
2285 5 : tok2 = tok2->linkAt(1);
2286 :
2287 : // skip over const/noexcept
2288 15 : while (Token::Match(tok2->next(), "const|noexcept")) {
2289 5 : tok2 = tok2->next();
2290 5 : if (Token::Match(tok2->next(), "( true|false )"))
2291 3 : tok2 = tok2->tokAt(3);
2292 : }
2293 :
2294 10 : tok2->insertToken(")");
2295 10 : tok2 = tok2->next();
2296 10 : Token::createMutualLinks(tok2, tok3);
2297 : }
2298 :
2299 34 : if (!tok2->next())
2300 2 : syntaxError(tok2); // can't recover so quit
2301 :
2302 : // skip over array dimensions
2303 33 : while (tok2->next()->str() == "[")
2304 1 : tok2 = tok2->linkAt(1);
2305 :
2306 32 : tok2 = TokenList::copyTokens(tok2, arrayStart, arrayEnd);
2307 32 : if (!tok2->next())
2308 0 : syntaxError(tok2);
2309 :
2310 32 : if (tok2->str() == "=") {
2311 0 : if (tok2->next()->str() == "{")
2312 0 : tok2 = tok2->next()->link()->next();
2313 0 : else if (tok2->next()->str().at(0) == '\"')
2314 0 : tok2 = tok2->tokAt(2);
2315 : }
2316 32 : } while (Token::Match(tok2, ", %name% ;|=|,"));
2317 : }
2318 :
2319 403 : simplifyType = false;
2320 : }
2321 13597 : if (!tok2)
2322 0 : break;
2323 : }
2324 :
2325 327 : if (!tok)
2326 0 : syntaxError(nullptr);
2327 :
2328 327 : if (tok->str() == ";")
2329 315 : done = true;
2330 12 : else if (tok->str() == ",") {
2331 9 : arrayStart = nullptr;
2332 9 : arrayEnd = nullptr;
2333 9 : tokOffset = tok->next();
2334 9 : pointers.clear();
2335 :
2336 25 : while (Token::Match(tokOffset, "*|&")) {
2337 16 : pointers.push_back(tokOffset->str());
2338 16 : tokOffset = tokOffset->next();
2339 : }
2340 :
2341 9 : if (Token::Match(tokOffset, "%type%")) {
2342 9 : typeName = tokOffset;
2343 9 : tokOffset = tokOffset->next();
2344 :
2345 9 : if (tokOffset && tokOffset->str() == "[") {
2346 0 : arrayStart = tokOffset;
2347 :
2348 : for (;;) {
2349 0 : while (tokOffset->next() && !Token::Match(tokOffset->next(), ";|,"))
2350 0 : tokOffset = tokOffset->next();
2351 :
2352 0 : if (!tokOffset->next())
2353 0 : return; // invalid input
2354 0 : if (tokOffset->next()->str() == ";")
2355 0 : break;
2356 0 : if (tokOffset->str() == "]")
2357 0 : break;
2358 0 : tokOffset = tokOffset->next();
2359 : }
2360 :
2361 0 : arrayEnd = tokOffset;
2362 0 : tokOffset = tokOffset->next();
2363 : }
2364 :
2365 9 : if (Token::Match(tokOffset, ";|,"))
2366 9 : tok = tokOffset;
2367 : else {
2368 : // we encountered a typedef we don't support yet so just continue
2369 0 : done = true;
2370 0 : ok = false;
2371 : }
2372 : } else {
2373 : // we encountered a typedef we don't support yet so just continue
2374 0 : done = true;
2375 0 : ok = false;
2376 : }
2377 : } else {
2378 : // something is really wrong (internal error)
2379 3 : done = true;
2380 3 : ok = false;
2381 : }
2382 : }
2383 :
2384 318 : if (ok) {
2385 : // remove typedef
2386 315 : Token::eraseTokens(typeDef, tok);
2387 :
2388 315 : if (typeDef != list.front()) {
2389 186 : tok = typeDef->previous();
2390 186 : tok->deleteNext();
2391 : //no need to remove last token in the list
2392 186 : if (tok->tokAt(2))
2393 185 : tok->deleteNext();
2394 : } else {
2395 129 : list.front()->deleteThis();
2396 : //no need to remove last token in the list
2397 129 : if (list.front()->next())
2398 126 : list.front()->deleteThis();
2399 129 : tok = list.front();
2400 : //now the next token to process is 'tok', not 'tok->next()';
2401 129 : goback = true;
2402 : }
2403 : }
2404 : }
2405 : }
2406 :
2407 : namespace {
2408 : struct ScopeInfo3 {
2409 : enum Type { Global, Namespace, Record, MemberFunction, Other };
2410 17685 : ScopeInfo3() : parent(nullptr), type(Global), bodyStart(nullptr), bodyEnd(nullptr) {}
2411 36279 : ScopeInfo3(ScopeInfo3 *parent_, Type type_, std::string name_, const Token *bodyStart_, const Token *bodyEnd_)
2412 36279 : : parent(parent_), type(type_), name(std::move(name_)), bodyStart(bodyStart_), bodyEnd(bodyEnd_) {
2413 36277 : if (name.empty())
2414 29058 : return;
2415 7219 : fullName = name;
2416 7219 : ScopeInfo3 *scope = parent;
2417 8330 : while (scope && scope->parent) {
2418 1231 : if (scope->name.empty())
2419 120 : break;
2420 1111 : fullName = scope->name + " :: " + fullName;
2421 1111 : scope = scope->parent;
2422 : }
2423 : }
2424 : ScopeInfo3 *parent;
2425 : std::list<ScopeInfo3> children;
2426 : Type type;
2427 : std::string fullName;
2428 : std::string name;
2429 : const Token * bodyStart;
2430 : const Token * bodyEnd;
2431 : std::set<std::string> usingNamespaces;
2432 : std::set<std::string> recordTypes;
2433 : std::set<std::string> baseTypes;
2434 :
2435 36280 : ScopeInfo3 *addChild(Type scopeType, const std::string &scopeName, const Token *bodyStartToken, const Token *bodyEndToken) {
2436 36280 : children.emplace_back(this, scopeType, scopeName, bodyStartToken, bodyEndToken);
2437 36277 : return &children.back();
2438 : }
2439 :
2440 2 : bool hasChild(const std::string &childName) const {
2441 2 : return std::any_of(children.cbegin(), children.cend(), [&](const ScopeInfo3& child) {
2442 2 : return child.name == childName;
2443 2 : });
2444 : }
2445 :
2446 455 : const ScopeInfo3 * findInChildren(const std::string & scope) const {
2447 819 : for (const auto & child : children) {
2448 374 : if (child.type == Record && (child.name == scope || child.fullName == scope))
2449 10 : return &child;
2450 :
2451 365 : const ScopeInfo3 * temp = child.findInChildren(scope);
2452 365 : if (temp)
2453 1 : return temp;
2454 : }
2455 445 : return nullptr;
2456 : }
2457 :
2458 58 : const ScopeInfo3 * findScope(const std::string & scope) const {
2459 58 : const ScopeInfo3 * tempScope = this;
2460 182 : while (tempScope) {
2461 : // check children
2462 159 : auto it = std::find_if(tempScope->children.cbegin(), tempScope->children.cend(), [&](const ScopeInfo3& child) {
2463 159 : return &child != this && child.type == Record && (child.name == scope || child.fullName == scope);
2464 158 : });
2465 158 : if (it != tempScope->children.end())
2466 34 : return &*it;
2467 : // check siblings for same name
2468 133 : if (tempScope->parent) {
2469 236 : for (const auto &sibling : tempScope->parent->children) {
2470 136 : if (sibling.name == tempScope->name && &sibling != this) {
2471 90 : const ScopeInfo3 * temp = sibling.findInChildren(scope);
2472 90 : if (temp)
2473 9 : return temp;
2474 : }
2475 : }
2476 : }
2477 124 : tempScope = tempScope->parent;
2478 : }
2479 24 : return nullptr;
2480 : }
2481 :
2482 35 : bool findTypeInBase(const std::string &scope) const {
2483 35 : if (scope.empty())
2484 5 : return false;
2485 : // check in base types first
2486 30 : if (baseTypes.find(scope) != baseTypes.end())
2487 6 : return true;
2488 : // check in base types base types
2489 26 : for (const std::string & base : baseTypes) {
2490 9 : const ScopeInfo3 * baseScope = findScope(base);
2491 : // bail on uninstantiated recursive template
2492 9 : if (baseScope == this)
2493 7 : return false;
2494 9 : if (baseScope && baseScope->fullName == scope)
2495 5 : return true;
2496 4 : if (baseScope && baseScope->findTypeInBase(scope))
2497 2 : return true;
2498 : }
2499 17 : return false;
2500 : }
2501 :
2502 90 : ScopeInfo3 * findScope(const ScopeInfo3 * scope) {
2503 90 : if (scope->bodyStart == bodyStart)
2504 25 : return this;
2505 87 : for (auto & child : children) {
2506 65 : ScopeInfo3 * temp = child.findScope(scope);
2507 65 : if (temp)
2508 43 : return temp;
2509 : }
2510 22 : return nullptr;
2511 : }
2512 : };
2513 :
2514 81288 : void setScopeInfo(Token *tok, ScopeInfo3 *&scopeInfo, bool debug=false)
2515 : {
2516 81288 : if (!tok)
2517 74901 : return;
2518 81288 : if (tok->str() == "{" && scopeInfo->parent && tok == scopeInfo->bodyStart)
2519 6286 : return;
2520 75002 : if (tok->str() == "}") {
2521 36301 : if (scopeInfo->parent && tok == scopeInfo->bodyEnd)
2522 36300 : scopeInfo = scopeInfo->parent;
2523 : else {
2524 : // Try to find parent scope
2525 1 : ScopeInfo3 *parent = scopeInfo->parent;
2526 2 : while (parent && parent->bodyEnd != tok)
2527 1 : parent = parent->parent;
2528 1 : if (parent) {
2529 0 : scopeInfo = parent;
2530 0 : if (debug)
2531 0 : throw std::runtime_error("Internal error: unmatched }");
2532 : }
2533 : }
2534 36301 : return;
2535 : }
2536 38700 : if (!Token::Match(tok, "namespace|class|struct|union %name% {|:|::|<")) {
2537 : // check for using namespace
2538 32317 : if (Token::Match(tok, "using namespace %name% ;|::")) {
2539 140 : const Token * tok1 = tok->tokAt(2);
2540 280 : std::string nameSpace;
2541 362 : while (tok1 && tok1->str() != ";") {
2542 222 : if (!nameSpace.empty())
2543 82 : nameSpace += " ";
2544 222 : nameSpace += tok1->str();
2545 222 : tok1 = tok1->next();
2546 : }
2547 140 : scopeInfo->usingNamespaces.insert(std::move(nameSpace));
2548 : }
2549 : // check for member function
2550 32178 : else if (tok->str() == "{") {
2551 29994 : bool added = false;
2552 29994 : Token *tok1 = tok;
2553 30340 : while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2554 346 : tok1 = tok1->previous();
2555 29994 : if (tok1->previous() && (tok1->strAt(-1) == ")" || tok->strAt(-1) == "}")) {
2556 26859 : tok1 = tok1->linkAt(-1);
2557 26859 : if (Token::Match(tok1->previous(), "throw|noexcept (")) {
2558 60 : tok1 = tok1->previous();
2559 78 : while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
2560 18 : tok1 = tok1->previous();
2561 60 : if (tok1->strAt(-1) != ")")
2562 1 : return;
2563 59 : tok1 = tok1->linkAt(-1);
2564 : } else {
2565 27255 : while (Token::Match(tok1->tokAt(-2), ":|, %name%")) {
2566 457 : tok1 = tok1->tokAt(-2);
2567 457 : if (tok1->strAt(-1) != ")" && tok1->strAt(-1) != "}")
2568 0 : return;
2569 457 : tok1 = tok1->linkAt(-1);
2570 : }
2571 : }
2572 26859 : if (tok1->strAt(-1) == ">")
2573 50 : tok1 = tok1->previous()->findOpeningBracket();
2574 52834 : if (tok1 && (Token::Match(tok1->tokAt(-3), "%name% :: %name%") ||
2575 25978 : Token::Match(tok1->tokAt(-4), "%name% :: ~ %name%"))) {
2576 933 : tok1 = tok1->tokAt(-2);
2577 933 : if (tok1->str() == "~")
2578 54 : tok1 = tok1->previous();
2579 933 : std::string scope = tok1->strAt(-1);
2580 1094 : while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
2581 161 : scope = tok1->strAt(-3) + " :: " + scope;
2582 161 : tok1 = tok1->tokAt(-2);
2583 : }
2584 933 : scopeInfo = scopeInfo->addChild(ScopeInfo3::MemberFunction, scope, tok, tok->link());
2585 933 : added = true;
2586 : }
2587 : }
2588 :
2589 29992 : if (!added)
2590 29060 : scopeInfo = scopeInfo->addChild(ScopeInfo3::Other, emptyString, tok, tok->link());
2591 : }
2592 32313 : return;
2593 : }
2594 :
2595 6382 : const bool record = Token::Match(tok, "class|struct|union %name%");
2596 6382 : tok = tok->next();
2597 12764 : std::string classname = tok->str();
2598 6581 : while (Token::Match(tok, "%name% :: %name%")) {
2599 199 : tok = tok->tokAt(2);
2600 199 : classname += " :: " + tok->str();
2601 : }
2602 :
2603 : // add record type to scope info
2604 6382 : if (record)
2605 5588 : scopeInfo->recordTypes.insert(classname);
2606 6382 : tok = tok->next();
2607 :
2608 : // skip template parameters
2609 6382 : if (tok && tok->str() == "<") {
2610 94 : tok = tok->findClosingBracket();
2611 94 : if (tok)
2612 93 : tok = tok->next();
2613 : }
2614 :
2615 : // get base class types
2616 12764 : std::set<std::string> baseTypes;
2617 6382 : if (tok && tok->str() == ":") {
2618 36 : do {
2619 694 : tok = tok->next();
2620 1164 : while (Token::Match(tok, "public|protected|private|virtual"))
2621 470 : tok = tok->next();
2622 1388 : std::string base;
2623 1489 : while (tok && !Token::Match(tok, ";|,|{")) {
2624 795 : if (!base.empty())
2625 105 : base += ' ';
2626 795 : base += tok->str();
2627 795 : tok = tok->next();
2628 : // add template parameters
2629 795 : if (tok && tok->str() == "<") {
2630 81 : const Token* endTok = tok->findClosingBracket();
2631 81 : if (endTok) {
2632 81 : endTok = endTok->next();
2633 466 : while (tok != endTok) {
2634 385 : base += tok->str();
2635 385 : tok = tok->next();
2636 : }
2637 : }
2638 : }
2639 : }
2640 694 : baseTypes.insert(std::move(base));
2641 694 : } while (tok && !Token::Match(tok, ";|{"));
2642 : }
2643 :
2644 6382 : if (tok && tok->str() == "{") {
2645 6286 : scopeInfo = scopeInfo->addChild(record ? ScopeInfo3::Record : ScopeInfo3::Namespace, classname, tok, tok->link());
2646 6286 : scopeInfo->baseTypes = std::move(baseTypes);
2647 : }
2648 : }
2649 :
2650 349 : Token *findSemicolon(Token *tok)
2651 : {
2652 349 : int level = 0;
2653 :
2654 7238 : for (; tok && (level > 0 || tok->str() != ";"); tok = tok->next()) {
2655 6889 : if (tok->str() == "{")
2656 15 : ++level;
2657 6874 : else if (level > 0 && tok->str() == "}")
2658 15 : --level;
2659 : }
2660 :
2661 349 : return tok;
2662 : }
2663 :
2664 9457 : bool usingMatch(
2665 : const Token *nameToken,
2666 : const std::string &scope,
2667 : Token *&tok,
2668 : const std::string &scope1,
2669 : const ScopeInfo3 *currentScope,
2670 : const ScopeInfo3 *memberClassScope)
2671 : {
2672 9457 : Token *tok1 = tok;
2673 :
2674 9457 : if (tok1 && tok1->str() != nameToken->str())
2675 9061 : return false;
2676 :
2677 : // skip this using
2678 396 : if (tok1 == nameToken) {
2679 155 : tok = findSemicolon(tok1);
2680 155 : return false;
2681 : }
2682 :
2683 : // skip other using with this name
2684 241 : if (tok1->strAt(-1) == "using") {
2685 : // fixme: this is wrong
2686 : // skip to end of scope
2687 12 : if (currentScope->bodyEnd)
2688 9 : tok = const_cast<Token*>(currentScope->bodyEnd->previous());
2689 12 : return false;
2690 : }
2691 :
2692 229 : if (Token::Match(tok1->tokAt(-1), "class|struct|union|enum|namespace")) {
2693 : // fixme
2694 12 : return false;
2695 : }
2696 :
2697 : // get qualification
2698 434 : std::string qualification;
2699 217 : const Token* tok2 = tok1;
2700 217 : std::string::size_type index = scope.size();
2701 217 : std::string::size_type new_index = std::string::npos;
2702 217 : bool match = true;
2703 262 : while (Token::Match(tok2->tokAt(-2), "%name% ::") && !tok2->tokAt(-2)->isKeyword()) {
2704 45 : std::string last;
2705 45 : if (match && !scope1.empty()) {
2706 35 : new_index = scope1.rfind(' ', index - 1);
2707 35 : if (new_index != std::string::npos)
2708 19 : last = scope1.substr(new_index, index - new_index);
2709 16 : else if (!qualification.empty())
2710 3 : last.clear();
2711 : else
2712 13 : last = scope1;
2713 : } else
2714 10 : match = false;
2715 45 : if (match && tok2->strAt(-2) == last)
2716 3 : index = new_index;
2717 : else {
2718 42 : if (!qualification.empty())
2719 14 : qualification = " :: " + qualification;
2720 42 : qualification = tok2->strAt(-2) + qualification;
2721 : }
2722 45 : tok2 = tok2->tokAt(-2);
2723 : }
2724 :
2725 434 : std::string fullScope1 = scope1;
2726 217 : if (!scope1.empty() && !qualification.empty())
2727 20 : fullScope1 += " :: ";
2728 217 : fullScope1 += qualification;
2729 :
2730 217 : if (scope == fullScope1)
2731 162 : return true;
2732 :
2733 55 : const ScopeInfo3 *scopeInfo = memberClassScope ? memberClassScope : currentScope;
2734 :
2735 : // check in base types
2736 55 : if (qualification.empty() && scopeInfo->findTypeInBase(scope))
2737 11 : return true;
2738 :
2739 : // check using namespace
2740 44 : const ScopeInfo3 * tempScope = scopeInfo;
2741 162 : while (tempScope) {
2742 : //if (!tempScope->parent->usingNamespaces.empty()) {
2743 125 : const std::set<std::string>& usingNS = tempScope->usingNamespaces;
2744 125 : if (!usingNS.empty()) {
2745 8 : if (qualification.empty()) {
2746 6 : if (usingNS.find(scope) != usingNS.end())
2747 6 : return true;
2748 : } else {
2749 2 : const std::string suffix = " :: " + qualification;
2750 2 : if (std::any_of(usingNS.cbegin(), usingNS.cend(), [&](const std::string& ns) {
2751 2 : return scope == ns + suffix;
2752 : }))
2753 1 : return true;
2754 : }
2755 : }
2756 118 : tempScope = tempScope->parent;
2757 : }
2758 :
2759 74 : std::string newScope1 = scope1;
2760 :
2761 : // scopes didn't match so try higher scopes
2762 37 : index = newScope1.size();
2763 54 : while (!newScope1.empty()) {
2764 43 : const std::string::size_type separator = newScope1.rfind(" :: ", index - 1);
2765 43 : if (separator != std::string::npos)
2766 15 : newScope1.resize(separator);
2767 : else
2768 28 : newScope1.clear();
2769 :
2770 43 : std::string newFullScope1 = newScope1;
2771 43 : if (!newScope1.empty() && !qualification.empty())
2772 10 : newFullScope1 += " :: ";
2773 43 : newFullScope1 += qualification;
2774 :
2775 43 : if (scope == newFullScope1)
2776 26 : return true;
2777 : }
2778 :
2779 11 : return false;
2780 : }
2781 :
2782 40 : std::string memberFunctionScope(const Token *tok)
2783 : {
2784 40 : std::string qualification;
2785 40 : const Token *qualTok = tok->strAt(-2) == "~" ? tok->tokAt(-4) : tok->tokAt(-3);
2786 83 : while (Token::Match(qualTok, "%type% ::")) {
2787 43 : if (!qualification.empty())
2788 3 : qualification = " :: " + qualification;
2789 43 : qualification = qualTok->str() + qualification;
2790 43 : qualTok = qualTok->tokAt(-2);
2791 : }
2792 40 : return qualification;
2793 : }
2794 :
2795 25 : const Token * memberFunctionEnd(const Token *tok)
2796 : {
2797 25 : if (tok->str() != "(")
2798 0 : return nullptr;
2799 25 : const Token *end = tok->link()->next();
2800 66 : while (end) {
2801 66 : if (end->str() == "{" && !Token::Match(end->tokAt(-2), ":|, %name%"))
2802 25 : return end;
2803 41 : if (end->str() == ";")
2804 0 : break;
2805 41 : end = end->next();
2806 : }
2807 0 : return nullptr;
2808 : }
2809 : } // namespace
2810 :
2811 9497 : bool Tokenizer::isMemberFunction(const Token *openParen)
2812 : {
2813 9497 : return (Token::Match(openParen->tokAt(-2), ":: %name% (") ||
2814 19035 : Token::Match(openParen->tokAt(-3), ":: ~ %name% (")) &&
2815 19035 : isFunctionHead(openParen, "{|:");
2816 : }
2817 :
2818 191 : static bool scopesMatch(const std::string &scope1, const std::string &scope2, const ScopeInfo3 *globalScope)
2819 : {
2820 191 : if (scope1.empty() || scope2.empty())
2821 163 : return false;
2822 :
2823 : // check if scopes match
2824 28 : if (scope1 == scope2)
2825 25 : return true;
2826 :
2827 : // check if scopes only differ by global qualification
2828 3 : if (scope1 == (":: " + scope2)) {
2829 2 : std::string::size_type end = scope2.find_first_of(' ');
2830 2 : if (end == std::string::npos)
2831 1 : end = scope2.size();
2832 2 : if (globalScope->hasChild(scope2.substr(0, end)))
2833 2 : return true;
2834 1 : } else if (scope2 == (":: " + scope1)) {
2835 0 : std::string::size_type end = scope1.find_first_of(' ');
2836 0 : if (end == std::string::npos)
2837 0 : end = scope1.size();
2838 0 : if (globalScope->hasChild(scope1.substr(0, end)))
2839 0 : return true;
2840 : }
2841 :
2842 1 : return false;
2843 : }
2844 :
2845 206 : static unsigned int tokDistance(const Token* tok1, const Token* tok2) {
2846 206 : unsigned int dist = 0;
2847 206 : const Token* tok = tok1;
2848 6268 : while (tok != tok2) {
2849 6062 : ++dist;
2850 6062 : tok = tok->next();
2851 : }
2852 206 : return dist;
2853 : }
2854 :
2855 23490 : bool Tokenizer::simplifyUsing()
2856 : {
2857 23490 : if (!isCPP() || mSettings.standards.cpp < Standards::CPP11)
2858 5985 : return false;
2859 :
2860 : // simplify using N::x; to using x = N::x;
2861 801552 : for (Token* tok = list.front(); tok; tok = tok->next()) {
2862 784049 : if (!Token::Match(tok, "using ::| %name% ::"))
2863 784022 : continue;
2864 25 : const Token* ns = tok->tokAt(tok->strAt(1) == "::" ? 2 : 1);
2865 25 : if (ns->isKeyword())
2866 2 : continue;
2867 23 : Token* end = tok->tokAt(3);
2868 72 : while (end && !Token::Match(end, "[;,]")) {
2869 49 : if (end->str() == "<") // skip template args
2870 3 : end = end->findClosingBracket();
2871 : else
2872 46 : end = end->next();
2873 : }
2874 23 : if (!end)
2875 0 : continue;
2876 23 : if (!end->tokAt(-1)->isNameOnly() || end->tokAt(-2)->isLiteral()) // e.g. operator=, operator""sv
2877 10 : continue;
2878 13 : tok->insertToken(end->strAt(-1))->insertToken("=")->isSimplifiedTypedef(true);
2879 13 : if (end->str() == ",") { // comma-separated list
2880 3 : end->str(";");
2881 3 : end->insertToken("using");
2882 : }
2883 13 : tok = end;
2884 : }
2885 :
2886 17504 : const unsigned int maxReplacementTokens = 1000; // limit the number of tokens we replace
2887 :
2888 17504 : bool substitute = false;
2889 35004 : ScopeInfo3 scopeInfo;
2890 17499 : ScopeInfo3 *currentScope = &scopeInfo;
2891 : struct Using {
2892 174 : Using(Token *start, Token *end) : startTok(start), endTok(end) {}
2893 : Token *startTok;
2894 : Token *endTok;
2895 : };
2896 35003 : std::list<Using> usingList;
2897 :
2898 760958 : for (Token *tok = list.front(); tok; tok = tok->next()) {
2899 743456 : if (!list.getFiles().empty())
2900 743454 : mErrorLogger.reportProgress(list.getFiles()[0], "Tokenize (using)", tok->progressValue());
2901 :
2902 743452 : if (Settings::terminated())
2903 0 : return substitute;
2904 :
2905 743455 : if (Token::Match(tok, "enum class|struct")) {
2906 75 : Token *bodyStart = tok;
2907 426 : while (Token::Match(bodyStart, "%name%|:|::|<")) {
2908 351 : if (bodyStart->str() == "<")
2909 0 : bodyStart = bodyStart->findClosingBracket();
2910 351 : bodyStart = bodyStart ? bodyStart->next() : nullptr;
2911 : }
2912 75 : if (Token::simpleMatch(bodyStart, "{"))
2913 71 : tok = bodyStart->link();
2914 743277 : continue;
2915 : }
2916 :
2917 1406718 : if (Token::Match(tok, "{|}|namespace|class|struct|union") ||
2918 663338 : Token::Match(tok, "using namespace %name% ;|::")) {
2919 : try {
2920 80173 : setScopeInfo(tok, currentScope, mSettings.debugwarnings);
2921 0 : } catch (const std::runtime_error &) {
2922 0 : reportError(tok, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
2923 0 : "simplifyUsing: unmatched body end");
2924 : }
2925 80172 : continue;
2926 : }
2927 :
2928 : // skip template declarations
2929 663208 : if (Token::Match(tok, "template < !!>")) {
2930 : // add template record type to scope info
2931 2127 : const Token *end = tok->next()->findClosingBracket();
2932 2127 : if (end && Token::Match(end->next(), "class|struct|union %name%"))
2933 1295 : currentScope->recordTypes.insert(end->strAt(2));
2934 :
2935 2127 : Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok);
2936 2127 : if (declEndToken)
2937 2126 : tok = declEndToken;
2938 2127 : continue;
2939 : }
2940 :
2941 : // look for non-template type aliases
2942 1317355 : if (!(tok->strAt(-1) != ">" &&
2943 656262 : (Token::Match(tok, "using %name% = ::| %name%") ||
2944 656078 : (Token::Match(tok, "using %name% [ [") &&
2945 0 : Token::Match(tok->linkAt(2), "] ] = ::| %name%")))))
2946 660899 : continue;
2947 :
2948 189 : const std::string& name = tok->strAt(1);
2949 184 : const Token *nameToken = tok->next();
2950 184 : std::string scope = currentScope->fullName;
2951 184 : Token *usingStart = tok;
2952 : Token *start;
2953 184 : if (tok->strAt(2) == "=") {
2954 184 : if (currentScope->type == ScopeInfo3::Record && tok->tokAt(2)->isSimplifiedTypedef()) // don't simplify within class definition
2955 4 : continue;
2956 180 : start = tok->tokAt(3);
2957 : }
2958 : else
2959 0 : start = tok->linkAt(2)->tokAt(3);
2960 180 : Token *usingEnd = findSemicolon(start);
2961 180 : if (!usingEnd)
2962 0 : continue;
2963 :
2964 : // Move struct defined in using out of using.
2965 : // using T = struct t { }; => struct t { }; using T = struct t;
2966 : // fixme: this doesn't handle attributes
2967 180 : if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
2968 14 : Token *structEnd = start->tokAt(1);
2969 14 : const bool hasName = Token::Match(structEnd, "%name%");
2970 :
2971 : // skip over name if present
2972 14 : if (hasName)
2973 5 : structEnd = structEnd->next();
2974 :
2975 : // skip over base class information
2976 14 : if (structEnd->str() == ":") {
2977 2 : structEnd = structEnd->next(); // skip over ":"
2978 6 : while (structEnd && structEnd->str() != "{")
2979 4 : structEnd = structEnd->next();
2980 2 : if (!structEnd)
2981 0 : continue;
2982 : }
2983 :
2984 : // use link to go to end
2985 14 : structEnd = structEnd->link();
2986 :
2987 : // add ';' after end of struct
2988 14 : structEnd->insertToken(";", emptyString);
2989 :
2990 : // add name for anonymous struct
2991 14 : if (!hasName) {
2992 18 : std::string newName;
2993 9 : if (structEnd->strAt(2) == ";")
2994 7 : newName = name;
2995 : else
2996 2 : newName = "Unnamed" + std::to_string(mUnnamedCount++);
2997 9 : TokenList::copyTokens(structEnd->next(), tok, start);
2998 9 : structEnd->tokAt(5)->insertToken(newName, emptyString);
2999 9 : start->insertToken(newName, emptyString);
3000 : } else
3001 5 : TokenList::copyTokens(structEnd->next(), tok, start->next());
3002 :
3003 : // add using after end of struct
3004 14 : usingStart = structEnd->tokAt(2);
3005 14 : nameToken = usingStart->next();
3006 14 : if (usingStart->strAt(2) == "=")
3007 14 : start = usingStart->tokAt(3);
3008 : else
3009 0 : start = usingStart->linkAt(2)->tokAt(3);
3010 14 : usingEnd = findSemicolon(start);
3011 :
3012 : // delete original using before struct
3013 14 : tok->deleteThis();
3014 14 : tok->deleteThis();
3015 14 : tok->deleteThis();
3016 14 : tok = usingStart;
3017 : }
3018 :
3019 : // remove 'typename' and 'template'
3020 166 : else if (start->str() == "typename") {
3021 1 : start->deleteThis();
3022 1 : Token *temp = start;
3023 2 : while (Token::Match(temp, "%name% ::"))
3024 1 : temp = temp->tokAt(2);
3025 1 : if (Token::Match(temp, "template %name%"))
3026 0 : temp->deleteThis();
3027 : }
3028 :
3029 180 : if (usingEnd)
3030 180 : tok = usingEnd;
3031 :
3032 : // Unfortunately we have to start searching from the beginning
3033 : // of the token stream because templates are instantiated at
3034 : // the end of the token stream and it may be used before then.
3035 180 : ScopeInfo3 scopeInfo1;
3036 180 : ScopeInfo3 *currentScope1 = &scopeInfo1;
3037 180 : Token *startToken = list.front();
3038 180 : Token *endToken = nullptr;
3039 180 : bool inMemberFunc = false;
3040 180 : const ScopeInfo3 * memberFuncScope = nullptr;
3041 180 : const Token * memberFuncEnd = nullptr;
3042 :
3043 : // We can limit the search to the current function when the type alias
3044 : // is defined in that function.
3045 180 : if (currentScope->type == ScopeInfo3::Other ||
3046 164 : currentScope->type == ScopeInfo3::MemberFunction) {
3047 25 : scopeInfo1 = scopeInfo;
3048 25 : currentScope1 = scopeInfo1.findScope(currentScope);
3049 25 : if (!currentScope1)
3050 0 : return substitute; // something bad happened
3051 25 : startToken = usingEnd->next();
3052 25 : endToken = const_cast<Token*>(currentScope->bodyEnd->next());
3053 25 : if (currentScope->type == ScopeInfo3::MemberFunction) {
3054 9 : const ScopeInfo3 * temp = currentScope->findScope(currentScope->fullName);
3055 9 : if (temp) {
3056 2 : inMemberFunc = true;
3057 2 : memberFuncScope = temp;
3058 2 : memberFuncEnd = endToken;
3059 : }
3060 : }
3061 : }
3062 :
3063 360 : std::string scope1 = currentScope1->fullName;
3064 180 : bool skip = false; // don't erase type aliases we can't parse
3065 180 : Token *enumOpenBrace = nullptr;
3066 10870 : for (Token* tok1 = startToken; !skip && tok1 && tok1 != endToken; tok1 = tok1->next()) {
3067 : // skip enum body
3068 10690 : if (tok1 && tok1 == enumOpenBrace) {
3069 11 : tok1 = tok1->link();
3070 11 : enumOpenBrace = nullptr;
3071 10485 : continue;
3072 : }
3073 :
3074 20255 : if ((Token::Match(tok1, "{|}|namespace|class|struct|union") && tok1->strAt(-1) != "using") ||
3075 9576 : Token::Match(tok1, "using namespace %name% ;|::")) {
3076 : try {
3077 1111 : setScopeInfo(tok1, currentScope1, mSettings.debugwarnings);
3078 0 : } catch (const std::runtime_error &) {
3079 0 : reportError(tok1, Severity::debug, "simplifyUsingUnmatchedBodyEnd",
3080 0 : "simplifyUsing: unmatched body end");
3081 : }
3082 1111 : scope1 = currentScope1->fullName;
3083 1111 : if (inMemberFunc && memberFuncEnd && tok1 == memberFuncEnd) {
3084 25 : inMemberFunc = false;
3085 25 : memberFuncScope = nullptr;
3086 25 : memberFuncEnd = nullptr;
3087 : }
3088 1111 : continue;
3089 : }
3090 :
3091 : // skip template definitions
3092 9568 : if (Token::Match(tok1, "template < !!>")) {
3093 58 : Token *declEndToken = TemplateSimplifier::findTemplateDeclarationEnd(tok1);
3094 58 : if (declEndToken)
3095 58 : tok1 = declEndToken;
3096 58 : continue;
3097 : }
3098 :
3099 : // check for enum with body
3100 9510 : if (tok1->str() == "enum") {
3101 13 : if (Token::Match(tok1, "enum class|struct"))
3102 2 : tok1 = tok1->next();
3103 13 : Token *defStart = tok1;
3104 41 : while (Token::Match(defStart, "%name%|::|:"))
3105 28 : defStart = defStart->next();
3106 13 : if (Token::simpleMatch(defStart, "{"))
3107 11 : enumOpenBrace = defStart;
3108 13 : continue;
3109 : }
3110 :
3111 : // check for member function and adjust scope
3112 9497 : if (isMemberFunction(tok1)) {
3113 40 : if (!scope1.empty())
3114 28 : scope1 += " :: ";
3115 40 : scope1 += memberFunctionScope(tok1);
3116 40 : const ScopeInfo3 * temp = currentScope1->findScope(scope1);
3117 40 : if (temp) {
3118 25 : const Token *end = memberFunctionEnd(tok1);
3119 25 : if (end) {
3120 25 : inMemberFunc = true;
3121 25 : memberFuncScope = temp;
3122 25 : memberFuncEnd = end;
3123 : }
3124 : }
3125 40 : continue;
3126 : }
3127 9457 : if (inMemberFunc && memberFuncScope) {
3128 145 : if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, memberFuncScope))
3129 129 : continue;
3130 9312 : } else if (!usingMatch(nameToken, scope, tok1, scope1, currentScope1, nullptr))
3131 9122 : continue;
3132 :
3133 206 : const auto nReplace = tokDistance(start, usingEnd);
3134 206 : if (nReplace > maxReplacementTokens) {
3135 1 : simplifyUsingError(usingStart, usingEnd);
3136 1 : continue;
3137 : }
3138 :
3139 : // remove the qualification
3140 205 : std::string fullScope = scope;
3141 205 : std::string removed;
3142 219 : while (Token::Match(tok1->tokAt(-2), "%name% ::") && !tok1->tokAt(-2)->isKeyword()) {
3143 41 : removed = (tok1->strAt(-2) + " :: ") + removed;
3144 41 : if (fullScope == tok1->strAt(-2)) {
3145 27 : tok1->deletePrevious();
3146 27 : tok1->deletePrevious();
3147 27 : break;
3148 : }
3149 14 : const std::string::size_type idx = fullScope.rfind("::");
3150 :
3151 14 : if (idx == std::string::npos)
3152 0 : break;
3153 :
3154 14 : if (tok1->strAt(-2) == fullScope.substr(idx + 3)) {
3155 14 : tok1->deletePrevious();
3156 14 : tok1->deletePrevious();
3157 14 : fullScope.resize(idx - 1);
3158 : } else
3159 0 : break;
3160 : }
3161 :
3162 : // remove global namespace if present
3163 205 : if (tok1->strAt(-1) == "::") {
3164 2 : removed.insert(0, ":: ");
3165 2 : tok1->deletePrevious();
3166 : }
3167 :
3168 205 : Token * arrayStart = nullptr;
3169 :
3170 : // parse the type
3171 205 : Token *type = start;
3172 205 : if (type->str() == "::") {
3173 2 : type = type->next();
3174 4 : while (Token::Match(type, "%type% ::"))
3175 2 : type = type->tokAt(2);
3176 2 : if (Token::Match(type, "%type%"))
3177 2 : type = type->next();
3178 203 : } else if (Token::Match(type, "%type% ::")) {
3179 1 : do {
3180 43 : type = type->tokAt(2);
3181 43 : } while (Token::Match(type, "%type% ::"));
3182 42 : if (Token::Match(type, "%type%"))
3183 42 : type = type->next();
3184 161 : } else if (Token::Match(type, "%type%")) {
3185 554 : while (Token::Match(type, "const|class|struct|union|enum %type%") ||
3186 346 : (type->next() && type->next()->isStandardType()))
3187 47 : type = type->next();
3188 :
3189 161 : type = type->next();
3190 :
3191 164 : while (Token::Match(type, "%type%") &&
3192 3 : (type->isStandardType() || Token::Match(type, "unsigned|signed"))) {
3193 0 : type = type->next();
3194 : }
3195 :
3196 161 : bool atEnd = false;
3197 327 : while (!atEnd) {
3198 166 : if (type && type->str() == "::") {
3199 2 : type = type->next();
3200 : }
3201 :
3202 171 : if (Token::Match(type, "%type%") &&
3203 171 : type->next() && !Token::Match(type->next(), "[|,|(")) {
3204 5 : type = type->next();
3205 161 : } else if (Token::simpleMatch(type, "const (")) {
3206 0 : type = type->next();
3207 0 : atEnd = true;
3208 : } else
3209 161 : atEnd = true;
3210 : }
3211 : } else
3212 0 : syntaxError(type);
3213 :
3214 : // check for invalid input
3215 205 : if (!type)
3216 0 : syntaxError(tok1);
3217 :
3218 : // check for template
3219 205 : if (type->str() == "<") {
3220 78 : type = type->findClosingBracket();
3221 :
3222 79 : while (type && Token::Match(type->next(), ":: %type%"))
3223 1 : type = type->tokAt(2);
3224 :
3225 78 : if (!type) {
3226 0 : syntaxError(tok1);
3227 : }
3228 :
3229 78 : while (Token::Match(type->next(), "const|volatile"))
3230 0 : type = type->next();
3231 :
3232 78 : type = type->next();
3233 : }
3234 :
3235 : // check for pointers and references
3236 205 : std::list<std::string> pointers;
3237 236 : while (Token::Match(type, "*|&|&&|const")) {
3238 31 : pointers.push_back(type->str());
3239 31 : type = type->next();
3240 : }
3241 :
3242 : // check for array
3243 205 : if (type && type->str() == "[") {
3244 0 : do {
3245 8 : if (!arrayStart)
3246 8 : arrayStart = type;
3247 :
3248 8 : bool atEnd = false;
3249 16 : while (!atEnd) {
3250 24 : while (type->next() && !Token::Match(type->next(), ";|,")) {
3251 16 : type = type->next();
3252 : }
3253 :
3254 8 : if (!type->next())
3255 0 : syntaxError(type); // invalid input
3256 8 : else if (type->next()->str() == ";")
3257 8 : atEnd = true;
3258 0 : else if (type->str() == "]")
3259 0 : atEnd = true;
3260 : else
3261 0 : type = type->next();
3262 : }
3263 :
3264 8 : type = type->next();
3265 8 : } while (type && type->str() == "[");
3266 : }
3267 :
3268 : // make sure we are in a good state
3269 205 : if (!tok1 || !tok1->next())
3270 0 : break; // bail
3271 :
3272 205 : Token* after = tok1->next();
3273 : // check if type was parsed
3274 205 : if (type && type == usingEnd) {
3275 : // check for array syntax and add type around variable
3276 199 : if (arrayStart) {
3277 8 : if (Token::Match(tok1->next(), "%name%")) {
3278 4 : TokenList::copyTokens(tok1->next(), arrayStart, usingEnd->previous());
3279 4 : TokenList::copyTokens(tok1, start, arrayStart->previous());
3280 4 : tok1->deleteThis();
3281 4 : substitute = true;
3282 : }
3283 : } else {
3284 : // add some qualification back if needed
3285 191 : std::string removed1 = std::move(removed);
3286 191 : std::string::size_type idx = removed1.rfind(" ::");
3287 191 : if (idx != std::string::npos)
3288 28 : removed1.resize(idx);
3289 191 : if (scopesMatch(removed1, scope, &scopeInfo1)) {
3290 27 : ScopeInfo3 * tempScope = currentScope;
3291 35 : while (tempScope->parent) {
3292 34 : if (tempScope->recordTypes.find(start->str()) != tempScope->recordTypes.end()) {
3293 12 : std::string::size_type spaceIdx = 0;
3294 12 : std::string::size_type startIdx = 0;
3295 23 : while ((spaceIdx = removed1.find(' ', startIdx)) != std::string::npos) {
3296 11 : tok1->previous()->insertToken(removed1.substr(startIdx, spaceIdx - startIdx));
3297 11 : startIdx = spaceIdx + 1;
3298 : }
3299 12 : tok1->previous()->insertToken(removed1.substr(startIdx));
3300 12 : tok1->previous()->insertToken("::");
3301 12 : break;
3302 : }
3303 22 : idx = removed1.rfind(" ::");
3304 22 : if (idx == std::string::npos)
3305 14 : break;
3306 :
3307 8 : removed1.resize(idx);
3308 8 : tempScope = tempScope->parent;
3309 : }
3310 : }
3311 :
3312 : // Is this a "T()" expression where T is a pointer type?
3313 191 : if (Token::Match(tok1, "%name% ( )") && !pointers.empty()) {
3314 1 : Token* tok2 = tok1->linkAt(1);
3315 1 : tok1->deleteThis();
3316 1 : TokenList::copyTokens(tok1, start, usingEnd->previous());
3317 1 : tok2->insertToken("0");
3318 1 : after = tok2->next();
3319 : }
3320 : else { // just replace simple type aliases
3321 190 : TokenList::copyTokens(tok1, start, usingEnd->previous());
3322 190 : tok1->deleteThis();
3323 : }
3324 191 : substitute = true;
3325 199 : }
3326 : } else {
3327 6 : skip = true;
3328 6 : simplifyUsingError(usingStart, usingEnd);
3329 : }
3330 205 : tok1 = after->previous();
3331 : }
3332 :
3333 180 : if (!skip)
3334 174 : usingList.emplace_back(usingStart, usingEnd);
3335 : }
3336 :
3337 : // delete all used type alias definitions
3338 17679 : for (std::list<Using>::reverse_iterator it = usingList.rbegin(); it != usingList.rend(); ++it) {
3339 174 : Token *usingStart = it->startTok;
3340 174 : Token *usingEnd = it->endTok;
3341 174 : if (usingStart->previous()) {
3342 135 : if (usingEnd->next())
3343 132 : Token::eraseTokens(usingStart->previous(), usingEnd->next());
3344 : else {
3345 3 : Token::eraseTokens(usingStart->previous(), usingEnd);
3346 3 : usingEnd->deleteThis();
3347 : }
3348 : } else {
3349 39 : if (usingEnd->next()) {
3350 38 : Token::eraseTokens(usingStart, usingEnd->next());
3351 38 : usingStart->deleteThis();
3352 : } else {
3353 : // this is the only code being checked so leave ';'
3354 1 : Token::eraseTokens(usingStart, usingEnd);
3355 1 : usingStart->deleteThis();
3356 : }
3357 : }
3358 : }
3359 :
3360 17504 : return substitute;
3361 : }
3362 :
3363 7 : void Tokenizer::simplifyUsingError(const Token* usingStart, const Token* usingEnd)
3364 : {
3365 7 : if (mSettings.debugwarnings) {
3366 4 : std::string str;
3367 2349 : for (const Token *tok = usingStart; tok && tok != usingEnd; tok = tok->next()) {
3368 2347 : if (!str.empty())
3369 2345 : str += ' ';
3370 2347 : str += tok->str();
3371 : }
3372 2 : str += " ;";
3373 2 : std::list<const Token *> callstack(1, usingStart);
3374 2 : mErrorLogger.reportErr(ErrorMessage(callstack, &list, Severity::debug, "simplifyUsing",
3375 4 : "Failed to parse \'" + str + "\'. The checking continues anyway.", Certainty::normal));
3376 : }
3377 7 : }
3378 :
3379 23291 : bool Tokenizer::simplifyTokens1(const std::string &configuration)
3380 : {
3381 : // Fill the map mTypeSize..
3382 23291 : fillTypeSizes();
3383 :
3384 23288 : mConfiguration = configuration;
3385 :
3386 23288 : if (mTimerResults) {
3387 1320 : Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1", mSettings.showtime, mTimerResults);
3388 660 : if (!simplifyTokenList1(list.getFiles().front().c_str()))
3389 0 : return false;
3390 : } else {
3391 22628 : if (!simplifyTokenList1(list.getFiles().front().c_str()))
3392 0 : return false;
3393 : }
3394 :
3395 22626 : if (mTimerResults) {
3396 1978 : Timer t("Tokenizer::simplifyTokens1::createAst", mSettings.showtime, mTimerResults);
3397 660 : list.createAst();
3398 659 : list.validateAst(mSettings.debugnormal);
3399 : } else {
3400 21966 : list.createAst();
3401 21963 : list.validateAst(mSettings.debugnormal);
3402 : }
3403 :
3404 22591 : if (mTimerResults) {
3405 1976 : Timer t("Tokenizer::simplifyTokens1::createSymbolDatabase", mSettings.showtime, mTimerResults);
3406 660 : createSymbolDatabase();
3407 : } else {
3408 21932 : createSymbolDatabase();
3409 : }
3410 :
3411 22567 : if (mTimerResults) {
3412 1980 : Timer t("Tokenizer::simplifyTokens1::setValueType", mSettings.showtime, mTimerResults);
3413 660 : mSymbolDatabase->setValueTypeInTokenList(false);
3414 660 : mSymbolDatabase->setValueTypeInTokenList(true);
3415 : } else {
3416 21907 : mSymbolDatabase->setValueTypeInTokenList(false);
3417 21910 : mSymbolDatabase->setValueTypeInTokenList(true);
3418 : }
3419 :
3420 22570 : if (!mSettings.buildDir.empty())
3421 0 : Summaries::create(*this, configuration);
3422 :
3423 : // TODO: do not run valueflow if no checks are being performed at all - e.g. unusedFunctions only
3424 22570 : const char* disableValueflowEnv = std::getenv("DISABLE_VALUEFLOW");
3425 22570 : const bool doValueFlow = !disableValueflowEnv || (std::strcmp(disableValueflowEnv, "1") != 0);
3426 :
3427 22570 : if (doValueFlow) {
3428 22570 : if (mTimerResults) {
3429 1980 : Timer t("Tokenizer::simplifyTokens1::ValueFlow", mSettings.showtime, mTimerResults);
3430 660 : ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults);
3431 : } else {
3432 21910 : ValueFlow::setValues(list, *mSymbolDatabase, mErrorLogger, mSettings, mTimerResults);
3433 : }
3434 :
3435 22566 : arraySizeAfterValueFlow();
3436 : }
3437 :
3438 : // Warn about unhandled character literals
3439 22566 : if (mSettings.severity.isEnabled(Severity::portability)) {
3440 447691 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
3441 441491 : if (tok->tokType() == Token::eChar && tok->values().empty()) {
3442 : try {
3443 0 : simplecpp::characterLiteralToLL(tok->str());
3444 0 : } catch (const std::exception &e) {
3445 0 : unhandledCharLiteral(tok, e.what());
3446 : }
3447 : }
3448 : }
3449 : }
3450 :
3451 22568 : if (doValueFlow) {
3452 22567 : mSymbolDatabase->setArrayDimensionsUsingValueFlow();
3453 : }
3454 :
3455 22570 : printDebugOutput(1);
3456 :
3457 22566 : return true;
3458 : }
3459 :
3460 : //---------------------------------------------------------------------------
3461 :
3462 16749 : void Tokenizer::findComplicatedSyntaxErrorsInTemplates()
3463 : {
3464 16749 : validate();
3465 16748 : mTemplateSimplifier->checkComplicatedSyntaxErrorsInTemplates();
3466 16744 : }
3467 :
3468 22669 : void Tokenizer::checkForEnumsWithTypedef()
3469 : {
3470 1006421 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
3471 983757 : if (Token::Match(tok, "enum %name% {")) {
3472 129 : tok = tok->tokAt(2);
3473 129 : const Token *tok2 = Token::findsimplematch(tok, "typedef", tok->link());
3474 129 : if (tok2)
3475 2 : syntaxError(tok2);
3476 127 : tok = tok->link();
3477 : }
3478 : }
3479 22667 : }
3480 :
3481 23291 : void Tokenizer::fillTypeSizes()
3482 : {
3483 23291 : mTypeSize.clear();
3484 23291 : mTypeSize["char"] = 1;
3485 23289 : mTypeSize["_Bool"] = mSettings.platform.sizeof_bool;
3486 23288 : mTypeSize["bool"] = mSettings.platform.sizeof_bool;
3487 23290 : mTypeSize["short"] = mSettings.platform.sizeof_short;
3488 23288 : mTypeSize["int"] = mSettings.platform.sizeof_int;
3489 23291 : mTypeSize["long"] = mSettings.platform.sizeof_long;
3490 23290 : mTypeSize["long long"] = mSettings.platform.sizeof_long_long;
3491 23291 : mTypeSize["float"] = mSettings.platform.sizeof_float;
3492 23290 : mTypeSize["double"] = mSettings.platform.sizeof_double;
3493 23291 : mTypeSize["long double"] = mSettings.platform.sizeof_long_double;
3494 23289 : mTypeSize["wchar_t"] = mSettings.platform.sizeof_wchar_t;
3495 23289 : mTypeSize["size_t"] = mSettings.platform.sizeof_size_t;
3496 23291 : mTypeSize["*"] = mSettings.platform.sizeof_pointer;
3497 23288 : }
3498 :
3499 23076 : void Tokenizer::combineOperators()
3500 : {
3501 23076 : const bool cpp = isCPP();
3502 :
3503 : // Combine tokens..
3504 987108 : for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
3505 964003 : const char c1 = tok->str()[0];
3506 :
3507 963997 : if (tok->str().length() == 1 && tok->next()->str().length() == 1) {
3508 442604 : const char c2 = tok->next()->str()[0];
3509 :
3510 : // combine +-*/ and =
3511 442604 : if (c2 == '=' && (std::strchr("+-*/%|^=!<>", c1)) && !Token::Match(tok->previous(), "%type% *")) {
3512 : // skip templates
3513 13 : if (cpp && (tok->str() == ">" || Token::simpleMatch(tok->previous(), "> *"))) {
3514 : const Token* opening =
3515 13 : tok->str() == ">" ? tok->findOpeningBracket() : tok->previous()->findOpeningBracket();
3516 13 : if (opening && Token::Match(opening->previous(), "%name%"))
3517 13 : continue;
3518 : }
3519 0 : tok->str(tok->str() + c2);
3520 0 : tok->deleteNext();
3521 0 : continue;
3522 : }
3523 521424 : } else if (tok->next()->str() == "=") {
3524 4643 : if (tok->str() == ">>") {
3525 0 : tok->str(">>=");
3526 0 : tok->deleteNext();
3527 4643 : } else if (tok->str() == "<<") {
3528 0 : tok->str("<<=");
3529 0 : tok->deleteNext();
3530 : }
3531 524014 : } else if (cpp && (c1 == 'p' || c1 == '_') &&
3532 7232 : Token::Match(tok, "private|protected|public|__published : !!:")) {
3533 1425 : bool simplify = false;
3534 1425 : int par = 0;
3535 1437 : for (const Token *prev = tok->previous(); prev; prev = prev->previous()) {
3536 1437 : if (prev->str() == ")") {
3537 3 : ++par;
3538 1434 : } else if (prev->str() == "(") {
3539 3 : if (par == 0U)
3540 0 : break;
3541 3 : --par;
3542 : }
3543 1437 : if (par != 0U || prev->str() == "(")
3544 8 : continue;
3545 1429 : if (Token::Match(prev, "[;{}]")) {
3546 1419 : simplify = true;
3547 1419 : break;
3548 : }
3549 10 : if (prev->isName() && prev->isUpperCaseName())
3550 4 : continue;
3551 6 : if (prev->isName() && endsWith(prev->str(), ':'))
3552 4 : simplify = true;
3553 6 : break;
3554 : }
3555 1425 : if (simplify) {
3556 1423 : tok->str(tok->str() + ":");
3557 1423 : tok->deleteNext();
3558 : }
3559 515357 : } else if (tok->str() == "->") {
3560 : // If the preceding sequence is "( & %name% )", replace it by "%name%"
3561 1526 : Token *t = tok->tokAt(-4);
3562 1526 : if (Token::Match(t, "( & %name% )") && !Token::simpleMatch(t->previous(), ">")) {
3563 62 : t->deleteThis();
3564 62 : t->deleteThis();
3565 62 : t->deleteNext();
3566 62 : tok->str(".");
3567 : } else {
3568 1464 : tok->str(".");
3569 1464 : tok->originalName("->");
3570 : }
3571 : }
3572 : }
3573 23075 : }
3574 :
3575 23631 : void Tokenizer::combineStringAndCharLiterals()
3576 : {
3577 : // Combine strings
3578 1024193 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3579 1000565 : if (!isStringLiteral(tok->str()))
3580 990092 : continue;
3581 :
3582 10470 : tok->str(simplifyString(tok->str()));
3583 :
3584 10484 : while (Token::Match(tok->next(), "%str%") || Token::Match(tok->next(), "_T|_TEXT|TEXT ( %str% )")) {
3585 14 : if (tok->next()->isName()) {
3586 1 : if (!mSettings.platform.isWindows())
3587 0 : break;
3588 1 : tok->deleteNext(2);
3589 1 : tok->next()->deleteNext();
3590 : }
3591 : // Two strings after each other, combine them
3592 14 : tok->concatStr(simplifyString(tok->next()->str()));
3593 14 : tok->deleteNext();
3594 : }
3595 : }
3596 23629 : }
3597 :
3598 22700 : void Tokenizer::concatenateNegativeNumberAndAnyPositive()
3599 : {
3600 1004033 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3601 981330 : if (!Token::Match(tok, "?|:|,|(|[|{|return|case|sizeof|%op% +|-") || tok->tokType() == Token::eIncDecOp)
3602 980508 : continue;
3603 :
3604 865 : while (tok->str() != ">" && tok->next() && tok->next()->str() == "+" && (!Token::Match(tok->tokAt(2), "%name% (|;") || Token::Match(tok, "%op%")))
3605 40 : tok->deleteNext();
3606 :
3607 825 : if (Token::Match(tok->next(), "- %num%")) {
3608 751 : tok->deleteNext();
3609 751 : tok->next()->str("-" + tok->next()->str());
3610 : }
3611 : }
3612 22701 : }
3613 :
3614 16765 : void Tokenizer::simplifyExternC()
3615 : {
3616 16765 : if (isC())
3617 0 : return;
3618 :
3619 : // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens.
3620 737963 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3621 721202 : if (Token::Match(tok, "extern \"C\"|\"C++\"")) {
3622 18 : Token *tok2 = tok->next();
3623 18 : const bool isExtC = tok->next()->str().size() == 3;
3624 18 : if (tok->strAt(2) == "{") {
3625 8 : tok2 = tok2->next(); // skip {
3626 85 : while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2))
3627 77 : tok2->isExternC(isExtC);
3628 8 : tok->linkAt(2)->deleteThis(); // }
3629 8 : tok->deleteNext(2); // "C" {
3630 : } else {
3631 80 : while ((tok2 = tok2->next()) && !Token::Match(tok2, "[;{]"))
3632 70 : tok2->isExternC(isExtC);
3633 10 : tok->deleteNext(); // "C"
3634 : }
3635 18 : tok->deleteThis(); // extern
3636 : }
3637 : }
3638 : }
3639 :
3640 22702 : void Tokenizer::simplifyRoundCurlyParentheses()
3641 : {
3642 1003924 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3643 981236 : while (Token::Match(tok, "[;{}:] ( {") &&
3644 10 : Token::simpleMatch(tok->linkAt(2), "} ) ;")) {
3645 4 : if (tok->str() == ":" && !Token::Match(tok->tokAt(-2),"[;{}] %type% :"))
3646 0 : break;
3647 4 : Token *end = tok->linkAt(2)->tokAt(-3);
3648 4 : if (Token::Match(end, "[;{}] %num%|%str% ;"))
3649 2 : end->deleteNext(2);
3650 4 : tok->linkAt(2)->previous()->deleteNext(3);
3651 4 : tok->deleteNext(2);
3652 : }
3653 981218 : if (Token::Match(tok, "( { %bool%|%char%|%num%|%str%|%name% ; } )")) {
3654 3 : tok->deleteNext();
3655 3 : tok->deleteThis();
3656 3 : tok->deleteNext(3);
3657 : }
3658 : }
3659 22700 : }
3660 :
3661 23254 : void Tokenizer::simplifySQL()
3662 : {
3663 1018893 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3664 995628 : if (!Token::simpleMatch(tok, "__CPPCHECK_EMBEDDED_SQL_EXEC__ SQL"))
3665 995631 : continue;
3666 :
3667 11 : const Token *end = findSQLBlockEnd(tok);
3668 12 : if (end == nullptr)
3669 4 : syntaxError(nullptr);
3670 :
3671 8 : const std::string instruction = tok->stringifyList(end);
3672 : // delete all tokens until the embedded SQL block end
3673 8 : Token::eraseTokens(tok, end);
3674 :
3675 : // insert "asm ( "instruction" ) ;"
3676 8 : tok->str("asm");
3677 : // it can happen that 'end' is NULL when wrong code is inserted
3678 8 : if (!tok->next())
3679 0 : tok->insertToken(";");
3680 8 : tok->insertToken(")");
3681 8 : tok->insertToken("\"" + instruction + "\"");
3682 8 : tok->insertToken("(");
3683 : // jump to ';' and continue
3684 8 : tok = tok->tokAt(3);
3685 : }
3686 23246 : }
3687 :
3688 22624 : void Tokenizer::simplifyArrayAccessSyntax()
3689 : {
3690 : // 0[a] -> a[0]
3691 1014451 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3692 991829 : if (tok->isNumber() && Token::Match(tok, "%num% [ %name% ]")) {
3693 2 : const std::string number(tok->str());
3694 1 : Token* indexTok = tok->tokAt(2);
3695 1 : tok->str(indexTok->str());
3696 1 : tok->varId(indexTok->varId());
3697 1 : indexTok->str(number);
3698 : }
3699 : }
3700 22625 : }
3701 :
3702 22626 : void Tokenizer::simplifyParameterVoid()
3703 : {
3704 1011399 : for (Token* tok = list.front(); tok; tok = tok->next()) {
3705 988779 : if (Token::Match(tok, "%name% ( void )") && !Token::Match(tok, "sizeof|decltype|typeof|return")) {
3706 2998 : tok->next()->deleteNext();
3707 2998 : tok->next()->setRemovedVoidParameter(true);
3708 : }
3709 : }
3710 22627 : }
3711 :
3712 22627 : void Tokenizer::simplifyRedundantConsecutiveBraces()
3713 : {
3714 : // Remove redundant consecutive braces, i.e. '.. { { .. } } ..' -> '.. { .. } ..'.
3715 1008750 : for (Token *tok = list.front(); tok;) {
3716 986124 : if (Token::simpleMatch(tok, "= {")) {
3717 579 : tok = tok->linkAt(1);
3718 985538 : } else if (Token::simpleMatch(tok, "{ {") && Token::simpleMatch(tok->next()->link(), "} }")) {
3719 : //remove internal parentheses
3720 36 : tok->next()->link()->deleteThis();
3721 36 : tok->deleteNext();
3722 : } else
3723 985505 : tok = tok->next();
3724 : }
3725 22627 : }
3726 :
3727 22626 : void Tokenizer::simplifyDoublePlusAndDoubleMinus()
3728 : {
3729 : // Convert - - into + and + - into -
3730 1014432 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3731 991826 : while (tok->next()) {
3732 969206 : if (tok->str() == "+") {
3733 1247 : if (tok->next()->str()[0] == '-') {
3734 6 : tok = tok->next();
3735 6 : if (tok->str().size() == 1) {
3736 2 : tok = tok->previous();
3737 2 : tok->str("-");
3738 2 : tok->deleteNext();
3739 4 : } else if (tok->isNumber()) {
3740 3 : tok->str(tok->str().substr(1));
3741 3 : tok = tok->previous();
3742 3 : tok->str("-");
3743 : }
3744 6 : continue;
3745 : }
3746 967954 : } else if (tok->str() == "-") {
3747 485 : if (tok->next()->str()[0] == '-') {
3748 7 : tok = tok->next();
3749 7 : if (tok->str().size() == 1) {
3750 4 : tok = tok->previous();
3751 4 : tok->str("+");
3752 4 : tok->deleteNext();
3753 3 : } else if (tok->isNumber()) {
3754 3 : tok->str(tok->str().substr(1));
3755 3 : tok = tok->previous();
3756 3 : tok->str("+");
3757 : }
3758 7 : continue;
3759 : }
3760 : }
3761 :
3762 969186 : break;
3763 : }
3764 : }
3765 22624 : }
3766 :
3767 : /** Specify array size if it hasn't been given */
3768 :
3769 22626 : void Tokenizer::arraySize()
3770 : {
3771 262 : auto getStrTok = [](Token* tok, bool addLength, Token*& endStmt) -> Token* {
3772 262 : if (addLength) {
3773 1 : endStmt = tok->tokAt(5);
3774 1 : return tok->tokAt(4);
3775 : }
3776 261 : if (Token::Match(tok, "%var% [ ] =")) {
3777 261 : tok = tok->tokAt(4);
3778 261 : int parCount = 0;
3779 262 : while (Token::simpleMatch(tok, "(")) {
3780 1 : ++parCount;
3781 1 : tok = tok->next();
3782 : }
3783 261 : if (Token::Match(tok, "%str%")) {
3784 106 : endStmt = tok->tokAt(parCount + 1);
3785 106 : return tok;
3786 : }
3787 : }
3788 155 : return nullptr;
3789 : };
3790 :
3791 1011997 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3792 989378 : if (!tok->isName() || !Token::Match(tok, "%var% [ ] ="))
3793 989109 : continue;
3794 262 : bool addlength = false;
3795 262 : if (Token::Match(tok->previous(), "!!* %var% [ ] = { %str% } ;")) {
3796 1 : Token *t = tok->tokAt(3);
3797 1 : t->deleteNext();
3798 1 : t->next()->deleteNext();
3799 1 : addlength = true;
3800 : }
3801 :
3802 262 : Token* endStmt{};
3803 262 : if (const Token* strTok = getStrTok(tok, addlength, endStmt)) {
3804 107 : const int sz = Token::getStrArraySize(strTok);
3805 107 : tok->next()->insertToken(std::to_string(sz));
3806 107 : tok = endStmt;
3807 : }
3808 :
3809 155 : else if (Token::Match(tok, "%var% [ ] = {")) {
3810 151 : MathLib::biguint sz = 1;
3811 151 : tok = tok->next();
3812 151 : Token *end = tok->linkAt(3);
3813 839 : for (Token *tok2 = tok->tokAt(4); tok2 && tok2 != end; tok2 = tok2->next()) {
3814 690 : if (tok2->link() && Token::Match(tok2, "{|(|[|<")) {
3815 33 : if (tok2->str() == "[" && tok2->link()->strAt(1) == "=") { // designated initializer
3816 4 : if (Token::Match(tok2, "[ %num% ]"))
3817 2 : sz = std::max(sz, MathLib::toBigUNumber(tok2->strAt(1)) + 1U);
3818 : else {
3819 2 : sz = 0;
3820 2 : break;
3821 : }
3822 : }
3823 31 : tok2 = tok2->link();
3824 657 : } else if (tok2->str() == ",") {
3825 207 : if (!Token::Match(tok2->next(), "[},]"))
3826 204 : ++sz;
3827 : else {
3828 3 : tok2 = tok2->previous();
3829 3 : tok2->deleteNext();
3830 : }
3831 : }
3832 : }
3833 :
3834 151 : if (sz != 0)
3835 149 : tok->insertToken(std::to_string(sz));
3836 :
3837 151 : tok = end->next() ? end->next() : end;
3838 : }
3839 : }
3840 22622 : }
3841 :
3842 22568 : void Tokenizer::arraySizeAfterValueFlow()
3843 : {
3844 : // After ValueFlow, adjust array sizes.
3845 97114 : for (const Variable* var: mSymbolDatabase->variableList()) {
3846 74545 : if (!var || !var->isArray())
3847 74545 : continue;
3848 2429 : if (!Token::Match(var->nameToken(), "%name% [ ] = { ["))
3849 2428 : continue;
3850 1 : MathLib::bigint maxIndex = -1;
3851 1 : const Token* const startToken = var->nameToken()->tokAt(4);
3852 1 : const Token* const endToken = startToken->link();
3853 7 : for (const Token* tok = startToken; tok != endToken; tok = tok->next()) {
3854 6 : if (!Token::Match(tok, "[{,] [") || !Token::simpleMatch(tok->linkAt(1), "] ="))
3855 5 : continue;
3856 1 : const Token* expr = tok->next()->astOperand1();
3857 1 : if (expr && expr->hasKnownIntValue())
3858 1 : maxIndex = std::max(maxIndex, expr->getKnownIntValue());
3859 : }
3860 1 : if (maxIndex >= 0) {
3861 : // insert array size
3862 1 : Token* tok = const_cast<Token*>(var->nameToken()->next());
3863 1 : tok->insertToken(std::to_string(maxIndex + 1));
3864 : // ast
3865 1 : tok->astOperand2(tok->next());
3866 : // Token::scope
3867 1 : tok->next()->scope(tok->scope());
3868 : // Value flow
3869 2 : ValueFlow::Value value(maxIndex + 1);
3870 1 : value.setKnown();
3871 1 : tok->next()->addValue(value);
3872 : // Set array dimensions
3873 1 : Dimension d;
3874 1 : d.num = maxIndex + 1;
3875 2 : std::vector<Dimension> dimensions{d};
3876 1 : const_cast<Variable*>(var)->setDimensions(dimensions);
3877 : }
3878 : }
3879 22565 : }
3880 :
3881 8 : static Token *skipTernaryOp(Token *tok)
3882 : {
3883 8 : int colonLevel = 1;
3884 16 : while (nullptr != (tok = tok->next())) {
3885 16 : if (tok->str() == "?") {
3886 0 : ++colonLevel;
3887 16 : } else if (tok->str() == ":") {
3888 6 : --colonLevel;
3889 6 : if (colonLevel == 0) {
3890 6 : tok = tok->next();
3891 6 : break;
3892 : }
3893 : }
3894 10 : if (tok->link() && Token::Match(tok, "[(<]"))
3895 3 : tok = tok->link();
3896 7 : else if (Token::Match(tok->next(), "[{};)]"))
3897 2 : break;
3898 : }
3899 8 : if (colonLevel > 0) // Ticket #5214: Make sure the ':' matches the proper '?'
3900 2 : return nullptr;
3901 6 : return tok;
3902 : }
3903 :
3904 : // Skips until the colon at the end of the case label, the argument must point to the "case" token.
3905 : // In case of success returns the colon token.
3906 : // In case of failure returns the token that caused the error.
3907 345 : static Token *skipCaseLabel(Token *tok)
3908 : {
3909 345 : assert(tok->str() == "case");
3910 708 : while (nullptr != (tok = tok->next())) {
3911 708 : if (Token::Match(tok, "(|["))
3912 10 : tok = tok->link();
3913 698 : else if (tok->str() == "?") {
3914 8 : Token * tok1 = skipTernaryOp(tok);
3915 8 : if (!tok1)
3916 2 : return tok;
3917 6 : tok = tok1;
3918 : }
3919 706 : if (Token::Match(tok, "[:{};]"))
3920 343 : return tok;
3921 : }
3922 0 : return nullptr;
3923 : }
3924 :
3925 991069 : const Token * Tokenizer::startOfExecutableScope(const Token * tok)
3926 : {
3927 991069 : if (tok->str() != ")")
3928 912212 : return nullptr;
3929 :
3930 78857 : tok = Tokenizer::isFunctionHead(tok, ":{");
3931 :
3932 78858 : if (Token::Match(tok, ": %name% [({]")) {
3933 1672 : while (Token::Match(tok, "[:,] %name% [({]"))
3934 892 : tok = tok->linkAt(2)->next();
3935 : }
3936 :
3937 78858 : return (tok && tok->str() == "{") ? tok : nullptr;
3938 : }
3939 :
3940 :
3941 : /** simplify labels and case|default in the code: add a ";" if not already in.*/
3942 :
3943 22684 : void Tokenizer::simplifyLabelsCaseDefault()
3944 : {
3945 22684 : const bool cpp = isCPP();
3946 22682 : bool executablescope = false;
3947 22682 : int indentLevel = 0;
3948 739200 : for (Token *tok = list.front(); tok; tok = tok->next()) {
3949 : // Simplify labels in the executable scope..
3950 716527 : auto *start = const_cast<Token *>(startOfExecutableScope(tok));
3951 716525 : if (start) {
3952 28980 : tok = start;
3953 28980 : executablescope = true;
3954 : }
3955 :
3956 716525 : if (!executablescope)
3957 321019 : continue;
3958 :
3959 395506 : if (tok->str() == "{") {
3960 41437 : if (tok->previous()->str() == "=")
3961 474 : tok = tok->link();
3962 : else
3963 40963 : ++indentLevel;
3964 354067 : } else if (tok->str() == "}") {
3965 40947 : --indentLevel;
3966 40947 : if (indentLevel == 0) {
3967 28971 : executablescope = false;
3968 28971 : continue;
3969 : }
3970 313124 : } else if (Token::Match(tok, "(|["))
3971 57354 : tok = tok->link();
3972 :
3973 366543 : if (Token::Match(tok, "[;{}:] case")) {
3974 337 : tok = skipCaseLabel(tok->next());
3975 337 : if (!tok)
3976 0 : break;
3977 337 : if (tok->str() != ":" || tok->strAt(-1) == "case" || !tok->next())
3978 8 : syntaxError(tok);
3979 329 : if (tok->next()->str() != ";" && tok->next()->str() != "case")
3980 262 : tok->insertToken(";");
3981 : else
3982 67 : tok = tok->previous();
3983 366201 : } else if (Token::Match(tok, "[;{}] %name% : !!;")) {
3984 124 : if (!cpp || !Token::Match(tok->next(), "class|struct|enum")) {
3985 121 : tok = tok->tokAt(2);
3986 121 : tok->insertToken(";");
3987 : }
3988 : }
3989 : }
3990 22675 : }
3991 :
3992 :
3993 22684 : void Tokenizer::simplifyCaseRange()
3994 : {
3995 1008035 : for (Token* tok = list.front(); tok; tok = tok->next()) {
3996 985355 : if (Token::Match(tok, "case %num%|%char% ... %num%|%char% :")) {
3997 8 : const MathLib::bigint start = MathLib::toBigNumber(tok->strAt(1));
3998 8 : MathLib::bigint end = MathLib::toBigNumber(tok->strAt(3));
3999 8 : end = std::min(start + 50, end); // Simplify it 50 times at maximum
4000 8 : if (start < end) {
4001 6 : tok = tok->tokAt(2);
4002 6 : tok->str(":");
4003 6 : tok->insertToken("case");
4004 61 : for (MathLib::bigint i = end-1; i > start; i--) {
4005 55 : tok->insertToken(":");
4006 55 : tok->insertToken(std::to_string(i));
4007 55 : tok->insertToken("case");
4008 : }
4009 : }
4010 : }
4011 : }
4012 22682 : }
4013 :
4014 16714 : void Tokenizer::calculateScopes()
4015 : {
4016 746972 : for (auto *tok = list.front(); tok; tok = tok->next())
4017 730265 : tok->scopeInfo(nullptr);
4018 :
4019 33424 : std::string nextScopeNameAddition;
4020 33424 : std::shared_ptr<ScopeInfo2> primaryScope = std::make_shared<ScopeInfo2>("", nullptr);
4021 16713 : list.front()->scopeInfo(std::move(primaryScope));
4022 :
4023 747102 : for (Token* tok = list.front(); tok; tok = tok->next()) {
4024 730385 : if (tok == list.front() || !tok->scopeInfo()) {
4025 695518 : if (tok != list.front())
4026 678804 : tok->scopeInfo(tok->previous()->scopeInfo());
4027 :
4028 695523 : if (Token::Match(tok, "using namespace %name% ::|<|;")) {
4029 108 : std::string usingNamespaceName;
4030 260 : for (const Token* namespaceNameToken = tok->tokAt(2);
4031 260 : namespaceNameToken && namespaceNameToken->str() != ";";
4032 152 : namespaceNameToken = namespaceNameToken->next()) {
4033 152 : usingNamespaceName += namespaceNameToken->str();
4034 152 : usingNamespaceName += " ";
4035 : }
4036 108 : if (!usingNamespaceName.empty())
4037 108 : usingNamespaceName.pop_back();
4038 108 : tok->scopeInfo()->usingNamespaces.insert(std::move(usingNamespaceName));
4039 695422 : } else if (Token::Match(tok, "namespace|class|struct|union %name% {|::|:|<")) {
4040 11514 : for (Token* nameTok = tok->next(); nameTok && !Token::Match(nameTok, "{|:"); nameTok = nameTok->next()) {
4041 6096 : if (Token::Match(nameTok, ";|<")) {
4042 178 : nextScopeNameAddition = "";
4043 178 : break;
4044 : }
4045 5918 : nextScopeNameAddition.append(nameTok->str());
4046 5918 : nextScopeNameAddition.append(" ");
4047 : }
4048 5596 : if (!nextScopeNameAddition.empty())
4049 5418 : nextScopeNameAddition.pop_back();
4050 : }
4051 :
4052 695505 : if (Token::simpleMatch(tok, "{")) {
4053 : // This might be the opening of a member function
4054 34869 : Token *tok1 = tok;
4055 35225 : while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4056 356 : tok1 = tok1->previous();
4057 34870 : if (tok1->previous() && tok1->strAt(-1) == ")") {
4058 26335 : bool member = true;
4059 26335 : tok1 = tok1->linkAt(-1);
4060 26336 : if (Token::Match(tok1->previous(), "throw|noexcept")) {
4061 62 : tok1 = tok1->previous();
4062 80 : while (Token::Match(tok1->previous(), "const|volatile|final|override|&|&&|noexcept"))
4063 18 : tok1 = tok1->previous();
4064 62 : if (tok1->strAt(-1) != ")")
4065 1 : member = false;
4066 26275 : } else if (Token::Match(tok->tokAt(-2), ":|, %name%")) {
4067 0 : tok1 = tok1->tokAt(-2);
4068 0 : if (tok1->strAt(-1) != ")")
4069 0 : member = false;
4070 : }
4071 26337 : if (member) {
4072 26336 : if (tok1->strAt(-1) == ">")
4073 41 : tok1 = tok1->previous()->findOpeningBracket();
4074 26336 : if (tok1 && Token::Match(tok1->tokAt(-3), "%name% :: %name%")) {
4075 696 : tok1 = tok1->tokAt(-2);
4076 1392 : std::string scope = tok1->strAt(-1);
4077 832 : while (Token::Match(tok1->tokAt(-2), ":: %name%")) {
4078 136 : scope = tok1->strAt(-3) + " :: " + scope;
4079 136 : tok1 = tok1->tokAt(-2);
4080 : }
4081 :
4082 696 : if (!nextScopeNameAddition.empty() && !scope.empty())
4083 4 : nextScopeNameAddition += " :: ";
4084 696 : nextScopeNameAddition += scope;
4085 : }
4086 : }
4087 : }
4088 :
4089 : // New scope is opening, record it here
4090 69750 : std::shared_ptr<ScopeInfo2> newScopeInfo = std::make_shared<ScopeInfo2>(tok->scopeInfo()->name, tok->link(), tok->scopeInfo()->usingNamespaces);
4091 :
4092 34877 : if (!newScopeInfo->name.empty() && !nextScopeNameAddition.empty())
4093 598 : newScopeInfo->name.append(" :: ");
4094 34875 : newScopeInfo->name.append(nextScopeNameAddition);
4095 34877 : nextScopeNameAddition = "";
4096 :
4097 34877 : if (tok->link())
4098 34876 : tok->link()->scopeInfo(tok->scopeInfo());
4099 34874 : tok->scopeInfo(std::move(newScopeInfo));
4100 : }
4101 : }
4102 : }
4103 16717 : }
4104 :
4105 16717 : void Tokenizer::simplifyTemplates()
4106 : {
4107 16717 : if (isC())
4108 0 : return;
4109 :
4110 16713 : const std::time_t maxTime = mSettings.templateMaxTime > 0 ? std::time(nullptr) + mSettings.templateMaxTime : 0;
4111 16713 : mTemplateSimplifier->simplifyTemplates(
4112 : maxTime);
4113 : }
4114 : //---------------------------------------------------------------------------
4115 :
4116 :
4117 : namespace {
4118 : /** Class used in Tokenizer::setVarIdPass1 */
4119 : class VariableMap {
4120 : private:
4121 : std::unordered_map<std::string, nonneg int> mVariableId;
4122 : std::unordered_map<std::string, nonneg int> mVariableId_global;
4123 : std::stack<std::vector<std::pair<std::string, nonneg int>>> mScopeInfo;
4124 : mutable nonneg int mVarId{};
4125 : public:
4126 22637 : VariableMap() = default;
4127 : void enterScope();
4128 : bool leaveScope();
4129 : void addVariable(const std::string& varname, bool globalNamespace);
4130 168 : bool hasVariable(const std::string& varname) const {
4131 168 : return mVariableId.find(varname) != mVariableId.end();
4132 : }
4133 :
4134 677793 : const std::unordered_map<std::string, nonneg int>& map(bool global) const {
4135 677793 : return global ? mVariableId_global : mVariableId;
4136 : }
4137 191503 : nonneg int& getVarId() {
4138 191503 : return mVarId;
4139 : }
4140 : };
4141 : }
4142 :
4143 :
4144 62003 : void VariableMap::enterScope()
4145 : {
4146 62003 : mScopeInfo.emplace(/*std::vector<std::pair<std::string, nonneg int>>()*/);
4147 62003 : }
4148 :
4149 62004 : bool VariableMap::leaveScope()
4150 : {
4151 62004 : if (mScopeInfo.empty())
4152 15 : return false;
4153 :
4154 110548 : for (const std::pair<std::string, nonneg int>& outerVariable : mScopeInfo.top()) {
4155 48558 : if (outerVariable.second != 0)
4156 137 : mVariableId[outerVariable.first] = outerVariable.second;
4157 : else
4158 48421 : mVariableId.erase(outerVariable.first);
4159 : }
4160 61988 : mScopeInfo.pop();
4161 61986 : return true;
4162 : }
4163 :
4164 50573 : void VariableMap::addVariable(const std::string& varname, bool globalNamespace)
4165 : {
4166 50573 : if (mScopeInfo.empty()) {
4167 2014 : mVariableId[varname] = ++mVarId;
4168 2014 : if (globalNamespace)
4169 2014 : mVariableId_global[varname] = mVariableId[varname];
4170 50434 : return;
4171 : }
4172 48558 : std::unordered_map<std::string, nonneg int>::iterator it = mVariableId.find(varname);
4173 48558 : if (it == mVariableId.end()) {
4174 48421 : mScopeInfo.top().emplace_back(varname, 0);
4175 48421 : mVariableId[varname] = ++mVarId;
4176 48420 : if (globalNamespace)
4177 15583 : mVariableId_global[varname] = mVariableId[varname];
4178 48420 : return;
4179 : }
4180 137 : mScopeInfo.top().emplace_back(varname, it->second);
4181 137 : it->second = ++mVarId;
4182 : }
4183 :
4184 250414 : static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope)
4185 : {
4186 250414 : const Token* const tok1 = tok;
4187 250414 : Token* tok2 = tok;
4188 250414 : if (!tok2->isName())
4189 99473 : return false;
4190 :
4191 150941 : nonneg int typeCount = 0;
4192 150941 : nonneg int singleNameCount = 0;
4193 150941 : bool hasstruct = false; // Is there a "struct" or "class"?
4194 150941 : bool bracket = false;
4195 150941 : bool ref = false;
4196 410020 : while (tok2) {
4197 409996 : if (tok2->isName()) {
4198 255257 : if (Token::simpleMatch(tok2, "alignas (")) {
4199 2 : tok2 = tok2->linkAt(1)->next();
4200 2 : continue;
4201 : }
4202 255255 : if (tok2->isCpp() && Token::Match(tok2, "namespace|public|private|protected"))
4203 500 : return false;
4204 254757 : if (tok2->isCpp() && Token::simpleMatch(tok2, "decltype (")) {
4205 30 : typeCount = 1;
4206 30 : tok2 = tok2->linkAt(1)->next();
4207 30 : continue;
4208 : }
4209 254727 : if (Token::Match(tok2, "struct|union|enum") || (tok2->isCpp() && Token::Match(tok2, "class|typename"))) {
4210 7741 : hasstruct = true;
4211 7741 : typeCount = 0;
4212 7741 : singleNameCount = 0;
4213 246986 : } else if (Token::Match(tok2, "const|extern")) {
4214 : // just skip "const", "extern"
4215 239037 : } else if (!hasstruct && variableMap.map(false).count(tok2->str()) && tok2->previous()->str() != "::") {
4216 23631 : ++typeCount;
4217 23631 : tok2 = tok2->next();
4218 23631 : if (!tok2 || tok2->str() != "::")
4219 23630 : break;
4220 : } else {
4221 215406 : if (tok2->str() != "void" || Token::Match(tok2, "void const| *|(")) // just "void" cannot be a variable type
4222 189975 : ++typeCount;
4223 215406 : ++singleNameCount;
4224 : }
4225 263310 : } else if (tok2->isCpp() && ((TemplateSimplifier::templateParameters(tok2) > 0) ||
4226 108571 : Token::simpleMatch(tok2, "< >") /* Ticket #4764 */)) {
4227 2784 : const Token *start = tok;
4228 2784 : if (Token::Match(start->previous(), "%or%|%oror%|&&|&|^|+|-|*|/"))
4229 0 : return false;
4230 2784 : Token* const closingBracket = tok2->findClosingBracket();
4231 2784 : if (closingBracket == nullptr) { /* Ticket #8151 */
4232 0 : throw tok2;
4233 : }
4234 2784 : tok2 = closingBracket;
4235 2784 : if (tok2->str() != ">")
4236 0 : break;
4237 2784 : singleNameCount = 1;
4238 2784 : if (Token::Match(tok2, "> %name% %or%|%oror%|&&|&|^|+|-|*|/") && !Token::Match(tok2, "> const [*&]"))
4239 1 : return false;
4240 2783 : if (Token::Match(tok2, "> %name% )")) {
4241 183 : if (Token::Match(tok2->linkAt(2)->previous(), "if|for|while ("))
4242 3 : return false;
4243 180 : if (!Token::Match(tok2->linkAt(2)->previous(), "%name%|] ("))
4244 1 : return false;
4245 : }
4246 151956 : } else if (Token::Match(tok2, "&|&&")) {
4247 4256 : ref = !bracket;
4248 147695 : } else if (singleNameCount >= 1 && Token::Match(tok2, "( [*&]") && Token::Match(tok2->link(), ") (|[")) {
4249 640 : for (const Token* tok3 = tok2->tokAt(2); Token::Match(tok3, "!!)"); tok3 = tok3->next()) {
4250 351 : if (Token::Match(tok3, "(|["))
4251 61 : tok3 = tok3->link();
4252 351 : if (tok3->str() == ",")
4253 1 : return false;
4254 : }
4255 289 : bracket = true; // Skip: Seems to be valid pointer to array or function pointer
4256 147405 : } else if (singleNameCount >= 1 && Token::Match(tok2, "( * %name% [") && Token::Match(tok2->linkAt(3), "] ) [;,]")) {
4257 3 : bracket = true;
4258 147402 : } else if (singleNameCount >= 1 && tok2->previous() && tok2->previous()->isStandardType() && Token::Match(tok2, "( *|&| %name% ) ;")) {
4259 9 : bracket = true;
4260 147392 : } else if (tok2->str() == "::") {
4261 7200 : singleNameCount = 0;
4262 140191 : } else if (tok2->str() != "*" && tok2->str() != "...") {
4263 126782 : break;
4264 : }
4265 259047 : tok2 = tok2->next();
4266 : }
4267 :
4268 150436 : if (tok2) {
4269 150412 : bool isLambdaArg = false;
4270 : {
4271 150412 : const Token *tok3 = tok->previous();
4272 150412 : if (tok3 && tok3->str() == ",") {
4273 77120 : while (tok3 && !Token::Match(tok3,";|(|[|{")) {
4274 64480 : if (Token::Match(tok3, ")|]"))
4275 1514 : tok3 = tok3->link();
4276 64480 : tok3 = tok3->previous();
4277 : }
4278 :
4279 12640 : if (tok3 && executableScope && Token::Match(tok3->previous(), "%name% (")) {
4280 6476 : const Token *fdecl = tok3->previous();
4281 6476 : int count = 0;
4282 13061 : while (Token::Match(fdecl, "%name%|*")) {
4283 6585 : fdecl = fdecl->previous();
4284 6585 : count++;
4285 : }
4286 6476 : if (!Token::Match(fdecl, "[;{}] %name%") || count <= 1)
4287 6375 : return false;
4288 : }
4289 : }
4290 :
4291 144183 : if (tok3 && tok3->isCpp() && Token::simpleMatch(tok3->previous(), "] (") &&
4292 149 : (Token::simpleMatch(tok3->link(), ") {") || Token::Match(tok3->link(), ") . %name%")))
4293 137 : isLambdaArg = true;
4294 : }
4295 :
4296 :
4297 144034 : tok = tok2;
4298 :
4299 : // In executable scopes, references must be assigned
4300 : // Catching by reference is an exception
4301 144034 : if (executableScope && ref && !isLambdaArg) {
4302 395 : if (Token::Match(tok2, "(|=|{|:"))
4303 : ; // reference is assigned => ok
4304 66 : else if (tok2->str() != ")" || tok2->link()->strAt(-1) != "catch")
4305 41 : return false; // not catching by reference => not declaration
4306 : }
4307 : }
4308 :
4309 : // Check if array declaration is valid (#2638)
4310 : // invalid declaration: AAA a[4] = 0;
4311 144019 : if (typeCount >= 2 && executableScope && Token::Match(tok2, ")| [")) {
4312 1518 : const Token *tok3 = tok2->str() == ")" ? tok2->next() : tok2;
4313 3100 : while (tok3 && tok3->str() == "[") {
4314 1582 : tok3 = tok3->link()->next();
4315 : }
4316 1518 : if (Token::Match(tok3, "= %num%"))
4317 3 : return false;
4318 1515 : if (bracket && Token::Match(tok1->previous(), "[(,]") && Token::Match(tok3, "[,)]"))
4319 2 : return false;
4320 : }
4321 :
4322 144014 : return (typeCount >= 2 && tok2 && Token::Match(tok2->tokAt(-2), "!!:: %type%"));
4323 : }
4324 :
4325 :
4326 118748 : static void setVarIdStructMembers(Token *&tok1,
4327 : std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4328 : nonneg int &varId)
4329 : {
4330 118748 : Token *tok = tok1;
4331 :
4332 118748 : if (Token::Match(tok, "%name% = { . %name% =|{")) {
4333 10 : const nonneg int struct_varid = tok->varId();
4334 10 : if (struct_varid == 0)
4335 0 : return;
4336 :
4337 10 : std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4338 :
4339 10 : tok = tok->tokAt(3);
4340 67 : while (tok->str() != "}") {
4341 57 : if (Token::Match(tok, "{|[|("))
4342 8 : tok = tok->link();
4343 57 : if (Token::Match(tok->previous(), "[,{] . %name% =|{")) {
4344 13 : tok = tok->next();
4345 13 : const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4346 13 : if (it == members.end()) {
4347 13 : members[tok->str()] = ++varId;
4348 13 : tok->varId(varId);
4349 : } else {
4350 0 : tok->varId(it->second);
4351 : }
4352 : }
4353 57 : tok = tok->next();
4354 : }
4355 :
4356 10 : return;
4357 : }
4358 :
4359 120468 : while (Token::Match(tok->next(), ")| . %name% !!(")) {
4360 : // Don't set varid for trailing return type
4361 3505 : if (tok->strAt(1) == ")" && Token::Match(tok->linkAt(1)->tokAt(-1), "%name%|]") &&
4362 1767 : Tokenizer::isFunctionHead(tok->linkAt(1), "{|;")) {
4363 25 : tok = tok->tokAt(3);
4364 25 : continue;
4365 : }
4366 1713 : const nonneg int struct_varid = tok->varId();
4367 1713 : tok = tok->tokAt(2);
4368 1713 : if (struct_varid == 0)
4369 0 : continue;
4370 :
4371 1713 : if (tok->str() == ".")
4372 44 : tok = tok->next();
4373 :
4374 : // Don't set varid for template function
4375 1713 : if (TemplateSimplifier::templateParameters(tok->next()) > 0)
4376 8 : break;
4377 :
4378 1705 : std::map<std::string, nonneg int>& members = structMembers[struct_varid];
4379 1705 : const std::map<std::string, nonneg int>::iterator it = members.find(tok->str());
4380 1705 : if (it == members.end()) {
4381 1344 : members[tok->str()] = ++varId;
4382 1344 : tok->varId(varId);
4383 : } else {
4384 361 : tok->varId(it->second);
4385 : }
4386 : }
4387 : // tok can't be null
4388 118738 : tok1 = tok;
4389 : }
4390 :
4391 6062 : static bool setVarIdClassDeclaration(Token* const startToken,
4392 : VariableMap& variableMap,
4393 : const nonneg int scopeStartVarId,
4394 : std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers)
4395 : {
4396 : // end of scope
4397 6062 : const Token* const endToken = startToken->link();
4398 :
4399 : // determine class name
4400 12124 : std::string className;
4401 13457 : for (const Token *tok = startToken->previous(); tok; tok = tok->previous()) {
4402 13376 : if (!tok->isName() && tok->str() != ":")
4403 662 : break;
4404 12714 : if (Token::Match(tok, "class|struct|enum %type% [:{]")) {
4405 5319 : className = tok->next()->str();
4406 5319 : break;
4407 : }
4408 : }
4409 :
4410 : // replace varids..
4411 6062 : int indentlevel = 0;
4412 6062 : bool initList = false;
4413 6062 : bool inEnum = false;
4414 6062 : const Token *initListArgLastToken = nullptr;
4415 79545 : for (Token *tok = startToken->next(); tok != endToken; tok = tok->next()) {
4416 73483 : if (!tok)
4417 0 : return false;
4418 73483 : if (initList) {
4419 3653 : if (tok == initListArgLastToken)
4420 412 : initListArgLastToken = nullptr;
4421 5656 : else if (!initListArgLastToken &&
4422 3734 : Token::Match(tok->previous(), "%name%|>|>> {|(") &&
4423 493 : Token::Match(tok->link(), "}|) ,|{"))
4424 412 : initListArgLastToken = tok->link();
4425 : }
4426 73483 : if (tok->str() == "{") {
4427 3445 : inEnum = isEnumStart(tok);
4428 3445 : if (initList && !initListArgLastToken)
4429 365 : initList = false;
4430 3445 : ++indentlevel;
4431 70038 : } else if (tok->str() == "}") {
4432 3445 : --indentlevel;
4433 3445 : inEnum = false;
4434 66593 : } else if (initList && indentlevel == 0 && Token::Match(tok->previous(), "[,:] %name% [({]")) {
4435 403 : const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4436 403 : if (it != variableMap.map(false).end()) {
4437 350 : tok->varId(it->second);
4438 : }
4439 66190 : } else if (tok->isName() && tok->varId() <= scopeStartVarId) {
4440 24505 : if (indentlevel > 0 || initList) {
4441 5049 : if (Token::Match(tok->previous(), "::|.") && tok->strAt(-2) != "this" && !Token::simpleMatch(tok->tokAt(-5), "( * this ) ."))
4442 538 : continue;
4443 4511 : if (!tok->next())
4444 0 : return false;
4445 4511 : if (tok->next()->str() == "::") {
4446 255 : if (tok->str() == className)
4447 16 : tok = tok->tokAt(2);
4448 : else
4449 239 : continue;
4450 : }
4451 :
4452 4272 : if (!inEnum) {
4453 4055 : const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4454 4055 : if (it != variableMap.map(false).end()) {
4455 628 : tok->varId(it->second);
4456 628 : setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4457 : }
4458 : }
4459 : }
4460 41685 : } else if (indentlevel == 0 && tok->str() == ":" && !initListArgLastToken)
4461 442 : initList = true;
4462 : }
4463 6062 : return true;
4464 : }
4465 :
4466 :
4467 :
4468 : // Update the variable ids..
4469 : // Parse each function..
4470 2666 : void Tokenizer::setVarIdClassFunction(const std::string &classname,
4471 : Token * const startToken,
4472 : const Token * const endToken,
4473 : const std::map<std::string, nonneg int> &varlist,
4474 : std::map<nonneg int, std::map<std::string, nonneg int>>& structMembers,
4475 : nonneg int &varId_)
4476 : {
4477 2666 : const auto pos = classname.rfind(' '); // TODO handle multiple scopes
4478 5332 : const std::string lastScope = classname.substr(pos == std::string::npos ? 0 : pos + 1);
4479 23672 : for (Token *tok2 = startToken; tok2 && tok2 != endToken; tok2 = tok2->next()) {
4480 21006 : if (tok2->varId() != 0 || !tok2->isName())
4481 17581 : continue;
4482 4279 : if (Token::Match(tok2->tokAt(-2), ("!!" + lastScope + " ::").c_str()))
4483 292 : continue;
4484 3987 : if (Token::Match(tok2->tokAt(-4), "%name% :: %name% ::")) // Currently unsupported
4485 8 : continue;
4486 3979 : if (Token::Match(tok2->tokAt(-2), "!!this .") && !Token::simpleMatch(tok2->tokAt(-5), "( * this ) ."))
4487 308 : continue;
4488 3671 : if (Token::Match(tok2, "%name% ::"))
4489 246 : continue;
4490 :
4491 3425 : const std::map<std::string, nonneg int>::const_iterator it = varlist.find(tok2->str());
4492 3425 : if (it != varlist.end()) {
4493 397 : tok2->varId(it->second);
4494 397 : setVarIdStructMembers(tok2, structMembers, varId_);
4495 : }
4496 : }
4497 2666 : }
4498 :
4499 :
4500 :
4501 22638 : void Tokenizer::setVarId()
4502 : {
4503 : // Clear all variable ids
4504 1014526 : for (Token *tok = list.front(); tok; tok = tok->next()) {
4505 991888 : if (tok->isName())
4506 396156 : tok->varId(0);
4507 : }
4508 :
4509 22637 : setVarIdPass1();
4510 :
4511 22633 : setPodTypes();
4512 :
4513 22629 : setVarIdPass2();
4514 22626 : }
4515 :
4516 :
4517 : // Variable declarations can't start with "return" etc.
4518 : #define NOTSTART_C "NOT", "case", "default", "goto", "not", "return", "sizeof", "typedef"
4519 : static const std::unordered_set<std::string> notstart_c = { NOTSTART_C };
4520 : static const std::unordered_set<std::string> notstart_cpp = { NOTSTART_C,
4521 : "delete", "friend", "new", "throw", "using", "virtual", "explicit", "const_cast", "dynamic_cast", "reinterpret_cast", "static_cast", "template"
4522 : };
4523 :
4524 22637 : void Tokenizer::setVarIdPass1()
4525 : {
4526 : // Variable declarations can't start with "return" etc.
4527 22637 : const std::unordered_set<std::string>& notstart = (isC()) ? notstart_c : notstart_cpp;
4528 :
4529 22642 : VariableMap variableMap;
4530 22641 : std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
4531 :
4532 22642 : std::stack<VarIdScopeInfo> scopeStack;
4533 :
4534 22634 : scopeStack.emplace(/*VarIdScopeInfo()*/);
4535 22639 : std::stack<const Token *> functionDeclEndStack;
4536 22633 : const Token *functionDeclEndToken = nullptr;
4537 22633 : bool initlist = false;
4538 22633 : bool inlineFunction = false;
4539 829077 : for (Token *tok = list.front(); tok; tok = tok->next()) {
4540 829002 : if (tok->isOp())
4541 55678 : continue;
4542 773321 : if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
4543 726 : Token* closingBracket = tok->next()->findClosingBracket();
4544 726 : if (closingBracket)
4545 726 : tok = closingBracket;
4546 726 : continue;
4547 : }
4548 :
4549 772598 : if (tok == functionDeclEndToken) {
4550 43028 : functionDeclEndStack.pop();
4551 43028 : functionDeclEndToken = functionDeclEndStack.empty() ? nullptr : functionDeclEndStack.top();
4552 43028 : if (tok->str() == ":")
4553 424 : initlist = true;
4554 42604 : else if (tok->str() == ";") {
4555 3497 : if (!variableMap.leaveScope())
4556 1 : cppcheckError(tok);
4557 39107 : } else if (tok->str() == "{") {
4558 39107 : scopeStack.emplace(true, scopeStack.top().isStructInit || tok->strAt(-1) == "=", /*isEnum=*/ false, variableMap.getVarId());
4559 :
4560 : // check if this '{' is a start of an "if" body
4561 39110 : const Token * ifToken = tok->previous();
4562 39110 : if (ifToken && ifToken->str() == ")")
4563 38697 : ifToken = ifToken->link();
4564 : else
4565 409 : ifToken = nullptr;
4566 39106 : if (ifToken)
4567 38697 : ifToken = ifToken->previous();
4568 39106 : if (ifToken && ifToken->str() == "if") {
4569 : // open another scope to differentiate between variables declared in the "if" condition and in the "if" body
4570 8638 : variableMap.enterScope();
4571 : }
4572 : }
4573 729570 : } else if (!initlist && tok->str()=="(") {
4574 105102 : const Token * newFunctionDeclEnd = nullptr;
4575 105102 : if (!scopeStack.top().isExecutable)
4576 43493 : newFunctionDeclEnd = isFunctionHead(tok, "{:;");
4577 : else {
4578 61609 : const Token* tokenLinkNext = tok->link()->next();
4579 61610 : if (Token::simpleMatch(tokenLinkNext, ".")) { // skip trailing return type
4580 330 : tokenLinkNext = tokenLinkNext->next();
4581 669 : while (Token::Match(tokenLinkNext, "%name%|::")) {
4582 339 : tokenLinkNext = tokenLinkNext->next();
4583 339 : if (Token::simpleMatch(tokenLinkNext, "<") && tokenLinkNext->link())
4584 0 : tokenLinkNext = tokenLinkNext->link()->next();
4585 : }
4586 : }
4587 61610 : if (tokenLinkNext && tokenLinkNext->str() == "{") // might be for- or while-loop or if-statement
4588 10379 : newFunctionDeclEnd = tokenLinkNext;
4589 : }
4590 105106 : if (newFunctionDeclEnd && newFunctionDeclEnd != functionDeclEndToken) {
4591 43036 : functionDeclEndStack.push(newFunctionDeclEnd);
4592 43035 : functionDeclEndToken = newFunctionDeclEnd;
4593 43035 : variableMap.enterScope();
4594 : }
4595 624471 : } else if (Token::Match(tok, "{|}")) {
4596 62229 : inlineFunction = false;
4597 :
4598 62229 : const Token * const startToken = (tok->str() == "{") ? tok : tok->link();
4599 :
4600 : // parse anonymous namespaces as part of the current scope
4601 124284 : if (!Token::Match(startToken->previous(), "union|struct|enum|namespace {") &&
4602 62054 : !(initlist && Token::Match(startToken->previous(), "%name%|>|>>|(") && Token::Match(startToken->link(), "} ,|{|)"))) {
4603 :
4604 61950 : if (tok->str() == "{") {
4605 : bool isExecutable;
4606 11419 : const Token *prev = tok->previous();
4607 27347 : while (Token::Match(prev, "%name%|."))
4608 15928 : prev = prev->previous();
4609 11419 : const bool isLambda = prev && prev->str() == ")" && Token::simpleMatch(prev->link()->previous(), "] (");
4610 11457 : if ((!isLambda && (tok->strAt(-1) == ")" || Token::Match(tok->tokAt(-2), ") %type%"))) ||
4611 38 : (initlist && tok->strAt(-1) == "}")) {
4612 427 : isExecutable = true;
4613 : } else {
4614 15402 : isExecutable = ((scopeStack.top().isExecutable || initlist || tok->strAt(-1) == "else") &&
4615 4416 : !isClassStructUnionEnumStart(tok));
4616 10987 : if (!(scopeStack.top().isStructInit || tok->strAt(-1) == "="))
4617 10330 : variableMap.enterScope();
4618 : }
4619 11413 : initlist = false;
4620 11413 : scopeStack.emplace(isExecutable, scopeStack.top().isStructInit || tok->strAt(-1) == "=", isEnumStart(tok), variableMap.getVarId());
4621 : } else { /* if (tok->str() == "}") */
4622 50532 : bool isNamespace = false;
4623 66376 : for (const Token *tok1 = tok->link()->previous(); tok1 && tok1->isName(); tok1 = tok1->previous()) {
4624 16297 : if (tok1->str() == "namespace") {
4625 453 : isNamespace = true;
4626 453 : break;
4627 : }
4628 : }
4629 : // Set variable ids in class declaration..
4630 50533 : if (!initlist && !isC() && !scopeStack.top().isExecutable && tok->link() && !isNamespace) {
4631 6062 : if (!setVarIdClassDeclaration(tok->link(),
4632 : variableMap,
4633 6062 : scopeStack.top().startVarid,
4634 : structMembers)) {
4635 0 : syntaxError(nullptr);
4636 : }
4637 : }
4638 :
4639 50531 : if (!scopeStack.top().isStructInit) {
4640 49871 : variableMap.leaveScope();
4641 :
4642 : // check if this '}' is an end of an "else" body or an "if" body without an "else" part
4643 49868 : const Token * ifToken = startToken->previous();
4644 49868 : if (ifToken && ifToken->str() == ")")
4645 39085 : ifToken = ifToken->link()->previous();
4646 : else
4647 10783 : ifToken = nullptr;
4648 49867 : if (startToken->strAt(-1) == "else" || (ifToken && ifToken->str() == "if" && tok->strAt(1) != "else")) {
4649 : // leave the extra scope used to differentiate between variables declared in the "if" condition and in the "if" body
4650 8636 : variableMap.leaveScope();
4651 : }
4652 : }
4653 :
4654 50527 : scopeStack.pop();
4655 50527 : if (scopeStack.empty()) { // should be impossible
4656 3 : scopeStack.emplace(/*VarIdScopeInfo()*/);
4657 : }
4658 : }
4659 : }
4660 : }
4661 :
4662 772600 : if ((!scopeStack.top().isStructInit &&
4663 770101 : (tok == list.front() ||
4664 1301922 : Token::Match(tok, "[;{}]") ||
4665 1982606 : (tok->str() == "(" && !scopeStack.top().isExecutable && isFunctionHead(tok,";:")) ||
4666 585132 : (tok->str() == "," && (!scopeStack.top().isExecutable || inlineFunction || !tok->previous()->varId())) ||
4667 2174906 : (tok->isName() && endsWith(tok->str(), ':')))) ||
4668 1404794 : (tok->str() == "(" && isFunctionHead(tok, "{"))) {
4669 :
4670 : // No variable declarations in sizeof
4671 282583 : if (Token::simpleMatch(tok->previous(), "sizeof (")) {
4672 9758 : continue;
4673 : }
4674 :
4675 282539 : if (Settings::terminated())
4676 0 : return;
4677 :
4678 : // locate the variable name..
4679 282538 : Token* tok2 = (tok->isName()) ? tok : tok->next();
4680 :
4681 : // private: protected: public: etc
4682 285070 : while (tok2 && endsWith(tok2->str(), ':')) {
4683 2531 : tok2 = tok2->next();
4684 : }
4685 282537 : if (!tok2)
4686 22560 : break;
4687 :
4688 : // Variable declaration can't start with "return", etc
4689 259977 : if (notstart.find(tok2->str()) != notstart.end())
4690 9555 : continue;
4691 :
4692 250420 : if (!isC() && Token::simpleMatch(tok2, "const new"))
4693 1 : continue;
4694 :
4695 : bool decl;
4696 250419 : if (isCPP() && mSettings.standards.cpp >= Standards::CPP17 && Token::Match(tok, "[(;{}] const| auto &|&&| [")) {
4697 : // Structured bindings
4698 7 : tok2 = Token::findsimplematch(tok, "[");
4699 11 : if ((Token::simpleMatch(tok->previous(), "for (") && Token::simpleMatch(tok2->link(), "] :")) ||
4700 4 : Token::simpleMatch(tok2->link(), "] =")) {
4701 37 : while (tok2 && tok2->str() != "]") {
4702 30 : if (Token::Match(tok2, "%name% [,]]"))
4703 15 : variableMap.addVariable(tok2->str(), false);
4704 30 : tok2 = tok2->next();
4705 : }
4706 7 : continue;
4707 : }
4708 : }
4709 :
4710 : try { /* Ticket #8151 */
4711 250415 : decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable);
4712 0 : } catch (const Token * errTok) {
4713 0 : syntaxError(errTok);
4714 : }
4715 :
4716 294994 : if (tok->str() == "(" && isFunctionHead(tok, "{") && scopeStack.top().isExecutable)
4717 11270 : inlineFunction = true;
4718 :
4719 250413 : if (decl) {
4720 58303 : if (isCPP()) {
4721 43412 : if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) {
4722 127 : for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) {
4723 102 : if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str()))
4724 7 : declTok->varId(variableMap.map(false).find(declTok->str())->second);
4725 : }
4726 : }
4727 : }
4728 :
4729 58307 : const Token* prev2 = tok2->previous();
4730 58307 : if (Token::Match(prev2, "%type% [;[=,)]") && tok2->previous()->str() != "const")
4731 : ;
4732 9820 : else if (Token::Match(prev2, "%type% :") && tok->strAt(-1) == "for")
4733 : ;
4734 9625 : else if (Token::Match(prev2, "%type% ( !!)") && Token::simpleMatch(tok2->link(), ") ;")) {
4735 : // In C++ , a variable can't be called operator+ or something like that.
4736 3635 : if (prev2->isCpp() &&
4737 1805 : prev2->isOperatorKeyword())
4738 148 : continue;
4739 :
4740 1682 : const Token *tok3 = tok2->next();
4741 1682 : if (!tok3->isStandardType() && tok3->str() != "void" && !Token::Match(tok3, "struct|union|class %type%") && tok3->str() != "." && !Token::Match(tok2->link()->previous(), "[&*]")) {
4742 1409 : if (!scopeStack.top().isExecutable) {
4743 : // 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.
4744 138 : decl = false;
4745 138 : bool rhs = false;
4746 280 : for (; tok3; tok3 = tok3->nextArgumentBeforeCreateLinks2()) {
4747 165 : if (tok3->str() == "=") {
4748 0 : rhs = true;
4749 0 : continue;
4750 : }
4751 :
4752 165 : if (tok3->str() == ",") {
4753 0 : rhs = false;
4754 0 : continue;
4755 : }
4756 :
4757 165 : if (rhs)
4758 0 : continue;
4759 :
4760 165 : if (tok3->isLiteral() ||
4761 289 : (tok3->isName() && (variableMap.hasVariable(tok3->str()) ||
4762 251 : (tok3->strAt(-1) == "(" && Token::simpleMatch(tok3->next(), "(") && !Token::simpleMatch(tok3->linkAt(1)->next(), "(")))) ||
4763 288 : tok3->isOp() ||
4764 463 : tok3->str() == "(" ||
4765 308 : notstart.find(tok3->str()) != notstart.end()) {
4766 23 : decl = true;
4767 23 : break;
4768 : }
4769 : }
4770 : }
4771 : } else
4772 273 : decl = false;
4773 7795 : } else if (isCPP() && Token::Match(prev2, "%type% {") && Token::simpleMatch(tok2->link(), "} ;")) { // C++11 initialization style
4774 984 : if (tok2->link() != tok2->next() && // add value-initialized variable T x{};
4775 404 : (Token::Match(prev2, "do|try|else") || Token::Match(prev2->tokAt(-2), "struct|class|:")))
4776 0 : continue;
4777 : } else
4778 7216 : decl = false;
4779 :
4780 58160 : if (decl) {
4781 50556 : if (isC() && Token::Match(prev2->previous(), "&|&&"))
4782 16 : syntaxErrorC(prev2, prev2->strAt(-2) + prev2->strAt(-1) + " " + prev2->str());
4783 50552 : variableMap.addVariable(prev2->str(), scopeStack.size() <= 1);
4784 :
4785 50549 : if (Token::simpleMatch(tok->previous(), "for (") && Token::Match(prev2, "%name% [=,]")) {
4786 2020 : for (const Token *tok3 = prev2->next(); tok3 && tok3->str() != ";"; tok3 = tok3->next()) {
4787 1492 : if (Token::Match(tok3, "[([]"))
4788 137 : tok3 = tok3->link();
4789 1492 : if (Token::Match(tok3, ", %name% [,=;]"))
4790 7 : variableMap.addVariable(tok3->next()->str(), false);
4791 : }
4792 : }
4793 :
4794 : // set varid for template parameters..
4795 50549 : tok = tok->next();
4796 150778 : while (Token::Match(tok, "%name%|::"))
4797 100228 : tok = tok->next();
4798 50546 : if (tok && tok->str() == "<") {
4799 2316 : const Token *end = tok->findClosingBracket();
4800 9035 : while (tok != end) {
4801 6854 : if (tok->isName() && !(Token::simpleMatch(tok->next(), "<") &&
4802 135 : Token::Match(tok->tokAt(-1), ":: %name%"))) {
4803 2928 : const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(false).find(tok->str());
4804 2928 : if (it != variableMap.map(false).end())
4805 6 : tok->varId(it->second);
4806 : }
4807 6719 : tok = tok->next();
4808 : }
4809 : }
4810 :
4811 50547 : tok = tok2->previous();
4812 : }
4813 : }
4814 : }
4815 :
4816 740280 : if (tok->isName() && !tok->isKeyword() && !tok->isStandardType()) {
4817 : // don't set variable id after a struct|enum|union
4818 230539 : if (Token::Match(tok->previous(), "struct|enum|union") || (tok->isCpp() && tok->strAt(-1) == "class"))
4819 6851 : continue;
4820 :
4821 223684 : bool globalNamespace = false;
4822 223684 : if (!isC()) {
4823 165020 : if (tok->previous() && tok->previous()->str() == "::") {
4824 84 : if (Token::Match(tok->tokAt(-2), ")|]|%name%"))
4825 0 : continue;
4826 84 : globalNamespace = true;
4827 : }
4828 165018 : if (tok->next() && tok->next()->str() == "::")
4829 6668 : continue;
4830 158352 : if (Token::simpleMatch(tok->tokAt(-2), ":: template"))
4831 0 : continue;
4832 : }
4833 :
4834 : // function declaration inside executable scope? Function declaration is of form: type name "(" args ")"
4835 217021 : if (scopeStack.top().isExecutable && Token::Match(tok, "%name% [,)[]")) {
4836 45244 : bool par = false;
4837 : const Token* start;
4838 : Token* end;
4839 :
4840 : // search begin of function declaration
4841 98765 : for (start = tok; Token::Match(start, "%name%|*|&|,|("); start = start->previous()) {
4842 93511 : if (start->str() == "(") {
4843 18909 : if (par)
4844 1 : break;
4845 18908 : par = true;
4846 : }
4847 93510 : if (Token::Match(start, "[(,]")) {
4848 40106 : if (!Token::Match(start, "[(,] %type% %name%|*|&"))
4849 39953 : break;
4850 : }
4851 53557 : if (start->varId() > 0)
4852 36 : break;
4853 : }
4854 :
4855 : // search end of function declaration
4856 109628 : for (end = tok->next(); Token::Match(end, "%name%|*|&|,|[|]|%num%"); end = end->next()) {}
4857 :
4858 : // there are tokens which can't appear at the begin of a function declaration such as "return"
4859 45244 : const bool isNotstartKeyword = start->next() && notstart.find(start->next()->str()) != notstart.end();
4860 :
4861 : // now check if it is a function declaration
4862 45244 : if (Token::Match(start, "[;{}] %type% %name%|*") && par && Token::simpleMatch(end, ") ;") && !isNotstartKeyword) {
4863 : // function declaration => don't set varid
4864 5 : tok = end;
4865 5 : continue;
4866 : }
4867 : }
4868 :
4869 433647 : if ((!scopeStack.top().isEnum || !(Token::Match(tok->previous(), "{|,") && Token::Match(tok->next(), ",|=|}"))) &&
4870 216633 : !Token::simpleMatch(tok->next(), ": ;")) {
4871 216494 : const std::unordered_map<std::string, nonneg int>::const_iterator it = variableMap.map(globalNamespace).find(tok->str());
4872 216503 : if (it != variableMap.map(globalNamespace).end()) {
4873 117723 : tok->varId(it->second);
4874 117723 : setVarIdStructMembers(tok, structMembers, variableMap.getVarId());
4875 : }
4876 : }
4877 509740 : } else if (Token::Match(tok, "::|. %name%") && Token::Match(tok->previous(), ")|]|>|%name%")) {
4878 : // Don't set varid after a :: or . token
4879 12344 : tok = tok->next();
4880 497401 : } else if (tok->str() == ":" && Token::Match(tok->tokAt(-2), "class %type%")) {
4881 667 : do {
4882 1022 : tok = tok->next();
4883 1022 : } while (tok && (tok->isName() || tok->str() == ","));
4884 355 : if (!tok)
4885 2 : break;
4886 353 : tok = tok->previous();
4887 : }
4888 : }
4889 :
4890 22631 : mVarId = variableMap.getVarId();
4891 : }
4892 :
4893 : namespace {
4894 : struct Member {
4895 11006 : Member(std::list<std::string> s, std::list<const Token *> ns, Token *t) : usingnamespaces(std::move(ns)), scope(std::move(s)), tok(t) {}
4896 : std::list<const Token *> usingnamespaces;
4897 : std::list<std::string> scope;
4898 : Token *tok;
4899 : };
4900 : }
4901 :
4902 5958 : static std::string getScopeName(const std::list<ScopeInfo2> &scopeInfo)
4903 : {
4904 5958 : std::string ret;
4905 6588 : for (const ScopeInfo2 &si : scopeInfo)
4906 630 : ret += (ret.empty() ? "" : " :: ") + (si.name);
4907 5958 : return ret;
4908 : }
4909 :
4910 8488 : static Token * matchMemberName(const std::list<std::string> &scope, const Token *nsToken, Token *memberToken, const std::list<ScopeInfo2> &scopeInfo)
4911 : {
4912 8488 : std::list<ScopeInfo2>::const_iterator scopeIt = scopeInfo.cbegin();
4913 :
4914 : // Current scope..
4915 9045 : for (std::list<std::string>::const_iterator it = scope.cbegin(); it != scope.cend(); ++it) {
4916 623 : if (scopeIt == scopeInfo.cend() || scopeIt->name != *it)
4917 66 : return nullptr;
4918 557 : ++scopeIt;
4919 : }
4920 :
4921 : // using namespace..
4922 8422 : if (nsToken) {
4923 1508 : while (Token::Match(nsToken, "%name% ::")) {
4924 516 : if (scopeIt != scopeInfo.end() && nsToken->str() == scopeIt->name) {
4925 222 : nsToken = nsToken->tokAt(2);
4926 222 : ++scopeIt;
4927 : } else {
4928 294 : return nullptr;
4929 : }
4930 : }
4931 992 : if (!Token::Match(nsToken, "%name% ;"))
4932 0 : return nullptr;
4933 992 : if (scopeIt == scopeInfo.end() || nsToken->str() != scopeIt->name)
4934 804 : return nullptr;
4935 188 : ++scopeIt;
4936 : }
4937 :
4938 : // Parse member tokens..
4939 8577 : while (scopeIt != scopeInfo.end()) {
4940 7922 : if (!Token::Match(memberToken, "%name% ::|<"))
4941 545 : return nullptr;
4942 7377 : if (memberToken->str() != scopeIt->name)
4943 6124 : return nullptr;
4944 1253 : if (memberToken->next()->str() == "<") {
4945 11 : memberToken = memberToken->next()->findClosingBracket();
4946 11 : if (!Token::simpleMatch(memberToken, "> ::"))
4947 0 : return nullptr;
4948 : }
4949 1253 : memberToken = memberToken->tokAt(2);
4950 1253 : ++scopeIt;
4951 : }
4952 :
4953 655 : return Token::Match(memberToken, "~| %name%") ? memberToken : nullptr;
4954 : }
4955 :
4956 7178 : static Token * matchMemberName(const Member &member, const std::list<ScopeInfo2> &scopeInfo)
4957 : {
4958 7178 : if (scopeInfo.empty())
4959 0 : return nullptr;
4960 :
4961 : // Does this member match without "using namespace"..
4962 7178 : Token *ret = matchMemberName(member.scope, nullptr, member.tok, scopeInfo);
4963 7178 : if (ret)
4964 636 : return ret;
4965 :
4966 : // Try to match member using the "using namespace ..." namespaces..
4967 7833 : for (const Token *ns : member.usingnamespaces) {
4968 1310 : ret = matchMemberName(member.scope, ns, member.tok, scopeInfo);
4969 1310 : if (ret)
4970 19 : return ret;
4971 : }
4972 :
4973 6523 : return nullptr;
4974 : }
4975 :
4976 3465 : static Token * matchMemberVarName(const Member &var, const std::list<ScopeInfo2> &scopeInfo)
4977 : {
4978 3465 : Token *tok = matchMemberName(var, scopeInfo);
4979 3465 : if (Token::Match(tok, "%name%")) {
4980 198 : if (!tok->next() || tok->strAt(1) != "(" || (tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
4981 198 : return tok;
4982 : }
4983 3267 : return nullptr;
4984 : }
4985 :
4986 3713 : static Token * matchMemberFunctionName(const Member &func, const std::list<ScopeInfo2> &scopeInfo)
4987 : {
4988 3713 : Token *tok = matchMemberName(func, scopeInfo);
4989 3713 : return Token::Match(tok, "~| %name% (") ? tok : nullptr;
4990 : }
4991 :
4992 : template<typename T>
4993 364 : static T* skipInitializerList(T* tok)
4994 : {
4995 364 : T* const start = tok;
4996 770 : while (Token::Match(tok, "[:,] ::| %name%")) {
4997 414 : tok = tok->tokAt(tok->strAt(1) == "::" ? 1 : 2);
4998 422 : while (Token::Match(tok, ":: %name%"))
4999 8 : tok = tok->tokAt(2);
5000 414 : if (!Token::Match(tok, "[({<]") || !tok->link())
5001 8 : return start;
5002 406 : const bool isTemplate = tok->str() == "<";
5003 406 : tok = tok->link()->next();
5004 406 : if (isTemplate && tok && tok->link())
5005 0 : tok = tok->link()->next();
5006 : }
5007 356 : return tok;
5008 : }
5009 :
5010 22631 : void Tokenizer::setVarIdPass2()
5011 : {
5012 45261 : std::map<nonneg int, std::map<std::string, nonneg int>> structMembers;
5013 :
5014 : // Member functions and variables in this source
5015 45261 : std::list<Member> allMemberFunctions;
5016 45262 : std::list<Member> allMemberVars;
5017 22632 : if (!isC()) {
5018 33426 : std::map<const Token *, std::string> endOfScope;
5019 33422 : std::list<std::string> scope;
5020 33421 : std::list<const Token *> usingnamespaces;
5021 720603 : for (Token *tok = list.front(); tok; tok = tok->next()) {
5022 703899 : if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
5023 139840 : if (Token::Match(tok, "using namespace %name% ::|;")) {
5024 108 : Token *endtok = tok->tokAt(2);
5025 130 : while (Token::Match(endtok, "%name% ::"))
5026 22 : endtok = endtok->tokAt(2);
5027 108 : if (Token::Match(endtok, "%name% ;"))
5028 108 : usingnamespaces.push_back(tok->tokAt(2));
5029 108 : tok = endtok;
5030 692882 : continue;
5031 : }
5032 139738 : if (Token::Match(tok, "namespace %name% {")) {
5033 453 : scope.push_back(tok->strAt(1));
5034 453 : endOfScope[tok->linkAt(2)] = tok->strAt(1);
5035 : }
5036 : }
5037 :
5038 703793 : if (tok->str() == "}") {
5039 35413 : const std::map<const Token *, std::string>::iterator it = endOfScope.find(tok);
5040 35406 : if (it != endOfScope.end())
5041 453 : scope.remove(it->second);
5042 : }
5043 :
5044 703779 : Token* const tok1 = tok;
5045 703779 : if (Token::Match(tok, "%name% :: ~| %name%"))
5046 10584 : tok = tok->next();
5047 693195 : else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5048 147 : tok = tok->next()->findClosingBracket()->next();
5049 700545 : else if (usingnamespaces.empty() || tok->varId() || !tok->isName() || tok->isStandardType() || tok->tokType() == Token::eKeyword || tok->tokType() == Token::eBoolean ||
5050 700823 : Token::Match(tok->previous(), ".|namespace|class|struct|&|&&|*|> %name%") || Token::Match(tok->previous(), "%type%| %name% ( %type%|)") || Token::Match(tok, "public:|private:|protected:") ||
5051 278 : (!tok->next() && Token::Match(tok->previous(), "}|; %name%")))
5052 692774 : continue;
5053 :
5054 11006 : if (tok->strAt(-1) == "::" && tok->tokAt(-2) && tok->tokAt(-2)->isName())
5055 0 : continue;
5056 :
5057 12047 : while (Token::Match(tok, ":: ~| %name%")) {
5058 11708 : tok = tok->next();
5059 11708 : if (tok->str() == "~")
5060 59 : tok = tok->next();
5061 11649 : else if (Token::Match(tok, "%name% <") && Token::Match(tok->next()->findClosingBracket(),"> :: ~| %name%"))
5062 419 : tok = tok->next()->findClosingBracket()->next();
5063 11230 : else if (Token::Match(tok, "%name% ::"))
5064 562 : tok = tok->next();
5065 : else
5066 10668 : break;
5067 : }
5068 11007 : if (!tok->next())
5069 1 : syntaxError(tok);
5070 11006 : if (Token::Match(tok, "%name% (") && !(tok->tokAt(2) && tok->tokAt(2)->isLiteral()))
5071 4412 : allMemberFunctions.emplace_back(scope, usingnamespaces, tok1);
5072 : else
5073 6594 : allMemberVars.emplace_back(scope, usingnamespaces, tok1);
5074 : }
5075 : }
5076 :
5077 45259 : std::list<ScopeInfo2> scopeInfo;
5078 :
5079 : // class members..
5080 45259 : std::map<std::string, std::map<std::string, nonneg int>> varsByClass;
5081 1014395 : for (Token *tok = list.front(); tok; tok = tok->next()) {
5082 997776 : while (tok->str() == "}" && !scopeInfo.empty() && tok == scopeInfo.back().bodyEnd)
5083 6005 : scopeInfo.pop_back();
5084 :
5085 991764 : if (!Token::Match(tok, "namespace|class|struct %name% {|:|::|<"))
5086 989047 : continue;
5087 :
5088 5960 : const std::string &scopeName(getScopeName(scopeInfo));
5089 5960 : const std::string scopeName2(scopeName.empty() ? std::string() : (scopeName + " :: "));
5090 :
5091 5960 : std::list<const Token*> classnameTokens{ tok->next() };
5092 5958 : Token* tokStart = tok->tokAt(2);
5093 6212 : while (Token::Match(tokStart, ":: %name%") || tokStart->str() == "<") {
5094 256 : if (tokStart->str() == "<") {
5095 : // skip the template part
5096 68 : Token* closeTok = tokStart->findClosingBracket();
5097 68 : if (!closeTok)
5098 2 : syntaxError(tok);
5099 66 : tokStart = closeTok->next();
5100 : } else {
5101 188 : classnameTokens.push_back(tokStart->next());
5102 188 : tokStart = tokStart->tokAt(2);
5103 : }
5104 : }
5105 :
5106 5956 : std::string classname;
5107 12100 : for (const Token *it : classnameTokens)
5108 6144 : classname += (classname.empty() ? "" : " :: ") + it->str();
5109 :
5110 5956 : std::map<std::string, nonneg int> &thisClassVars = varsByClass[scopeName2 + classname];
5111 7998 : while (Token::Match(tokStart, ":|::|,|%name%")) {
5112 2042 : if (Token::Match(tokStart, "%name% <")) { // TODO: why skip templates?
5113 75 : tokStart = tokStart->next()->findClosingBracket();
5114 75 : if (tokStart)
5115 75 : tokStart = tokStart->next();
5116 75 : continue;
5117 : }
5118 1967 : if (Token::Match(tokStart, "%name% ,|{")) {
5119 1264 : std::string baseClassName = tokStart->str();
5120 632 : const Token* baseStart = tokStart;
5121 670 : while (Token::Match(baseStart->tokAt(-2), "%name% ::")) { // build base class name
5122 38 : baseClassName.insert(0, baseStart->strAt(-2) + " :: ");
5123 38 : baseStart = baseStart->tokAt(-2);
5124 : }
5125 1264 : std::string scopeName3(scopeName2);
5126 636 : while (!scopeName3.empty()) {
5127 42 : const std::string name = scopeName3 + baseClassName;
5128 42 : if (varsByClass.find(name) != varsByClass.end()) {
5129 7 : baseClassName = name;
5130 7 : break;
5131 : }
5132 : // Remove last scope name
5133 35 : if (scopeName3.size() <= 8)
5134 29 : break;
5135 6 : scopeName3.erase(scopeName3.size() - 4);
5136 6 : const std::string::size_type pos = scopeName3.rfind(" :: ");
5137 6 : if (pos == std::string::npos)
5138 2 : break;
5139 4 : scopeName3.erase(pos + 4);
5140 : }
5141 632 : const std::map<std::string, nonneg int>& baseClassVars = varsByClass[baseClassName];
5142 632 : thisClassVars.insert(baseClassVars.cbegin(), baseClassVars.cend());
5143 : }
5144 1967 : tokStart = tokStart->next();
5145 : }
5146 5956 : if (!Token::simpleMatch(tokStart, "{"))
5147 81 : continue;
5148 :
5149 : // What member variables are there in this class?
5150 6005 : std::transform(classnameTokens.cbegin(), classnameTokens.cend(), std::back_inserter(scopeInfo), [&](const Token* tok) {
5151 12010 : return ScopeInfo2(tok->str(), tokStart->link());
5152 5875 : });
5153 :
5154 43805 : for (Token *tok2 = tokStart->next(); tok2 && tok2 != tokStart->link(); tok2 = tok2->next()) {
5155 : // skip parentheses..
5156 37930 : if (tok2->link()) {
5157 6422 : if (tok2->str() == "(") {
5158 4605 : Token *funcstart = const_cast<Token*>(isFunctionHead(tok2, "{"));
5159 4605 : if (funcstart) {
5160 2257 : setVarIdClassFunction(scopeName2 + classname, funcstart, funcstart->link(), thisClassVars, structMembers, mVarId);
5161 2257 : tok2 = funcstart->link();
5162 2257 : continue;
5163 : }
5164 : }
5165 4165 : if (tok2->str() == "{" && !Token::simpleMatch(tok2->previous(), "union")) {
5166 721 : if (tok2->strAt(-1) == ")")
5167 0 : setVarIdClassFunction(scopeName2 + classname, tok2, tok2->link(), thisClassVars, structMembers, mVarId);
5168 721 : tok2 = tok2->link();
5169 3444 : } else if (Token::Match(tok2, "( %name%|)") && !Token::Match(tok2->link(), "(|[")) {
5170 2306 : tok2 = tok2->link();
5171 :
5172 : // Skip initialization list
5173 2306 : if (Token::simpleMatch(tok2, ") :"))
5174 354 : tok2 = skipInitializerList(tok2->next());
5175 : }
5176 : }
5177 :
5178 : // Found a member variable..
5179 31508 : else if (tok2->varId() > 0)
5180 3557 : thisClassVars[tok2->str()] = tok2->varId();
5181 : }
5182 :
5183 : // Are there any member variables in this class?
5184 5875 : if (thisClassVars.empty())
5185 3015 : continue;
5186 :
5187 : // Member variables
5188 6325 : for (const Member &var : allMemberVars) {
5189 3465 : Token *tok2 = matchMemberVarName(var, scopeInfo);
5190 3465 : if (!tok2)
5191 3267 : continue;
5192 198 : if (tok2->varId() == 0)
5193 188 : tok2->varId(thisClassVars[tok2->str()]);
5194 : }
5195 :
5196 2860 : if (isC() || tok->str() == "namespace")
5197 140 : continue;
5198 :
5199 : // Set variable ids in member functions for this class..
5200 6433 : for (const Member &func : allMemberFunctions) {
5201 3713 : Token *tok2 = matchMemberFunctionName(func, scopeInfo);
5202 3713 : if (!tok2)
5203 3294 : continue;
5204 :
5205 419 : if (tok2->str() == "~")
5206 25 : tok2 = tok2->linkAt(2);
5207 : else
5208 394 : tok2 = tok2->linkAt(1);
5209 :
5210 : // If this is a function implementation.. add it to funclist
5211 419 : Token * start = const_cast<Token *>(isFunctionHead(tok2, "{"));
5212 419 : if (start) {
5213 355 : setVarIdClassFunction(classname, start, start->link(), thisClassVars, structMembers, mVarId);
5214 : }
5215 :
5216 419 : if (Token::Match(tok2, ") %name% ("))
5217 5 : tok2 = tok2->linkAt(2);
5218 :
5219 : // constructor with initializer list
5220 419 : if (!Token::Match(tok2, ") : ::| %name%"))
5221 364 : continue;
5222 :
5223 55 : Token *tok3 = tok2;
5224 115 : while (Token::Match(tok3, "[)}] [,:]")) {
5225 60 : tok3 = tok3->tokAt(2);
5226 60 : if (Token::Match(tok3, ":: %name%"))
5227 1 : tok3 = tok3->next();
5228 60 : while (Token::Match(tok3, "%name% :: %name%"))
5229 0 : tok3 = tok3->tokAt(2);
5230 60 : if (!Token::Match(tok3, "%name% (|{|<"))
5231 0 : break;
5232 :
5233 : // set varid
5234 60 : const std::map<std::string, nonneg int>::const_iterator varpos = thisClassVars.find(tok3->str());
5235 60 : if (varpos != thisClassVars.end())
5236 53 : tok3->varId(varpos->second);
5237 :
5238 : // goto end of var
5239 60 : if (tok3->strAt(1) == "<") {
5240 1 : tok3 = tok3->next()->findClosingBracket();
5241 1 : if (tok3 && tok3->next() && tok3->next()->link())
5242 1 : tok3 = tok3->next()->link();
5243 : } else
5244 59 : tok3 = tok3->linkAt(1);
5245 : }
5246 55 : if (Token::Match(tok3, ")|} {")) {
5247 54 : setVarIdClassFunction(classname, tok2, tok3->next()->link(), thisClassVars, structMembers, mVarId);
5248 : }
5249 : }
5250 : }
5251 22626 : }
5252 :
5253 3008216 : static void linkBrackets(const Tokenizer & tokenizer, std::stack<const Token*>& type, std::stack<Token*>& links, Token * const token, const char open, const char close)
5254 : {
5255 3008216 : if (token->str()[0] == open) {
5256 162365 : links.push(token);
5257 162365 : type.push(token);
5258 2845867 : } else if (token->str()[0] == close) {
5259 162353 : if (links.empty()) {
5260 : // Error, { and } don't match.
5261 8 : tokenizer.unmatchedToken(token);
5262 : }
5263 162347 : if (type.top()->str()[0] != open) {
5264 5 : tokenizer.unmatchedToken(type.top());
5265 : }
5266 162340 : type.pop();
5267 :
5268 162341 : Token::createMutualLinks(links.top(), token);
5269 162340 : links.pop();
5270 : }
5271 3008224 : }
5272 :
5273 23751 : void Tokenizer::createLinks()
5274 : {
5275 47500 : std::stack<const Token*> type;
5276 47499 : std::stack<Token*> links1;
5277 47500 : std::stack<Token*> links2;
5278 47502 : std::stack<Token*> links3;
5279 1026510 : for (Token *token = list.front(); token; token = token->next()) {
5280 1002773 : if (token->link()) {
5281 0 : token->link(nullptr);
5282 : }
5283 :
5284 1002773 : linkBrackets(*this, type, links1, token, '{', '}');
5285 :
5286 1002769 : linkBrackets(*this, type, links2, token, '(', ')');
5287 :
5288 1002768 : linkBrackets(*this, type, links3, token, '[', ']');
5289 : }
5290 :
5291 23738 : if (!links1.empty()) {
5292 : // Error, { and } don't match.
5293 5 : unmatchedToken(links1.top());
5294 : }
5295 :
5296 23733 : if (!links2.empty()) {
5297 : // Error, ( and ) don't match.
5298 2 : unmatchedToken(links2.top());
5299 : }
5300 :
5301 23731 : if (!links3.empty()) {
5302 : // Error, [ and ] don't match.
5303 2 : unmatchedToken(links3.top());
5304 : }
5305 23728 : }
5306 :
5307 23004 : void Tokenizer::createLinks2()
5308 : {
5309 23004 : if (isC())
5310 5917 : return;
5311 :
5312 17086 : bool isStruct = false;
5313 :
5314 34174 : std::stack<Token*> type;
5315 34175 : std::stack<Token*> templateTokens;
5316 751789 : for (Token *token = list.front(); token; token = token->next()) {
5317 734702 : if (Token::Match(token, "%name%|> %name% [:<]"))
5318 1156 : isStruct = true;
5319 733548 : else if (Token::Match(token, "[;{}]"))
5320 140682 : isStruct = false;
5321 :
5322 734694 : if (token->link()) {
5323 229088 : if (Token::Match(token, "{|[|("))
5324 114539 : type.push(token);
5325 114548 : else if (!type.empty() && Token::Match(token, "}|]|)")) {
5326 114575 : while (type.top()->str() == "<") {
5327 31 : if (!templateTokens.empty() && templateTokens.top()->next() == type.top())
5328 0 : templateTokens.pop();
5329 31 : type.pop();
5330 : }
5331 114543 : type.pop();
5332 : }
5333 505606 : } else if (templateTokens.empty() && !isStruct && Token::Match(token, "%oror%|&&|;")) {
5334 70510 : if (Token::Match(token, "&& [,>]"))
5335 1 : continue;
5336 : // If there is some such code: A<B||C>..
5337 : // Then this is probably a template instantiation if either "B" or "C" has comparisons
5338 70510 : if (token->tokType() == Token::eLogicalOp && !type.empty() && type.top()->str() == "<") {
5339 18 : const Token *prev = token->previous();
5340 18 : bool foundComparison = false;
5341 38 : while (Token::Match(prev, "%name%|%num%|%str%|%cop%|)|]") && prev != type.top()) {
5342 20 : if (prev->str() == ")" || prev->str() == "]")
5343 1 : prev = prev->link();
5344 19 : else if (prev->tokType() == Token::eLogicalOp)
5345 0 : break;
5346 19 : else if (prev->isComparisonOp())
5347 1 : foundComparison = true;
5348 20 : prev = prev->previous();
5349 : }
5350 18 : if (prev == type.top() && foundComparison)
5351 1 : continue;
5352 17 : const Token *next = token->next();
5353 17 : foundComparison = false;
5354 42 : while (Token::Match(next, "%name%|%num%|%str%|%cop%|(|[") && next->str() != ">") {
5355 26 : if (next->str() == "(" || next->str() == "[")
5356 1 : next = next->link();
5357 25 : else if (next->tokType() == Token::eLogicalOp)
5358 1 : break;
5359 24 : else if (next->isComparisonOp())
5360 4 : foundComparison = true;
5361 25 : next = next->next();
5362 : }
5363 17 : if (next && next->str() == ">" && foundComparison)
5364 1 : continue;
5365 : }
5366 :
5367 70545 : while (!type.empty() && type.top()->str() == "<") {
5368 44 : const Token* end = type.top()->findClosingBracket();
5369 44 : if (Token::Match(end, "> %comp%|;|.|=|{|(|::"))
5370 6 : break;
5371 : // Variable declaration
5372 38 : if (Token::Match(end, "> %var% ;") && (type.top()->tokAt(-2) == nullptr || Token::Match(type.top()->tokAt(-2), ";|}|{")))
5373 1 : break;
5374 37 : type.pop();
5375 : }
5376 445970 : } else if (token->str() == "<" &&
5377 10864 : ((token->previous() && (token->previous()->isTemplate() ||
5378 6291 : (token->previous()->isName() && !token->previous()->varId()) ||
5379 1744 : (token->strAt(-1) == "]" && (!Token::Match(token->linkAt(-1)->previous(), "%name%|)") || token->linkAt(-1)->previous()->isKeyword())) ||
5380 930 : (token->strAt(-1) == ")" && token->linkAt(-1)->strAt(-1) == "operator"))) ||
5381 858 : Token::Match(token->next(), ">|>>"))) {
5382 4573 : type.push(token);
5383 4573 : if (token->previous()->str() == "template")
5384 754 : templateTokens.push(token);
5385 430531 : } else if (token->str() == ">" || token->str() == ">>") {
5386 5183 : if (type.empty() || type.top()->str() != "<") // < and > don't match.
5387 682 : continue;
5388 4506 : Token * const top1 = type.top();
5389 4506 : type.pop();
5390 4506 : Token * const top2 = type.empty() ? nullptr : type.top();
5391 4506 : type.push(top1);
5392 4506 : if (!top2 || top2->str() != "<") {
5393 4159 : if (token->str() == ">>")
5394 2 : continue;
5395 4159 : if (!Token::Match(token->next(), "%name%|%cop%|%assign%|::|,|(|)|{|}|;|[|]|:|.|=|?|...") &&
5396 2 : !Token::Match(token->next(), "&& %name% ="))
5397 2 : continue;
5398 : }
5399 :
5400 4502 : if (token->str() == ">>" && top1 && top2) {
5401 1 : type.pop();
5402 1 : type.pop();
5403 : // Split the angle brackets
5404 1 : token->str(">");
5405 1 : Token::createMutualLinks(top1, token->insertTokenBefore(">"));
5406 1 : Token::createMutualLinks(top2, token);
5407 1 : if (templateTokens.size() == 2 && (top1 == templateTokens.top() || top2 == templateTokens.top())) {
5408 0 : templateTokens.pop();
5409 0 : templateTokens.pop();
5410 : }
5411 : } else {
5412 4501 : type.pop();
5413 6794 : if (Token::Match(token, "> %name%") && !token->next()->isKeyword() &&
5414 6795 : Token::Match(top1->tokAt(-2), "%op% %name% <") && top1->strAt(-2) != "<" &&
5415 1 : (templateTokens.empty() || top1 != templateTokens.top()))
5416 1 : continue;
5417 4500 : Token::createMutualLinks(top1, token);
5418 4500 : if (!templateTokens.empty() && top1 == templateTokens.top())
5419 754 : templateTokens.pop();
5420 : }
5421 : }
5422 : }
5423 : }
5424 :
5425 22628 : void Tokenizer::markCppCasts()
5426 : {
5427 22628 : if (isC())
5428 5917 : return;
5429 745601 : for (Token* tok = list.front(); tok; tok = tok->next()) {
5430 728893 : if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast")) {
5431 197 : if (!Token::simpleMatch(tok->next(), "<") || !Token::simpleMatch(tok->linkAt(1), "> ("))
5432 2 : syntaxError(tok);
5433 195 : tok = tok->linkAt(1)->next();
5434 195 : tok->isCast(true);
5435 : }
5436 : }
5437 :
5438 : }
5439 :
5440 22687 : void Tokenizer::sizeofAddParentheses()
5441 : {
5442 1007944 : for (Token *tok = list.front(); tok; tok = tok->next()) {
5443 985261 : if (!Token::Match(tok, "sizeof !!("))
5444 985215 : continue;
5445 42 : if (tok->next()->isLiteral() || Token::Match(tok->next(), "%name%|*|~|!|&")) {
5446 37 : Token *endToken = tok->next();
5447 37 : while (Token::simpleMatch(endToken, "* *"))
5448 0 : endToken = endToken->next();
5449 65 : while (Token::Match(endToken->next(), "%name%|%num%|%str%|[|(|.|::|++|--|!|~") || (Token::Match(endToken, "%type% * %op%|?|:|const|;|,"))) {
5450 28 : if (Token::Match(endToken->next(), "(|["))
5451 4 : endToken = endToken->linkAt(1);
5452 : else
5453 24 : endToken = endToken->next();
5454 : }
5455 :
5456 : // Add ( after sizeof and ) behind endToken
5457 37 : tok->insertToken("(");
5458 37 : endToken->insertToken(")");
5459 37 : Token::createMutualLinks(tok->next(), endToken->next());
5460 : }
5461 : }
5462 22685 : }
5463 :
5464 23291 : bool Tokenizer::simplifyTokenList1(const char FileName[])
5465 : {
5466 23291 : if (Settings::terminated())
5467 0 : return false;
5468 :
5469 : // if MACRO
5470 1020485 : for (Token *tok = list.front(); tok; tok = tok->next()) {
5471 997200 : if (Token::Match(tok, "if|for|while|BOOST_FOREACH %name% (")) {
5472 9 : if (Token::simpleMatch(tok, "for each")) {
5473 : // 'for each ( )' -> 'asm ( )'
5474 2 : tok->str("asm");
5475 2 : tok->deleteNext();
5476 7 : } else if (tok->strAt(1) == "constexpr") {
5477 5 : tok->deleteNext();
5478 5 : tok->isConstexpr(true);
5479 : } else {
5480 2 : syntaxError(tok);
5481 : }
5482 : }
5483 : }
5484 :
5485 : // Is there C++ code in C file?
5486 23289 : validateC();
5487 :
5488 : // Combine strings and character literals, e.g. L"string", L'c', "string1" "string2"
5489 23254 : combineStringAndCharLiterals();
5490 :
5491 : // replace inline SQL with "asm()" (Oracle PRO*C). Ticket: #1959
5492 23253 : simplifySQL();
5493 :
5494 23248 : createLinks();
5495 :
5496 : // Simplify debug intrinsics
5497 23228 : simplifyDebug();
5498 :
5499 23228 : removePragma();
5500 :
5501 : // Simplify the C alternative tokens (and, or, etc.)
5502 23225 : simplifyCAlternativeTokens();
5503 :
5504 23225 : simplifyFunctionTryCatch();
5505 :
5506 23228 : simplifyHeadersAndUnusedTemplates();
5507 :
5508 : // Remove __asm..
5509 23229 : simplifyAsm();
5510 :
5511 : // foo < bar < >> => foo < bar < > >
5512 23227 : if (isCPP() || mSettings.daca)
5513 17084 : splitTemplateRightAngleBrackets(!isCPP());
5514 :
5515 : // Remove extra "template" tokens that are not used by cppcheck
5516 23225 : removeExtraTemplateKeywords();
5517 :
5518 23223 : simplifySpaceshipOperator();
5519 :
5520 : // @..
5521 23226 : simplifyAt();
5522 :
5523 : // Remove __declspec()
5524 23224 : simplifyDeclspec();
5525 :
5526 : // Remove "inline", "register", and "restrict"
5527 23228 : simplifyKeyword();
5528 :
5529 : // Remove [[attribute]]
5530 23226 : simplifyCPPAttribute();
5531 :
5532 : // remove __attribute__((?))
5533 23223 : simplifyAttribute();
5534 :
5535 : // Bail out if code is garbage
5536 23218 : if (mTimerResults) {
5537 1980 : Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::findGarbageCode", mSettings.showtime, mTimerResults);
5538 660 : findGarbageCode();
5539 : } else {
5540 22558 : findGarbageCode();
5541 : }
5542 :
5543 22703 : checkConfiguration();
5544 :
5545 : // if (x) MACRO() ..
5546 961816 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
5547 939124 : if (Token::simpleMatch(tok, "if (")) {
5548 8656 : tok = tok->next()->link();
5549 8656 : if (Token::Match(tok, ") %name% (") &&
5550 8660 : tok->next()->isUpperCaseName() &&
5551 4 : Token::Match(tok->linkAt(2), ") {|else")) {
5552 4 : syntaxError(tok->next());
5553 : }
5554 : }
5555 : }
5556 :
5557 22698 : if (Settings::terminated())
5558 0 : return false;
5559 :
5560 : // convert C++17 style nested namespaces to old style namespaces
5561 22701 : simplifyNestedNamespace();
5562 :
5563 : // convert c++20 coroutines
5564 22702 : simplifyCoroutines();
5565 :
5566 : // simplify namespace aliases
5567 22703 : simplifyNamespaceAliases();
5568 :
5569 : // simplify cppcheck attributes __cppcheck_?__(?)
5570 22702 : simplifyCppcheckAttribute();
5571 :
5572 : // Combine tokens..
5573 22700 : combineOperators();
5574 :
5575 : // combine "- %num%"
5576 22699 : concatenateNegativeNumberAndAnyPositive();
5577 :
5578 : // remove extern "C" and extern "C" {}
5579 22701 : if (isCPP())
5580 16765 : simplifyExternC();
5581 :
5582 : // simplify weird but legal code: "[;{}] ( { code; } ) ;"->"[;{}] code;"
5583 22702 : simplifyRoundCurlyParentheses();
5584 :
5585 : // check for simple syntax errors..
5586 1003857 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
5587 981166 : if (Token::simpleMatch(tok, "> struct {") &&
5588 2 : Token::simpleMatch(tok->linkAt(2), "} ;")) {
5589 2 : syntaxError(tok);
5590 : }
5591 : }
5592 :
5593 22697 : if (!simplifyAddBraces())
5594 0 : return false;
5595 :
5596 22687 : sizeofAddParentheses();
5597 :
5598 : // Simplify: 0[foo] -> *(foo)
5599 1007914 : for (Token* tok = list.front(); tok; tok = tok->next()) {
5600 985238 : if (Token::simpleMatch(tok, "0 [") && tok->linkAt(1)) {
5601 1 : tok->str("*");
5602 1 : tok->next()->str("(");
5603 1 : tok->linkAt(1)->str(")");
5604 : }
5605 : }
5606 :
5607 22684 : if (Settings::terminated())
5608 0 : return false;
5609 :
5610 22684 : validate();
5611 :
5612 : // simplify simple calculations inside <..>
5613 22686 : if (isCPP()) {
5614 16754 : Token *lt = nullptr;
5615 741799 : for (Token *tok = list.front(); tok; tok = tok->next()) {
5616 725042 : if (Token::Match(tok, "[;{}]"))
5617 129899 : lt = nullptr;
5618 595136 : else if (Token::Match(tok, "%type% <"))
5619 6807 : lt = tok->next();
5620 588340 : else if (lt && Token::Match(tok, ">|>> %name%|::|(")) {
5621 4408 : const Token * const end = tok;
5622 17272 : for (tok = lt; tok != end; tok = tok->next()) {
5623 12864 : if (tok->isNumber())
5624 310 : TemplateSimplifier::simplifyNumericCalculations(tok);
5625 : }
5626 4408 : lt = tok->next();
5627 : }
5628 : }
5629 : }
5630 :
5631 : // Convert K&R function declarations to modern C
5632 22683 : simplifyVarDecl(true);
5633 22683 : simplifyFunctionParameters();
5634 :
5635 : // simplify case ranges (gcc extension)
5636 22678 : simplifyCaseRange();
5637 :
5638 : // simplify labels and 'case|default'-like syntaxes
5639 22682 : simplifyLabelsCaseDefault();
5640 :
5641 39424 : if (!isC() && !mSettings.library.markupFile(FileName)) {
5642 16749 : findComplicatedSyntaxErrorsInTemplates();
5643 : }
5644 :
5645 22672 : if (Settings::terminated())
5646 0 : return false;
5647 :
5648 : // remove calling conventions __cdecl, __stdcall..
5649 22672 : simplifyCallingConvention();
5650 :
5651 22674 : addSemicolonAfterUnknownMacro();
5652 :
5653 : // remove some unhandled macros in global scope
5654 22670 : removeMacrosInGlobalScope();
5655 :
5656 : // remove undefined macro in class definition:
5657 : // class DLLEXPORT Fred { };
5658 : // class Fred FINAL : Base { };
5659 22666 : removeMacroInClassDef();
5660 :
5661 : // That call here fixes #7190
5662 22667 : validate();
5663 :
5664 : // remove unnecessary member qualification..
5665 22667 : removeUnnecessaryQualification();
5666 :
5667 : // convert Microsoft memory functions
5668 22667 : simplifyMicrosoftMemoryFunctions();
5669 :
5670 : // convert Microsoft string functions
5671 22669 : simplifyMicrosoftStringFunctions();
5672 :
5673 22668 : if (Settings::terminated())
5674 0 : return false;
5675 :
5676 : // remove Borland stuff..
5677 22668 : simplifyBorland();
5678 :
5679 : // syntax error: enum with typedef in it
5680 22668 : checkForEnumsWithTypedef();
5681 :
5682 : // Add parentheses to ternary operator where necessary
5683 22667 : prepareTernaryOpForAST();
5684 :
5685 : // Change initialisation of variable to assignment
5686 22664 : simplifyInitVar();
5687 :
5688 : // Split up variable declarations.
5689 22665 : simplifyVarDecl(false);
5690 :
5691 22665 : reportUnknownMacros();
5692 :
5693 22651 : simplifyTypedefLHS();
5694 :
5695 : // typedef..
5696 22649 : if (mTimerResults) {
5697 1979 : Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTypedef", mSettings.showtime, mTimerResults);
5698 660 : simplifyTypedef();
5699 : } else {
5700 21990 : simplifyTypedef();
5701 : }
5702 :
5703 : // using A = B;
5704 22712 : while (simplifyUsing())
5705 : ;
5706 :
5707 : // Add parentheses to ternary operator where necessary
5708 : // TODO: this is only necessary if one typedef simplification had a comma and was used within ?:
5709 : // If typedef handling is refactored and moved to symboldatabase someday we can remove this
5710 22640 : prepareTernaryOpForAST();
5711 :
5712 : // class x y {
5713 22640 : if (isCPP() && mSettings.severity.isEnabled(Severity::information)) {
5714 164146 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
5715 163706 : if (Token::Match(tok, "class %type% %type% [:{]")) {
5716 1 : unhandled_macro_class_x_y(tok);
5717 : }
5718 : }
5719 : }
5720 :
5721 : // catch bad typedef canonicalization
5722 : //
5723 : // to reproduce bad typedef, download upx-ucl from:
5724 : // http://packages.debian.org/sid/upx-ucl
5725 : // analyse the file src/stub/src/i386-linux.elf.interp-main.c
5726 22641 : validate();
5727 :
5728 : // The simplify enum have inner loops
5729 22642 : if (Settings::terminated())
5730 0 : return false;
5731 :
5732 : // Put ^{} statements in asm()
5733 22642 : simplifyAsm2();
5734 :
5735 : // When the assembly code has been cleaned up, no @ is allowed
5736 629870 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
5737 607226 : if (tok->str() == "(") {
5738 87504 : const Token *tok1 = tok;
5739 87504 : tok = tok->link();
5740 87504 : if (!tok)
5741 0 : syntaxError(tok1);
5742 519734 : } else if (tok->str() == "@") {
5743 0 : syntaxError(tok);
5744 : }
5745 : }
5746 :
5747 : // Order keywords "static" and "const"
5748 22640 : simplifyStaticConst();
5749 :
5750 : // convert platform dependent types to standard types
5751 : // 32 bits: size_t -> unsigned long
5752 : // 64 bits: size_t -> unsigned long long
5753 22637 : list.simplifyPlatformTypes();
5754 :
5755 : // collapse compound standard types into a single token
5756 : // unsigned long long int => long (with _isUnsigned=true,_isLong=true)
5757 22634 : list.simplifyStdType();
5758 :
5759 22642 : if (Settings::terminated())
5760 0 : return false;
5761 :
5762 : // simplify bit fields..
5763 22642 : simplifyBitfields();
5764 :
5765 22638 : if (Settings::terminated())
5766 0 : return false;
5767 :
5768 : // struct simplification "struct S {} s; => struct S { } ; S s ;
5769 22638 : simplifyStructDecl();
5770 :
5771 22642 : if (Settings::terminated())
5772 0 : return false;
5773 :
5774 : // x = ({ 123; }); => { x = 123; }
5775 22642 : simplifyAssignmentBlock();
5776 :
5777 22638 : if (Settings::terminated())
5778 0 : return false;
5779 :
5780 22638 : simplifyVariableMultipleAssign();
5781 :
5782 : // Collapse operator name tokens into single token
5783 : // operator = => operator=
5784 22641 : simplifyOperatorName();
5785 :
5786 : // Remove redundant parentheses
5787 22641 : simplifyRedundantParentheses();
5788 :
5789 22636 : if (isCPP()) {
5790 16713 : simplifyTypeIntrinsics();
5791 :
5792 : // Handle templates..
5793 16715 : if (mTimerResults) {
5794 1979 : Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::simplifyTemplates", mSettings.showtime, mTimerResults);
5795 660 : simplifyTemplates();
5796 : } else {
5797 16055 : simplifyTemplates();
5798 : }
5799 :
5800 : // The simplifyTemplates have inner loops
5801 16716 : if (Settings::terminated())
5802 0 : return false;
5803 :
5804 16716 : validate(); // #6847 - invalid code
5805 : }
5806 :
5807 : // Simplify pointer to standard types (C only)
5808 22640 : simplifyPointerToStandardType();
5809 :
5810 : // simplify function pointers
5811 22640 : simplifyFunctionPointers();
5812 :
5813 : // Change initialisation of variable to assignment
5814 22638 : simplifyInitVar();
5815 :
5816 : // Split up variable declarations.
5817 22637 : simplifyVarDecl(false);
5818 :
5819 22638 : elseif();
5820 :
5821 22638 : validate(); // #6772 "segmentation fault (invalid code) in Tokenizer::setVarId"
5822 :
5823 22636 : if (mTimerResults) {
5824 1978 : Timer t("Tokenizer::simplifyTokens1::simplifyTokenList1::setVarId", mSettings.showtime, mTimerResults);
5825 660 : setVarId();
5826 : } else {
5827 21976 : setVarId();
5828 : }
5829 :
5830 : // Link < with >
5831 22627 : createLinks2();
5832 :
5833 : // Mark C++ casts
5834 22628 : markCppCasts();
5835 :
5836 : // specify array size
5837 22627 : arraySize();
5838 :
5839 : // The simplify enum might have inner loops
5840 22622 : if (Settings::terminated())
5841 0 : return false;
5842 :
5843 : // Add std:: in front of std classes, when using namespace std; was given
5844 22624 : simplifyNamespaceStd();
5845 :
5846 : // Change initialisation of variable to assignment
5847 22626 : simplifyInitVar();
5848 :
5849 22626 : simplifyDoublePlusAndDoubleMinus();
5850 :
5851 22624 : simplifyArrayAccessSyntax();
5852 :
5853 22625 : Token::assignProgressValues(list.front());
5854 :
5855 22624 : removeRedundantSemicolons();
5856 :
5857 22626 : simplifyParameterVoid();
5858 :
5859 22627 : simplifyRedundantConsecutiveBraces();
5860 :
5861 22627 : simplifyEmptyNamespaces();
5862 :
5863 22627 : simplifyIfSwitchForInit();
5864 :
5865 22628 : simplifyOverloadedOperators();
5866 :
5867 22622 : validate();
5868 :
5869 22627 : list.front()->assignIndexes();
5870 :
5871 22626 : return true;
5872 : }
5873 : //---------------------------------------------------------------------------
5874 :
5875 23249 : void Tokenizer::printDebugOutput(int simplification) const
5876 : {
5877 46497 : const bool debug = (simplification != 1U && mSettings.debugSimplified) ||
5878 23248 : (simplification != 2U && mSettings.debugnormal);
5879 :
5880 23249 : if (debug && list.front()) {
5881 0 : list.front()->printOut(nullptr, list.getFiles());
5882 :
5883 0 : if (mSettings.xml)
5884 0 : std::cout << "<debug>" << std::endl;
5885 :
5886 0 : if (mSymbolDatabase) {
5887 0 : if (mSettings.xml)
5888 0 : mSymbolDatabase->printXml(std::cout);
5889 0 : else if (mSettings.verbose) {
5890 0 : mSymbolDatabase->printOut("Symbol database");
5891 : }
5892 : }
5893 :
5894 0 : if (mSettings.verbose)
5895 0 : list.front()->printAst(mSettings.verbose, mSettings.xml, list.getFiles(), std::cout);
5896 :
5897 0 : list.front()->printValueFlow(mSettings.xml, std::cout);
5898 :
5899 0 : if (mSettings.xml)
5900 0 : std::cout << "</debug>" << std::endl;
5901 : }
5902 :
5903 23249 : if (mSymbolDatabase && simplification == 2U && mSettings.debugwarnings) {
5904 0 : printUnknownTypes();
5905 :
5906 : // the typeStartToken() should come before typeEndToken()
5907 0 : for (const Variable *var : mSymbolDatabase->variableList()) {
5908 0 : if (!var)
5909 0 : continue;
5910 :
5911 0 : const Token * typetok = var->typeStartToken();
5912 0 : while (typetok && typetok != var->typeEndToken())
5913 0 : typetok = typetok->next();
5914 :
5915 0 : if (typetok != var->typeEndToken()) {
5916 0 : reportError(var->typeStartToken(),
5917 : Severity::debug,
5918 : "debug",
5919 0 : "Variable::typeStartToken() of variable '" + var->name() + "' is not located before Variable::typeEndToken(). The location of the typeStartToken() is '" + var->typeStartToken()->str() + "' at line " + std::to_string(var->typeStartToken()->linenr()));
5920 : }
5921 : }
5922 : }
5923 23249 : }
5924 :
5925 4 : void Tokenizer::dump(std::ostream &out) const
5926 : {
5927 : // Create a xml data dump.
5928 : // The idea is not that this will be readable for humans. It's a
5929 : // data dump that 3rd party tools could load and get useful info from.
5930 :
5931 8 : std::string outs;
5932 :
5933 8 : std::set<const Library::Container*> containers;
5934 :
5935 4 : outs += " <directivelist>";
5936 4 : outs += '\n';
5937 28 : for (const Directive &dir : mDirectives) {
5938 24 : outs += " <directive ";
5939 24 : outs += "file=\"";
5940 24 : outs += ErrorLogger::toxml(Path::getRelativePath(dir.file, mSettings.basePaths));
5941 24 : outs += "\" ";
5942 24 : outs += "linenr=\"";
5943 24 : outs += std::to_string(dir.linenr);
5944 24 : outs += "\" ";
5945 : // str might contain characters such as '"', '<' or '>' which
5946 : // could result in invalid XML, so run it through toxml().
5947 24 : outs += "str=\"";
5948 24 : outs += ErrorLogger::toxml(dir.str);
5949 24 : outs +="\"/>";
5950 24 : outs += '\n';
5951 : }
5952 4 : outs += " </directivelist>";
5953 4 : outs += '\n';
5954 :
5955 : // tokens..
5956 4 : outs += " <tokenlist>";
5957 4 : outs += '\n';
5958 4 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
5959 0 : outs += " <token id=\"";
5960 0 : outs += id_string(tok);
5961 0 : outs += "\" file=\"";
5962 0 : outs += ErrorLogger::toxml(list.file(tok));
5963 0 : outs += "\" linenr=\"";
5964 0 : outs += std::to_string(tok->linenr());
5965 0 : outs += "\" column=\"";
5966 0 : outs += std::to_string(tok->column());
5967 0 : outs += "\"";
5968 :
5969 0 : outs += " str=\"";
5970 0 : outs += ErrorLogger::toxml(tok->str());
5971 0 : outs += '\"';
5972 :
5973 0 : outs += " scope=\"";
5974 0 : outs += id_string(tok->scope());
5975 0 : outs += '\"';
5976 0 : if (tok->isName()) {
5977 0 : outs += " type=\"name\"";
5978 0 : if (tok->isUnsigned())
5979 0 : outs += " isUnsigned=\"true\"";
5980 0 : else if (tok->isSigned())
5981 0 : outs += " isSigned=\"true\"";
5982 0 : } else if (tok->isNumber()) {
5983 0 : outs += " type=\"number\"";
5984 0 : if (MathLib::isInt(tok->str()))
5985 0 : outs += " isInt=\"true\"";
5986 0 : if (MathLib::isFloat(tok->str()))
5987 0 : outs += " isFloat=\"true\"";
5988 0 : } else if (tok->tokType() == Token::eString) {
5989 0 : outs += " type=\"string\" strlen=\"";
5990 0 : outs += std::to_string(Token::getStrLength(tok));
5991 0 : outs += '\"';
5992 : }
5993 0 : else if (tok->tokType() == Token::eChar)
5994 0 : outs += " type=\"char\"";
5995 0 : else if (tok->isBoolean())
5996 0 : outs += " type=\"boolean\"";
5997 0 : else if (tok->isOp()) {
5998 0 : outs += " type=\"op\"";
5999 0 : if (tok->isArithmeticalOp())
6000 0 : outs += " isArithmeticalOp=\"true\"";
6001 0 : else if (tok->isAssignmentOp())
6002 0 : outs += " isAssignmentOp=\"true\"";
6003 0 : else if (tok->isComparisonOp())
6004 0 : outs += " isComparisonOp=\"true\"";
6005 0 : else if (tok->tokType() == Token::eLogicalOp)
6006 0 : outs += " isLogicalOp=\"true\"";
6007 : }
6008 0 : if (tok->isCast())
6009 0 : outs += " isCast=\"true\"";
6010 0 : if (tok->isExternC())
6011 0 : outs += " externLang=\"C\"";
6012 0 : if (tok->isExpandedMacro())
6013 0 : outs += " macroName=\"" + tok->getMacroName() + "\"";
6014 0 : if (tok->isTemplateArg())
6015 0 : outs += " isTemplateArg=\"true\"";
6016 0 : if (tok->isRemovedVoidParameter())
6017 0 : outs += " isRemovedVoidParameter=\"true\"";
6018 0 : if (tok->isSplittedVarDeclComma())
6019 0 : outs += " isSplittedVarDeclComma=\"true\"";
6020 0 : if (tok->isSplittedVarDeclEq())
6021 0 : outs += " isSplittedVarDeclEq=\"true\"";
6022 0 : if (tok->isImplicitInt())
6023 0 : outs += " isImplicitInt=\"true\"";
6024 0 : if (tok->isComplex())
6025 0 : outs += " isComplex=\"true\"";
6026 0 : if (tok->isRestrict())
6027 0 : outs += " isRestrict=\"true\"";
6028 0 : if (tok->isAtomic())
6029 0 : outs += " isAtomic=\"true\"";
6030 0 : if (tok->isAttributeExport())
6031 0 : outs += " isAttributeExport=\"true\"";
6032 0 : if (tok->isAttributeMaybeUnused())
6033 0 : outs += " isAttributeMaybeUnused=\"true\"";
6034 0 : if (tok->isAttributeUnused())
6035 0 : outs += " isAttributeUnused=\"true\"";
6036 0 : if (tok->link()) {
6037 0 : outs += " link=\"";
6038 0 : outs += id_string(tok->link());
6039 0 : outs += '\"';
6040 : }
6041 0 : if (tok->varId() > 0) {
6042 0 : outs += " varId=\"";
6043 0 : outs += std::to_string(tok->varId());
6044 0 : outs += '\"';
6045 : }
6046 0 : if (tok->exprId() > 0) {
6047 0 : outs += " exprId=\"";
6048 0 : outs += std::to_string(tok->exprId());
6049 0 : outs += '\"';
6050 : }
6051 0 : if (tok->variable()) {
6052 0 : outs += " variable=\"";
6053 0 : outs += id_string(tok->variable());
6054 0 : outs += '\"';
6055 : }
6056 0 : if (tok->function()) {
6057 0 : outs += " function=\"";
6058 0 : outs += id_string(tok->function());
6059 0 : outs += '\"';
6060 : }
6061 0 : if (!tok->values().empty()) {
6062 0 : outs += " values=\"";
6063 0 : outs += id_string(&tok->values());
6064 0 : outs += '\"';
6065 : }
6066 0 : if (tok->type()) {
6067 0 : outs += " type-scope=\"";
6068 0 : outs += id_string(tok->type()->classScope);
6069 0 : outs += '\"';
6070 : }
6071 0 : if (tok->astParent()) {
6072 0 : outs += " astParent=\"";
6073 0 : outs += id_string(tok->astParent());
6074 0 : outs += '\"';
6075 : }
6076 0 : if (tok->astOperand1()) {
6077 0 : outs += " astOperand1=\"";
6078 0 : outs += id_string(tok->astOperand1());
6079 0 : outs += '\"';
6080 : }
6081 0 : if (tok->astOperand2()) {
6082 0 : outs += " astOperand2=\"";
6083 0 : outs += id_string(tok->astOperand2());
6084 0 : outs += '\"';
6085 : }
6086 0 : if (!tok->originalName().empty()) {
6087 0 : outs += " originalName=\"";
6088 0 : outs += tok->originalName();
6089 0 : outs += '\"';
6090 : }
6091 0 : if (tok->valueType()) {
6092 0 : const std::string vt = tok->valueType()->dump();
6093 0 : if (!vt.empty()) {
6094 0 : outs += ' ';
6095 0 : outs += vt;
6096 : }
6097 0 : containers.insert(tok->valueType()->container);
6098 : }
6099 0 : if (!tok->varId() && tok->scope()->isExecutable() && Token::Match(tok, "%name% (")) {
6100 0 : if (mSettings.library.isnoreturn(tok))
6101 0 : outs += " noreturn=\"true\"";
6102 : }
6103 :
6104 0 : outs += "/>";
6105 0 : outs += '\n';
6106 : }
6107 4 : outs += " </tokenlist>";
6108 4 : outs += '\n';
6109 :
6110 4 : out << outs;
6111 4 : outs.clear();
6112 :
6113 4 : if (mSymbolDatabase)
6114 0 : mSymbolDatabase->printXml(out);
6115 :
6116 4 : containers.erase(nullptr);
6117 4 : if (!containers.empty()) {
6118 0 : outs += " <containers>";
6119 0 : outs += '\n';
6120 0 : for (const Library::Container* c: containers) {
6121 0 : outs += " <container id=\"";
6122 0 : outs += id_string(c);
6123 0 : outs += "\" array-like-index-op=\"";
6124 0 : outs += bool_to_string(c->arrayLike_indexOp);
6125 0 : outs += "\" ";
6126 0 : outs += "std-string-like=\"";
6127 0 : outs += bool_to_string(c->stdStringLike);
6128 0 : outs += "\"/>";
6129 0 : outs += '\n';
6130 : }
6131 0 : outs += " </containers>";
6132 0 : outs += '\n';
6133 : }
6134 :
6135 4 : if (list.front())
6136 0 : list.front()->printValueFlow(true, out);
6137 :
6138 4 : if (!mTypedefInfo.empty()) {
6139 0 : outs += " <typedef-info>";
6140 0 : outs += '\n';
6141 0 : for (const TypedefInfo &typedefInfo: mTypedefInfo) {
6142 0 : outs += " <info";
6143 :
6144 0 : outs += " name=\"";
6145 0 : outs += typedefInfo.name;
6146 0 : outs += "\"";
6147 :
6148 0 : outs += " file=\"";
6149 0 : outs += ErrorLogger::toxml(typedefInfo.filename);
6150 0 : outs += "\"";
6151 :
6152 0 : outs += " line=\"";
6153 0 : outs += std::to_string(typedefInfo.lineNumber);
6154 0 : outs += "\"";
6155 :
6156 0 : outs += " column=\"";
6157 0 : outs += std::to_string(typedefInfo.column);
6158 0 : outs += "\"";
6159 :
6160 0 : outs += " used=\"";
6161 0 : outs += std::to_string(typedefInfo.used?1:0);
6162 0 : outs += "\"";
6163 :
6164 0 : outs += "/>";
6165 0 : outs += '\n';
6166 : }
6167 0 : outs += " </typedef-info>";
6168 0 : outs += '\n';
6169 : }
6170 4 : outs += mTemplateSimplifier->dump();
6171 :
6172 4 : out << outs;
6173 4 : }
6174 :
6175 23229 : void Tokenizer::simplifyHeadersAndUnusedTemplates()
6176 : {
6177 23229 : if (mSettings.checkHeaders && mSettings.checkUnusedTemplates)
6178 : // Full analysis. All information in the headers are kept.
6179 23225 : return;
6180 :
6181 4 : const bool checkHeaders = mSettings.checkHeaders;
6182 4 : const bool removeUnusedIncludedFunctions = !mSettings.checkHeaders;
6183 4 : const bool removeUnusedIncludedClasses = !mSettings.checkHeaders;
6184 4 : const bool removeUnusedIncludedTemplates = !mSettings.checkUnusedTemplates || !mSettings.checkHeaders;
6185 4 : const bool removeUnusedTemplates = !mSettings.checkUnusedTemplates;
6186 :
6187 : // checkHeaders:
6188 : //
6189 : // If it is true then keep all code in the headers. It's possible
6190 : // to remove unused types/variables if false positives / false
6191 : // negatives can be avoided.
6192 : //
6193 : // If it is false, then we want to remove selected stuff from the
6194 : // headers but not *everything*. The intention here is to not damage
6195 : // the analysis of the source file. You should get all warnings in
6196 : // the source file. You should not get false positives.
6197 :
6198 : // functions and types to keep
6199 8 : std::set<std::string> keep;
6200 135 : for (const Token *tok = list.front(); tok; tok = tok->next()) {
6201 131 : if (tok->isCpp() && Token::simpleMatch(tok, "template <")) {
6202 4 : const Token *closingBracket = tok->next()->findClosingBracket();
6203 4 : if (Token::Match(closingBracket, "> class|struct %name% {"))
6204 1 : tok = closingBracket->linkAt(3);
6205 : }
6206 :
6207 131 : if (!tok->isName() || tok->isKeyword())
6208 87 : continue;
6209 :
6210 44 : if (!checkHeaders && tok->fileIndex() != 0)
6211 12 : continue;
6212 :
6213 32 : if (Token::Match(tok, "%name% (") && !Token::simpleMatch(tok->linkAt(1), ") {")) {
6214 4 : keep.insert(tok->str());
6215 4 : continue;
6216 : }
6217 :
6218 28 : if (Token::Match(tok, "%name% %name%|::|*|&|<")) {
6219 10 : keep.insert(tok->str());
6220 : }
6221 : }
6222 :
6223 64 : const std::set<std::string> functionStart{"static", "const", "unsigned", "signed", "void", "bool", "char", "short", "int", "long", "float", "*"};
6224 :
6225 16 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6226 12 : const bool isIncluded = (tok->fileIndex() != 0);
6227 :
6228 : // Remove executable code
6229 12 : if (isIncluded && !mSettings.checkHeaders && tok->str() == "{") {
6230 : // TODO: We probably need to keep the executable code if this function is called from the source file.
6231 0 : const Token *prev = tok->previous();
6232 0 : while (prev && prev->isName())
6233 0 : prev = prev->previous();
6234 0 : if (Token::simpleMatch(prev, ")")) {
6235 : // Replace all tokens from { to } with a ";".
6236 0 : Token::eraseTokens(tok,tok->link()->next());
6237 0 : tok->str(";");
6238 0 : tok->link(nullptr);
6239 : }
6240 : }
6241 :
6242 12 : if (!tok->previous() || Token::Match(tok->previous(), "[;{}]")) {
6243 : // Remove unused function declarations
6244 7 : if (isIncluded && removeUnusedIncludedFunctions) {
6245 : while (true) {
6246 1 : Token *start = tok;
6247 1 : while (start && functionStart.find(start->str()) != functionStart.end())
6248 0 : start = start->next();
6249 1 : if (Token::Match(start, "%name% (") && Token::Match(start->linkAt(1), ") const| ;") && keep.find(start->str()) == keep.end()) {
6250 0 : Token::eraseTokens(tok, start->linkAt(1)->tokAt(2));
6251 0 : tok->deleteThis();
6252 : } else
6253 1 : break;
6254 0 : }
6255 : }
6256 :
6257 7 : if (isIncluded && removeUnusedIncludedClasses) {
6258 1 : if (Token::Match(tok, "class|struct %name% [:{]") && keep.find(tok->strAt(1)) == keep.end()) {
6259 : // Remove this class/struct
6260 1 : const Token *endToken = tok->tokAt(2);
6261 1 : if (endToken->str() == ":") {
6262 0 : endToken = endToken->next();
6263 0 : while (Token::Match(endToken, "%name%|,"))
6264 0 : endToken = endToken->next();
6265 : }
6266 1 : if (endToken && endToken->str() == "{" && Token::simpleMatch(endToken->link(), "} ;")) {
6267 1 : Token::eraseTokens(tok, endToken->link()->next());
6268 1 : tok->deleteThis();
6269 : }
6270 : }
6271 : }
6272 :
6273 7 : if (removeUnusedTemplates || (isIncluded && removeUnusedIncludedTemplates)) {
6274 7 : if (Token::Match(tok, "template < %name%")) {
6275 3 : const Token *closingBracket = tok->next()->findClosingBracket();
6276 3 : if (Token::Match(closingBracket, "> class|struct %name% [;:{]") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6277 1 : const Token *endToken = closingBracket->tokAt(3);
6278 1 : if (endToken->str() == ":") {
6279 0 : endToken = endToken->next();
6280 0 : while (Token::Match(endToken, "%name%|,"))
6281 0 : endToken = endToken->next();
6282 : }
6283 1 : if (endToken && endToken->str() == "{")
6284 1 : endToken = endToken->link()->next();
6285 1 : if (endToken && endToken->str() == ";") {
6286 1 : Token::eraseTokens(tok, endToken);
6287 1 : tok->deleteThis();
6288 : }
6289 2 : } else if (Token::Match(closingBracket, "> %type% %name% (") && Token::simpleMatch(closingBracket->linkAt(3), ") {") && keep.find(closingBracket->strAt(2)) == keep.end()) {
6290 2 : const Token *endToken = closingBracket->linkAt(3)->linkAt(1)->next();
6291 2 : Token::eraseTokens(tok, endToken);
6292 2 : tok->deleteThis();
6293 : }
6294 : }
6295 : }
6296 : }
6297 : }
6298 : }
6299 :
6300 23225 : void Tokenizer::removeExtraTemplateKeywords()
6301 : {
6302 23225 : if (isCPP()) {
6303 747644 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6304 730565 : if (Token::Match(tok, "%name%|>|) .|:: template %name%")) {
6305 10 : tok->next()->deleteNext();
6306 10 : Token* templateName = tok->tokAt(2);
6307 20 : while (Token::Match(templateName, "%name%|::")) {
6308 10 : templateName->isTemplate(true);
6309 10 : templateName = templateName->next();
6310 : }
6311 10 : if (!templateName)
6312 0 : syntaxError(tok);
6313 10 : if (Token::Match(templateName->previous(), "operator %op%|(")) {
6314 2 : templateName->isTemplate(true);
6315 2 : if (templateName->str() == "(" && templateName->link())
6316 1 : templateName->link()->isTemplate(true);
6317 : }
6318 : }
6319 : }
6320 : }
6321 23223 : }
6322 :
6323 0 : static std::string getExpression(const Token *tok)
6324 : {
6325 0 : std::string line;
6326 0 : for (const Token *prev = tok->previous(); prev && !Token::Match(prev, "[;{}]"); prev = prev->previous())
6327 0 : line = prev->str() + " " + line;
6328 0 : line += "!!!" + tok->str() + "!!!";
6329 0 : for (const Token *next = tok->next(); next && !Token::Match(next, "[;{}]"); next = next->next())
6330 0 : line += " " + next->str();
6331 0 : return line;
6332 : }
6333 :
6334 17170 : void Tokenizer::splitTemplateRightAngleBrackets(bool check)
6335 : {
6336 34342 : std::vector<std::pair<std::string, int>> vars;
6337 :
6338 17173 : int scopeLevel = 0;
6339 749425 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6340 732254 : if (tok->str() == "{")
6341 33458 : ++scopeLevel;
6342 698793 : else if (tok->str() == "}") {
6343 0 : vars.erase(std::remove_if(vars.begin(), vars.end(), [scopeLevel](const std::pair<std::string, int>& v) {
6344 9261 : return v.second == scopeLevel;
6345 33459 : }), vars.end());
6346 33458 : --scopeLevel;
6347 : }
6348 732251 : if (Token::Match(tok, "[;{}] %type% %type% [;,=]") && tok->next()->isStandardType())
6349 7578 : vars.emplace_back(tok->strAt(2), scopeLevel);
6350 :
6351 : // Ticket #6181: normalize C++11 template parameter list closing syntax
6352 732244 : if (tok->previous() && tok->str() == "<" && TemplateSimplifier::templateParameters(tok) && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6353 99 : return v.first == tok->previous()->str();
6354 : })) {
6355 6065 : Token *endTok = tok->findClosingBracket();
6356 6065 : if (check) {
6357 0 : if (Token::Match(endTok, ">>|>>="))
6358 0 : reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6359 0 : continue;
6360 : }
6361 6065 : if (endTok && endTok->str() == ">>") {
6362 276 : endTok->str(">");
6363 276 : endTok->insertToken(">");
6364 5789 : } else if (endTok && endTok->str() == ">>=") {
6365 1 : endTok->str(">");
6366 1 : endTok->insertToken("=");
6367 1 : endTok->insertToken(">");
6368 : }
6369 726177 : } else if (Token::Match(tok, "class|struct|union|=|:|public|protected|private %name% <") && std::none_of(vars.begin(), vars.end(), [&](const std::pair<std::string, int>& v) {
6370 60 : return v.first == tok->next()->str();
6371 : })) {
6372 498 : Token *endTok = tok->tokAt(2)->findClosingBracket();
6373 498 : if (check) {
6374 0 : if (Token::simpleMatch(endTok, ">>"))
6375 0 : reportError(tok, Severity::debug, "dacaWrongSplitTemplateRightAngleBrackets", "bad closing bracket for !!!<!!!: " + getExpression(tok), false);
6376 0 : continue;
6377 : }
6378 498 : if (Token::Match(endTok, ">> ;|{|%type%")) {
6379 21 : endTok->str(">");
6380 21 : endTok->insertToken(">");
6381 : }
6382 : }
6383 : }
6384 17170 : }
6385 :
6386 22670 : void Tokenizer::removeMacrosInGlobalScope()
6387 : {
6388 239929 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6389 217264 : if (tok->str() == "(") {
6390 33817 : tok = tok->link();
6391 33817 : if (Token::Match(tok, ") %type% {") &&
6392 323 : !tok->next()->isStandardType() &&
6393 321 : !tok->next()->isKeyword() &&
6394 34149 : !Token::Match(tok->next(), "override|final") &&
6395 9 : tok->next()->isUpperCaseName())
6396 9 : tok->deleteNext();
6397 : }
6398 :
6399 236090 : if (Token::Match(tok, "%type%") && tok->isUpperCaseName() &&
6400 18826 : (!tok->previous() || Token::Match(tok->previous(), "[;{}]") || (tok->previous()->isName() && endsWith(tok->previous()->str(), ':')))) {
6401 2421 : const Token *tok2 = tok->next();
6402 2421 : if (tok2 && tok2->str() == "(")
6403 721 : tok2 = tok2->link()->next();
6404 :
6405 : // Several unknown macros...
6406 2424 : while (Token::Match(tok2, "%type% (") && tok2->isUpperCaseName())
6407 3 : tok2 = tok2->linkAt(1)->next();
6408 :
6409 2428 : if (Token::Match(tok, "%name% (") && Token::Match(tok2, "%name% *|&|::|<| %name%") &&
6410 7 : !Token::Match(tok2, "requires|namespace|class|struct|union|private:|protected:|public:"))
6411 3 : unknownMacroError(tok);
6412 :
6413 2420 : if (Token::Match(tok, "%type% (") && Token::Match(tok2, "%type% (") && !Token::Match(tok2, "noexcept|throw") && isFunctionHead(tok2->next(), ":;{"))
6414 2 : unknownMacroError(tok);
6415 :
6416 : // remove unknown macros before namespace|class|struct|union
6417 2416 : if (Token::Match(tok2, "namespace|class|struct|union")) {
6418 : // is there a "{" for?
6419 4 : const Token *tok3 = tok2;
6420 12 : while (tok3 && !Token::Match(tok3,"[;{}()]"))
6421 8 : tok3 = tok3->next();
6422 4 : if (tok3 && tok3->str() == "{") {
6423 2 : Token::eraseTokens(tok, tok2);
6424 2 : tok->deleteThis();
6425 : }
6426 4 : continue;
6427 : }
6428 :
6429 : // replace unknown macros before foo(
6430 : /*
6431 : if (Token::Match(tok2, "%type% (") && isFunctionHead(tok2->next(), "{")) {
6432 : std::string typeName;
6433 : for (const Token* tok3 = tok; tok3 != tok2; tok3 = tok3->next())
6434 : typeName += tok3->str();
6435 : Token::eraseTokens(tok, tok2);
6436 : tok->str(typeName);
6437 : }
6438 : */
6439 : // remove unknown macros before foo::foo(
6440 2412 : if (Token::Match(tok2, "%type% :: %type%")) {
6441 3 : const Token *tok3 = tok2;
6442 3 : while (Token::Match(tok3, "%type% :: %type% ::"))
6443 0 : tok3 = tok3->tokAt(2);
6444 3 : if (Token::Match(tok3, "%type% :: %type% (") && tok3->str() == tok3->strAt(2)) {
6445 0 : Token::eraseTokens(tok, tok2);
6446 0 : tok->deleteThis();
6447 : }
6448 3 : continue;
6449 : }
6450 : }
6451 :
6452 : // Skip executable scopes
6453 217253 : if (tok->str() == "{") {
6454 35417 : const Token *prev = tok->previous();
6455 47187 : while (prev && prev->isName())
6456 11770 : prev = prev->previous();
6457 35417 : if (prev && prev->str() == ")")
6458 28887 : tok = tok->link();
6459 : }
6460 : }
6461 22666 : }
6462 :
6463 : //---------------------------------------------------------------------------
6464 :
6465 23229 : void Tokenizer::removePragma()
6466 : {
6467 23229 : if (isC() && mSettings.standards.c == Standards::C89)
6468 50 : return;
6469 23177 : if (isCPP() && mSettings.standards.cpp == Standards::CPP03)
6470 60 : return;
6471 1015957 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6472 992846 : while (Token::simpleMatch(tok, "_Pragma (")) {
6473 2 : Token::eraseTokens(tok, tok->linkAt(1)->next());
6474 2 : tok->deleteThis();
6475 : }
6476 : }
6477 : }
6478 :
6479 : //---------------------------------------------------------------------------
6480 :
6481 22666 : void Tokenizer::removeMacroInClassDef()
6482 : {
6483 1008086 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6484 985419 : if (!Token::Match(tok, "class|struct %name% %name% final| {|:"))
6485 985408 : continue;
6486 :
6487 12 : const bool nextIsUppercase = tok->next()->isUpperCaseName();
6488 12 : const bool afterNextIsUppercase = tok->tokAt(2)->isUpperCaseName();
6489 12 : if (nextIsUppercase && !afterNextIsUppercase)
6490 6 : tok->deleteNext();
6491 6 : else if (!nextIsUppercase && afterNextIsUppercase)
6492 2 : tok->next()->deleteNext();
6493 : }
6494 22667 : }
6495 :
6496 : //---------------------------------------------------------------------------
6497 :
6498 22673 : void Tokenizer::addSemicolonAfterUnknownMacro()
6499 : {
6500 22673 : if (!isCPP())
6501 5928 : return;
6502 742121 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6503 725371 : if (tok->str() != ")")
6504 651063 : continue;
6505 74312 : const Token *macro = tok->link() ? tok->link()->previous() : nullptr;
6506 74311 : if (!macro || !macro->isName())
6507 12521 : continue;
6508 61790 : if (Token::simpleMatch(tok, ") try") && !Token::Match(macro, "if|for|while"))
6509 1 : tok->insertToken(";");
6510 61789 : else if (Token::simpleMatch(tok, ") using"))
6511 3 : tok->insertToken(";");
6512 : }
6513 : }
6514 : //---------------------------------------------------------------------------
6515 :
6516 22626 : void Tokenizer::simplifyEmptyNamespaces()
6517 : {
6518 22626 : if (isC())
6519 5917 : return;
6520 :
6521 16710 : bool goback = false;
6522 145842 : for (Token *tok = list.front(); tok; tok = tok ? tok->next() : nullptr) {
6523 129131 : if (goback) {
6524 24 : tok = tok->previous();
6525 24 : goback = false;
6526 : }
6527 129131 : if (Token::Match(tok, "(|[|{")) {
6528 44358 : tok = tok->link();
6529 44358 : continue;
6530 : }
6531 84772 : if (!Token::Match(tok, "namespace %name%| {"))
6532 84274 : continue;
6533 500 : const bool isAnonymousNS = tok->strAt(1) == "{";
6534 500 : if (tok->strAt(3 - isAnonymousNS) == "}") {
6535 40 : tok->deleteNext(3 - isAnonymousNS); // remove '%name%| { }'
6536 40 : if (!tok->previous()) {
6537 : // remove 'namespace' or replace it with ';' if isolated
6538 19 : tok->deleteThis();
6539 19 : goback = true;
6540 : } else { // '%any% namespace %any%'
6541 21 : tok = tok->previous(); // goto previous token
6542 21 : tok->deleteNext(); // remove next token: 'namespace'
6543 21 : if (tok->str() == "{") {
6544 : // Go back in case we were within a namespace that's empty now
6545 13 : tok = tok->tokAt(-2) ? tok->tokAt(-2) : tok->previous();
6546 13 : goback = true;
6547 : }
6548 : }
6549 : } else {
6550 460 : tok = tok->tokAt(2 - isAnonymousNS);
6551 : }
6552 : }
6553 : }
6554 :
6555 22624 : void Tokenizer::removeRedundantSemicolons()
6556 : {
6557 628841 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6558 606211 : if (tok->link() && tok->str() == "(") {
6559 87749 : tok = tok->link();
6560 87749 : continue;
6561 : }
6562 : for (;;) {
6563 518524 : if (Token::simpleMatch(tok, "; ;")) {
6564 58 : tok->deleteNext();
6565 518465 : } else if (Token::simpleMatch(tok, "; { ; }")) {
6566 1 : tok->deleteNext(3);
6567 : } else {
6568 518468 : break;
6569 : }
6570 : }
6571 : }
6572 22626 : }
6573 :
6574 :
6575 22700 : bool Tokenizer::simplifyAddBraces()
6576 : {
6577 1008079 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6578 985391 : Token const * tokRet=simplifyAddBracesToCommand(tok);
6579 985379 : if (!tokRet)
6580 0 : return false;
6581 : }
6582 22687 : return true;
6583 : }
6584 :
6585 2988668 : Token *Tokenizer::simplifyAddBracesToCommand(Token *tok)
6586 : {
6587 2988668 : Token * tokEnd=tok;
6588 2988668 : if (Token::Match(tok,"for|switch|BOOST_FOREACH")) {
6589 1196 : tokEnd=simplifyAddBracesPair(tok,true);
6590 2987479 : } else if (tok->str()=="while") {
6591 359 : Token *tokPossibleDo=tok->previous();
6592 359 : if (Token::simpleMatch(tok->previous(), "{"))
6593 71 : tokPossibleDo = nullptr;
6594 288 : else if (Token::simpleMatch(tokPossibleDo,"}"))
6595 106 : tokPossibleDo = tokPossibleDo->link();
6596 359 : if (!tokPossibleDo || tokPossibleDo->strAt(-1) != "do")
6597 273 : tokEnd=simplifyAddBracesPair(tok,true);
6598 2987119 : } else if (tok->str()=="do") {
6599 96 : tokEnd=simplifyAddBracesPair(tok,false);
6600 93 : if (tokEnd!=tok) {
6601 : // walk on to next token, i.e. "while"
6602 : // such that simplifyAddBracesPair does not close other braces
6603 : // before the "while"
6604 93 : if (tokEnd) {
6605 93 : tokEnd=tokEnd->next();
6606 93 : if (!tokEnd || tokEnd->str()!="while") // no while
6607 5 : syntaxError(tok);
6608 : }
6609 : }
6610 2987022 : } else if (tok->str()=="if" && !Token::simpleMatch(tok->tokAt(-2), "operator \"\"")) {
6611 2009893 : tokEnd=simplifyAddBracesPair(tok,true);
6612 2009890 : if (!tokEnd)
6613 0 : return nullptr;
6614 2009890 : if (tokEnd->strAt(1) == "else") {
6615 2001558 : Token * tokEndNextNext= tokEnd->tokAt(2);
6616 2001558 : if (!tokEndNextNext || tokEndNextNext->str() == "}")
6617 0 : syntaxError(tokEndNextNext);
6618 2001558 : if (tokEndNextNext->str() == "if")
6619 : // do not change "else if ..." to "else { if ... }"
6620 2001125 : tokEnd=simplifyAddBracesToCommand(tokEndNextNext);
6621 : else
6622 433 : tokEnd=simplifyAddBracesPair(tokEnd->next(),false);
6623 : }
6624 : }
6625 :
6626 2988657 : return tokEnd;
6627 : }
6628 :
6629 2011891 : Token *Tokenizer::simplifyAddBracesPair(Token *tok, bool commandWithCondition)
6630 : {
6631 2011891 : Token * tokCondition=tok->next();
6632 2011891 : if (!tokCondition) // Missing condition
6633 0 : return tok;
6634 :
6635 2011891 : Token *tokAfterCondition=tokCondition;
6636 2011891 : if (commandWithCondition) {
6637 2011362 : if (tokCondition->str()=="(")
6638 2011362 : tokAfterCondition=tokCondition->link();
6639 : else
6640 0 : syntaxError(tok); // Bad condition
6641 :
6642 2011362 : if (!tokAfterCondition || tokAfterCondition->strAt(1) == "]")
6643 0 : syntaxError(tok); // Bad condition
6644 :
6645 2011362 : tokAfterCondition=tokAfterCondition->next();
6646 2011362 : if (!tokAfterCondition || Token::Match(tokAfterCondition, ")|}|,")) {
6647 : // No tokens left where to add braces around
6648 7 : return tok;
6649 : }
6650 : }
6651 : // Skip labels
6652 2011884 : Token * tokStatement = tokAfterCondition;
6653 : while (true) {
6654 2011924 : if (Token::Match(tokStatement, "%name% :"))
6655 32 : tokStatement = tokStatement->tokAt(2);
6656 2011892 : else if (tokStatement->str() == "case") {
6657 8 : tokStatement = skipCaseLabel(tokStatement);
6658 8 : if (!tokStatement)
6659 0 : return tok;
6660 8 : if (tokStatement->str() != ":")
6661 0 : syntaxError(tokStatement);
6662 8 : tokStatement = tokStatement->next();
6663 : } else
6664 2011884 : break;
6665 40 : if (!tokStatement)
6666 0 : return tok;
6667 : }
6668 2011884 : Token * tokBracesEnd=nullptr;
6669 2011884 : if (tokStatement->str() == "{") {
6670 : // already surrounded by braces
6671 2009725 : if (tokStatement != tokAfterCondition) {
6672 : // Move the opening brace before labels
6673 6 : Token::move(tokStatement, tokStatement, tokAfterCondition->previous());
6674 : }
6675 2009725 : tokBracesEnd = tokStatement->link();
6676 2164 : } else if (Token::simpleMatch(tokStatement, "try {") &&
6677 5 : Token::simpleMatch(tokStatement->linkAt(1), "} catch (")) {
6678 5 : tokAfterCondition->previous()->insertToken("{");
6679 5 : Token * tokOpenBrace = tokAfterCondition->previous();
6680 5 : Token * tokEnd = tokStatement->linkAt(1)->linkAt(2)->linkAt(1);
6681 5 : if (!tokEnd) {
6682 0 : syntaxError(tokStatement);
6683 : }
6684 5 : tokEnd->insertToken("}");
6685 5 : Token * tokCloseBrace = tokEnd->next();
6686 :
6687 5 : Token::createMutualLinks(tokOpenBrace, tokCloseBrace);
6688 5 : tokBracesEnd = tokCloseBrace;
6689 : } else {
6690 2154 : Token * tokEnd = simplifyAddBracesToCommand(tokStatement);
6691 2154 : if (!tokEnd) // Ticket #4887
6692 0 : return tok;
6693 2154 : if (tokEnd->str()!="}") {
6694 : // Token does not end with brace
6695 : // Look for ; to add own closing brace after it
6696 7319 : while (tokEnd && !Token::Match(tokEnd, ";|)|}")) {
6697 5303 : if (tokEnd->tokType()==Token::eBracket || tokEnd->str() == "(") {
6698 450 : tokEnd = tokEnd->link();
6699 450 : if (!tokEnd) {
6700 : // Inner bracket does not close
6701 0 : return tok;
6702 : }
6703 : }
6704 5303 : tokEnd=tokEnd->next();
6705 : }
6706 2016 : if (!tokEnd || tokEnd->str() != ";") {
6707 : // No trailing ;
6708 8 : if (tokStatement->isUpperCaseName())
6709 3 : unknownMacroError(tokStatement);
6710 : else
6711 5 : syntaxError(tokStatement);
6712 : }
6713 : }
6714 :
6715 2146 : tokAfterCondition->previous()->insertToken("{");
6716 2146 : Token * tokOpenBrace=tokAfterCondition->previous();
6717 :
6718 2146 : tokEnd->insertToken("}");
6719 2146 : Token * tokCloseBrace=tokEnd->next();
6720 :
6721 2146 : Token::createMutualLinks(tokOpenBrace,tokCloseBrace);
6722 2146 : tokBracesEnd=tokCloseBrace;
6723 : }
6724 :
6725 2011876 : return tokBracesEnd;
6726 : }
6727 :
6728 22685 : void Tokenizer::simplifyFunctionParameters()
6729 : {
6730 183578 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6731 160903 : if (tok->link() && Token::Match(tok, "{|[|(")) {
6732 57783 : tok = tok->link();
6733 : }
6734 :
6735 : // Find the function e.g. foo( x ) or foo( x, y )
6736 106472 : else if (Token::Match(tok, "%name% ( %name% [,)]") &&
6737 3354 : !(tok->strAt(-1) == ":" || tok->strAt(-1) == "," || tok->strAt(-1) == "::")) {
6738 : // We have found old style function, now we need to change it
6739 :
6740 : // First step: Get list of argument names in parentheses
6741 3296 : std::map<std::string, Token *> argumentNames;
6742 3294 : bool bailOut = false;
6743 3294 : Token * tokparam = nullptr;
6744 :
6745 : //take count of the function name..
6746 3294 : const std::string& funcName(tok->str());
6747 :
6748 : //floating token used to check for parameters
6749 3294 : Token *tok1 = tok;
6750 :
6751 3406 : while (nullptr != (tok1 = tok1->tokAt(2))) {
6752 3406 : if (!Token::Match(tok1, "%name% [,)]")) {
6753 39 : bailOut = true;
6754 39 : break;
6755 : }
6756 :
6757 : //same parameters: take note of the parameter
6758 3367 : if (argumentNames.find(tok1->str()) != argumentNames.end())
6759 33 : tokparam = tok1;
6760 3334 : else if (tok1->str() != funcName)
6761 3327 : argumentNames[tok1->str()] = tok1;
6762 : else {
6763 7 : if (tok1->next()->str() == ")") {
6764 4 : if (tok1->previous()->str() == ",") {
6765 1 : tok1 = tok1->tokAt(-2);
6766 1 : tok1->deleteNext(2);
6767 : } else {
6768 3 : tok1 = tok1->previous();
6769 3 : tok1->deleteNext();
6770 3 : bailOut = true;
6771 3 : break;
6772 : }
6773 : } else {
6774 3 : tok1 = tok1->tokAt(-2);
6775 3 : tok1->next()->deleteNext(2);
6776 : }
6777 : }
6778 :
6779 3364 : if (tok1->next()->str() == ")") {
6780 3252 : tok1 = tok1->tokAt(2);
6781 : //expect at least a type name after round brace..
6782 3252 : if (!tok1 || !tok1->isName())
6783 3219 : bailOut = true;
6784 3252 : break;
6785 : }
6786 : }
6787 :
6788 : //goto '('
6789 3294 : tok = tok->next();
6790 :
6791 3294 : if (bailOut) {
6792 3261 : tok = tok->link();
6793 3261 : continue;
6794 : }
6795 :
6796 33 : tok1 = tok->link()->next();
6797 :
6798 : // there should be the sequence '; {' after the round parentheses
6799 322 : for (const Token* tok2 = tok1; tok2; tok2 = tok2->next()) {
6800 314 : if (Token::simpleMatch(tok2, "; {"))
6801 16 : break;
6802 298 : if (tok2->str() == "{") {
6803 9 : bailOut = true;
6804 9 : break;
6805 : }
6806 : }
6807 :
6808 33 : if (bailOut) {
6809 9 : tok = tok->link();
6810 9 : continue;
6811 : }
6812 :
6813 : // Last step: check out if the declarations between ')' and '{' match the parameters list
6814 26 : std::map<std::string, Token *> argumentNames2;
6815 :
6816 155 : while (tok1 && tok1->str() != "{") {
6817 141 : if (Token::Match(tok1, "(|)")) {
6818 1 : bailOut = true;
6819 1 : break;
6820 : }
6821 140 : if (tok1->str() == ";") {
6822 34 : if (tokparam) {
6823 1 : syntaxError(tokparam);
6824 : }
6825 33 : Token *tok2 = tok1->previous();
6826 35 : while (tok2->str() == "]")
6827 2 : tok2 = tok2->link()->previous();
6828 :
6829 : //it should be a name..
6830 33 : if (!tok2->isName()) {
6831 1 : bailOut = true;
6832 1 : break;
6833 : }
6834 :
6835 32 : if (argumentNames2.find(tok2->str()) != argumentNames2.end()) {
6836 : //same parameter names...
6837 1 : syntaxError(tok1);
6838 : } else
6839 31 : argumentNames2[tok2->str()] = tok2;
6840 :
6841 31 : if (argumentNames.find(tok2->str()) == argumentNames.end()) {
6842 : //non-matching parameter... bailout
6843 6 : bailOut = true;
6844 6 : break;
6845 : }
6846 : }
6847 131 : tok1 = tok1->next();
6848 : }
6849 :
6850 22 : if (bailOut || !tok1) {
6851 8 : tok = tok->link();
6852 8 : continue;
6853 : }
6854 :
6855 : //the two containers may not hold the same size...
6856 : //in that case, the missing parameters are defined as 'int'
6857 14 : if (argumentNames.size() != argumentNames2.size()) {
6858 : //move back 'tok1' to the last ';'
6859 2 : tok1 = tok1->previous();
6860 10 : for (const std::pair<const std::string, Token *>& argumentName : argumentNames) {
6861 8 : if (argumentNames2.find(argumentName.first) == argumentNames2.end()) {
6862 : //add the missing parameter argument declaration
6863 5 : tok1->insertToken(";");
6864 5 : tok1->insertToken(argumentName.first);
6865 : //register the change inside argumentNames2
6866 5 : argumentNames2[argumentName.first] = tok1->next();
6867 5 : tok1->insertToken("int");
6868 : }
6869 : }
6870 : }
6871 :
6872 43 : while (tok->str() != ")") {
6873 : //initialize start and end tokens to be moved
6874 29 : Token *declStart = argumentNames2[tok->next()->str()];
6875 29 : Token *declEnd = declStart;
6876 71 : while (declStart->previous()->str() != ";" && declStart->previous()->str() != ")")
6877 42 : declStart = declStart->previous();
6878 31 : while (declEnd->next()->str() != ";" && declEnd->next()->str() != "{")
6879 2 : declEnd = declEnd->next();
6880 :
6881 : //remove ';' after declaration
6882 29 : declEnd->deleteNext();
6883 :
6884 : //replace the parameter name in the parentheses with all the declaration
6885 29 : Token::replace(tok->next(), declStart, declEnd);
6886 :
6887 : //since there are changes to tokens, put tok where tok1 is
6888 29 : tok = declEnd->next();
6889 :
6890 : //fix up line number
6891 29 : if (tok->str() == ",")
6892 15 : tok->linenr(tok->previous()->linenr());
6893 : }
6894 : //goto forward and continue
6895 14 : tok = tok->next()->link();
6896 : }
6897 : }
6898 22678 : }
6899 :
6900 22640 : void Tokenizer::simplifyPointerToStandardType()
6901 : {
6902 22640 : if (!isC())
6903 16716 : return;
6904 :
6905 264197 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6906 258273 : if (!Token::Match(tok, "& %name% [ 0 ] !!["))
6907 258250 : continue;
6908 :
6909 23 : if (!Token::Match(tok->previous(), "[,(=]"))
6910 1 : continue;
6911 :
6912 : // Remove '[ 0 ]' suffix
6913 22 : Token::eraseTokens(tok->next(), tok->tokAt(5));
6914 : // Remove '&' prefix
6915 22 : tok = tok->previous();
6916 22 : if (!tok)
6917 0 : break;
6918 22 : tok->deleteNext();
6919 : }
6920 : }
6921 :
6922 22640 : void Tokenizer::simplifyFunctionPointers()
6923 : {
6924 911637 : for (Token *tok = list.front(); tok; tok = tok->next()) {
6925 : // #2873 - do not simplify function pointer usage here:
6926 : // (void)(xy(*p)(0));
6927 888993 : if (Token::simpleMatch(tok, ") (")) {
6928 501 : tok = tok->next()->link();
6929 501 : continue;
6930 : }
6931 :
6932 : // check for function pointer cast
6933 1776927 : if (Token::Match(tok, "( %type% %type%| *| *| ( * ) (") ||
6934 888430 : Token::Match(tok, "static_cast < %type% %type%| *| *| ( * ) (")) {
6935 65 : Token *tok1 = tok;
6936 :
6937 65 : if (tok1->isCpp() && tok1->str() == "static_cast")
6938 0 : tok1 = tok1->next();
6939 :
6940 65 : tok1 = tok1->next();
6941 :
6942 65 : if (Token::Match(tok1->next(), "%type%"))
6943 0 : tok1 = tok1->next();
6944 :
6945 71 : while (tok1->next()->str() == "*")
6946 6 : tok1 = tok1->next();
6947 :
6948 : // check that the cast ends
6949 65 : if (!Token::Match(tok1->linkAt(4), ") )|>"))
6950 0 : continue;
6951 :
6952 : // ok simplify this function pointer cast to an ordinary pointer cast
6953 65 : tok1->deleteNext();
6954 65 : tok1->next()->deleteNext();
6955 65 : Token::eraseTokens(tok1->next(), tok1->linkAt(2)->next());
6956 65 : continue;
6957 : }
6958 :
6959 : // check for start of statement
6960 888433 : if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|,|(|public:|protected:|private:"))
6961 557124 : continue;
6962 :
6963 331310 : if (Token::Match(tok, "delete|else|return|throw|typedef"))
6964 10295 : continue;
6965 :
6966 416296 : while (Token::Match(tok, "%type%|:: %type%|::"))
6967 95285 : tok = tok->next();
6968 :
6969 321010 : Token *tok2 = (tok && tok->isName()) ? tok->next() : nullptr;
6970 350075 : while (Token::Match(tok2, "*|&"))
6971 29063 : tok2 = tok2->next();
6972 321013 : if (!tok2 || tok2->str() != "(")
6973 264616 : continue;
6974 84695 : while (Token::Match(tok2, "(|:: %type%"))
6975 28296 : tok2 = tok2->tokAt(2);
6976 56399 : if (!Token::Match(tok2, "(|:: * *| %name%"))
6977 55919 : continue;
6978 479 : tok2 = tok2->tokAt(2);
6979 479 : if (tok2->str() == "*")
6980 11 : tok2 = tok2->next();
6981 505 : while (Token::Match(tok2, "%type%|:: %type%|::"))
6982 26 : tok2 = tok2->next();
6983 :
6984 479 : if (!Token::Match(tok2, "%name% ) (") &&
6985 769 : !Token::Match(tok2, "%name% [ ] ) (") &&
6986 290 : !(Token::Match(tok2, "%name% (") && Token::simpleMatch(tok2->linkAt(1), ") ) (")))
6987 258 : continue;
6988 :
6989 468 : while (tok && tok->str() != "(")
6990 247 : tok = tok->next();
6991 :
6992 : // check that the declaration ends
6993 221 : if (!tok || !tok->link() || !tok->link()->next()) {
6994 2 : syntaxError(nullptr);
6995 : }
6996 219 : Token *endTok = tok->link()->next()->link();
6997 219 : if (Token::simpleMatch(endTok, ") throw ("))
6998 1 : endTok = endTok->linkAt(2);
6999 219 : if (!Token::Match(endTok, ") const|volatile| const|volatile| ;|,|)|=|[|{"))
7000 26 : continue;
7001 :
7002 228 : while (Token::Match(endTok->next(), "const|volatile"))
7003 35 : endTok->deleteNext();
7004 :
7005 : // ok simplify this function pointer to an ordinary pointer
7006 193 : if (Token::simpleMatch(tok->link()->previous(), ") )")) {
7007 : // Function returning function pointer
7008 : // void (*dostuff(void))(void) {}
7009 31 : Token::eraseTokens(tok->link(), endTok->next());
7010 31 : tok->link()->deleteThis();
7011 31 : tok->deleteThis();
7012 : } else {
7013 162 : Token::eraseTokens(tok->link()->linkAt(1), endTok->next());
7014 :
7015 : // remove variable names
7016 162 : int indent = 0;
7017 356 : for (Token* tok3 = tok->link()->tokAt(2); Token::Match(tok3, "%name%|*|&|[|(|)|::|,|<"); tok3 = tok3->next()) {
7018 355 : if (tok3->str() == ")" && --indent < 0)
7019 161 : break;
7020 194 : if (tok3->str() == "<" && tok3->link())
7021 0 : tok3 = tok3->link();
7022 194 : else if (Token::Match(tok3, "["))
7023 0 : tok3 = tok3->link();
7024 194 : else if (tok3->str() == "(") {
7025 1 : tok3 = tok3->link();
7026 1 : if (Token::simpleMatch(tok3, ") (")) {
7027 1 : tok3 = tok3->next();
7028 1 : ++indent;
7029 : } else
7030 0 : break;
7031 : }
7032 194 : if (Token::Match(tok3, "%type%|*|&|> %name% [,)[]"))
7033 19 : tok3->deleteNext();
7034 : }
7035 :
7036 : // TODO Keep this info
7037 222 : while (Token::Match(tok, "( %type% ::"))
7038 60 : tok->deleteNext(2);
7039 : }
7040 : }
7041 22638 : }
7042 :
7043 67987 : void Tokenizer::simplifyVarDecl(const bool only_k_r_fpar)
7044 : {
7045 67987 : simplifyVarDecl(list.front(), nullptr, only_k_r_fpar);
7046 67986 : }
7047 :
7048 68255 : void Tokenizer::simplifyVarDecl(Token * tokBegin, const Token * const tokEnd, const bool only_k_r_fpar)
7049 : {
7050 68255 : const bool isCPP11 = isCPP() && (mSettings.standards.cpp >= Standards::CPP11);
7051 :
7052 : // Split up variable declarations..
7053 : // "int a=4;" => "int a; a=4;"
7054 68256 : bool finishedwithkr = true;
7055 68256 : bool scopeDecl = false;
7056 1427695 : for (Token *tok = tokBegin; tok != tokEnd; tok = tok->next()) {
7057 1359437 : if (Token::Match(tok, "{|;"))
7058 314309 : scopeDecl = false;
7059 1359437 : if (isCPP()) {
7060 1023848 : if (Token::Match(tok, "class|struct|namespace|union"))
7061 20687 : scopeDecl = true;
7062 1023851 : if (Token::Match(tok, "decltype|noexcept (")) {
7063 325 : tok = tok->next()->link();
7064 : // skip decltype(...){...}
7065 325 : if (tok && Token::simpleMatch(tok->previous(), ") {"))
7066 0 : tok = tok->link();
7067 2045990 : } else if (Token::simpleMatch(tok, "= {") ||
7068 1022485 : (!scopeDecl && Token::Match(tok, "%name%|> {") &&
7069 4202 : !Token::Match(tok, "else|try|do|const|constexpr|override|volatile|noexcept"))) {
7070 3553 : if (!tok->next()->link())
7071 0 : syntaxError(tokBegin);
7072 : // Check for lambdas before skipping
7073 3553 : if (Token::Match(tok->tokAt(-2), ") . %name%")) { // trailing return type
7074 : // TODO: support lambda without parameter clause?
7075 67 : Token* lambdaStart = tok->linkAt(-2)->previous();
7076 67 : if (Token::simpleMatch(lambdaStart, "]"))
7077 23 : lambdaStart = lambdaStart->link();
7078 67 : Token* lambdaEnd = findLambdaEndScope(lambdaStart);
7079 67 : if (lambdaEnd)
7080 23 : simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7081 : } else {
7082 19314 : for (Token* tok2 = tok->next(); tok2 != tok->next()->link(); tok2 = tok2->next()) {
7083 15828 : Token* lambdaEnd = findLambdaEndScope(tok2);
7084 15828 : if (!lambdaEnd)
7085 15783 : continue;
7086 45 : simplifyVarDecl(lambdaEnd->link()->next(), lambdaEnd, only_k_r_fpar);
7087 : }
7088 : }
7089 3553 : tok = tok->next()->link();
7090 : }
7091 :
7092 335590 : } else if (Token::simpleMatch(tok, "= {")) {
7093 191 : tok = tok->next()->link();
7094 : }
7095 1359419 : if (!tok) {
7096 0 : syntaxError(tokBegin);
7097 : }
7098 1359419 : if (only_k_r_fpar && finishedwithkr) {
7099 161344 : if (Token::Match(tok, "(|[|{")) {
7100 60190 : tok = tok->link();
7101 60190 : if (tok->next() && Token::Match(tok, ") !!{"))
7102 2162 : tok = tok->next();
7103 : else
7104 58028 : continue;
7105 : } else
7106 101156 : continue;
7107 1198075 : } else if (tok->str() == "(") {
7108 175156 : if (isCPP()) {
7109 667408 : for (Token * tok2 = tok; tok2 && tok2 != tok->link(); tok2 = tok2->next()) {
7110 556349 : if (Token::Match(tok2, "[(,] [")) {
7111 : // lambda function at tok2->next()
7112 : // find start of lambda body
7113 202 : Token * lambdaBody = tok2;
7114 1687 : while (lambdaBody && lambdaBody != tok2->link() && lambdaBody->str() != "{")
7115 1485 : lambdaBody = lambdaBody->next();
7116 202 : if (lambdaBody && lambdaBody != tok2->link() && lambdaBody->link())
7117 200 : simplifyVarDecl(lambdaBody, lambdaBody->link()->next(), only_k_r_fpar);
7118 : }
7119 : }
7120 : }
7121 175155 : tok = tok->link();
7122 : }
7123 :
7124 1200238 : if (!tok)
7125 0 : syntaxError(nullptr); // #7043 invalid code
7126 1200238 : if (tok->previous() && !Token::Match(tok->previous(), "{|}|;|)|public:|protected:|private:"))
7127 662019 : continue;
7128 538228 : if (Token::simpleMatch(tok, "template <"))
7129 2026 : continue;
7130 :
7131 536200 : Token *type0 = tok;
7132 536200 : if (!Token::Match(type0, "::|extern| %type%"))
7133 273475 : continue;
7134 262736 : if (Token::Match(type0, "else|return|public:|protected:|private:"))
7135 22444 : continue;
7136 240292 : if (isCPP11 && type0->str() == "using")
7137 461 : continue;
7138 239830 : if (type0->isCpp() && Token::Match(type0, "namespace|delete"))
7139 1532 : continue;
7140 :
7141 238298 : bool isconst = false;
7142 238298 : bool isstatic = false;
7143 238298 : Token *tok2 = type0;
7144 238298 : int typelen = 1;
7145 :
7146 238298 : if (Token::Match(tok2, "::|extern")) {
7147 292 : tok2 = tok2->next();
7148 292 : typelen++;
7149 : }
7150 :
7151 : //check if variable is declared 'const' or 'static' or both
7152 260704 : while (tok2) {
7153 260704 : if (!Token::Match(tok2, "const|static|constexpr") && Token::Match(tok2, "%type% const|static")) {
7154 69 : tok2 = tok2->next();
7155 69 : ++typelen;
7156 : }
7157 :
7158 260704 : if (Token::Match(tok2, "const|constexpr"))
7159 7855 : isconst = true;
7160 :
7161 252851 : else if (Token::Match(tok2, "static|constexpr"))
7162 1129 : isstatic = true;
7163 :
7164 251723 : else if (Token::Match(tok2, "%type% :: %type%")) {
7165 13437 : tok2 = tok2->next();
7166 13437 : ++typelen;
7167 : }
7168 :
7169 : else
7170 238286 : break;
7171 :
7172 22421 : if (tok2->strAt(1) == "*")
7173 15 : break;
7174 :
7175 22406 : if (Token::Match(tok2->next(), "& %name% ,"))
7176 0 : break;
7177 :
7178 22406 : tok2 = tok2->next();
7179 22406 : ++typelen;
7180 : }
7181 :
7182 : // strange looking variable declaration => don't split up.
7183 238301 : if (Token::Match(tok2, "%type% *|&| %name% , %type% *|&| %name%"))
7184 8 : continue;
7185 :
7186 238290 : if (Token::Match(tok2, "struct|union|class %type%")) {
7187 11821 : tok2 = tok2->next();
7188 11821 : ++typelen;
7189 : }
7190 :
7191 : // check for qualification..
7192 238290 : if (Token::Match(tok2, ":: %type%")) {
7193 7 : ++typelen;
7194 7 : tok2 = tok2->next();
7195 : }
7196 :
7197 : //skip combinations of templates and namespaces
7198 242593 : while (!isC() && (Token::Match(tok2, "%type% <") || Token::Match(tok2, "%type% ::"))) {
7199 4341 : if (tok2->next()->str() == "<" && !TemplateSimplifier::templateParameters(tok2->next())) {
7200 38 : tok2 = nullptr;
7201 38 : break;
7202 : }
7203 4303 : typelen += 2;
7204 4303 : tok2 = tok2->tokAt(2);
7205 4303 : if (tok2 && tok2->previous()->str() == "::")
7206 321 : continue;
7207 3982 : int indentlevel = 0;
7208 3982 : int parens = 0;
7209 :
7210 12220 : for (Token *tok3 = tok2; tok3; tok3 = tok3->next()) {
7211 12220 : ++typelen;
7212 :
7213 12220 : if (!parens && tok3->str() == "<") {
7214 386 : ++indentlevel;
7215 11834 : } else if (!parens && tok3->str() == ">") {
7216 4368 : if (indentlevel == 0) {
7217 3982 : tok2 = tok3->next();
7218 3982 : break;
7219 : }
7220 386 : --indentlevel;
7221 7466 : } else if (!parens && tok3->str() == ">>") {
7222 0 : if (indentlevel <= 1) {
7223 0 : tok2 = tok3->next();
7224 0 : break;
7225 : }
7226 0 : indentlevel -= 2;
7227 7466 : } else if (tok3->str() == "(") {
7228 166 : ++parens;
7229 7300 : } else if (tok3->str() == ")") {
7230 166 : if (!parens) {
7231 0 : tok2 = nullptr;
7232 0 : break;
7233 : }
7234 166 : --parens;
7235 7134 : } else if (tok3->str() == ";") {
7236 0 : break;
7237 : }
7238 : }
7239 :
7240 3982 : if (Token::Match(tok2, ":: %type%")) {
7241 611 : ++typelen;
7242 611 : tok2 = tok2->next();
7243 : }
7244 :
7245 : // east const
7246 3982 : if (Token::simpleMatch(tok2, "const"))
7247 7 : isconst = true;
7248 : }
7249 :
7250 : //pattern: "%type% *| ... *| const| %name% ,|="
7251 240025 : if (Token::Match(tok2, "%type%") ||
7252 1736 : (tok2 && tok2->previous() && tok2->previous()->str() == ">")) {
7253 237048 : Token *varName = tok2;
7254 237048 : if (!tok2->previous() || tok2->previous()->str() != ">")
7255 233688 : varName = varName->next();
7256 : else
7257 3360 : --typelen;
7258 237047 : if (isCPP() && Token::Match(varName, "public:|private:|protected:|using"))
7259 5 : continue;
7260 : //skip all the pointer part
7261 237046 : bool isPointerOrRef = false;
7262 252362 : while (Token::simpleMatch(varName, "*") || Token::Match(varName, "& %name% ,")) {
7263 15316 : isPointerOrRef = true;
7264 15316 : varName = varName->next();
7265 : }
7266 :
7267 241983 : while (Token::Match(varName, "%type% %type%")) {
7268 4936 : if (varName->str() != "const" && varName->str() != "volatile") {
7269 4799 : ++typelen;
7270 : }
7271 4936 : varName = varName->next();
7272 : }
7273 : // Function pointer
7274 237048 : if (Token::simpleMatch(varName, "( *") &&
7275 237216 : Token::Match(varName->link()->previous(), "%name% ) (") &&
7276 170 : Token::simpleMatch(varName->link()->linkAt(1), ") =")) {
7277 18 : Token *endDecl = varName->link()->linkAt(1);
7278 18 : varName = varName->link()->previous();
7279 18 : endDecl->insertToken(";");
7280 18 : endDecl = endDecl->next();
7281 18 : endDecl->next()->isSplittedVarDeclEq(true);
7282 18 : endDecl->insertToken(varName->str());
7283 18 : endDecl->next()->setMacroName(varName->getMacroName());
7284 18 : continue;
7285 : }
7286 : //non-VLA case
7287 237028 : if (Token::Match(varName, "%name% ,|=")) {
7288 10174 : if (varName->str() != "operator") {
7289 10163 : tok2 = varName->next(); // The ',' or '=' token
7290 :
7291 10163 : if (tok2->str() == "=" && (isstatic || (isconst && !isPointerOrRef))) {
7292 : //do not split const non-pointer variables..
7293 4094 : while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7294 3177 : if (Token::Match(tok2, "{|(|["))
7295 472 : tok2 = tok2->link();
7296 3177 : const Token *tok3 = tok2;
7297 3177 : if (!isC() && tok2->str() == "<" && TemplateSimplifier::templateParameters(tok2) > 0) {
7298 24 : tok2 = tok2->findClosingBracket();
7299 : }
7300 3177 : if (!tok2)
7301 0 : syntaxError(tok3); // #6881 invalid code
7302 3177 : tok2 = tok2->next();
7303 : }
7304 917 : if (tok2 && tok2->str() == ";")
7305 876 : tok2 = nullptr;
7306 : }
7307 : } else
7308 11 : tok2 = nullptr;
7309 : }
7310 :
7311 : //VLA case
7312 226855 : else if (Token::Match(varName, "%name% [")) {
7313 4098 : tok2 = varName->next();
7314 :
7315 5499 : while (Token::Match(tok2->link(), "] ,|=|["))
7316 1401 : tok2 = tok2->link()->next();
7317 4098 : if (!Token::Match(tok2, "=|,"))
7318 2894 : tok2 = nullptr;
7319 4098 : if (tok2 && tok2->str() == "=") {
7320 3515 : while (tok2 && tok2->str() != "," && tok2->str() != ";") {
7321 2348 : if (Token::Match(tok2, "{|(|["))
7322 815 : tok2 = tok2->link();
7323 2348 : tok2 = tok2->next();
7324 : }
7325 1167 : if (tok2 && tok2->str() == ";")
7326 1154 : tok2 = nullptr;
7327 : }
7328 : }
7329 :
7330 : // brace initialization
7331 222756 : else if (Token::Match(varName, "%name% {")) {
7332 1629 : tok2 = varName->next();
7333 1629 : tok2 = tok2->link();
7334 1629 : if (tok2)
7335 1629 : tok2 = tok2->next();
7336 1629 : if (tok2 && tok2->str() != ",")
7337 1614 : tok2 = nullptr;
7338 : }
7339 :
7340 : // function declaration
7341 221127 : else if (Token::Match(varName, "%name% (")) {
7342 60232 : Token* commaTok = varName->linkAt(1)->next();
7343 61286 : while (Token::Match(commaTok, "const|noexcept|override|final")) {
7344 1053 : commaTok = commaTok->next();
7345 1053 : if (Token::Match(commaTok, "( true|false )"))
7346 104 : commaTok = commaTok->link()->next();
7347 : }
7348 60232 : tok2 = Token::simpleMatch(commaTok, ",") ? commaTok : nullptr;
7349 : }
7350 :
7351 : else
7352 160896 : tok2 = nullptr;
7353 : } else {
7354 1239 : tok2 = nullptr;
7355 : }
7356 :
7357 238268 : if (!tok2) {
7358 228921 : if (only_k_r_fpar)
7359 378 : finishedwithkr = false;
7360 228921 : continue;
7361 : }
7362 :
7363 9347 : if (tok2->str() == ",") {
7364 2060 : tok2->str(";");
7365 2060 : tok2->isSplittedVarDeclComma(true);
7366 : //TODO: should we have to add also template '<>' links?
7367 2060 : TokenList::insertTokens(tok2, type0, typelen);
7368 : }
7369 :
7370 : else {
7371 7287 : Token *eq = tok2;
7372 :
7373 30099 : while (tok2) {
7374 30052 : if (Token::Match(tok2, "{|(|["))
7375 4811 : tok2 = tok2->link();
7376 :
7377 25240 : else if (!isC() && tok2->str() == "<" && ((tok2->previous()->isName() && !tok2->previous()->varId()) || tok2->strAt(-1) == "]"))
7378 156 : tok2 = tok2->findClosingBracket();
7379 :
7380 25085 : else if (std::strchr(";,", tok2->str()[0])) {
7381 : // "type var =" => "type var; var ="
7382 7241 : const Token *varTok = type0->tokAt(typelen);
7383 9213 : while (Token::Match(varTok, "%name%|*|& %name%|*|&"))
7384 1972 : varTok = varTok->next();
7385 7241 : if (!varTok)
7386 0 : syntaxError(tok2); // invalid code
7387 7241 : TokenList::insertTokens(eq, varTok, 2);
7388 7242 : eq->str(";");
7389 7241 : eq->isSplittedVarDeclEq(true);
7390 :
7391 : // "= x, " => "= x; type "
7392 7241 : if (tok2->str() == ",") {
7393 65 : tok2->str(";");
7394 65 : tok2->isSplittedVarDeclComma(true);
7395 65 : TokenList::insertTokens(tok2, type0, typelen);
7396 : }
7397 7241 : break;
7398 : }
7399 22811 : if (tok2)
7400 22782 : tok2 = tok2->next();
7401 : }
7402 : }
7403 9346 : finishedwithkr = (only_k_r_fpar && tok2 && tok2->strAt(1) == "{");
7404 : }
7405 68254 : }
7406 :
7407 22642 : void Tokenizer::simplifyStaticConst()
7408 : {
7409 : // This function will simplify the token list so that the qualifiers "extern", "static"
7410 : // and "const" appear in the same order as in the array below.
7411 158476 : const std::string qualifiers[] = {"extern", "static", "const"};
7412 :
7413 : // Move 'const' before all other qualifiers and types and then
7414 : // move 'static' before all other qualifiers and types, ...
7415 1021842 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7416 999201 : bool continue2 = false;
7417 3996513 : for (int i = 0; i < sizeof(qualifiers)/sizeof(qualifiers[0]); i++) {
7418 :
7419 : // Keep searching for a qualifier
7420 2997358 : if (!tok->next() || tok->next()->str() != qualifiers[i])
7421 2988367 : continue;
7422 :
7423 : // Look backwards to find the beginning of the declaration
7424 8990 : Token* leftTok = tok;
7425 8990 : bool behindOther = false;
7426 9302 : for (; leftTok; leftTok = leftTok->previous()) {
7427 36357 : for (int j = 0; j <= i; j++) {
7428 27170 : if (leftTok->str() == qualifiers[j]) {
7429 104 : behindOther = true;
7430 104 : break;
7431 : }
7432 : }
7433 9291 : if (behindOther)
7434 104 : break;
7435 9187 : if (isCPP() && Token::simpleMatch(leftTok, ">")) {
7436 50 : Token* opening = leftTok->findOpeningBracket();
7437 50 : if (opening) {
7438 50 : leftTok = opening;
7439 50 : continue;
7440 : }
7441 : }
7442 9491 : if (!Token::Match(leftTok, "%type%|struct|::") ||
7443 354 : (isCPP() && Token::Match(leftTok, "private:|protected:|public:|operator|template"))) {
7444 8875 : break;
7445 : }
7446 : }
7447 :
7448 : // The token preceding the declaration should indicate the start of a declaration
7449 8992 : if (leftTok == tok)
7450 8804 : continue;
7451 :
7452 188 : if (leftTok && !behindOther && !Token::Match(leftTok, ";|{|}|(|,|private:|protected:|public:")) {
7453 47 : continue2 = true;
7454 47 : break;
7455 : }
7456 :
7457 : // Move the qualifier to the left-most position in the declaration
7458 141 : tok->deleteNext();
7459 141 : if (!leftTok) {
7460 13 : list.front()->insertToken(qualifiers[i]);
7461 13 : list.front()->swapWithNext();
7462 13 : tok = list.front();
7463 128 : } else if (leftTok->next()) {
7464 128 : leftTok->next()->insertTokenBefore(qualifiers[i]);
7465 128 : tok = leftTok->next();
7466 : } else {
7467 0 : leftTok->insertToken(qualifiers[i]);
7468 0 : tok = leftTok;
7469 : }
7470 : }
7471 999202 : if (continue2)
7472 47 : continue;
7473 : }
7474 22638 : }
7475 :
7476 22638 : void Tokenizer::simplifyVariableMultipleAssign()
7477 : {
7478 1013689 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7479 991055 : if (Token::Match(tok, "%name% = %name% = %num%|%name% ;")) {
7480 : // skip intermediate assignments
7481 11 : Token *tok2 = tok->previous();
7482 24 : while (tok2 &&
7483 49 : tok2->str() == "=" &&
7484 14 : Token::Match(tok2->previous(), "%name%")) {
7485 14 : tok2 = tok2->tokAt(-2);
7486 : }
7487 :
7488 11 : if (!tok2 || tok2->str() != ";") {
7489 6 : continue;
7490 : }
7491 :
7492 5 : Token *stopAt = tok->tokAt(2);
7493 5 : const Token *valueTok = stopAt->tokAt(2);
7494 5 : const std::string& value(valueTok->str());
7495 5 : tok2 = tok2->next();
7496 :
7497 23 : while (tok2 != stopAt) {
7498 18 : tok2->next()->insertToken(";");
7499 18 : tok2->next()->insertToken(value);
7500 18 : tok2 = tok2->tokAt(4);
7501 : }
7502 : }
7503 : }
7504 22641 : }
7505 :
7506 : // Binary operators simplification map
7507 : static const std::unordered_map<std::string, std::string> cAlternativeTokens = {
7508 : std::make_pair("and", "&&")
7509 : , std::make_pair("and_eq", "&=")
7510 : , std::make_pair("bitand", "&")
7511 : , std::make_pair("bitor", "|")
7512 : , std::make_pair("not_eq", "!=")
7513 : , std::make_pair("or", "||")
7514 : , std::make_pair("or_eq", "|=")
7515 : , std::make_pair("xor", "^")
7516 : , std::make_pair("xor_eq", "^=")
7517 : };
7518 :
7519 : // Simplify the C alternative tokens:
7520 : // and => &&
7521 : // and_eq => &=
7522 : // bitand => &
7523 : // bitor => |
7524 : // compl => ~
7525 : // not => !
7526 : // not_eq => !=
7527 : // or => ||
7528 : // or_eq => |=
7529 : // xor => ^
7530 : // xor_eq => ^=
7531 23229 : bool Tokenizer::simplifyCAlternativeTokens()
7532 : {
7533 : /* executable scope level */
7534 23229 : int executableScopeLevel = 0;
7535 :
7536 46456 : std::vector<Token *> alt;
7537 23229 : bool replaceAll = false; // replace all or none
7538 :
7539 979694 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7540 956469 : if (tok->str() == ")") {
7541 107715 : if (const Token *end = isFunctionHead(tok, "{")) {
7542 37618 : ++executableScopeLevel;
7543 37618 : tok = const_cast<Token *>(end);
7544 557175 : continue;
7545 : }
7546 : }
7547 :
7548 918848 : if (tok->str() == "{") {
7549 9314 : if (executableScopeLevel > 0)
7550 2220 : ++executableScopeLevel;
7551 9314 : continue;
7552 : }
7553 :
7554 909535 : if (tok->str() == "}") {
7555 46927 : if (executableScopeLevel > 0)
7556 39833 : --executableScopeLevel;
7557 46927 : continue;
7558 : }
7559 :
7560 862602 : if (!tok->isName())
7561 463297 : continue;
7562 :
7563 399307 : const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7564 399311 : if (cOpIt != cAlternativeTokens.end()) {
7565 44 : alt.push_back(tok);
7566 :
7567 : // Is this a variable declaration..
7568 44 : if (isC() && Token::Match(tok->previous(), "%type%|* %name% [;,=]"))
7569 1 : return false;
7570 :
7571 43 : if (!Token::Match(tok->previous(), "%name%|%num%|%char%|)|]|> %name% %name%|%num%|%char%|%op%|("))
7572 5 : continue;
7573 38 : if (Token::Match(tok->next(), "%assign%|%or%|%oror%|&&|*|/|%|^") && !Token::Match(tok->previous(), "%num%|%char%|) %name% *"))
7574 1 : continue;
7575 37 : if (executableScopeLevel == 0 && Token::Match(tok, "%name% (")) {
7576 1 : const Token *start = tok;
7577 3 : while (Token::Match(start, "%name%|*"))
7578 2 : start = start->previous();
7579 1 : if (!start || Token::Match(start, "[;}]"))
7580 1 : continue;
7581 : }
7582 36 : replaceAll = true;
7583 399264 : } else if (Token::Match(tok, "not|compl")) {
7584 28 : alt.push_back(tok);
7585 :
7586 28 : if ((Token::Match(tok->previous(), "%assign%") || Token::Match(tok->next(), "%num%")) && !Token::Match(tok->next(), ".|->")) {
7587 2 : replaceAll = true;
7588 2 : continue;
7589 : }
7590 :
7591 : // Don't simplify 'not p;' (in case 'not' is a type)
7592 26 : if (!Token::Match(tok->next(), "%name%|(") ||
7593 30 : Token::Match(tok->previous(), "[;{}]") ||
7594 4 : (executableScopeLevel == 0U && tok->strAt(-1) == "("))
7595 10 : continue;
7596 :
7597 16 : replaceAll = true;
7598 : }
7599 : }
7600 :
7601 23226 : if (!replaceAll)
7602 23179 : return false;
7603 :
7604 101 : for (Token *tok: alt) {
7605 54 : const std::unordered_map<std::string, std::string>::const_iterator cOpIt = cAlternativeTokens.find(tok->str());
7606 54 : if (cOpIt != cAlternativeTokens.end())
7607 36 : tok->str(cOpIt->second);
7608 18 : else if (tok->str() == "not")
7609 15 : tok->str("!");
7610 : else
7611 3 : tok->str("~");
7612 : }
7613 :
7614 47 : return !alt.empty();
7615 : }
7616 :
7617 : // int i(0); => int i; i = 0;
7618 : // int i(0), j; => int i; i = 0; int j;
7619 67931 : void Tokenizer::simplifyInitVar()
7620 : {
7621 67931 : if (isC())
7622 17767 : return;
7623 :
7624 2233150 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7625 2182975 : if (!tok->isName() || (tok->previous() && !Token::Match(tok->previous(), "[;{}]")))
7626 1917162 : continue;
7627 :
7628 265826 : if (tok->str() == "return")
7629 20076 : continue;
7630 :
7631 245751 : if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ;")) {
7632 2311 : tok = initVar(tok);
7633 243438 : } else if (Token::Match(tok, "%type% *| %name% ( %type% (")) {
7634 210 : const Token* tok2 = tok->tokAt(2);
7635 210 : if (!tok2->link())
7636 3 : tok2 = tok2->next();
7637 210 : if (!tok2->link() || (tok2->link()->strAt(1) == ";" && !Token::simpleMatch(tok2->linkAt(2), ") (")))
7638 130 : tok = initVar(tok);
7639 243230 : } else if (Token::Match(tok, "class|struct|union| %type% *| %name% ( &| %any% ) ,") && tok->str() != "new") {
7640 4 : Token *tok1 = tok->tokAt(5);
7641 5 : while (tok1->str() != ",")
7642 1 : tok1 = tok1->next();
7643 4 : tok1->str(";");
7644 :
7645 4 : const int numTokens = (Token::Match(tok, "class|struct|union")) ? 2U : 1U;
7646 4 : TokenList::insertTokens(tok1, tok, numTokens);
7647 4 : tok = initVar(tok);
7648 : }
7649 : }
7650 : }
7651 :
7652 2445 : Token * Tokenizer::initVar(Token * tok)
7653 : {
7654 : // call constructor of class => no simplification
7655 2445 : if (Token::Match(tok, "class|struct|union")) {
7656 9 : if (tok->strAt(2) != "*")
7657 6 : return tok;
7658 :
7659 3 : tok = tok->next();
7660 2436 : } else if (!tok->isStandardType() && tok->str() != "auto" && tok->next()->str() != "*")
7661 1597 : return tok;
7662 :
7663 : // goto variable name..
7664 842 : tok = tok->next();
7665 842 : if (tok->str() == "*")
7666 63 : tok = tok->next();
7667 :
7668 : // sizeof is not a variable name..
7669 842 : if (tok->str() == "sizeof")
7670 3 : return tok;
7671 :
7672 : // check initializer..
7673 839 : if (tok->tokAt(2)->isStandardType() || tok->strAt(2) == "void")
7674 701 : return tok;
7675 138 : if (!tok->tokAt(2)->isNumber() && !Token::Match(tok->tokAt(2), "%type% (") && tok->strAt(2) != "&" && tok->tokAt(2)->varId() == 0)
7676 91 : return tok;
7677 :
7678 : // insert '; var ='
7679 47 : tok->insertToken(";");
7680 47 : tok->next()->insertToken(tok->str());
7681 47 : tok->tokAt(2)->varId(tok->varId());
7682 47 : tok = tok->tokAt(2);
7683 47 : tok->insertToken("=");
7684 :
7685 : // goto '('..
7686 47 : tok = tok->tokAt(2);
7687 :
7688 : // delete ')'
7689 47 : tok->link()->deleteThis();
7690 :
7691 : // delete this
7692 47 : tok->deleteThis();
7693 :
7694 47 : return tok;
7695 : }
7696 :
7697 22638 : void Tokenizer::elseif()
7698 : {
7699 1014449 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7700 991818 : if (tok->str() != "else")
7701 989314 : continue;
7702 :
7703 2497 : if (!Token::Match(tok->previous(), ";|}"))
7704 0 : syntaxError(tok->previous());
7705 :
7706 2497 : if (!Token::Match(tok->next(), "%name%"))
7707 388 : continue;
7708 :
7709 2109 : if (tok->strAt(1) != "if")
7710 0 : unknownMacroError(tok->next());
7711 :
7712 8004558 : for (Token *tok2 = tok; tok2; tok2 = tok2->next()) {
7713 8004558 : if (Token::Match(tok2, "(|{|["))
7714 4002279 : tok2 = tok2->link();
7715 :
7716 8004558 : if (Token::Match(tok2, "}|;")) {
7717 2001156 : if (tok2->next() && tok2->next()->str() != "else") {
7718 2109 : tok->insertToken("{");
7719 2109 : tok2->insertToken("}");
7720 2109 : Token::createMutualLinks(tok->next(), tok2->next());
7721 2109 : break;
7722 : }
7723 : }
7724 : }
7725 : }
7726 22638 : }
7727 :
7728 :
7729 22627 : void Tokenizer::simplifyIfSwitchForInit()
7730 : {
7731 22627 : if (!isCPP() || mSettings.standards.cpp < Standards::CPP17)
7732 7172 : return;
7733 :
7734 15455 : const bool forInit = (mSettings.standards.cpp >= Standards::CPP20);
7735 :
7736 652714 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7737 637261 : if (!Token::Match(tok, "if|switch|for ("))
7738 632085 : continue;
7739 :
7740 5174 : Token *semicolon = tok->tokAt(2);
7741 25011 : while (!Token::Match(semicolon, "[;)]")) {
7742 19837 : if (Token::Match(semicolon, "(|{|[") && semicolon->link())
7743 1891 : semicolon = semicolon->link();
7744 19837 : semicolon = semicolon->next();
7745 : }
7746 5174 : if (semicolon->str() != ";")
7747 4453 : continue;
7748 :
7749 721 : if (tok->str() == "for") {
7750 713 : if (!forInit)
7751 0 : continue;
7752 :
7753 : // Is it a for range..
7754 713 : const Token *tok2 = semicolon->next();
7755 713 : bool rangeFor = false;
7756 3451 : while (!Token::Match(tok2, "[;)]")) {
7757 2742 : if (tok2->str() == "(")
7758 259 : tok2 = tok2->link();
7759 2483 : else if (!rangeFor && tok2->str() == "?")
7760 4 : break;
7761 2479 : else if (tok2->str() == ":")
7762 1 : rangeFor = true;
7763 2738 : tok2 = tok2->next();
7764 : }
7765 713 : if (!rangeFor || tok2->str() != ")")
7766 712 : continue;
7767 : }
7768 :
7769 9 : Token *endpar = tok->linkAt(1);
7770 9 : if (!Token::simpleMatch(endpar, ") {"))
7771 0 : continue;
7772 :
7773 9 : Token *endscope = endpar->linkAt(1);
7774 9 : if (Token::simpleMatch(endscope, "} else {"))
7775 2 : endscope = endscope->linkAt(2);
7776 :
7777 : // Simplify, the initialization expression is broken out..
7778 9 : semicolon->insertToken(tok->str());
7779 9 : semicolon->next()->insertToken("(");
7780 9 : Token::createMutualLinks(semicolon->next()->next(), endpar);
7781 9 : tok->deleteNext();
7782 9 : tok->str("{");
7783 9 : endscope->insertToken("}");
7784 9 : Token::createMutualLinks(tok, endscope->next());
7785 9 : tok->isSimplifiedScope(true);
7786 : }
7787 : }
7788 :
7789 :
7790 22641 : bool Tokenizer::simplifyRedundantParentheses()
7791 : {
7792 22641 : bool ret = false;
7793 1005208 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7794 982565 : if (tok->str() != "(")
7795 876035 : continue;
7796 :
7797 106531 : if (tok->isCpp() && Token::simpleMatch(tok->previous(), "} (")) {
7798 39 : const Token* plp = tok->previous()->link()->previous();
7799 39 : if (Token::Match(plp, "%name%|>|] {") || (Token::simpleMatch(plp, ")") && Token::simpleMatch(plp->link()->previous(), "]")))
7800 25 : continue;
7801 : }
7802 :
7803 106506 : if (Token::simpleMatch(tok, "( {"))
7804 43 : continue;
7805 :
7806 106467 : if (Token::Match(tok->link(), ") %num%")) {
7807 2092 : tok = tok->link();
7808 2092 : continue;
7809 : }
7810 :
7811 : // Do not simplify if there is comma inside parentheses..
7812 104375 : if (Token::Match(tok->previous(), "%op% (") || Token::Match(tok->link(), ") %op%")) {
7813 6199 : bool innerComma = false;
7814 18328 : for (const Token *inner = tok->link()->previous(); inner != tok; inner = inner->previous()) {
7815 12352 : if (inner->str() == ")")
7816 2841 : inner = inner->link();
7817 12350 : if (inner->str() == ",") {
7818 220 : innerComma = true;
7819 220 : break;
7820 : }
7821 : }
7822 6196 : if (innerComma)
7823 220 : continue;
7824 : }
7825 :
7826 : // !!operator = ( x ) ;
7827 208299 : if (tok->strAt(-2) != "operator" &&
7828 208864 : tok->previous() && tok->previous()->str() == "=" &&
7829 209490 : tok->next() && tok->next()->str() != "{" &&
7830 597 : Token::simpleMatch(tok->link(), ") ;")) {
7831 149 : tok->link()->deleteThis();
7832 149 : tok->deleteThis();
7833 149 : continue;
7834 : }
7835 :
7836 106902 : while (Token::simpleMatch(tok, "( (") &&
7837 106902 : tok->link() && tok->link()->previous() == tok->next()->link()) {
7838 : // We have "(( *something* ))", remove the inner
7839 : // parentheses
7840 75 : tok->deleteNext();
7841 75 : tok->link()->tokAt(-2)->deleteNext();
7842 75 : ret = true;
7843 : }
7844 :
7845 104000 : if (isCPP() && Token::Match(tok->tokAt(-2), "[;{}=(] new (") && Token::Match(tok->link(), ") [;,{}[]")) {
7846 : // Remove the parentheses in "new (type)" constructs
7847 5 : tok->link()->deleteThis();
7848 5 : tok->deleteThis();
7849 5 : ret = true;
7850 : }
7851 :
7852 104001 : if (Token::Match(tok->previous(), "! ( %name% )")) {
7853 : // Remove the parentheses
7854 17 : tok->deleteThis();
7855 17 : tok->deleteNext();
7856 17 : ret = true;
7857 : }
7858 :
7859 104001 : if (Token::Match(tok->previous(), "[(,;{}] ( %name% ) .")) {
7860 : // Remove the parentheses
7861 11 : tok->deleteThis();
7862 11 : tok->deleteNext();
7863 11 : ret = true;
7864 : }
7865 :
7866 104065 : if (Token::Match(tok->previous(), "[(,;{}] ( %name% (") && !tok->next()->isKeyword() &&
7867 63 : tok->link()->previous() == tok->linkAt(2)) {
7868 : // We have "( func ( *something* ))", remove the outer
7869 : // parentheses
7870 6 : tok->link()->deleteThis();
7871 6 : tok->deleteThis();
7872 6 : ret = true;
7873 : }
7874 :
7875 104003 : if (Token::Match(tok->previous(), "[,;{}] ( delete [| ]| %name% ) ;")) {
7876 : // We have "( delete [| ]| var )", remove the outer
7877 : // parentheses
7878 2 : tok->link()->deleteThis();
7879 2 : tok->deleteThis();
7880 2 : ret = true;
7881 : }
7882 :
7883 104002 : if (!Token::simpleMatch(tok->tokAt(-2), "operator delete") &&
7884 112195 : Token::Match(tok->previous(), "delete|; (") &&
7885 216198 : (tok->previous()->str() != "delete" || tok->next()->varId() > 0) &&
7886 8185 : Token::Match(tok->link(), ") ;|,")) {
7887 24 : tok->link()->deleteThis();
7888 24 : tok->deleteThis();
7889 24 : ret = true;
7890 : }
7891 :
7892 113258 : if (Token::Match(tok->previous(), "[(!*;{}] ( %name% )") &&
7893 113259 : (tok->next()->varId() != 0 || Token::Match(tok->tokAt(3), "[+-/=]")) && !tok->next()->isStandardType()) {
7894 : // We have "( var )", remove the parentheses
7895 6 : tok->deleteThis();
7896 6 : tok->deleteNext();
7897 6 : ret = true;
7898 : }
7899 :
7900 104011 : while (Token::Match(tok->previous(), "[;{}[(,!*] ( %name% .")) {
7901 45 : Token *tok2 = tok->tokAt(2);
7902 86 : while (Token::Match(tok2, ". %name%")) {
7903 41 : tok2 = tok2->tokAt(2);
7904 : }
7905 45 : if (tok2 != tok->link())
7906 38 : break;
7907 : // We have "( var . var . ... . var )", remove the parentheses
7908 7 : tok = tok->previous();
7909 7 : tok->deleteNext();
7910 7 : tok2->deleteThis();
7911 7 : ret = true;
7912 : }
7913 :
7914 104445 : while (Token::Match(tok->previous(), "[{([,] ( !!{") &&
7915 2150 : Token::Match(tok->link(), ") [;,])]") &&
7916 107042 : !Token::simpleMatch(tok->tokAt(-2), "operator ,") && // Ticket #5709
7917 446 : !Token::findsimplematch(tok, ",", tok->link())) {
7918 : // We have "( ... )", remove the parentheses
7919 441 : tok->link()->deleteThis();
7920 441 : tok->deleteThis();
7921 441 : ret = true;
7922 : }
7923 :
7924 104101 : if (Token::simpleMatch(tok->previous(), ", (") &&
7925 96 : Token::simpleMatch(tok->link(), ") =")) {
7926 4 : tok->link()->deleteThis();
7927 4 : tok->deleteThis();
7928 4 : ret = true;
7929 : }
7930 :
7931 : // Simplify "!!operator !!%name%|)|]|>|>> ( %num%|%bool% ) %op%|;|,|)"
7932 106388 : if (Token::Match(tok, "( %bool%|%num% ) %cop%|;|,|)") &&
7933 4766 : tok->strAt(-2) != "operator" &&
7934 2383 : tok->previous() &&
7935 106497 : !Token::Match(tok->previous(), "%name%|)|]") &&
7936 110 : (!(isCPP() && Token::Match(tok->previous(),">|>>")))) {
7937 53 : tok->link()->deleteThis();
7938 53 : tok->deleteThis();
7939 53 : ret = true;
7940 : }
7941 :
7942 104004 : if (Token::Match(tok->previous(), "*|& ( %name% )")) {
7943 : // We may have a variable declaration looking like "type_name *(var_name)"
7944 20 : Token *tok2 = tok->tokAt(-2);
7945 27 : while (Token::Match(tok2, "%type%|static|const|extern") && tok2->str() != "operator") {
7946 7 : tok2 = tok2->previous();
7947 : }
7948 20 : if (tok2 && !Token::Match(tok2, "[;,{]")) {
7949 : // Not a variable declaration
7950 : } else {
7951 5 : tok->deleteThis();
7952 5 : tok->deleteNext();
7953 : }
7954 : }
7955 : }
7956 22636 : return ret;
7957 : }
7958 :
7959 16713 : void Tokenizer::simplifyTypeIntrinsics()
7960 : {
7961 : static const std::unordered_map<std::string, std::string> intrinsics = {
7962 : { "__has_nothrow_assign", "has_nothrow_assign" },
7963 : { "__has_nothrow_constructor", "has_nothrow_constructor" },
7964 : { "__has_nothrow_copy", "has_nothrow_copy" },
7965 : { "__has_trivial_assign", "has_trivial_assign" },
7966 : { "__has_trivial_constructor", "has_trivial_constructor" },
7967 : { "__has_trivial_copy", "has_trivial_copy" },
7968 : { "__has_trivial_destructor", "has_trivial_destructor" },
7969 : { "__has_virtual_destructor", "has_virtual_destructor" },
7970 : { "__is_abstract", "is_abstract" },
7971 : { "__is_aggregate", "is_aggregate" },
7972 : { "__is_assignable", "is_assignable" },
7973 : { "__is_base_of", "is_base_of" },
7974 : { "__is_class", "is_class" },
7975 : { "__is_constructible", "is_constructible" },
7976 : { "__is_convertible_to", "is_convertible_to" },
7977 : { "__is_destructible", "is_destructible" },
7978 : { "__is_empty", "is_empty" },
7979 : { "__is_enum", "is_enum" },
7980 : { "__is_final", "is_final" },
7981 : { "__is_nothrow_assignable", "is_nothrow_assignable" },
7982 : { "__is_nothrow_constructible", "is_nothrow_constructible" },
7983 : { "__is_nothrow_destructible", "is_nothrow_destructible" },
7984 : { "__is_pod", "is_pod" },
7985 : { "__is_polymorphic", "is_polymorphic" },
7986 : { "__is_trivially_assignable", "is_trivially_assignable" },
7987 : { "__is_trivially_constructible", "is_trivially_constructible" },
7988 : { "__is_union", "is_union" },
7989 17105 : };
7990 747185 : for (Token *tok = list.front(); tok; tok = tok->next()) {
7991 730469 : if (!Token::Match(tok, "%name% ("))
7992 730461 : continue;
7993 61893 : auto p = intrinsics.find(tok->str());
7994 61896 : if (p == intrinsics.end())
7995 61888 : continue;
7996 11 : Token * end = tok->next()->link();
7997 11 : Token * prev = tok->previous();
7998 11 : tok->str(p->second);
7999 11 : prev->insertToken("::");
8000 11 : prev->insertToken("std");
8001 11 : tok->next()->str("<");
8002 11 : end->str(">");
8003 11 : end->insertToken("}");
8004 11 : end->insertToken("{");
8005 11 : Token::createMutualLinks(end->tokAt(1), end->tokAt(2));
8006 : }
8007 16715 : }
8008 :
8009 : //---------------------------------------------------------------------------
8010 : // Helper functions for handling the tokens list
8011 : //---------------------------------------------------------------------------
8012 :
8013 : //---------------------------------------------------------------------------
8014 :
8015 624 : bool Tokenizer::isScopeNoReturn(const Token *endScopeToken, bool *unknown) const
8016 : {
8017 1248 : std::string unknownFunc;
8018 624 : const bool ret = mSettings.library.isScopeNoReturn(endScopeToken,&unknownFunc);
8019 624 : if (!unknownFunc.empty() && mSettings.summaryReturn.find(unknownFunc) != mSettings.summaryReturn.end()) {
8020 0 : return false;
8021 : }
8022 624 : if (unknown)
8023 452 : *unknown = !unknownFunc.empty();
8024 624 : if (!unknownFunc.empty() && mSettings.checkLibrary) {
8025 38 : bool warn = true;
8026 38 : if (Token::simpleMatch(endScopeToken->tokAt(-2), ") ; }")) {
8027 38 : const Token * const ftok = endScopeToken->linkAt(-2)->previous();
8028 38 : if (ftok && (ftok->type() || ftok->function() || ftok->variable())) // constructor call
8029 23 : warn = false;
8030 : }
8031 :
8032 38 : if (warn) {
8033 15 : reportError(endScopeToken->previous(),
8034 : Severity::information,
8035 : "checkLibraryNoReturn",
8036 30 : "--check-library: Function " + unknownFunc + "() should have <noreturn> configuration");
8037 : }
8038 : }
8039 624 : return ret;
8040 : }
8041 :
8042 : //---------------------------------------------------------------------------
8043 :
8044 575 : void Tokenizer::syntaxError(const Token *tok, const std::string &code) const
8045 : {
8046 575 : printDebugOutput(0);
8047 1069 : throw InternalError(tok, code.empty() ? "syntax error" : "syntax error: " + code, InternalError::SYNTAX);
8048 : }
8049 :
8050 22 : void Tokenizer::unmatchedToken(const Token *tok) const
8051 : {
8052 22 : printDebugOutput(0);
8053 22 : throw InternalError(tok,
8054 44 : "Unmatched '" + tok->str() + "'. Configuration: '" + mConfiguration + "'.",
8055 44 : InternalError::SYNTAX);
8056 : }
8057 :
8058 38 : void Tokenizer::syntaxErrorC(const Token *tok, const std::string &what) const
8059 : {
8060 38 : printDebugOutput(0);
8061 38 : throw InternalError(tok, "Code '"+what+"' is invalid C code. Use --std or --language to configure the language.", InternalError::SYNTAX);
8062 : }
8063 :
8064 44 : void Tokenizer::unknownMacroError(const Token *tok1) const
8065 : {
8066 44 : printDebugOutput(0);
8067 44 : 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);
8068 : }
8069 :
8070 1 : void Tokenizer::unhandled_macro_class_x_y(const Token *tok) const
8071 : {
8072 1 : reportError(tok,
8073 : Severity::information,
8074 : "class_X_Y",
8075 0 : "The code '" +
8076 2 : tok->str() + " " +
8077 3 : tok->strAt(1) + " " +
8078 3 : tok->strAt(2) + " " +
8079 3 : tok->strAt(3) + "' is not handled. You can use -I or --include to add handling of this code.");
8080 1 : }
8081 :
8082 0 : void Tokenizer::macroWithSemicolonError(const Token *tok, const std::string ¯oName) const
8083 : {
8084 0 : reportError(tok,
8085 : Severity::information,
8086 : "macroWithSemicolon",
8087 0 : "Ensure that '" + macroName + "' is defined either using -I, --include or -D.");
8088 0 : }
8089 :
8090 1 : void Tokenizer::cppcheckError(const Token *tok) const
8091 : {
8092 1 : printDebugOutput(0);
8093 1 : throw InternalError(tok, "Analysis failed. If the code is valid then please report this failure.", InternalError::INTERNAL);
8094 : }
8095 :
8096 0 : void Tokenizer::unhandledCharLiteral(const Token *tok, const std::string& msg) const
8097 : {
8098 0 : std::string s = tok ? (" " + tok->str()) : "";
8099 0 : for (int i = 0; i < s.size(); ++i) {
8100 0 : if ((unsigned char)s[i] >= 0x80)
8101 0 : s.clear();
8102 : }
8103 :
8104 0 : reportError(tok,
8105 : Severity::portability,
8106 : "nonStandardCharLiteral",
8107 0 : "Non-standard character literal" + s + ". " + msg);
8108 0 : }
8109 :
8110 : /**
8111 : * Helper function to check whether number is equal to integer constant X
8112 : * or floating point pattern X.0
8113 : * @param s the string to check
8114 : * @param intConstant the integer constant to check against
8115 : * @param floatConstant the string with stringified float constant to check against
8116 : * @return true in case s is equal to X or X.0 and false otherwise.
8117 : */
8118 22 : static bool isNumberOneOf(const std::string &s, MathLib::bigint intConstant, const char* floatConstant)
8119 : {
8120 22 : if (MathLib::isInt(s)) {
8121 11 : if (MathLib::toBigNumber(s) == intConstant)
8122 11 : return true;
8123 11 : } else if (MathLib::isFloat(s)) {
8124 9 : if (MathLib::toString(MathLib::toDoubleNumber(s)) == floatConstant)
8125 7 : return true;
8126 : }
8127 4 : return false;
8128 : }
8129 :
8130 : // ------------------------------------------------------------------------
8131 : // Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
8132 : // @param s the string to check
8133 : // @return true in case s is one and false otherwise.
8134 : // ------------------------------------------------------------------------
8135 24 : bool Tokenizer::isOneNumber(const std::string &s)
8136 : {
8137 24 : if (!MathLib::isPositive(s))
8138 2 : return false;
8139 22 : return isNumberOneOf(s, 1L, "1.0");
8140 : }
8141 : // ------------------------------------------------------------------------
8142 22707 : void Tokenizer::checkConfiguration() const
8143 : {
8144 22707 : if (!mSettings.checkConfiguration)
8145 22706 : return;
8146 1 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8147 0 : if (!Token::Match(tok, "%name% ("))
8148 0 : continue;
8149 0 : if (tok->isControlFlowKeyword())
8150 0 : continue;
8151 0 : for (const Token *tok2 = tok->tokAt(2); tok2 && tok2->str() != ")"; tok2 = tok2->next()) {
8152 0 : if (tok2->str() == ";") {
8153 0 : macroWithSemicolonError(tok, tok->str());
8154 0 : break;
8155 : }
8156 0 : if (Token::Match(tok2, "(|{"))
8157 0 : tok2 = tok2->link();
8158 : }
8159 : }
8160 : }
8161 :
8162 23289 : void Tokenizer::validateC() const
8163 : {
8164 23289 : if (isCPP())
8165 17106 : return;
8166 271318 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8167 : // That might trigger false positives, but it's much faster to have this truncated pattern
8168 265170 : if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
8169 4 : syntaxErrorC(tok, "C++ cast <...");
8170 : // Template function..
8171 265168 : if (Token::Match(tok, "%name% < %name% > (")) {
8172 6 : const Token *tok2 = tok->tokAt(5);
8173 6 : while (tok2 && !Token::Match(tok2, "[()]"))
8174 0 : tok2 = tok2->next();
8175 6 : if (Token::simpleMatch(tok2, ") {"))
8176 4 : syntaxErrorC(tok, tok->str() + '<' + tok->strAt(2) + ">() {}");
8177 : }
8178 265167 : if (tok->previous() && !Token::Match(tok->previous(), "[;{}]"))
8179 215209 : continue;
8180 49958 : if (Token::Match(tok, "using namespace %name% ;"))
8181 2 : syntaxErrorC(tok, "using namespace " + tok->strAt(2));
8182 49957 : if (Token::Match(tok, "template < class|typename %name% [,>]"))
8183 18 : syntaxErrorC(tok, "template<...");
8184 49948 : if (Token::Match(tok, "%name% :: %name%"))
8185 15 : syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8186 49943 : if (Token::Match(tok, "class|namespace %name% [:{]"))
8187 32 : syntaxErrorC(tok, tok->str() + tok->strAt(1) + tok->strAt(2));
8188 : }
8189 : }
8190 :
8191 146740 : void Tokenizer::validate() const
8192 : {
8193 293471 : std::stack<const Token *> linkTokens;
8194 146747 : const Token *lastTok = nullptr;
8195 6552966 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8196 6406185 : lastTok = tok;
8197 6406185 : if (Token::Match(tok, "[{([]") || (tok->str() == "<" && tok->link())) {
8198 1038143 : if (tok->link() == nullptr)
8199 0 : cppcheckError(tok);
8200 :
8201 1038143 : linkTokens.push(tok);
8202 : }
8203 :
8204 5368051 : else if (Token::Match(tok, "[})]]") || (Token::Match(tok, ">|>>") && tok->link())) {
8205 1038112 : if (tok->link() == nullptr)
8206 0 : cppcheckError(tok);
8207 :
8208 1038112 : if (linkTokens.empty())
8209 0 : cppcheckError(tok);
8210 :
8211 1038111 : if (tok->link() != linkTokens.top())
8212 0 : cppcheckError(tok);
8213 :
8214 1038135 : if (tok != tok->link()->link())
8215 0 : cppcheckError(tok);
8216 :
8217 1038122 : linkTokens.pop();
8218 : }
8219 :
8220 4329849 : else if (tok->link() != nullptr)
8221 0 : cppcheckError(tok);
8222 : }
8223 :
8224 146731 : if (!linkTokens.empty())
8225 0 : cppcheckError(linkTokens.top());
8226 :
8227 : // Validate that the Tokenizer::list.back() is updated correctly during simplifications
8228 146731 : if (lastTok != list.back())
8229 0 : cppcheckError(lastTok);
8230 146743 : }
8231 :
8232 61345 : static const Token *findUnmatchedTernaryOp(const Token * const begin, const Token * const end, int depth = 0)
8233 : {
8234 122688 : std::stack<const Token *> ternaryOp;
8235 389369 : for (const Token *tok = begin; tok != end && tok->str() != ";"; tok = tok->next()) {
8236 328046 : if (tok->str() == "?")
8237 349 : ternaryOp.push(tok);
8238 327695 : else if (!ternaryOp.empty() && tok->str() == ":")
8239 321 : ternaryOp.pop();
8240 327374 : else if (depth < 100 && Token::Match(tok,"(|[")) {
8241 38543 : const Token *inner = findUnmatchedTernaryOp(tok->next(), tok->link(), depth+1);
8242 38542 : if (inner)
8243 22 : return inner;
8244 38520 : tok = tok->link();
8245 : }
8246 : }
8247 61320 : return ternaryOp.empty() ? nullptr : ternaryOp.top();
8248 : }
8249 :
8250 1714591 : static bool isCPPAttribute(const Token * tok)
8251 : {
8252 1714591 : return Token::simpleMatch(tok, "[ [") && tok->link() && tok->link()->previous() == tok->linkAt(1);
8253 : }
8254 :
8255 1714199 : static bool isAlignAttribute(const Token * tok)
8256 : {
8257 1714199 : return Token::simpleMatch(tok, "alignas (") && tok->next()->link();
8258 : }
8259 :
8260 : template<typename T>
8261 192 : static T* skipCPPOrAlignAttribute(T * tok)
8262 : {
8263 192 : if (isCPPAttribute(tok))
8264 180 : return tok->link();
8265 12 : if (isAlignAttribute(tok)) {
8266 12 : return tok->next()->link();
8267 : }
8268 0 : return tok;
8269 : }
8270 :
8271 88540 : static bool isNonMacro(const Token* tok)
8272 : {
8273 88540 : if (tok->isKeyword() || tok->isStandardType())
8274 12420 : return true;
8275 76120 : if (cAlternativeTokens.count(tok->str()) > 0)
8276 1 : return true;
8277 76122 : if (startsWith(tok->str(), "__")) // attribute/annotation
8278 70 : return true;
8279 76052 : if (Token::simpleMatch(tok, "alignas ("))
8280 2 : return true;
8281 76050 : return false;
8282 : }
8283 :
8284 22665 : void Tokenizer::reportUnknownMacros() const
8285 : {
8286 : // Report unknown macros used in expressions "%name% %num%"
8287 1024654 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8288 1001989 : if (Token::Match(tok, "%name% %num%")) {
8289 : // A keyword is not an unknown macro
8290 3075 : if (tok->isKeyword())
8291 3074 : continue;
8292 :
8293 1 : if (Token::Match(tok->previous(), "%op%|("))
8294 1 : unknownMacroError(tok);
8295 : }
8296 : }
8297 :
8298 : // Report unknown macros before } "{ .. if (x) MACRO }"
8299 1024652 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8300 1001986 : if (Token::Match(tok, ")|; %name% } !!)")) {
8301 5 : if (tok->link() && !Token::simpleMatch(tok->link()->tokAt(-1), "if"))
8302 2 : continue;
8303 3 : const Token* prev = tok->linkAt(2);
8304 6 : while (Token::simpleMatch(prev, "{"))
8305 3 : prev = prev->previous();
8306 3 : if (Token::Match(prev, ";|)"))
8307 1 : unknownMacroError(tok->next());
8308 : }
8309 : }
8310 :
8311 : // Report unknown macros that contain several statements "MACRO(a;b;c)"
8312 1024648 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8313 1001985 : if (!Token::Match(tok, "%name% ("))
8314 913494 : continue;
8315 88488 : if (!tok->isUpperCaseName())
8316 77143 : continue;
8317 11347 : const Token *endTok = tok->linkAt(1);
8318 63369 : for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8319 52022 : if (Token::Match(inner, "[[({]"))
8320 10057 : inner = inner->link();
8321 41965 : else if (inner->str() == ";")
8322 0 : unknownMacroError(tok);
8323 : }
8324 : }
8325 :
8326 : // Report unknown macros that contain struct initialization "MACRO(a, .b=3)"
8327 1024621 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8328 1001952 : if (!Token::Match(tok, "%name% ("))
8329 913471 : continue;
8330 88484 : const Token *endTok = tok->linkAt(1);
8331 338790 : for (const Token *inner = tok->tokAt(2); inner != endTok; inner = inner->next()) {
8332 250303 : if (Token::Match(inner, "[[({]"))
8333 16741 : inner = inner->link();
8334 233562 : else if (Token::Match(inner->previous(), "[,(] . %name% =|{"))
8335 1 : unknownMacroError(tok);
8336 : }
8337 : }
8338 :
8339 : // Report unknown macros in non-executable scopes..
8340 45327 : std::set<std::string> possible;
8341 406329 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8342 : // Skip executable scopes..
8343 383673 : if (tok->str() == "{") {
8344 35456 : const Token *prev = tok->previous();
8345 47239 : while (prev && prev->isName())
8346 11783 : prev = prev->previous();
8347 35456 : if (prev && prev->str() == ")")
8348 28893 : tok = tok->link();
8349 : else
8350 6563 : possible.clear();
8351 348217 : } else if (tok->str() == "}")
8352 6560 : possible.clear();
8353 :
8354 383673 : if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::simpleMatch(tok->linkAt(1), ") (") && Token::simpleMatch(tok->linkAt(1)->linkAt(1), ") {")) {
8355 : // A keyword is not an unknown macro
8356 2 : if (tok->isKeyword())
8357 0 : continue;
8358 :
8359 2 : const Token *bodyStart = tok->linkAt(1)->linkAt(1)->tokAt(2);
8360 2 : const Token *bodyEnd = tok->link();
8361 2 : for (const Token *tok2 = bodyStart; tok2 && tok2 != bodyEnd; tok2 = tok2->next()) {
8362 2 : if (Token::Match(tok2, "if|switch|for|while|return"))
8363 2 : unknownMacroError(tok);
8364 : }
8365 383668 : } else if (Token::Match(tok, "%name% (") && tok->isUpperCaseName() && Token::Match(tok->linkAt(1), ") %name% (") && Token::Match(tok->linkAt(1)->linkAt(2), ") [;{]")) {
8366 9 : if (!(tok->linkAt(1)->next() && tok->linkAt(1)->next()->isKeyword())) { // e.g. noexcept(true)
8367 2 : if (possible.count(tok->str()) == 0)
8368 1 : possible.insert(tok->str());
8369 : else
8370 1 : unknownMacroError(tok);
8371 : }
8372 383661 : } else if (isCPP() && Token::Match(tok, "public|private|protected %name% :")) {
8373 2 : unknownMacroError(tok->next());
8374 : }
8375 : }
8376 :
8377 : // String concatenation with unknown macros
8378 1024407 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8379 2003529 : if ((Token::Match(tok, "%str% %name% (") && Token::Match(tok->linkAt(2), ") %str%")) ||
8380 1001768 : (Token::Match(tok, "%str% %name% %str%") && !(startsWith(tok->strAt(1), "PRI") || startsWith(tok->strAt(1), "SCN")))) { // TODO: implement macros in std.cfg
8381 4 : if (tok->next()->isKeyword())
8382 0 : continue;
8383 4 : unknownMacroError(tok->next());
8384 : }
8385 1001765 : if (Token::Match(tok, "[(,] %name% (") && Token::Match(tok->linkAt(2), ") %name% %name%|,|)")) {
8386 4 : if (tok->next()->isKeyword() || tok->linkAt(2)->next()->isKeyword())
8387 3 : continue;
8388 1 : if (cAlternativeTokens.count(tok->linkAt(2)->next()->str()) > 0)
8389 0 : continue;
8390 1 : if (startsWith(tok->next()->str(), "__")) // attribute/annotation
8391 0 : continue;
8392 1 : unknownMacroError(tok->next());
8393 : }
8394 : }
8395 :
8396 : // Report unknown macros without commas or operators inbetween statements: MACRO1() MACRO2()
8397 1024322 : for (const Token* tok = tokens(); tok; tok = tok->next()) {
8398 1001669 : if (!Token::Match(tok, "%name% ("))
8399 913219 : continue;
8400 88449 : if (isNonMacro(tok) && !tok->isStandardType())
8401 11980 : continue;
8402 :
8403 76475 : const Token* endTok = tok->linkAt(1);
8404 76475 : if (!Token::Match(endTok, ") %name% (|."))
8405 76387 : continue;
8406 :
8407 88 : const Token* tok2 = endTok->next();
8408 88 : if (isNonMacro(tok2))
8409 83 : continue;
8410 :
8411 5 : if (tok2->next()->str() == "(") {
8412 4 : if (Token::Match(tok->previous(), "%name%|::|>"))
8413 2 : continue;
8414 : }
8415 :
8416 3 : unknownMacroError(tok->isStandardType() ? tok2 : tok);
8417 : }
8418 22651 : }
8419 :
8420 23218 : void Tokenizer::findGarbageCode() const
8421 : {
8422 23218 : const bool isCPP11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
8423 :
8424 : static const std::unordered_set<std::string> nonConsecutiveKeywords{ "break",
8425 : "continue",
8426 : "for",
8427 : "goto",
8428 : "if",
8429 : "return",
8430 : "switch",
8431 : "throw",
8432 : "typedef",
8433 23503 : "while" };
8434 :
8435 1014640 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8436 : // initialization: = {
8437 991566 : if (Token::simpleMatch(tok, "= {") && Token::simpleMatch(tok->linkAt(1), "} ("))
8438 4 : syntaxError(tok->linkAt(1));
8439 :
8440 : // Inside [] there can't be ; or various keywords
8441 991545 : else if (tok->str() == "[") {
8442 10935 : for (const Token* inner = tok->next(); inner != tok->link(); inner = inner->next()) {
8443 5391 : if (Token::Match(inner, "(|[|{"))
8444 128 : inner = inner->link();
8445 5263 : else if (Token::Match(inner, ";|goto|return|typedef"))
8446 12 : syntaxError(inner);
8447 : }
8448 : }
8449 :
8450 : // array assignment
8451 985989 : else if (Token::Match(tok, "%assign% [") && Token::simpleMatch(tok->linkAt(1), "] ;"))
8452 12 : syntaxError(tok, tok->str() + "[...];");
8453 :
8454 986003 : else if (Token::Match(tok, "[({<] %assign%"))
8455 21 : syntaxError(tok);
8456 :
8457 985976 : else if (Token::Match(tok, "[`\\@]"))
8458 9 : syntaxError(tok);
8459 :
8460 : // UNKNOWN_MACRO(return)
8461 991496 : if (tok->isKeyword() && Token::Match(tok, "throw|return )") && Token::Match(tok->linkAt(1)->previous(), "%name% ("))
8462 3 : unknownMacroError(tok->linkAt(1)->previous());
8463 :
8464 : // UNKNOWN_MACRO(return)
8465 991494 : else if (Token::Match(tok, "%name% throw|return") && std::isupper(tok->str()[0]))
8466 1 : unknownMacroError(tok);
8467 :
8468 : // Assign/increment/decrement literal
8469 991506 : else if (Token::Match(tok, "!!) %num%|%str%|%char% %assign%|++|--")) {
8470 5 : if (!isCPP() || mSettings.standards.cpp < Standards::CPP20 || !Token::Match(tok->previous(), "%name% : %num% ="))
8471 12 : syntaxError(tok, tok->next()->str() + " " + tok->strAt(2));
8472 : }
8473 991492 : else if (Token::simpleMatch(tok, ") return") && !Token::Match(tok->link()->previous(), "if|while|for (")) {
8474 4 : if (tok->link()->previous() && tok->link()->previous()->isUpperCaseName())
8475 1 : unknownMacroError(tok->link()->previous());
8476 : else
8477 3 : syntaxError(tok);
8478 : }
8479 :
8480 991492 : if (tok->isControlFlowKeyword() && Token::Match(tok, "if|while|for|switch")) { // if|while|for|switch (EXPR) { ... }
8481 10277 : if (tok->previous() && !Token::Match(tok->previous(), "%name%|:|;|{|}|)")) {
8482 16 : if (Token::Match(tok->previous(), "[,(]")) {
8483 12 : const Token *prev = tok->previous();
8484 32 : while (prev && prev->str() != "(") {
8485 20 : if (prev->str() == ")")
8486 2 : prev = prev->link();
8487 20 : prev = prev->previous();
8488 : }
8489 12 : if (prev && Token::Match(prev->previous(), "%name% ("))
8490 5 : unknownMacroError(prev->previous());
8491 : }
8492 11 : if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if"))
8493 9 : syntaxError(tok);
8494 : }
8495 10263 : if (!Token::Match(tok->next(), "( !!)"))
8496 32 : syntaxError(tok);
8497 10231 : if (tok->str() != "for") {
8498 9229 : if (isGarbageExpr(tok->next(), tok->linkAt(1), isCPP() && (mSettings.standards.cpp>=Standards::cppstd_t::CPP17)))
8499 0 : syntaxError(tok);
8500 : }
8501 : }
8502 :
8503 : // keyword keyword
8504 991449 : if (tok->isKeyword() && nonConsecutiveKeywords.count(tok->str()) != 0) {
8505 18808 : if (Token::Match(tok, "%name% %name%") && nonConsecutiveKeywords.count(tok->next()->str()) == 1)
8506 14 : syntaxError(tok);
8507 18794 : const Token* prev = tok;
8508 39812 : while (prev && prev->isName())
8509 21016 : prev = prev->previous();
8510 18794 : if (Token::Match(prev, "%op%|%num%|%str%|%char%")) {
8511 21 : if (!Token::simpleMatch(tok->tokAt(-2), "operator \"\" if") &&
8512 39 : !Token::simpleMatch(tok->tokAt(-2), "extern \"C\"") &&
8513 18 : !Token::simpleMatch(prev, "> typedef"))
8514 60 : syntaxError(tok, prev == tok->previous() ? (prev->str() + " " + tok->str()) : (prev->str() + " .. " + tok->str()));
8515 : }
8516 : }
8517 : }
8518 :
8519 : // invalid struct declaration
8520 1013218 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8521 990154 : if (Token::Match(tok, "struct|class|enum %name%| {") && (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
8522 4062 : const Token *tok2 = tok->linkAt(tok->next()->isName() ? 2 : 1);
8523 4062 : if (Token::Match(tok2, "} %op%")) {
8524 17 : tok2 = tok2->next();
8525 17 : if (!Token::Match(tok2, "*|&|&&"))
8526 12 : syntaxError(tok2, "Unexpected token '" + tok2->str() + "'");
8527 26 : while (Token::Match(tok2, "*|&|&&"))
8528 13 : tok2 = tok2->next();
8529 13 : if (!Token::Match(tok2, "%name%"))
8530 16 : syntaxError(tok2, "Unexpected token '" + (tok2 ? tok2->str() : "") + "'");
8531 : }
8532 : }
8533 990133 : if (Token::Match(tok, "enum : %num%| {"))
8534 6 : syntaxError(tok->tokAt(2), "Unexpected token '" + tok->strAt(2) + "'");
8535 : }
8536 :
8537 : // Keywords in global scope
8538 : static const std::unordered_set<std::string> nonGlobalKeywords{"break",
8539 : "continue",
8540 : "for",
8541 : "goto",
8542 : "if",
8543 : "return",
8544 : "switch",
8545 : "while",
8546 : "try",
8547 23354 : "catch"};
8548 343387 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8549 320341 : if (tok->str() == "{")
8550 32321 : tok = tok->link();
8551 288017 : else if (tok->isKeyword() && nonGlobalKeywords.count(tok->str()) && !Token::Match(tok->tokAt(-2), "operator %str%"))
8552 42 : syntaxError(tok, "keyword '" + tok->str() + "' is not allowed in global scope");
8553 : }
8554 :
8555 : // case keyword must be inside switch
8556 615499 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8557 592441 : if (Token::simpleMatch(tok, "switch (")) {
8558 203 : if (Token::simpleMatch(tok->linkAt(1), ") {")) {
8559 193 : tok = tok->linkAt(1)->linkAt(1);
8560 193 : continue;
8561 : }
8562 10 : const Token *switchToken = tok;
8563 10 : tok = tok->linkAt(1);
8564 10 : if (!tok)
8565 0 : syntaxError(switchToken);
8566 : // Look for the end of the switch statement, i.e. the first semi-colon or '}'
8567 86 : for (; tok; tok = tok->next()) {
8568 86 : if (tok->str() == "{") {
8569 5 : tok = tok->link();
8570 : }
8571 86 : if (Token::Match(tok, ";|}")) {
8572 : // We're at the end of the switch block
8573 10 : if (tok->str() == "}" && tok->strAt(-1) == ":") // Invalid case
8574 2 : syntaxError(switchToken);
8575 8 : break;
8576 : }
8577 : }
8578 8 : if (!tok)
8579 0 : break;
8580 592243 : } else if (tok->str() == "(") {
8581 87920 : tok = tok->link();
8582 504331 : } else if (tok->str() == "case") {
8583 7 : syntaxError(tok);
8584 : }
8585 : }
8586 :
8587 1012643 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8588 989603 : if (!Token::simpleMatch(tok, "for (")) // find for loops
8589 988614 : continue;
8590 : // count number of semicolons
8591 989 : int semicolons = 0, colons = 0;
8592 989 : const Token* const startTok = tok;
8593 989 : tok = tok->next()->link()->previous(); // find ")" of the for-loop
8594 : // walk backwards until we find the beginning (startTok) of the for() again
8595 13304 : for (; tok != startTok; tok = tok->previous()) {
8596 12316 : if (tok->str() == ";") { // do the counting
8597 1553 : semicolons++;
8598 10763 : } else if (tok->str() == ":") {
8599 214 : colons++;
8600 10549 : } else if (tok->str() == ")") { // skip pairs of ( )
8601 519 : tok = tok->link();
8602 : }
8603 : }
8604 : // if we have an invalid number of semicolons inside for( ), assume syntax error
8605 988 : if (semicolons > 2)
8606 0 : syntaxError(tok);
8607 988 : if (semicolons == 1 && !(isCPP() && mSettings.standards.cpp >= Standards::CPP20))
8608 1 : syntaxError(tok);
8609 987 : if (semicolons == 0 && colons == 0)
8610 5 : syntaxError(tok);
8611 : }
8612 :
8613 : // Operators without operands..
8614 23040 : const Token *templateEndToken = nullptr;
8615 1010023 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8616 987221 : if (!templateEndToken) {
8617 968613 : if (tok->str() == "<" && isCPP())
8618 6433 : templateEndToken = tok->findClosingBracket();
8619 : } else {
8620 18608 : if (templateEndToken == tok)
8621 5497 : templateEndToken = nullptr;
8622 18608 : if (Token::Match(tok, "> %cop%"))
8623 1072 : continue;
8624 : }
8625 : // skip C++ attributes [[...]]
8626 986149 : if (isCPP11 && (isCPPAttribute(tok) || isAlignAttribute(tok))) {
8627 0 : tok = skipCPPOrAlignAttribute(tok);
8628 0 : continue;
8629 : }
8630 : {
8631 986150 : bool match1 = Token::Match(tok, "%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|++|--|::|sizeof");
8632 986166 : bool match2 = Token::Match(tok->next(), "{|if|else|while|do|for|return|switch|break");
8633 986165 : if (isCPP()) {
8634 724276 : match1 = match1 || Token::Match(tok, "throw|decltype|typeof");
8635 724277 : match2 = match2 || Token::Match(tok->next(), "try|catch|namespace");
8636 : }
8637 986172 : if (match1 && !tok->isIncDecOp()) {
8638 23018 : match2 = match2 || Token::Match(tok->next(), "%assign%");
8639 : }
8640 986172 : if (match1 && match2)
8641 23 : syntaxError(tok);
8642 : }
8643 986149 : if (Token::Match(tok, "%or%|%oror%|~|^|!|%comp%|+|-|/|%")) {
8644 41752 : std::string code;
8645 20876 : if (Token::Match(tok->next(), ")|]|}"))
8646 75 : code = tok->str() + tok->next()->str();
8647 20876 : if (Token::simpleMatch(tok->next(), "( )"))
8648 191 : code = tok->str() + "()";
8649 20876 : if (!code.empty()) {
8650 266 : if (isC() || (tok->str() != ">" && !Token::simpleMatch(tok->previous(), "operator")))
8651 26 : syntaxError(tok, code);
8652 : }
8653 : }
8654 986099 : if (Token::Match(tok, "%num%|%bool%|%char%|%str% %num%|%bool%|%char%|%str%") && !Token::Match(tok, "%str% %str%"))
8655 12 : syntaxError(tok);
8656 986084 : if (Token::Match(tok, "%assign% typename|class %assign%"))
8657 8 : syntaxError(tok);
8658 986087 : if (Token::Match(tok, "%assign% [;)}]") && (!isCPP() || !Token::simpleMatch(tok->previous(), "operator")))
8659 36 : syntaxError(tok);
8660 986052 : if (Token::Match(tok, "%cop%|=|,|[ %or%|%oror%|/|%"))
8661 7 : syntaxError(tok);
8662 986037 : if (Token::Match(tok, "[;([{] %comp%|%oror%|%or%|%|/"))
8663 41 : syntaxError(tok);
8664 985991 : if (Token::Match(tok, "%cop%|= ]") && !(isCPP() && Token::Match(tok->previous(), "%type%|[|,|%num% &|=|> ]")))
8665 0 : syntaxError(tok);
8666 985998 : if (Token::Match(tok, "[+-] [;,)]}]") && !(isCPP() && Token::simpleMatch(tok->previous(), "operator")))
8667 8 : syntaxError(tok);
8668 1024420 : if (Token::simpleMatch(tok, ",") &&
8669 38436 : !Token::Match(tok->tokAt(-2), "[ = , &|%name%")) {
8670 38431 : if (Token::Match(tok->previous(), "(|[|{|<|%assign%|%or%|%oror%|==|!=|+|-|/|!|>=|<=|~|^|::|sizeof"))
8671 16 : syntaxError(tok);
8672 38415 : if (isCPP() && Token::Match(tok->previous(), "throw|decltype|typeof"))
8673 0 : syntaxError(tok);
8674 38415 : if (Token::Match(tok->next(), ")|]|>|%assign%|%or%|%oror%|==|!=|/|>=|<=|&&"))
8675 6 : syntaxError(tok);
8676 : }
8677 985961 : if ((!isCPP() || !Token::simpleMatch(tok->previous(), "operator")) && Token::Match(tok, "[,;] ,"))
8678 4 : syntaxError(tok);
8679 985950 : if (Token::simpleMatch(tok, ".") &&
8680 5332 : !Token::simpleMatch(tok->previous(), ".") &&
8681 5332 : !Token::simpleMatch(tok->next(), ".") &&
8682 996570 : !Token::Match(tok->previous(), "{|, . %name% =|.|[|{") &&
8683 5288 : !Token::Match(tok->previous(), ", . %name%")) {
8684 5288 : if (!Token::Match(tok->previous(), "%name%|)|]|>|}"))
8685 20 : syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8686 5284 : if (!Token::Match(tok->next(), "%name%|*|~"))
8687 0 : syntaxError(tok, tok->strAt(-1) + " " + tok->str() + " " + tok->strAt(1));
8688 : }
8689 985946 : if (Token::Match(tok, "[!|+-/%^~] )|]"))
8690 0 : syntaxError(tok);
8691 985949 : if (Token::Match(tok, "==|!=|<=|>= %comp%") && tok->strAt(-1) != "operator")
8692 2 : syntaxError(tok, tok->str() + " " + tok->strAt(1));
8693 999639 : if (Token::simpleMatch(tok, "::") && (!Token::Match(tok->next(), "%name%|*|~") ||
8694 13692 : (tok->next()->isKeyword() && !Token::Match(tok->next(), "new|delete|operator"))))
8695 4 : syntaxError(tok);
8696 985946 : if (Token::Match(tok, "& %comp%|&&|%oror%|&|%or%") && tok->strAt(1) != ">")
8697 0 : syntaxError(tok);
8698 985944 : if (Token::Match(tok, "^ %op%") && !Token::Match(tok->next(), "[>*+-!~]"))
8699 0 : syntaxError(tok);
8700 985948 : if (Token::Match(tok, ": [)]=]"))
8701 3 : syntaxError(tok);
8702 985945 : if (Token::Match(tok, "typedef [,;]"))
8703 0 : syntaxError(tok);
8704 985957 : if (Token::Match(tok, "! %comp%"))
8705 0 : syntaxError(tok);
8706 985954 : if (Token::Match(tok, "] %name%") && (!isCPP() || !(tok->tokAt(-1) && Token::simpleMatch(tok->tokAt(-2), "delete ["))))
8707 9 : syntaxError(tok);
8708 :
8709 985943 : if (tok->link() && Token::Match(tok, "[([]") && (!tok->tokAt(-1) || !tok->tokAt(-1)->isControlFlowKeyword())) {
8710 102611 : const Token* const end = tok->link();
8711 300340918 : for (const Token* inner = tok->next(); inner != end; inner = inner->next()) {
8712 300238340 : if (inner->str() == "{")
8713 260 : inner = inner->link();
8714 300238077 : else if (inner->str() == ";") {
8715 30 : if (tok->tokAt(-1) && tok->tokAt(-1)->isUpperCaseName())
8716 7 : unknownMacroError(tok->tokAt(-1));
8717 : else
8718 23 : syntaxError(inner);
8719 : }
8720 : }
8721 : }
8722 : }
8723 :
8724 : // ternary operator without :
8725 22801 : if (const Token *ternaryOp = findUnmatchedTernaryOp(tokens(), nullptr))
8726 12 : syntaxError(ternaryOp);
8727 :
8728 : // Code must not start with an arithmetical operand
8729 22791 : if (Token::Match(list.front(), "%cop%"))
8730 11 : syntaxError(list.front());
8731 :
8732 : // Code must end with } ; ) NAME
8733 22780 : if (!Token::Match(list.back(), "%name%|;|}|)"))
8734 42 : syntaxError(list.back());
8735 22738 : if (list.back()->str() == ")" && !Token::Match(list.back()->link()->previous(), "%name%|> ("))
8736 6 : syntaxError(list.back());
8737 22800 : for (const Token *end = list.back(); end && end->isName(); end = end->previous()) {
8738 86 : 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"))
8739 18 : syntaxError(list.back());
8740 : }
8741 22713 : if ((list.back()->str()==")" || list.back()->str()=="}") && list.back()->previous() && list.back()->previous()->isControlFlowKeyword())
8742 1 : syntaxError(list.back()->previous());
8743 :
8744 : // Garbage templates..
8745 22707 : if (isCPP()) {
8746 733920 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8747 717162 : if (!Token::simpleMatch(tok, "template <"))
8748 715860 : continue;
8749 1297 : if (tok->previous() && !Token::Match(tok->previous(), ":|;|{|}|)|>|\"C++\"")) {
8750 5 : if (tok->previous()->isUpperCaseName())
8751 2 : unknownMacroError(tok->previous());
8752 : else
8753 3 : syntaxError(tok);
8754 : }
8755 1292 : const Token * const tok1 = tok;
8756 1292 : tok = tok->next()->findClosingBracket();
8757 1292 : if (!tok)
8758 1 : syntaxError(tok1);
8759 1291 : if (!Token::Match(tok, ">|>> ::|...| %name%") &&
8760 1293 : !Token::Match(tok, ">|>> [ [ %name%") &&
8761 2 : !Token::Match(tok, "> >|*"))
8762 0 : syntaxError(tok->next() ? tok->next() : tok1);
8763 : }
8764 : }
8765 :
8766 : // Objective C/C++
8767 1006571 : for (const Token *tok = tokens(); tok; tok = tok->next()) {
8768 983873 : if (Token::Match(tok, "[;{}] [ %name% %name% ] ;"))
8769 1 : syntaxError(tok->next());
8770 : }
8771 22703 : }
8772 :
8773 :
8774 9229 : bool Tokenizer::isGarbageExpr(const Token *start, const Token *end, bool allowSemicolon)
8775 : {
8776 47354 : for (const Token *tok = start; tok != end; tok = tok->next()) {
8777 38125 : if (tok->isControlFlowKeyword())
8778 0 : return true;
8779 38125 : if (!allowSemicolon && tok->str() == ";")
8780 0 : return true;
8781 38125 : if (tok->str() == "{")
8782 19 : tok = tok->link();
8783 : }
8784 9229 : return false;
8785 : }
8786 :
8787 10499 : std::string Tokenizer::simplifyString(const std::string &source)
8788 : {
8789 10499 : std::string str = source;
8790 :
8791 60798 : for (std::string::size_type i = 0; i + 1U < str.size(); ++i) {
8792 50299 : if (str[i] != '\\')
8793 50101 : continue;
8794 :
8795 217 : int c = 'a'; // char
8796 217 : int sz = 0; // size of stringdata
8797 217 : if (str[i+1] == 'x') {
8798 17 : sz = 2;
8799 43 : while (sz < 4 && std::isxdigit((unsigned char)str[i+sz]))
8800 26 : sz++;
8801 17 : if (sz > 2) {
8802 34 : std::istringstream istr(str.substr(i+2, sz-2));
8803 17 : istr >> std::hex >> c;
8804 : }
8805 200 : } else if (MathLib::isOctalDigit(str[i+1])) {
8806 19 : sz = 2;
8807 31 : while (sz < 4 && MathLib::isOctalDigit(str[i+sz]))
8808 12 : sz++;
8809 38 : std::istringstream istr(str.substr(i+1, sz-1));
8810 19 : istr >> std::oct >> c;
8811 19 : str = str.replace(i, sz, std::string(1U, (char)c));
8812 19 : continue;
8813 : }
8814 :
8815 198 : if (sz <= 2)
8816 181 : i++;
8817 17 : else if (i+sz < str.size())
8818 17 : str.replace(i, sz, std::string(1U, (char)c));
8819 : else
8820 0 : str.replace(i, str.size() - i - 1U, "a");
8821 : }
8822 :
8823 10499 : return str;
8824 : }
8825 :
8826 23227 : void Tokenizer::simplifyFunctionTryCatch()
8827 : {
8828 23227 : if (!isCPP())
8829 6143 : return;
8830 :
8831 747660 : for (Token * tok = list.front(); tok; tok = tok->next()) {
8832 730578 : if (!Token::Match(tok, "try {|:"))
8833 730493 : continue;
8834 84 : if (!isFunctionHead(tok->previous(), "try"))
8835 74 : continue;
8836 :
8837 10 : Token* tryStartToken = skipInitializerList(tok->next());
8838 :
8839 10 : if (!Token::simpleMatch(tryStartToken, "{"))
8840 0 : syntaxError(tryStartToken, "Invalid function-try-catch block code. Did not find '{' for try body.");
8841 :
8842 : // find the end of the last catch block
8843 10 : Token * const tryEndToken = tryStartToken->link();
8844 10 : Token * endToken = tryEndToken;
8845 21 : while (Token::simpleMatch(endToken, "} catch (")) {
8846 13 : endToken = endToken->linkAt(2)->next();
8847 13 : if (!endToken)
8848 0 : break;
8849 13 : if (endToken->str() != "{") {
8850 2 : endToken = nullptr;
8851 2 : break;
8852 : }
8853 11 : endToken = endToken->link();
8854 : }
8855 10 : if (!endToken || endToken == tryEndToken)
8856 3 : continue;
8857 :
8858 7 : tok->previous()->insertToken("{");
8859 7 : endToken->insertToken("}");
8860 7 : Token::createMutualLinks(tok->previous(), endToken->next());
8861 : }
8862 : }
8863 :
8864 395802 : static bool isAnonymousEnum(const Token* tok)
8865 : {
8866 395802 : if (!Token::Match(tok, "enum {|:"))
8867 395734 : return false;
8868 71 : if (tok->index() > 2 && Token::Match(tok->tokAt(-3), "using %name% ="))
8869 0 : return false;
8870 71 : const Token* end = tok->next();
8871 71 : if (end->str() == ":") {
8872 3 : end = end->next();
8873 8 : while (Token::Match(end, "%name%|::"))
8874 5 : end = end->next();
8875 : }
8876 71 : return end && Token::Match(end->link(), "} (| %type%| )| [,;[({=]");
8877 : }
8878 :
8879 22638 : void Tokenizer::simplifyStructDecl()
8880 : {
8881 22638 : const bool cpp = isCPP();
8882 :
8883 : // A counter that is used when giving unique names for anonymous structs.
8884 22640 : int count = 0;
8885 :
8886 : // Add names for anonymous structs
8887 1013167 : for (Token *tok = list.front(); tok; tok = tok->next()) {
8888 990516 : if (!tok->isName())
8889 594597 : continue;
8890 : // check for anonymous struct/union
8891 395913 : if (Token::Match(tok, "struct|union {")) {
8892 123 : if (Token::Match(tok->next()->link(), "} const| *|&| const| %type% ,|;|[|(|{|=")) {
8893 65 : tok->insertToken("Anonymous" + std::to_string(count++));
8894 : }
8895 : }
8896 : // check for derived anonymous class/struct
8897 395803 : else if (cpp && Token::Match(tok, "class|struct :")) {
8898 1 : const Token *tok1 = Token::findsimplematch(tok, "{");
8899 1 : if (tok1 && Token::Match(tok1->link(), "} const| *|&| const| %type% ,|;|[|(|{")) {
8900 1 : tok->insertToken("Anonymous" + std::to_string(count++));
8901 : }
8902 : }
8903 : // check for anonymous enum
8904 395799 : else if (isAnonymousEnum(tok)) {
8905 66 : Token *start = tok->strAt(1) == ":" ? tok->linkAt(3) : tok->linkAt(1);
8906 66 : if (start && Token::Match(start->next(), "( %type% )")) {
8907 0 : start->next()->link()->deleteThis();
8908 0 : start->next()->deleteThis();
8909 : }
8910 66 : tok->insertToken("Anonymous" + std::to_string(count++));
8911 : }
8912 : }
8913 :
8914 : // "{" token for current scope
8915 45281 : std::stack<const Token*> scopeStart;
8916 22642 : const Token* functionEnd = nullptr;
8917 :
8918 1013812 : for (Token *tok = list.front(); tok; tok = tok->next()) {
8919 :
8920 : // check for start of scope and determine if it is in a function
8921 991172 : if (tok->str() == "{") {
8922 48120 : scopeStart.push(tok);
8923 48120 : if (!functionEnd && Token::Match(tok->previous(), "const|)"))
8924 28817 : functionEnd = tok->link();
8925 : }
8926 :
8927 : // end of scope
8928 943052 : else if (tok->str() == "}") {
8929 48119 : if (!scopeStart.empty())
8930 48119 : scopeStart.pop();
8931 48119 : if (tok == functionEnd)
8932 28817 : functionEnd = nullptr;
8933 : }
8934 :
8935 : // check for named struct/union
8936 894932 : else if (Token::Match(tok, "class|struct|union|enum %type% :|{")) {
8937 5330 : Token *start = tok;
8938 5488 : while (Token::Match(start->previous(), "%type%"))
8939 158 : start = start->previous();
8940 5330 : const Token * const type = tok->next();
8941 5330 : Token *next = tok->tokAt(2);
8942 :
8943 7660 : while (next && !Token::Match(next, "[{;]"))
8944 2330 : next = next->next();
8945 5330 : if (!next || next->str() == ";")
8946 12 : continue;
8947 5318 : Token* after = next->link();
8948 5318 : if (!after)
8949 0 : break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8950 :
8951 : // check for named type
8952 5318 : if (Token::Match(after->next(), "const|static|volatile| *|&| const| (| %type% )| ,|;|[|=|(|{")) {
8953 214 : after->insertToken(";");
8954 214 : after = after->next();
8955 227 : while (!Token::Match(start, "struct|class|union|enum")) {
8956 13 : after->insertToken(start->str());
8957 13 : after = after->next();
8958 13 : start->deleteThis();
8959 : }
8960 214 : tok = start;
8961 214 : if (!after)
8962 0 : break; // see #4869 segmentation fault in Tokenizer::simplifyStructDecl (invalid code)
8963 214 : after->insertToken(type->str());
8964 214 : if (start->str() != "class") {
8965 188 : after->insertToken(start->str());
8966 188 : after = after->next();
8967 : }
8968 :
8969 214 : after = after->tokAt(2);
8970 :
8971 214 : if (Token::Match(after, "( %type% )")) {
8972 1 : after->link()->deleteThis();
8973 1 : after->deleteThis();
8974 : }
8975 :
8976 : // check for initialization
8977 214 : if (Token::Match(after, "%any% (|{")) {
8978 16 : after->insertToken("=");
8979 16 : after = after->next();
8980 16 : const bool isEnum = start->str() == "enum";
8981 16 : if (!isEnum && cpp) {
8982 7 : after->insertToken(type->str());
8983 7 : after = after->next();
8984 : }
8985 :
8986 16 : if (isEnum) {
8987 9 : if (Token::Match(after->next(), "{ !!}")) {
8988 4 : after->next()->str("(");
8989 4 : after->linkAt(1)->str(")");
8990 : }
8991 : }
8992 : }
8993 : }
8994 : }
8995 :
8996 : // check for anonymous struct/union
8997 : else {
8998 : // unnamed anonymous struct/union so possibly remove it
8999 889602 : bool done = false;
9000 889656 : while (!done && Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->linkAt(1), "} ;")) {
9001 54 : done = true;
9002 :
9003 : // is this a class/struct/union scope?
9004 54 : bool isClassStructUnionScope = false;
9005 54 : if (!scopeStart.empty()) {
9006 99 : for (const Token* tok2 = scopeStart.top()->previous(); tok2 && !Token::Match(tok2, "[;{}]"); tok2 = tok2->previous()) {
9007 89 : if (Token::Match(tok2, "class|struct|union")) {
9008 36 : isClassStructUnionScope = true;
9009 36 : break;
9010 : }
9011 : }
9012 : }
9013 :
9014 : // remove unnamed anonymous struct/union
9015 : // * not in class/struct/union scopes
9016 54 : if (Token::simpleMatch(tok->linkAt(1), "} ;") && !isClassStructUnionScope && tok->str() != "union") {
9017 10 : tok->linkAt(1)->previous()->deleteNext(2);
9018 10 : tok->deleteNext();
9019 10 : tok->deleteThis();
9020 10 : done = false;
9021 : }
9022 : }
9023 : }
9024 : }
9025 22642 : }
9026 :
9027 22671 : void Tokenizer::simplifyCallingConvention()
9028 : {
9029 22671 : const bool windows = mSettings.platform.isWindows();
9030 :
9031 1008229 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9032 985590 : while (Token::Match(tok, "__cdecl|__stdcall|__fastcall|__thiscall|__clrcall|__syscall|__pascal|__fortran|__far|__near") || (windows && Token::Match(tok, "WINAPI|APIENTRY|CALLBACK"))) {
9033 33 : tok->deleteThis();
9034 : }
9035 : }
9036 22674 : }
9037 :
9038 1989761 : static bool isAttribute(const Token* tok, bool gcc) {
9039 1989761 : return gcc ? Token::Match(tok, "__attribute__|__attribute (") : Token::Match(tok, "__declspec|_declspec (");
9040 : }
9041 :
9042 169 : static Token* getTokenAfterAttributes(Token* tok, bool gccattr) {
9043 169 : Token* after = tok;
9044 375 : while (isAttribute(after, gccattr))
9045 206 : after = after->linkAt(1)->next();
9046 169 : return after;
9047 : }
9048 :
9049 155 : Token* Tokenizer::getAttributeFuncTok(Token* tok, bool gccattr) const {
9050 155 : if (!Token::Match(tok, "%name% ("))
9051 0 : return nullptr;
9052 155 : Token* const after = getTokenAfterAttributes(tok, gccattr);
9053 155 : if (!after)
9054 2 : syntaxError(tok);
9055 :
9056 153 : if (Token::Match(after, "%name%|*|&|(")) {
9057 68 : Token *ftok = after;
9058 103 : while (Token::Match(ftok, "%name%|::|<|*|& !!(")) {
9059 35 : if (ftok->str() == "<") {
9060 2 : ftok = ftok->findClosingBracket();
9061 2 : if (!ftok)
9062 0 : break;
9063 : }
9064 35 : ftok = ftok->next();
9065 : }
9066 68 : if (Token::simpleMatch(ftok, "( *"))
9067 1 : ftok = ftok->tokAt(2);
9068 68 : if (Token::Match(ftok, "%name% (|)"))
9069 52 : return ftok;
9070 85 : } else if (Token::Match(after, "[;{=:]")) {
9071 79 : Token *prev = tok->previous();
9072 93 : while (Token::Match(prev, "%name%"))
9073 14 : prev = prev->previous();
9074 79 : if (Token::simpleMatch(prev, ")")) {
9075 64 : if (Token::Match(prev->link()->previous(), "%name% ("))
9076 60 : return prev->link()->previous();
9077 4 : if (Token::Match(prev->link()->tokAt(-2), "%name% ) ("))
9078 1 : return prev->link()->tokAt(-2);
9079 : }
9080 18 : if (Token::simpleMatch(prev, ")") && Token::Match(prev->link()->tokAt(-2), "operator %op% (") && isCPP())
9081 1 : return prev->link()->tokAt(-2);
9082 17 : if ((!prev || Token::Match(prev, "[;{}*]")) && Token::Match(tok->previous(), "%name%"))
9083 8 : return tok->previous();
9084 : }
9085 31 : return nullptr;
9086 : }
9087 :
9088 23226 : void Tokenizer::simplifyDeclspec()
9089 : {
9090 1018672 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9091 995460 : while (isAttribute(tok, false)) {
9092 14 : if (Token::Match(tok->tokAt(2), "noreturn|nothrow|dllexport")) {
9093 9 : Token *functok = getAttributeFuncTok(tok, false);
9094 9 : if (functok) {
9095 5 : if (tok->strAt(2) == "noreturn")
9096 0 : functok->isAttributeNoreturn(true);
9097 5 : else if (tok->strAt(2) == "nothrow")
9098 4 : functok->isAttributeNothrow(true);
9099 : else
9100 1 : functok->isAttributeExport(true);
9101 : }
9102 5 : } else if (tok->strAt(2) == "property")
9103 1 : tok->next()->link()->insertToken("__property");
9104 :
9105 14 : Token::eraseTokens(tok, tok->next()->link()->next());
9106 14 : tok->deleteThis();
9107 : }
9108 : }
9109 23228 : }
9110 :
9111 23224 : void Tokenizer::simplifyAttribute()
9112 : {
9113 1017023 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9114 993806 : if (!tok->isKeyword() && Token::Match(tok, "%type% (") && !mSettings.library.isNotLibraryFunction(tok)) {
9115 23245 : if (mSettings.library.isFunctionConst(tok->str(), true))
9116 4918 : tok->isAttributePure(true);
9117 23245 : if (mSettings.library.isFunctionConst(tok->str(), false))
9118 18 : tok->isAttributeConst(true);
9119 : }
9120 993936 : while (isAttribute(tok, true)) {
9121 146 : Token *functok = getAttributeFuncTok(tok, true);
9122 :
9123 466 : for (Token *attr = tok->tokAt(2); attr->str() != ")"; attr = attr->next()) {
9124 328 : if (Token::Match(attr, "%name% ("))
9125 20 : attr = attr->linkAt(1);
9126 :
9127 328 : if (Token::Match(attr, "[(,] constructor|__constructor__ [,()]")) {
9128 11 : if (!functok)
9129 4 : syntaxError(tok);
9130 7 : functok->isAttributeConstructor(true);
9131 : }
9132 :
9133 317 : else if (Token::Match(attr, "[(,] destructor|__destructor__ [,()]")) {
9134 9 : if (!functok)
9135 2 : syntaxError(tok);
9136 7 : functok->isAttributeDestructor(true);
9137 : }
9138 :
9139 308 : else if (Token::Match(attr, "[(,] unused|__unused__|used|__used__ [,)]")) {
9140 14 : Token *vartok = nullptr;
9141 14 : Token *after = getTokenAfterAttributes(tok, true);
9142 :
9143 : // check if after variable name
9144 14 : if (Token::Match(after, ";|=")) {
9145 9 : Token *prev = tok->previous();
9146 12 : while (Token::simpleMatch(prev, "]"))
9147 3 : prev = prev->link()->previous();
9148 9 : if (Token::Match(prev, "%type%"))
9149 5 : vartok = prev;
9150 : }
9151 :
9152 : // check if before variable name
9153 5 : else if (Token::Match(after, "%type%"))
9154 3 : vartok = after;
9155 :
9156 14 : if (vartok) {
9157 8 : const std::string &attribute(attr->next()->str());
9158 8 : if (attribute.find("unused") != std::string::npos)
9159 6 : vartok->isAttributeUnused(true);
9160 : else
9161 2 : vartok->isAttributeUsed(true);
9162 : }
9163 : }
9164 :
9165 294 : else if (Token::Match(attr, "[(,] pure|__pure__|const|__const__|noreturn|__noreturn__|nothrow|__nothrow__|warn_unused_result [,)]")) {
9166 107 : if (!functok)
9167 0 : syntaxError(tok);
9168 :
9169 107 : const std::string &attribute(attr->next()->str());
9170 107 : if (attribute.find("pure") != std::string::npos)
9171 42 : functok->isAttributePure(true);
9172 65 : else if (attribute.find("const") != std::string::npos)
9173 25 : functok->isAttributeConst(true);
9174 40 : else if (attribute.find("noreturn") != std::string::npos)
9175 9 : functok->isAttributeNoreturn(true);
9176 31 : else if (attribute.find("nothrow") != std::string::npos)
9177 27 : functok->isAttributeNothrow(true);
9178 4 : else if (attribute.find("warn_unused_result") != std::string::npos)
9179 4 : functok->isAttributeNodiscard(true);
9180 : }
9181 :
9182 187 : else if (Token::Match(attr, "[(,] packed [,)]") && Token::simpleMatch(tok->previous(), "}"))
9183 1 : tok->previous()->isAttributePacked(true);
9184 :
9185 186 : else if (functok && Token::simpleMatch(attr, "( __visibility__ ( \"default\" ) )"))
9186 1 : functok->isAttributeExport(true);
9187 : }
9188 :
9189 138 : Token::eraseTokens(tok, tok->linkAt(1)->next());
9190 138 : tok->deleteThis();
9191 : }
9192 : }
9193 23220 : }
9194 :
9195 22702 : void Tokenizer::simplifyCppcheckAttribute()
9196 : {
9197 1006371 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9198 983651 : if (tok->str() != "(")
9199 876498 : continue;
9200 107172 : if (!tok->previous())
9201 49 : continue;
9202 107123 : const std::string &attr = tok->previous()->str();
9203 107120 : if (!startsWith(attr, "__cppcheck_"))
9204 107120 : continue;
9205 2 : if (attr.compare(attr.size()-2, 2, "__") != 0) // TODO: ends_with("__")
9206 0 : continue;
9207 :
9208 2 : Token *vartok = tok->link();
9209 7 : while (Token::Match(vartok->next(), "%name%|*|&|::")) {
9210 5 : vartok = vartok->next();
9211 5 : if (Token::Match(vartok, "%name% (") && startsWith(vartok->str(),"__cppcheck_"))
9212 1 : vartok = vartok->linkAt(1);
9213 : }
9214 :
9215 2 : if (vartok->isName()) {
9216 2 : if (Token::Match(tok->previous(), "__cppcheck_low__ ( %num% )"))
9217 1 : vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9218 : MathLib::toBigNumber(tok->next()->str()));
9219 1 : else if (Token::Match(tok->previous(), "__cppcheck_high__ ( %num% )"))
9220 1 : vartok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9221 : MathLib::toBigNumber(tok->next()->str()));
9222 : }
9223 :
9224 : // Delete cppcheck attribute..
9225 2 : if (tok->tokAt(-2)) {
9226 2 : tok = tok->tokAt(-2);
9227 2 : Token::eraseTokens(tok, tok->linkAt(2)->next());
9228 : } else {
9229 0 : tok = tok->previous();
9230 0 : Token::eraseTokens(tok, tok->linkAt(1)->next());
9231 0 : tok->str(";");
9232 : }
9233 : }
9234 22700 : }
9235 :
9236 23226 : void Tokenizer::simplifyCPPAttribute()
9237 : {
9238 23226 : if ((isCPP() && mSettings.standards.cpp < Standards::CPP11) || (isC() && mSettings.standards.c < Standards::C23))
9239 154 : return;
9240 :
9241 1014689 : for (Token *tok = list.front(); tok;) {
9242 991621 : if (!isCPPAttribute(tok) && !isAlignAttribute(tok)) {
9243 991510 : tok = tok->next();
9244 991511 : continue;
9245 : }
9246 107 : if (isCPPAttribute(tok)) {
9247 96 : if (Token::findsimplematch(tok->tokAt(2), "noreturn", tok->link())) {
9248 16 : Token * head = skipCPPOrAlignAttribute(tok)->next();
9249 18 : while (isCPPAttribute(head) || isAlignAttribute(head))
9250 2 : head = skipCPPOrAlignAttribute(head)->next();
9251 48 : while (Token::Match(head, "%name%|::|*|&|<|>|,")) // skip return type
9252 32 : head = head->next();
9253 32 : if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9254 16 : head->previous()->isAttributeNoreturn(true);
9255 : }
9256 80 : } else if (Token::findsimplematch(tok->tokAt(2), "nodiscard", tok->link())) {
9257 13 : Token * head = skipCPPOrAlignAttribute(tok)->next();
9258 14 : while (isCPPAttribute(head) || isAlignAttribute(head))
9259 1 : head = skipCPPOrAlignAttribute(head)->next();
9260 45 : while (Token::Match(head, "%name%|::|*|&|<|>|,"))
9261 32 : head = head->next();
9262 26 : if (head && head->str() == "(" && isFunctionHead(head, "{|;")) {
9263 13 : head->previous()->isAttributeNodiscard(true);
9264 : }
9265 67 : } else if (Token::findsimplematch(tok->tokAt(2), "maybe_unused", tok->link())) {
9266 50 : Token* head = skipCPPOrAlignAttribute(tok)->next();
9267 53 : while (isCPPAttribute(head) || isAlignAttribute(head))
9268 3 : head = skipCPPOrAlignAttribute(head)->next();
9269 50 : head->isAttributeMaybeUnused(true);
9270 17 : } else if (Token::Match(tok->previous(), ") [ [ expects|ensures|assert default|audit|axiom| : %name% <|<=|>|>= %num% ] ]")) {
9271 1 : const Token *vartok = tok->tokAt(4);
9272 1 : if (vartok->str() == ":")
9273 0 : vartok = vartok->next();
9274 1 : Token *argtok = tok->tokAt(-2);
9275 1 : while (argtok && argtok->str() != "(") {
9276 1 : if (argtok->str() == vartok->str())
9277 1 : break;
9278 0 : if (argtok->str() == ")")
9279 0 : argtok = argtok->link();
9280 0 : argtok = argtok->previous();
9281 : }
9282 1 : if (argtok && argtok->str() == vartok->str()) {
9283 1 : if (vartok->next()->str() == ">=")
9284 0 : argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9285 : MathLib::toBigNumber(vartok->strAt(2)));
9286 1 : else if (vartok->next()->str() == ">")
9287 0 : argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::LOW,
9288 0 : MathLib::toBigNumber(vartok->strAt(2)) + 1);
9289 1 : else if (vartok->next()->str() == "<=")
9290 1 : argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9291 : MathLib::toBigNumber(vartok->strAt(2)));
9292 0 : else if (vartok->next()->str() == "<")
9293 0 : argtok->setCppcheckAttribute(TokenImpl::CppcheckAttributes::Type::HIGH,
9294 0 : MathLib::toBigNumber(vartok->strAt(2)) - 1);
9295 : }
9296 : }
9297 : } else {
9298 11 : if (Token::simpleMatch(tok, "alignas (")) {
9299 : // alignment requirements could be checked here
9300 : }
9301 : }
9302 107 : Token::eraseTokens(tok, skipCPPOrAlignAttribute(tok)->next());
9303 107 : tok->deleteThis();
9304 : }
9305 : }
9306 :
9307 23603 : void Tokenizer::simplifySpaceshipOperator()
9308 : {
9309 23603 : if (isCPP() && mSettings.standards.cpp >= Standards::CPP20) {
9310 642709 : for (Token *tok = list.front(); tok && tok->next(); tok = tok->next()) {
9311 626554 : if (Token::simpleMatch(tok, "<= >")) {
9312 6 : tok->str("<=>");
9313 6 : tok->deleteNext();
9314 : }
9315 : }
9316 : }
9317 23601 : }
9318 :
9319 : static const std::unordered_set<std::string> keywords = {
9320 : "inline"
9321 : , "_inline"
9322 : , "__inline"
9323 : , "__forceinline"
9324 : , "register"
9325 : , "__restrict"
9326 : , "__restrict__"
9327 : , "__thread"
9328 : };
9329 : // Remove "inline", "register", "restrict", "override", "static" and "constexpr"
9330 : // "restrict" keyword
9331 : // - New to 1999 ANSI/ISO C standard
9332 : // - Not in C++ standard yet
9333 23227 : void Tokenizer::simplifyKeyword()
9334 : {
9335 : // FIXME: There is a risk that "keywords" are removed by mistake. This
9336 : // code should be fixed so it doesn't remove variables etc. Nonstandard
9337 : // keywords should be defined with a library instead. For instance the
9338 : // linux kernel code at least uses "_inline" as struct member name at some
9339 : // places.
9340 :
9341 23227 : const bool c99 = isC() && mSettings.standards.c >= Standards::C99;
9342 23228 : const bool cpp11 = isCPP() && mSettings.standards.cpp >= Standards::CPP11;
9343 23228 : const bool cpp20 = isCPP() && mSettings.standards.cpp >= Standards::CPP20;
9344 :
9345 1018313 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9346 995086 : if (keywords.find(tok->str()) != keywords.end()) {
9347 : // Don't remove struct members
9348 59 : if (!Token::simpleMatch(tok->previous(), ".")) {
9349 58 : const bool isinline = (tok->str().find("inline") != std::string::npos);
9350 58 : const bool isrestrict = (tok->str().find("restrict") != std::string::npos);
9351 58 : if (isinline || isrestrict) {
9352 133 : for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9353 83 : if (isinline)
9354 79 : temp->isInline(true);
9355 83 : if (isrestrict)
9356 4 : temp->isRestrict(true);
9357 : }
9358 : }
9359 58 : tok->deleteThis(); // Simplify..
9360 : }
9361 : }
9362 :
9363 995080 : if (isC() || mSettings.standards.cpp == Standards::CPP03) {
9364 266439 : if (tok->str() == "auto")
9365 10 : tok->deleteThis();
9366 : }
9367 :
9368 : // simplify static keyword:
9369 : // void foo( int [ static 5 ] ); ==> void foo( int [ 5 ] );
9370 995082 : if (Token::Match(tok, "[ static %num%"))
9371 2 : tok->deleteNext();
9372 :
9373 995082 : if (c99) {
9374 417 : auto getTypeTokens = [tok]() {
9375 139 : std::vector<Token*> ret;
9376 278 : for (Token *temp = tok; Token::Match(temp, "%name%"); temp = temp->previous()) {
9377 139 : if (!temp->isKeyword())
9378 0 : ret.emplace_back(temp);
9379 : }
9380 277 : for (Token *temp = tok->next(); Token::Match(temp, "%name%"); temp = temp->next()) {
9381 138 : if (!temp->isKeyword())
9382 138 : ret.emplace_back(temp);
9383 : }
9384 139 : return ret;
9385 263842 : };
9386 :
9387 263842 : if (tok->str() == "restrict") {
9388 277 : for (Token* temp: getTypeTokens())
9389 138 : temp->isRestrict(true);
9390 139 : tok->deleteThis();
9391 : }
9392 :
9393 263842 : if (mSettings.standards.c >= Standards::C11) {
9394 263835 : while (tok->str() == "_Atomic") {
9395 0 : for (Token* temp: getTypeTokens())
9396 0 : temp->isAtomic(true);
9397 0 : tok->deleteThis();
9398 : }
9399 : }
9400 : }
9401 :
9402 731240 : else if (cpp11) {
9403 728644 : if (cpp20 && tok->str() == "consteval") {
9404 1 : tok->originalName(tok->str());
9405 1 : tok->str("constexpr");
9406 728641 : } else if (cpp20 && tok->str() == "constinit") {
9407 1 : tok->deleteThis();
9408 : }
9409 :
9410 : // final:
9411 : // 1) struct name final { }; <- struct is final
9412 728643 : if (Token::Match(tok->previous(), "struct|class|union %type%")) {
9413 6346 : Token* finalTok = tok->next();
9414 6346 : if (tok->isUpperCaseName() && Token::Match(finalTok, "%type%") && finalTok->str() != "final") {
9415 150 : tok = finalTok;
9416 150 : finalTok = finalTok->next();
9417 : }
9418 6346 : if (Token::simpleMatch(finalTok, "<")) { // specialization
9419 131 : finalTok = finalTok->findClosingBracket();
9420 131 : if (finalTok)
9421 129 : finalTok = finalTok->next();
9422 : }
9423 6346 : if (Token::Match(finalTok, "final [:{]")) {
9424 14 : finalTok->deleteThis();
9425 14 : tok->previous()->isFinalType(true);
9426 : }
9427 : }
9428 :
9429 : // noexcept -> noexcept(true)
9430 : // 2) void f() noexcept; -> void f() noexcept(true);
9431 722300 : else if (Token::Match(tok, ") const|override|final| noexcept :|{|;|,|const|override|final")) {
9432 : // Insertion is done in inverse order
9433 : // The brackets are linked together accordingly afterwards
9434 48 : Token* tokNoExcept = tok->next();
9435 69 : while (tokNoExcept->str() != "noexcept")
9436 21 : tokNoExcept = tokNoExcept->next();
9437 48 : tokNoExcept->insertToken(")");
9438 48 : Token * braceEnd = tokNoExcept->next();
9439 48 : tokNoExcept->insertToken("true");
9440 48 : tokNoExcept->insertToken("(");
9441 48 : Token * braceStart = tokNoExcept->next();
9442 48 : tok = tok->tokAt(3);
9443 48 : Token::createMutualLinks(braceStart, braceEnd);
9444 : }
9445 :
9446 : // 3) thread_local -> static
9447 : // on single thread thread_local has the effect of static
9448 722256 : else if (tok->str() == "thread_local") {
9449 3 : tok->originalName(tok->str());
9450 3 : tok->str("static");
9451 : }
9452 : }
9453 : }
9454 23226 : }
9455 :
9456 0 : static Token* setTokenDebug(Token* start, TokenDebug td)
9457 : {
9458 0 : if (!start->link())
9459 0 : return nullptr;
9460 0 : Token* end = start->link();
9461 0 : start->deleteThis();
9462 0 : for (Token* tok = start; tok != end; tok = tok->next()) {
9463 0 : tok->setTokenDebug(td);
9464 : }
9465 0 : end->deleteThis();
9466 0 : return end;
9467 : }
9468 :
9469 23229 : void Tokenizer::simplifyDebug()
9470 : {
9471 23229 : if (!mSettings.debugnormal && !mSettings.debugwarnings)
9472 21201 : return;
9473 0 : static const std::unordered_map<std::string, TokenDebug> m = {{"debug_valueflow", TokenDebug::ValueFlow},
9474 2106 : {"debug_valuetype", TokenDebug::ValueType}};
9475 394874 : for (Token* tok = list.front(); tok; tok = tok->next()) {
9476 392846 : if (!Token::Match(tok, "%name% ("))
9477 355973 : continue;
9478 36873 : auto it = m.find(tok->str());
9479 36873 : if (it != m.end()) {
9480 0 : tok->deleteThis();
9481 0 : tok = setTokenDebug(tok, it->second);
9482 : }
9483 : }
9484 : }
9485 :
9486 22642 : void Tokenizer::simplifyAssignmentBlock()
9487 : {
9488 1013712 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9489 991073 : if (Token::Match(tok, "[;{}] %name% = ( {")) {
9490 6 : const std::string &varname = tok->next()->str();
9491 :
9492 : // goto the "} )"
9493 6 : int indentlevel = 0;
9494 6 : Token *tok2 = tok;
9495 75 : while (nullptr != (tok2 = tok2->next())) {
9496 75 : if (Token::Match(tok2, "(|{"))
9497 17 : ++indentlevel;
9498 58 : else if (Token::Match(tok2, ")|}")) {
9499 11 : if (indentlevel <= 2)
9500 6 : break;
9501 5 : --indentlevel;
9502 47 : } else if (indentlevel == 2 && tok2->str() == varname && Token::Match(tok2->previous(), "%type%|*"))
9503 : // declaring variable in inner scope with same name as lhs variable
9504 0 : break;
9505 : }
9506 6 : if (indentlevel == 2 && Token::simpleMatch(tok2, "} )")) {
9507 6 : tok2 = tok2->tokAt(-3);
9508 6 : if (Token::Match(tok2, "[;{}] %num%|%name% ;")) {
9509 0 : tok2->insertToken("=");
9510 0 : tok2->insertToken(tok->next()->str());
9511 0 : tok2->next()->varId(tok->next()->varId());
9512 0 : tok->deleteNext(3);
9513 0 : tok2->tokAt(5)->deleteNext();
9514 : }
9515 : }
9516 : }
9517 : }
9518 22638 : }
9519 :
9520 : // Remove __asm..
9521 23229 : void Tokenizer::simplifyAsm()
9522 : {
9523 46456 : std::string instruction;
9524 1018385 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9525 995167 : if (Token::Match(tok, "__asm|_asm|asm {") &&
9526 11 : tok->next()->link()->next()) {
9527 9 : instruction = tok->tokAt(2)->stringifyList(tok->next()->link());
9528 9 : Token::eraseTokens(tok, tok->next()->link()->next());
9529 : }
9530 :
9531 995143 : else if (Token::Match(tok, "asm|__asm|__asm__ volatile|__volatile|__volatile__| (")) {
9532 : // Goto "("
9533 35 : Token *partok = tok->next();
9534 35 : if (partok->str() != "(")
9535 7 : partok = partok->next();
9536 35 : instruction = partok->next()->stringifyList(partok->link());
9537 35 : Token::eraseTokens(tok, partok->link()->next());
9538 : }
9539 :
9540 995107 : else if (Token::Match(tok, "_asm|__asm")) {
9541 7 : Token *endasm = tok->next();
9542 7 : const Token *firstSemiColon = nullptr;
9543 7 : int comment = 0;
9544 28 : while (Token::Match(endasm, "%num%|%name%|,|:|;") || (endasm && endasm->linenr() == comment)) {
9545 23 : if (Token::Match(endasm, "_asm|__asm|__endasm"))
9546 2 : break;
9547 21 : if (endasm->str() == ";") {
9548 3 : comment = endasm->linenr();
9549 3 : if (!firstSemiColon)
9550 3 : firstSemiColon = endasm;
9551 : }
9552 21 : endasm = endasm->next();
9553 : }
9554 7 : if (Token::simpleMatch(endasm, "__endasm")) {
9555 2 : instruction = tok->next()->stringifyList(endasm);
9556 2 : Token::eraseTokens(tok, endasm->next());
9557 2 : if (!Token::simpleMatch(tok->next(), ";"))
9558 0 : tok->insertToken(";");
9559 5 : } else if (firstSemiColon) {
9560 2 : instruction = tok->next()->stringifyList(firstSemiColon);
9561 2 : Token::eraseTokens(tok, firstSemiColon);
9562 3 : } else if (!endasm) {
9563 1 : instruction = tok->next()->stringifyList(endasm);
9564 1 : Token::eraseTokens(tok, endasm);
9565 1 : tok->insertToken(";");
9566 : } else
9567 2 : continue;
9568 : }
9569 :
9570 : else
9571 995105 : continue;
9572 :
9573 49 : if (Token::Match(tok->previous(), ") %name% %name% (")) {
9574 1 : tok->deleteThis();
9575 1 : continue;
9576 : }
9577 :
9578 : // insert "asm ( "instruction" )"
9579 48 : tok->str("asm");
9580 48 : if (tok->strAt(1) != ";" && tok->strAt(1) != "{")
9581 6 : tok->insertToken(";");
9582 48 : tok->insertToken(")");
9583 48 : tok->insertToken("\"" + instruction + "\"");
9584 48 : tok->insertToken("(");
9585 :
9586 48 : tok = tok->next();
9587 48 : Token::createMutualLinks(tok, tok->tokAt(2));
9588 :
9589 : //move the new tokens in the same line as ";" if available
9590 48 : tok = tok->tokAt(2);
9591 94 : if (tok->next() && tok->next()->str() == ";" &&
9592 46 : tok->next()->linenr() != tok->linenr()) {
9593 2 : const int endposition = tok->next()->linenr();
9594 2 : tok = tok->tokAt(-3);
9595 10 : for (int i = 0; i < 4; ++i) {
9596 8 : tok = tok->next();
9597 8 : tok->linenr(endposition);
9598 : }
9599 : }
9600 : }
9601 23227 : }
9602 :
9603 22642 : void Tokenizer::simplifyAsm2()
9604 : {
9605 : // Block declarations: ^{}
9606 : // A C extension used to create lambda like closures.
9607 :
9608 : // Put ^{} statements in asm()
9609 1021678 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9610 999040 : if (tok->str() != "^")
9611 999008 : continue;
9612 :
9613 28 : if (Token::simpleMatch(tok, "^ {") || (Token::simpleMatch(tok->linkAt(1), ") {") && tok->strAt(-1) != "operator")) {
9614 1 : Token * start = tok;
9615 2 : while (start && !Token::Match(start, "[,(;{}=]")) {
9616 1 : if (start->link() && Token::Match(start, ")|]|>"))
9617 0 : start = start->link();
9618 1 : start = start->previous();
9619 : }
9620 :
9621 1 : const Token *last = tok->next()->link();
9622 1 : if (Token::simpleMatch(last, ") {"))
9623 1 : last = last->linkAt(1);
9624 1 : last = last->next();
9625 1 : while (last && !Token::Match(last, "%cop%|,|;|{|}|)")) {
9626 0 : if (Token::Match(last, "(|["))
9627 0 : last = last->link();
9628 0 : last = last->next();
9629 : }
9630 :
9631 1 : if (start && last) {
9632 1 : std::string asmcode;
9633 8 : while (start->next() != last) {
9634 7 : asmcode += start->next()->str();
9635 7 : start->deleteNext();
9636 : }
9637 1 : if (last->str() == "}")
9638 0 : start->insertToken(";");
9639 1 : start->insertToken(")");
9640 1 : start->insertToken("\"" + asmcode + "\"");
9641 1 : start->insertToken("(");
9642 1 : start->insertToken("asm");
9643 1 : start->tokAt(2)->link(start->tokAt(4));
9644 1 : start->tokAt(4)->link(start->tokAt(2));
9645 1 : tok = start->tokAt(4);
9646 : }
9647 : }
9648 : }
9649 22641 : }
9650 :
9651 23228 : void Tokenizer::simplifyAt()
9652 : {
9653 46455 : std::set<std::string> var;
9654 :
9655 1018762 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9656 995538 : if (Token::Match(tok, "%name%|] @ %num%|%name%|%str%|(")) {
9657 9 : const Token *end = tok->tokAt(2);
9658 9 : if (end->isLiteral())
9659 5 : end = end->next();
9660 4 : else if (end->str() == "(") {
9661 1 : int par = 0;
9662 4 : while ((end = end->next()) != nullptr) {
9663 4 : if (end->str() == "(")
9664 0 : par++;
9665 4 : else if (end->str() == ")") {
9666 1 : if (--par < 0)
9667 1 : break;
9668 : }
9669 : }
9670 1 : end = end ? end->next() : nullptr;
9671 3 : } else if (var.find(end->str()) != var.end())
9672 1 : end = end->next();
9673 : else
9674 2 : continue;
9675 :
9676 7 : if (Token::Match(end, ": %num% ;"))
9677 2 : end = end->tokAt(2);
9678 :
9679 7 : if (Token::Match(end, "[;=]")) {
9680 7 : if (tok->isName())
9681 6 : var.insert(tok->str());
9682 7 : tok->isAtAddress(true);
9683 7 : Token::eraseTokens(tok, end);
9684 : }
9685 : }
9686 :
9687 : // keywords in compiler from cosmic software for STM8
9688 : // TODO: Should use platform configuration.
9689 995541 : if (Token::Match(tok, "@ builtin|eeprom|far|inline|interrupt|near|noprd|nostack|nosvf|packed|stack|svlreg|tiny|vector")) {
9690 1 : tok->str(tok->next()->str() + "@");
9691 1 : tok->deleteNext();
9692 : }
9693 : }
9694 23224 : }
9695 :
9696 : // Simplify bitfields
9697 22642 : void Tokenizer::simplifyBitfields()
9698 : {
9699 22642 : bool goback = false;
9700 998913 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9701 976277 : if (goback) {
9702 3 : goback = false;
9703 3 : tok = tok->previous();
9704 : }
9705 976277 : Token *last = nullptr;
9706 :
9707 976277 : if (Token::simpleMatch(tok, "for ("))
9708 972 : tok = tok->linkAt(1);
9709 :
9710 976277 : if (!Token::Match(tok, ";|{|}|public:|protected:|private:"))
9711 788598 : continue;
9712 :
9713 187673 : bool isEnum = false;
9714 187673 : if (tok->str() == "}") {
9715 48112 : const Token *type = tok->link()->previous();
9716 61412 : while (type && type->isName()) {
9717 13524 : if (type->str() == "enum") {
9718 224 : isEnum = true;
9719 224 : break;
9720 : }
9721 13300 : type = type->previous();
9722 : }
9723 : }
9724 :
9725 187681 : if (Token::Match(tok->next(), "const| %type% %name% :") &&
9726 187757 : !Token::Match(tok->next(), "case|public|protected|private|class|struct") &&
9727 73 : !Token::simpleMatch(tok->tokAt(2), "default :")) {
9728 72 : Token *tok1 = (tok->next()->str() == "const") ? tok->tokAt(3) : tok->tokAt(2);
9729 72 : if (Token::Match(tok1, "%name% : %num% [;=]"))
9730 55 : tok1->setBits(MathLib::toBigNumber(tok1->strAt(2)));
9731 144 : if (tok1 && tok1->tokAt(2) &&
9732 72 : (Token::Match(tok1->tokAt(2), "%bool%|%num%") ||
9733 11 : !Token::Match(tok1->tokAt(2), "public|protected|private| %type% ::|<|,|{|;"))) {
9734 195 : while (tok1->next() && !Token::Match(tok1->next(), "[;,)]{}=]")) {
9735 130 : if (Token::Match(tok1->next(), "[([]"))
9736 2 : Token::eraseTokens(tok1, tok1->next()->link());
9737 130 : tok1->deleteNext();
9738 : }
9739 :
9740 65 : last = tok1->next();
9741 : }
9742 187612 : } else if (isEnum && Token::Match(tok, "} %name%| : %num% ;")) {
9743 2 : if (tok->next()->str() == ":") {
9744 1 : tok->deleteNext(2);
9745 1 : tok->insertToken("Anonymous");
9746 : } else {
9747 1 : tok->next()->deleteNext(2);
9748 : }
9749 187613 : } else if (Token::Match(tok->next(), "const| %type% : %num%|%bool% ;") &&
9750 3 : tok->next()->str() != "default") {
9751 3 : const int offset = (tok->next()->str() == "const") ? 1 : 0;
9752 3 : if (!Token::Match(tok->tokAt(3 + offset), "[{};()]")) {
9753 3 : tok->deleteNext(4 + offset);
9754 3 : goback = true;
9755 : }
9756 : }
9757 :
9758 187673 : if (last && last->str() == ",") {
9759 3 : Token * tok1 = last;
9760 3 : tok1->str(";");
9761 :
9762 3 : const Token *const tok2 = tok->next();
9763 3 : tok1->insertToken(tok2->str());
9764 3 : tok1 = tok1->next();
9765 3 : tok1->isSigned(tok2->isSigned());
9766 3 : tok1->isUnsigned(tok2->isUnsigned());
9767 3 : tok1->isLong(tok2->isLong());
9768 : }
9769 : }
9770 22638 : }
9771 :
9772 323 : static bool isStdContainerOrIterator(const Token* tok, const Settings& settings)
9773 : {
9774 323 : const Library::Container* ctr = settings.library.detectContainerOrIterator(tok, nullptr, /*withoutStd*/ true);
9775 323 : return ctr && startsWith(ctr->startPattern, "std ::");
9776 : }
9777 :
9778 72 : static bool isStdSmartPointer(const Token* tok, const Settings& settings)
9779 : {
9780 72 : const Library::SmartPointer* ptr = settings.library.detectSmartPointer(tok, /*withoutStd*/ true);
9781 72 : return ptr && startsWith(ptr->name, "std::");
9782 : }
9783 :
9784 : // Add std:: in front of std classes, when using namespace std; was given
9785 22624 : void Tokenizer::simplifyNamespaceStd()
9786 : {
9787 22624 : if (!isCPP())
9788 5917 : return;
9789 :
9790 33416 : std::set<std::string> userFunctions;
9791 :
9792 20708 : for (Token* tok = Token::findsimplematch(list.front(), "using namespace std ;"); tok; tok = tok->next()) {
9793 4001 : bool insert = false;
9794 4001 : if (Token::Match(tok, "enum class|struct| %name%| :|{")) { // Don't replace within enum definitions
9795 8 : skipEnumBody(tok);
9796 : }
9797 4001 : if (!tok->isName() || tok->isKeyword() || tok->isStandardType() || tok->varId())
9798 3364 : continue;
9799 637 : if (Token::Match(tok->previous(), ".|::|namespace"))
9800 223 : continue;
9801 414 : if (Token::simpleMatch(tok->next(), "(")) {
9802 146 : if (isFunctionHead(tok->next(), "{"))
9803 83 : userFunctions.insert(tok->str());
9804 63 : else if (isFunctionHead(tok->next(), ";")) {
9805 61 : const Token *start = tok;
9806 141 : while (Token::Match(start->previous(), "%type%|*|&"))
9807 80 : start = start->previous();
9808 61 : if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
9809 15 : userFunctions.insert(tok->str());
9810 : }
9811 146 : if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings.library.matchArguments(tok, "std::" + tok->str()))
9812 10 : insert = true;
9813 356 : } else if (Token::simpleMatch(tok->next(), "<") &&
9814 88 : (isStdContainerOrIterator(tok, mSettings) || isStdSmartPointer(tok, mSettings)))
9815 21 : insert = true;
9816 494 : else if (mSettings.library.hasAnyTypeCheck("std::" + tok->str()) ||
9817 729 : mSettings.library.podtype("std::" + tok->str()) ||
9818 235 : isStdContainerOrIterator(tok, mSettings))
9819 20 : insert = true;
9820 :
9821 414 : if (insert) {
9822 51 : tok->previous()->insertToken("std");
9823 51 : tok->previous()->linenr(tok->linenr()); // For stylistic reasons we put the std:: in the same line as the following token
9824 51 : tok->previous()->fileIndex(tok->fileIndex());
9825 51 : tok->previous()->insertToken("::");
9826 : }
9827 : }
9828 :
9829 746625 : for (Token* tok = list.front(); tok; tok = tok->next()) {
9830 729927 : if (Token::simpleMatch(tok, "using namespace std ;")) {
9831 51 : Token::eraseTokens(tok, tok->tokAt(4));
9832 51 : tok->deleteThis();
9833 : }
9834 : }
9835 : }
9836 :
9837 :
9838 22669 : void Tokenizer::simplifyMicrosoftMemoryFunctions()
9839 : {
9840 : // skip if not Windows
9841 22669 : if (!mSettings.platform.isWindows())
9842 19129 : return;
9843 :
9844 99918 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9845 96381 : if (tok->strAt(1) != "(")
9846 84651 : continue;
9847 :
9848 11730 : if (Token::Match(tok, "CopyMemory|RtlCopyMemory|RtlCopyBytes")) {
9849 3 : tok->str("memcpy");
9850 11727 : } else if (Token::Match(tok, "MoveMemory|RtlMoveMemory")) {
9851 2 : tok->str("memmove");
9852 11725 : } else if (Token::Match(tok, "FillMemory|RtlFillMemory|RtlFillBytes")) {
9853 : // FillMemory(dst, len, val) -> memset(dst, val, len)
9854 4 : tok->str("memset");
9855 :
9856 4 : Token *tok1 = tok->tokAt(2);
9857 4 : if (tok1)
9858 4 : tok1 = tok1->nextArgument(); // Second argument
9859 4 : if (tok1) {
9860 4 : Token *tok2 = tok1->nextArgument(); // Third argument
9861 :
9862 4 : if (tok2)
9863 4 : Token::move(tok1->previous(), tok2->tokAt(-2), tok->next()->link()->previous()); // Swap third with second argument
9864 : }
9865 11721 : } else if (Token::Match(tok, "ZeroMemory|RtlZeroMemory|RtlZeroBytes|RtlSecureZeroMemory")) {
9866 : // ZeroMemory(dst, len) -> memset(dst, 0, len)
9867 29 : tok->str("memset");
9868 :
9869 29 : Token *tok1 = tok->tokAt(2);
9870 29 : if (tok1)
9871 29 : tok1 = tok1->nextArgument(); // Second argument
9872 :
9873 29 : if (tok1) {
9874 29 : tok1 = tok1->previous();
9875 29 : tok1->insertToken("0");
9876 29 : tok1 = tok1->next();
9877 29 : tok1->insertToken(",");
9878 : }
9879 11692 : } else if (Token::simpleMatch(tok, "RtlCompareMemory")) {
9880 : // RtlCompareMemory(src1, src2, len) -> memcmp(src1, src2, len)
9881 13 : tok->str("memcmp");
9882 : // For the record, when memcmp returns 0, both strings are equal.
9883 : // When RtlCompareMemory returns len, both strings are equal.
9884 : // It might be needed to improve this replacement by something
9885 : // like ((len - memcmp(src1, src2, len)) % (len + 1)) to
9886 : // respect execution path (if required)
9887 : }
9888 : }
9889 : }
9890 :
9891 : namespace {
9892 : struct triplet {
9893 2496 : triplet(const char* m, const char* u) : mbcs(m), unicode(u) {}
9894 : std::string mbcs, unicode;
9895 : };
9896 :
9897 : const std::map<std::string, triplet> apis = {
9898 : std::make_pair("_topen", triplet("open", "_wopen")),
9899 : std::make_pair("_tsopen_s", triplet("_sopen_s", "_wsopen_s")),
9900 : std::make_pair("_tfopen", triplet("fopen", "_wfopen")),
9901 : std::make_pair("_tfopen_s", triplet("fopen_s", "_wfopen_s")),
9902 : std::make_pair("_tfreopen", triplet("freopen", "_wfreopen")),
9903 : std::make_pair("_tfreopen_s", triplet("freopen_s", "_wfreopen_s")),
9904 : std::make_pair("_tcscat", triplet("strcat", "wcscat")),
9905 : std::make_pair("_tcschr", triplet("strchr", "wcschr")),
9906 : std::make_pair("_tcscmp", triplet("strcmp", "wcscmp")),
9907 : std::make_pair("_tcsdup", triplet("strdup", "wcsdup")),
9908 : std::make_pair("_tcscpy", triplet("strcpy", "wcscpy")),
9909 : std::make_pair("_tcslen", triplet("strlen", "wcslen")),
9910 : std::make_pair("_tcsncat", triplet("strncat", "wcsncat")),
9911 : std::make_pair("_tcsncpy", triplet("strncpy", "wcsncpy")),
9912 : std::make_pair("_tcsnlen", triplet("strnlen", "wcsnlen")),
9913 : std::make_pair("_tcsrchr", triplet("strrchr", "wcsrchr")),
9914 : std::make_pair("_tcsstr", triplet("strstr", "wcsstr")),
9915 : std::make_pair("_tcstok", triplet("strtok", "wcstok")),
9916 : std::make_pair("_ftprintf", triplet("fprintf", "fwprintf")),
9917 : std::make_pair("_tprintf", triplet("printf", "wprintf")),
9918 : std::make_pair("_stprintf", triplet("sprintf", "swprintf")),
9919 : std::make_pair("_sntprintf", triplet("_snprintf", "_snwprintf")),
9920 : std::make_pair("_ftscanf", triplet("fscanf", "fwscanf")),
9921 : std::make_pair("_tscanf", triplet("scanf", "wscanf")),
9922 : std::make_pair("_stscanf", triplet("sscanf", "swscanf")),
9923 : std::make_pair("_ftprintf_s", triplet("fprintf_s", "fwprintf_s")),
9924 : std::make_pair("_tprintf_s", triplet("printf_s", "wprintf_s")),
9925 : std::make_pair("_stprintf_s", triplet("sprintf_s", "swprintf_s")),
9926 : std::make_pair("_sntprintf_s", triplet("_snprintf_s", "_snwprintf_s")),
9927 : std::make_pair("_ftscanf_s", triplet("fscanf_s", "fwscanf_s")),
9928 : std::make_pair("_tscanf_s", triplet("scanf_s", "wscanf_s")),
9929 : std::make_pair("_stscanf_s", triplet("sscanf_s", "swscanf_s"))
9930 : };
9931 : }
9932 :
9933 22669 : void Tokenizer::simplifyMicrosoftStringFunctions()
9934 : {
9935 : // skip if not Windows
9936 22669 : if (!mSettings.platform.isWindows())
9937 19130 : return;
9938 :
9939 3537 : const bool ansi = mSettings.platform.type == Platform::Type::Win32A;
9940 99098 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9941 95561 : if (tok->strAt(1) != "(")
9942 83844 : continue;
9943 :
9944 11717 : const std::map<std::string, triplet>::const_iterator match = apis.find(tok->str());
9945 11717 : if (match!=apis.end()) {
9946 177 : tok->str(ansi ? match->second.mbcs : match->second.unicode);
9947 177 : tok->originalName(match->first);
9948 11540 : } else if (Token::Match(tok, "_T|_TEXT|TEXT ( %char%|%str% )")) {
9949 256 : tok->deleteNext();
9950 256 : tok->deleteThis();
9951 256 : tok->deleteNext();
9952 256 : if (!ansi) {
9953 164 : tok->isLong(true);
9954 164 : if (tok->str()[0] != 'L')
9955 164 : tok->str("L" + tok->str());
9956 : }
9957 269 : while (Token::Match(tok->next(), "_T|_TEXT|TEXT ( %char%|%str% )")) {
9958 13 : tok->next()->deleteNext();
9959 13 : tok->next()->deleteThis();
9960 13 : tok->next()->deleteNext();
9961 13 : tok->concatStr(tok->next()->str());
9962 13 : tok->deleteNext();
9963 : }
9964 : }
9965 : }
9966 : }
9967 :
9968 : // Remove Borland code
9969 22669 : void Tokenizer::simplifyBorland()
9970 : {
9971 : // skip if not Windows
9972 22669 : if (!mSettings.platform.isWindows())
9973 19132 : return;
9974 3537 : if (isC())
9975 2656 : return;
9976 51789 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9977 50908 : if (Token::Match(tok, "( __closure * %name% )")) {
9978 1 : tok->deleteNext();
9979 : }
9980 : }
9981 :
9982 : // I think that these classes are always declared at the outer scope
9983 : // I save some time by ignoring inner classes.
9984 11165 : for (Token *tok = list.front(); tok; tok = tok->next()) {
9985 10284 : if (tok->str() == "{" && !Token::Match(tok->tokAt(-2), "namespace %type%")) {
9986 1230 : tok = tok->link();
9987 1230 : if (!tok)
9988 0 : break;
9989 9054 : } else if (Token::Match(tok, "class %name% :|{")) {
9990 33 : while (tok && tok->str() != "{" && tok->str() != ";")
9991 25 : tok = tok->next();
9992 8 : if (!tok)
9993 0 : break;
9994 8 : if (tok->str() == ";")
9995 0 : continue;
9996 :
9997 8 : const Token* end = tok->link()->next();
9998 79 : for (Token *tok2 = tok->next(); tok2 != end; tok2 = tok2->next()) {
9999 73 : if (tok2->str() == "__property" &&
10000 2 : Token::Match(tok2->previous(), ";|{|}|protected:|public:|__published:")) {
10001 8 : while (tok2->next() && !Token::Match(tok2->next(), "{|;"))
10002 6 : tok2->deleteNext();
10003 2 : tok2->deleteThis();
10004 2 : if (tok2->str() == "{") {
10005 2 : Token::eraseTokens(tok2, tok2->link());
10006 2 : tok2->deleteNext();
10007 2 : tok2->deleteThis();
10008 :
10009 : // insert "; __property ;"
10010 2 : tok2->previous()->insertToken(";");
10011 2 : tok2->previous()->insertToken("__property");
10012 2 : tok2->previous()->insertToken(";");
10013 : }
10014 : }
10015 : }
10016 : }
10017 : }
10018 : }
10019 :
10020 22733 : void Tokenizer::createSymbolDatabase()
10021 : {
10022 22733 : if (!mSymbolDatabase)
10023 22695 : mSymbolDatabase = new SymbolDatabase(*this, mSettings, mErrorLogger);
10024 22708 : mSymbolDatabase->validate();
10025 22704 : }
10026 :
10027 548 : bool Tokenizer::operatorEnd(const Token * tok)
10028 : {
10029 548 : if (tok && tok->str() == ")") {
10030 547 : if (isFunctionHead(tok, "{|;|?|:|["))
10031 481 : return true;
10032 :
10033 66 : tok = tok->next();
10034 66 : while (tok && !Token::Match(tok, "[=;{),]")) {
10035 64 : if (Token::Match(tok, "const|volatile|override")) {
10036 0 : tok = tok->next();
10037 64 : } else if (tok->str() == "noexcept") {
10038 0 : tok = tok->next();
10039 0 : if (tok && tok->str() == "(") {
10040 0 : tok = tok->link()->next();
10041 : }
10042 64 : } else if (tok->str() == "throw" && tok->next() && tok->next()->str() == "(") {
10043 0 : tok = tok->next()->link()->next();
10044 : }
10045 : // unknown macros ") MACRO {" and ") MACRO(...) {"
10046 64 : else if (tok->isUpperCaseName()) {
10047 0 : tok = tok->next();
10048 0 : if (tok && tok->str() == "(") {
10049 0 : tok = tok->link()->next();
10050 : }
10051 184 : } else if (Token::Match(tok, "%op% !!(") ||
10052 120 : (Token::Match(tok, "%op% (") && !isFunctionHead(tok->next(), "{")))
10053 14 : break;
10054 : else
10055 50 : return false;
10056 : }
10057 :
10058 16 : return true;
10059 : }
10060 :
10061 1 : return false;
10062 : }
10063 :
10064 22641 : void Tokenizer::simplifyOperatorName()
10065 : {
10066 22641 : if (isC())
10067 5924 : return;
10068 :
10069 748640 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10070 731925 : if (Token::Match(tok, "using|:: operator %op%|%name% ;")) {
10071 4 : tok->next()->str("operator" + tok->strAt(2));
10072 4 : tok->next()->deleteNext();
10073 731348 : continue;
10074 : }
10075 :
10076 731924 : if (tok->str() != "operator")
10077 731341 : continue;
10078 : // operator op
10079 579 : if (Token::Match(tok, "operator %op% (") && !operatorEnd(tok->linkAt(2))) {
10080 3 : tok->str(tok->str() + tok->next()->str());
10081 3 : tok->deleteNext();
10082 3 : continue;
10083 : }
10084 1152 : std::string op;
10085 576 : Token *par = tok->next();
10086 576 : bool done = false;
10087 1671 : while (!done && par) {
10088 1176 : done = true;
10089 1176 : if (par->isName()) {
10090 66 : op += par->str();
10091 66 : par = par->next();
10092 : // merge namespaces eg. 'operator std :: string () const {'
10093 66 : if (Token::Match(par, ":: %name%|%op%|.")) {
10094 7 : op += par->str();
10095 7 : par = par->next();
10096 : }
10097 66 : done = false;
10098 1110 : } else if (Token::Match(par, ".|%op%|,")) {
10099 : // check for operator in template
10100 476 : if (par->str() == "," && !op.empty())
10101 2 : break;
10102 474 : if (!(Token::Match(par, "<|>") && !op.empty())) {
10103 468 : op += par->str() == "." ? par->originalName() : par->str();
10104 468 : par = par->next();
10105 468 : done = false;
10106 : }
10107 634 : } else if (Token::simpleMatch(par, "[ ]")) {
10108 19 : op += "[]";
10109 19 : par = par->tokAt(2);
10110 19 : done = false;
10111 615 : } else if (Token::Match(par, "( *| )")) {
10112 : // break out and simplify..
10113 125 : if (operatorEnd(par->next()))
10114 77 : break;
10115 :
10116 97 : while (par->str() != ")") {
10117 49 : op += par->str();
10118 49 : par = par->next();
10119 : }
10120 48 : op += ")";
10121 48 : par = par->next();
10122 48 : if (Token::simpleMatch(par, "...")) {
10123 1 : op.clear();
10124 1 : par = nullptr;
10125 1 : break;
10126 : }
10127 47 : done = false;
10128 490 : } else if (Token::Match(par, "\"\" %name% )| (|;|<")) {
10129 12 : op += "\"\"";
10130 12 : op += par->strAt(1);
10131 12 : par = par->tokAt(2);
10132 12 : if (par->str() == ")") {
10133 1 : par->link()->deleteThis();
10134 1 : par = par->next();
10135 1 : par->deletePrevious();
10136 1 : tok = par->tokAt(-3);
10137 : }
10138 12 : done = true;
10139 478 : } else if (par->str() == "::") {
10140 1 : op += par->str();
10141 1 : par = par->next();
10142 1 : done = false;
10143 477 : } else if (par->str() == ";" || par->str() == ")") {
10144 4 : done = true;
10145 473 : } else if (par->str() != "(") {
10146 2 : syntaxError(par, "operator");
10147 : }
10148 : }
10149 :
10150 575 : const bool returnsRef = Token::simpleMatch(par, "( & (") && tok->next()->isName();
10151 575 : if (par && !op.empty()) {
10152 569 : if (returnsRef) {
10153 3 : par->next()->insertToken("operator" + op)->isOperatorKeyword(true);
10154 3 : tok->deleteThis();
10155 : }
10156 : else {
10157 566 : tok->str("operator" + op);
10158 566 : Token::eraseTokens(tok, par);
10159 : }
10160 : }
10161 :
10162 575 : if (!op.empty() && !returnsRef)
10163 566 : tok->isOperatorKeyword(true);
10164 : }
10165 :
10166 748593 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10167 731873 : if (Token::Match(tok, "%op% %str% %name%")) {
10168 2 : const std::string name = tok->strAt(2);
10169 1 : Token * const str = tok->next();
10170 1 : str->deleteNext();
10171 1 : tok->insertToken("operator\"\"" + name);
10172 1 : tok = tok->next();
10173 1 : tok->isOperatorKeyword(true);
10174 1 : tok->insertToken("(");
10175 1 : str->insertToken(")");
10176 1 : Token::createMutualLinks(tok->next(), str->next());
10177 1 : str->insertToken(std::to_string(Token::getStrLength(str)));
10178 1 : str->insertToken(",");
10179 : }
10180 : }
10181 :
10182 16717 : if (mSettings.debugwarnings) {
10183 1362 : const Token *tok = list.front();
10184 :
10185 1365 : while ((tok = Token::findsimplematch(tok, "operator")) != nullptr) {
10186 3 : reportError(tok, Severity::debug, "debug",
10187 6 : "simplifyOperatorName: found unsimplified operator name");
10188 3 : tok = tok->next();
10189 : }
10190 : }
10191 : }
10192 :
10193 22628 : void Tokenizer::simplifyOverloadedOperators()
10194 : {
10195 22628 : if (isC())
10196 5917 : return;
10197 33416 : std::set<std::string> classNames;
10198 33417 : std::set<nonneg int> classVars;
10199 744967 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10200 728244 : if (!tok->isName())
10201 432763 : continue;
10202 :
10203 295477 : if (Token::simpleMatch(tok, "this ) (") && Token::simpleMatch(tok->tokAt(-2), "( *")) {
10204 1 : tok = tok->next();
10205 1 : tok->insertToken("operator()");
10206 1 : tok->insertToken(".");
10207 1 : continue;
10208 : }
10209 :
10210 : // Get classes that have operator() member
10211 295490 : if (Token::Match(tok, "class|struct %name% [:{]")) {
10212 5180 : int indent = 0;
10213 66399 : for (const Token *tok2 = tok->next(); tok2; tok2 = tok2->next()) {
10214 66394 : if (tok2->str() == "}")
10215 5131 : break;
10216 61263 : if (indent == 0 && tok2->str() == ";")
10217 2 : break;
10218 61261 : if (tok2->str() == "{") {
10219 8008 : if (indent == 0)
10220 5172 : ++indent;
10221 : else
10222 2836 : tok2 = tok2->link();
10223 53295 : } else if (indent == 1 && Token::simpleMatch(tok2, "operator() (") && isFunctionHead(tok2->next(), ";{")) {
10224 42 : classNames.insert(tok->strAt(1));
10225 42 : break;
10226 : }
10227 : }
10228 : }
10229 :
10230 : // Get variables that have operator() member
10231 295490 : if (Token::Match(tok, "%type% &| %var%") && classNames.find(tok->str()) != classNames.end()) {
10232 6 : tok = tok->next();
10233 6 : while (!tok->isName())
10234 0 : tok = tok->next();
10235 6 : classVars.insert(tok->varId());
10236 : }
10237 :
10238 : // Simplify operator() calls
10239 295492 : if (Token::Match(tok, "%var% (") && classVars.find(tok->varId()) != classVars.end()) {
10240 : // constructor init list..
10241 5 : if (Token::Match(tok->previous(), "[:,]")) {
10242 1 : const Token *start = tok->previous();
10243 1 : while (Token::simpleMatch(start, ",")) {
10244 1 : if (Token::simpleMatch(start->previous(), ")"))
10245 0 : start = start->linkAt(-1);
10246 : else
10247 1 : break;
10248 0 : if (Token::Match(start->previous(), "%name%"))
10249 0 : start = start->tokAt(-2);
10250 : else
10251 0 : break;
10252 : }
10253 1 : const Token *after = tok->linkAt(1);
10254 1 : while (Token::Match(after, ")|} , %name% (|{"))
10255 0 : after = after->linkAt(3);
10256 :
10257 : // Do not simplify initlist
10258 1 : if (Token::simpleMatch(start, ":") && Token::simpleMatch(after, ") {"))
10259 0 : continue;
10260 : }
10261 :
10262 5 : tok->insertToken("operator()");
10263 5 : tok->insertToken(".");
10264 : }
10265 : }
10266 : }
10267 :
10268 : // remove unnecessary member qualification..
10269 22669 : void Tokenizer::removeUnnecessaryQualification()
10270 : {
10271 22669 : if (isC())
10272 5935 : return;
10273 :
10274 16740 : std::vector<Space> classInfo;
10275 729712 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10276 720299 : if (Token::Match(tok, "class|struct|namespace %type% :|{") &&
10277 7322 : (!tok->previous() || tok->previous()->str() != "enum")) {
10278 5168 : Space info;
10279 5168 : info.isNamespace = tok->str() == "namespace";
10280 5168 : tok = tok->next();
10281 5168 : info.className = tok->str();
10282 5168 : tok = tok->next();
10283 7204 : while (tok && tok->str() != "{")
10284 2036 : tok = tok->next();
10285 5168 : if (!tok)
10286 7 : return;
10287 5161 : info.bodyEnd = tok->link();
10288 5161 : classInfo.push_back(std::move(info));
10289 707813 : } else if (!classInfo.empty()) {
10290 74345 : if (tok == classInfo.back().bodyEnd)
10291 5161 : classInfo.pop_back();
10292 69184 : else if (tok->str() == classInfo.back().className &&
10293 71362 : !classInfo.back().isNamespace && tok->previous()->str() != ":" &&
10294 2178 : (Token::Match(tok, "%type% :: ~| %type% (") ||
10295 2173 : Token::Match(tok, "%type% :: operator"))) {
10296 5 : const Token *tok1 = tok->tokAt(3);
10297 5 : if (tok->strAt(2) == "operator") {
10298 : // check for operator ()
10299 0 : if (tok1->str() == "(")
10300 0 : tok1 = tok1->next();
10301 :
10302 0 : while (tok1 && tok1->str() != "(") {
10303 0 : if (tok1->str() == ";")
10304 0 : break;
10305 0 : tok1 = tok1->next();
10306 : }
10307 0 : if (!tok1 || tok1->str() != "(")
10308 0 : continue;
10309 5 : } else if (tok->strAt(2) == "~")
10310 0 : tok1 = tok1->next();
10311 :
10312 5 : if (!tok1 || !Token::Match(tok1->link(), ") const| {|;|:")) {
10313 0 : continue;
10314 : }
10315 :
10316 : const bool isConstructorOrDestructor =
10317 5 : Token::Match(tok, "%type% :: ~| %type%") && (tok->strAt(2) == tok->str() || (tok->strAt(2) == "~" && tok->strAt(3) == tok->str()));
10318 5 : if (!isConstructorOrDestructor) {
10319 5 : bool isPrependedByType = Token::Match(tok->previous(), "%type%");
10320 5 : if (!isPrependedByType) {
10321 1 : const Token* tok2 = tok->tokAt(-2);
10322 1 : isPrependedByType = Token::Match(tok2, "%type% *|&");
10323 : }
10324 5 : if (!isPrependedByType) {
10325 1 : const Token* tok3 = tok->tokAt(-3);
10326 1 : isPrependedByType = Token::Match(tok3, "%type% * *|&");
10327 : }
10328 5 : if (!isPrependedByType) {
10329 : // It's not a constructor declaration and it's not a function declaration so
10330 : // this is a function call which can have all the qualifiers just fine - skip.
10331 1 : continue;
10332 : }
10333 : }
10334 : }
10335 : }
10336 : }
10337 : }
10338 :
10339 1 : void Tokenizer::printUnknownTypes() const
10340 : {
10341 1 : if (!mSymbolDatabase)
10342 0 : return;
10343 :
10344 2 : std::vector<std::pair<std::string, const Token *>> unknowns;
10345 :
10346 2 : for (int i = 1; i <= mVarId; ++i) {
10347 1 : const Variable *var = mSymbolDatabase->getVariableFromVarId(i);
10348 1 : if (!var)
10349 1 : continue;
10350 : // is unknown type?
10351 1 : if (var->type() || var->typeStartToken()->isStandardType())
10352 1 : continue;
10353 :
10354 0 : std::string name;
10355 : const Token * nameTok;
10356 :
10357 : // single token type?
10358 0 : if (var->typeStartToken() == var->typeEndToken()) {
10359 0 : nameTok = var->typeStartToken();
10360 0 : name = nameTok->str();
10361 : }
10362 :
10363 : // complicated type
10364 : else {
10365 0 : const Token *tok = var->typeStartToken();
10366 0 : int level = 0;
10367 :
10368 0 : nameTok = tok;
10369 :
10370 0 : while (tok) {
10371 : // skip pointer and reference part of type
10372 0 : if (level == 0 && Token::Match(tok, "*|&"))
10373 0 : break;
10374 :
10375 0 : name += tok->str();
10376 :
10377 0 : if (Token::Match(tok, "struct|union|enum"))
10378 0 : name += " ";
10379 :
10380 : // pointers and references are OK in template
10381 0 : else if (tok->str() == "<")
10382 0 : ++level;
10383 0 : else if (tok->str() == ">")
10384 0 : --level;
10385 :
10386 0 : if (tok == var->typeEndToken())
10387 0 : break;
10388 :
10389 0 : tok = tok->next();
10390 : }
10391 : }
10392 :
10393 0 : unknowns.emplace_back(std::move(name), nameTok);
10394 : }
10395 :
10396 1 : if (!unknowns.empty()) {
10397 0 : std::string last;
10398 0 : int count = 0;
10399 :
10400 0 : for (auto it = unknowns.cbegin(); it != unknowns.cend(); ++it) {
10401 : // skip types is std namespace because they are not interesting
10402 0 : if (it->first.find("std::") != 0) {
10403 0 : if (it->first != last) {
10404 0 : last = it->first;
10405 0 : count = 1;
10406 0 : reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10407 : } else {
10408 0 : if (count < 3) // limit same type to 3
10409 0 : reportError(it->second, Severity::debug, "debug", "Unknown type \'" + it->first + "\'.");
10410 0 : count++;
10411 : }
10412 : }
10413 : }
10414 : }
10415 : }
10416 :
10417 45683 : void Tokenizer::prepareTernaryOpForAST()
10418 : {
10419 : // http://en.cppreference.com/w/cpp/language/operator_precedence says about ternary operator:
10420 : // "The expression in the middle of the conditional operator (between ? and :) is parsed as if parenthesized: its precedence relative to ?: is ignored."
10421 : // The AST parser relies on this function to add such parentheses where necessary.
10422 2034124 : for (Token* tok = list.front(); tok; tok = tok->next()) {
10423 1988454 : if (tok->str() == "?") {
10424 1202 : bool parenthesesNeeded = false;
10425 1202 : int depth = 0;
10426 1202 : Token* tok2 = tok->next();
10427 2846 : for (; tok2; tok2 = tok2->next()) {
10428 2846 : if (tok2->link() && Token::Match(tok2, "[|(|<"))
10429 196 : tok2 = tok2->link();
10430 2650 : else if (tok2->str() == ":") {
10431 1181 : if (depth == 0)
10432 1178 : break;
10433 3 : depth--;
10434 1469 : } else if (tok2->str() == ";" || (tok2->link() && tok2->str() != "{" && tok2->str() != "}"))
10435 24 : break;
10436 1445 : else if (tok2->str() == ",")
10437 11 : parenthesesNeeded = true;
10438 1434 : else if (tok2->str() == "<")
10439 5 : parenthesesNeeded = true;
10440 1429 : else if (tok2->str() == "?") {
10441 19 : depth++;
10442 19 : parenthesesNeeded = true;
10443 : }
10444 : }
10445 1202 : if (parenthesesNeeded && tok2 && tok2->str() == ":") {
10446 17 : tok->insertToken("(");
10447 17 : tok2->insertTokenBefore(")");
10448 17 : Token::createMutualLinks(tok->next(), tok2->previous());
10449 : }
10450 : }
10451 : }
10452 45677 : }
10453 :
10454 23 : void Tokenizer::reportError(const Token* tok, const Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10455 : {
10456 46 : const std::list<const Token*> callstack(1, tok);
10457 23 : reportError(callstack, severity, id, msg, inconclusive);
10458 23 : }
10459 :
10460 23 : void Tokenizer::reportError(const std::list<const Token*>& callstack, Severity severity, const std::string& id, const std::string& msg, bool inconclusive) const
10461 : {
10462 46 : const ErrorMessage errmsg(callstack, &list, severity, id, msg, inconclusive ? Certainty::inconclusive : Certainty::normal);
10463 23 : mErrorLogger.reportErr(errmsg);
10464 23 : }
10465 :
10466 22633 : void Tokenizer::setPodTypes()
10467 : {
10468 1014357 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10469 991717 : if (!tok->isName() || tok->varId())
10470 715555 : continue;
10471 :
10472 : // pod type
10473 276167 : const Library::PodType *podType = mSettings.library.podtype(tok->str());
10474 276169 : if (podType) {
10475 2278 : const Token *prev = tok->previous();
10476 2814 : while (prev && prev->isName())
10477 536 : prev = prev->previous();
10478 2278 : if (prev && !Token::Match(prev, ";|{|}|,|("))
10479 71 : continue;
10480 2207 : tok->isStandardType(true);
10481 : }
10482 : }
10483 22629 : }
10484 :
10485 12 : const Token *Tokenizer::findSQLBlockEnd(const Token *tokSQLStart)
10486 : {
10487 12 : const Token *tokLastEnd = nullptr;
10488 76 : for (const Token *tok = tokSQLStart->tokAt(2); tok != nullptr; tok = tok->next()) {
10489 71 : if (tokLastEnd == nullptr && tok->str() == ";")
10490 8 : tokLastEnd = tok;
10491 63 : else if (tok->str() == "__CPPCHECK_EMBEDDED_SQL_EXEC__") {
10492 5 : if (Token::simpleMatch(tok->tokAt(-2), "END - __CPPCHECK_EMBEDDED_SQL_EXEC__ ;"))
10493 2 : return tok->next();
10494 3 : return tokLastEnd;
10495 58 : } else if (Token::Match(tok, "{|}|==|&&|!|^|<<|>>|++|+=|-=|/=|*=|>>=|<<=|~"))
10496 2 : break; // We are obviously outside the SQL block
10497 : }
10498 :
10499 7 : return tokLastEnd;
10500 : }
10501 :
10502 22703 : void Tokenizer::simplifyNestedNamespace()
10503 : {
10504 22703 : if (!isCPP())
10505 5936 : return;
10506 :
10507 740147 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10508 723379 : if (Token::Match(tok, "namespace %name% ::") && tok->strAt(-1) != "using") {
10509 7 : Token * tok2 = tok->tokAt(2);
10510 :
10511 : // validate syntax
10512 15 : while (Token::Match(tok2, ":: %name%"))
10513 8 : tok2 = tok2->tokAt(2);
10514 :
10515 7 : if (!tok2 || tok2->str() != "{")
10516 1 : return; // syntax error
10517 :
10518 12 : std::stack<Token *> links;
10519 6 : tok2 = tok->tokAt(2);
10520 :
10521 13 : while (tok2->str() == "::") {
10522 7 : links.push(tok2);
10523 7 : tok2->str("{");
10524 7 : tok2->insertToken("namespace");
10525 7 : tok2 = tok2->tokAt(3);
10526 : }
10527 :
10528 6 : tok = tok2;
10529 :
10530 6 : if (!links.empty() && tok2->str() == "{") {
10531 6 : tok2 = tok2->link();
10532 13 : while (!links.empty()) {
10533 7 : tok2->insertToken("}");
10534 7 : tok2 = tok2->next();
10535 7 : Token::createMutualLinks(links.top(), tok2);
10536 7 : links.pop();
10537 : }
10538 : }
10539 : }
10540 : }
10541 : }
10542 :
10543 22703 : void Tokenizer::simplifyCoroutines()
10544 : {
10545 22703 : if (!isCPP() || mSettings.standards.cpp < Standards::CPP20)
10546 7219 : return;
10547 647099 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10548 631612 : if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await"))
10549 631613 : continue;
10550 3 : Token *end = tok->next();
10551 8 : while (end && end->str() != ";") {
10552 5 : if (Token::Match(end, "[({[]"))
10553 1 : end = end->link();
10554 4 : else if (Token::Match(end, "[)]}]"))
10555 0 : break;
10556 5 : end = end->next();
10557 : }
10558 3 : if (Token::simpleMatch(end, ";")) {
10559 3 : tok->insertToken("(");
10560 3 : end->previous()->insertToken(")");
10561 3 : Token::createMutualLinks(tok->next(), end->previous());
10562 : }
10563 : }
10564 : }
10565 :
10566 23 : static bool sameTokens(const Token *first, const Token *last, const Token *other)
10567 : {
10568 23 : while (other && first->str() == other->str()) {
10569 22 : if (first == last)
10570 7 : return true;
10571 15 : first = first->next();
10572 15 : other = other->next();
10573 : }
10574 :
10575 1 : return false;
10576 : }
10577 :
10578 21 : static bool alreadyHasNamespace(const Token *first, const Token *last, const Token *end)
10579 : {
10580 21 : while (end && last->str() == end->str()) {
10581 10 : if (first == last)
10582 1 : return true;
10583 9 : last = last->previous();
10584 9 : end = end->previous();
10585 : }
10586 :
10587 11 : return false;
10588 : }
10589 :
10590 8 : static Token * deleteAlias(Token * tok)
10591 : {
10592 8 : Token::eraseTokens(tok, Token::findsimplematch(tok, ";"));
10593 :
10594 : // delete first token
10595 8 : tok->deleteThis();
10596 :
10597 : // delete ';' if not last token
10598 8 : tok->deleteThis();
10599 :
10600 8 : return tok;
10601 : }
10602 :
10603 22703 : void Tokenizer::simplifyNamespaceAliases()
10604 : {
10605 22703 : if (!isCPP())
10606 5936 : return;
10607 :
10608 16767 : int scope = 0;
10609 :
10610 740071 : for (Token *tok = list.front(); tok; tok = tok->next()) {
10611 723299 : bool isPrev{};
10612 723299 : if (tok->str() == "{")
10613 32955 : scope++;
10614 690334 : else if (tok->str() == "}")
10615 32956 : scope--;
10616 657376 : else if (Token::Match(tok, "namespace %name% =") || (isPrev = Token::Match(tok->previous(), "namespace %name% ="))) {
10617 17 : if (isPrev)
10618 1 : tok = tok->previous();
10619 17 : if (tok->tokAt(-1) && !Token::Match(tok->tokAt(-1), "[;{}]"))
10620 0 : syntaxError(tok->tokAt(-1));
10621 18 : const std::string name(tok->next()->str());
10622 17 : Token * tokNameStart = tok->tokAt(3);
10623 17 : Token * tokNameEnd = tokNameStart;
10624 :
10625 52 : while (tokNameEnd && tokNameEnd->next() && tokNameEnd->next()->str() != ";") {
10626 36 : if (tokNameEnd->str() == "(") {
10627 1 : if (tokNameEnd->previous()->isName())
10628 1 : unknownMacroError(tokNameEnd->previous());
10629 : else
10630 0 : syntaxError(tokNameEnd);
10631 : }
10632 35 : tokNameEnd = tokNameEnd->next();
10633 : }
10634 :
10635 16 : if (!tokNameEnd)
10636 0 : return; // syntax error
10637 :
10638 16 : int endScope = scope;
10639 16 : Token * tokLast = tokNameEnd->next();
10640 16 : if (!tokLast)
10641 0 : return;
10642 16 : Token * tokNext = tokLast->next();
10643 16 : Token * tok2 = tokNext;
10644 :
10645 246 : while (tok2 && endScope >= scope) {
10646 230 : if (Token::simpleMatch(tok2, "{"))
10647 9 : endScope++;
10648 221 : else if (Token::simpleMatch(tok2, "}"))
10649 12 : endScope--;
10650 209 : else if (tok2->str() == name) {
10651 21 : if (Token::Match(tok2->previous(), "namespace %name% =")) {
10652 : // check for possible duplicate aliases
10653 8 : if (sameTokens(tokNameStart, tokNameEnd, tok2->tokAt(2))) {
10654 : // delete duplicate
10655 7 : tok2 = deleteAlias(tok2->previous());
10656 7 : continue;
10657 : }
10658 : // conflicting declaration (syntax error)
10659 : // cppcheck-suppress duplicateBranch - remove when TODO below is addressed
10660 1 : if (endScope == scope) {
10661 : // delete conflicting declaration
10662 0 : tok2 = deleteAlias(tok2->previous());
10663 : }
10664 :
10665 : // new declaration
10666 : else {
10667 : // TODO: use the new alias in this scope
10668 1 : tok2 = deleteAlias(tok2->previous());
10669 : }
10670 1 : continue;
10671 : }
10672 :
10673 13 : if (tok2->strAt(1) == "::" && !alreadyHasNamespace(tokNameStart, tokNameEnd, tok2)) {
10674 11 : if (Token::simpleMatch(tok2->tokAt(-1), "::") && tokNameStart->str() == "::")
10675 1 : tok2->deletePrevious();
10676 11 : tok2->str(tokNameStart->str());
10677 11 : Token * tok3 = tokNameStart;
10678 28 : while (tok3 != tokNameEnd) {
10679 17 : tok2->insertToken(tok3->next()->str());
10680 17 : tok2 = tok2->next();
10681 17 : tok3 = tok3->next();
10682 : }
10683 : }
10684 : }
10685 222 : tok2 = tok2->next();
10686 : }
10687 :
10688 16 : if (tok->previous() && tokNext) {
10689 8 : Token::eraseTokens(tok->previous(), tokNext);
10690 8 : tok = tokNext->previous();
10691 8 : } else if (tok->previous()) {
10692 1 : Token::eraseTokens(tok->previous(), tokLast);
10693 1 : tok = tokLast;
10694 7 : } else if (tokNext) {
10695 5 : Token::eraseTokens(tok, tokNext);
10696 5 : tok->deleteThis();
10697 : } else {
10698 2 : Token::eraseTokens(tok, tokLast);
10699 2 : tok->deleteThis();
10700 : }
10701 : }
10702 : }
10703 : }
10704 :
10705 3441 : void Tokenizer::setDirectives(std::list<Directive> directives)
10706 : {
10707 3441 : mDirectives = std::move(directives);
10708 3442 : }
10709 :
10710 18331 : bool Tokenizer::hasIfdef(const Token *start, const Token *end) const
10711 : {
10712 18331 : const auto& directives = mDirectives;
10713 18331 : return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10714 759285 : return startsWith(d.str, "#if") &&
10715 115741 : d.linenr >= start->linenr() &&
10716 46568 : d.linenr <= end->linenr() &&
10717 875138 : start->fileIndex() < list.getFiles().size() &&
10718 759397 : d.file == list.getFiles()[start->fileIndex()];
10719 18331 : });
10720 : }
10721 :
10722 164 : bool Tokenizer::isPacked(const Token * bodyStart) const
10723 : {
10724 164 : const auto& directives = mDirectives;
10725 : // TODO: should this return true if the #pragma exists in any line before the start token?
10726 164 : return std::any_of(directives.cbegin(), directives.cend(), [&](const Directive& d) {
10727 932 : return d.linenr < bodyStart->linenr() && d.str == "#pragma pack(1)" && d.file == list.getFiles().front();
10728 164 : });
10729 : }
|