Cppcheck
symboldatabase.cpp
Go to the documentation of this file.
1 /*
2  * Cppcheck - A tool for static C/C++ code analysis
3  * Copyright (C) 2007-2024 Cppcheck team.
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 //---------------------------------------------------------------------------
20 #include "symboldatabase.h"
21 
22 #include "astutils.h"
23 #include "errorlogger.h"
24 #include "errortypes.h"
25 #include "keywords.h"
26 #include "library.h"
27 #include "mathlib.h"
28 #include "path.h"
29 #include "platform.h"
30 #include "settings.h"
31 #include "standards.h"
32 #include "templatesimplifier.h"
33 #include "token.h"
34 #include "tokenize.h"
35 #include "tokenlist.h"
36 #include "utils.h"
37 #include "valueflow.h"
38 
39 #include <algorithm>
40 #include <cassert>
41 #include <cstring>
42 #include <initializer_list>
43 #include <iomanip>
44 #include <iostream>
45 #include <iterator>
46 #include <sstream>
47 #include <stack>
48 #include <string>
49 #include <tuple>
50 #include <type_traits>
51 #include <unordered_map>
52 #include <unordered_set>
53 //---------------------------------------------------------------------------
54 
55 SymbolDatabase::SymbolDatabase(Tokenizer& tokenizer, const Settings& settings, ErrorLogger& errorLogger)
56  : mTokenizer(tokenizer), mSettings(settings), mErrorLogger(errorLogger)
57 {
58  if (!mTokenizer.tokens())
59  return;
60 
63  else if (mSettings.platform.defaultSign == 'u' || mSettings.platform.defaultSign == 'U')
65  else
67 
89 }
90 
91 static const Token* skipScopeIdentifiers(const Token* tok)
92 {
93  if (Token::Match(tok, ":: %name%"))
94  tok = tok->next();
95  while (Token::Match(tok, "%name% ::") ||
96  (Token::Match(tok, "%name% <") && Token::Match(tok->linkAt(1), ">|>> ::"))) {
97  if (tok->strAt(1) == "::")
98  tok = tok->tokAt(2);
99  else
100  tok = tok->linkAt(1)->tokAt(2);
101  }
102 
103  return tok;
104 }
105 
106 static bool isExecutableScope(const Token* tok)
107 {
108  if (!Token::simpleMatch(tok, "{"))
109  return false;
110  const Token * tok2 = tok->link()->previous();
111  if (Token::simpleMatch(tok2, "; }"))
112  return true;
113  if (tok2 == tok)
114  return false;
115  if (Token::simpleMatch(tok2, "} }")) { // inner scope
116  const Token* startTok = tok2->link();
117  if (Token::Match(startTok->previous(), "do|try|else {"))
118  return true;
119  if (Token::Match(startTok->previous(), ")|] {"))
120  return !findLambdaStartToken(tok2);
121  return isExecutableScope(startTok);
122  }
123  return false;
124 }
125 
126 static bool isEnumDefinition(const Token* tok)
127 {
128  if (!Token::Match(tok, "enum class| %name% {|:"))
129  return false;
130  while (!Token::Match(tok, "[{:]"))
131  tok = tok->next();
132  if (tok->str() == "{")
133  return true;
134  tok = tok->next(); // skip ':'
135  while (Token::Match(tok, "%name%|::"))
136  tok = tok->next();
137  return Token::simpleMatch(tok, "{");
138 }
139 
141 {
142  // create global scope
143  scopeList.emplace_back(this, nullptr, nullptr);
144 
145  // pointer to current scope
146  Scope *scope = &scopeList.back();
147 
148  // Store the ending of init lists
149  std::stack<std::pair<const Token*, const Scope*>> endInitList;
150  auto inInitList = [&] {
151  if (endInitList.empty())
152  return false;
153  return endInitList.top().second == scope;
154  };
155 
156  auto addLambda = [this, &scope](const Token* tok, const Token* lambdaEndToken) -> const Token* {
157  const Token* lambdaStartToken = lambdaEndToken->link();
158  const Token* argStart = lambdaStartToken->astParent();
159  const Token* funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
160  const Function* function = addGlobalFunction(scope, tok, argStart, funcStart);
161  if (!function)
162  mTokenizer.syntaxError(tok);
163  return lambdaStartToken;
164  };
165 
166  // Store current access in each scope (depends on evaluation progress)
167  std::map<const Scope*, AccessControl> access;
168 
169  // find all scopes
170  for (const Token *tok = mTokenizer.tokens(); tok; tok = tok ? tok->next() : nullptr) {
171  // #5593 suggested to add here:
173  "SymbolDatabase",
174  tok->progressValue());
175  // Locate next class
176  if ((tok->isCpp() && tok->isKeyword() &&
177  ((Token::Match(tok, "class|struct|union|namespace ::| %name% final| {|:|::|<") &&
178  !Token::Match(tok->previous(), "new|friend|const|enum|typedef|mutable|volatile|using|)|(|<")) ||
179  isEnumDefinition(tok)))
180  || (tok->isC() && tok->isKeyword() && Token::Match(tok, "struct|union|enum %name% {"))) {
181  const Token *tok2 = tok->tokAt(2);
182 
183  if (tok->strAt(1) == "::")
184  tok2 = tok2->next();
185  else if (tok->isCpp() && tok->strAt(1) == "class")
186  tok2 = tok2->next();
187 
188  while (Token::Match(tok2, ":: %name%"))
189  tok2 = tok2->tokAt(2);
190  while (Token::Match(tok2, "%name% :: %name%"))
191  tok2 = tok2->tokAt(2);
192 
193  // skip over template args
194  while (tok2 && tok2->str() == "<" && tok2->link()) {
195  tok2 = tok2->link()->next();
196  while (Token::Match(tok2, ":: %name%"))
197  tok2 = tok2->tokAt(2);
198  }
199 
200  // skip over final
201  if (tok2 && tok2->isCpp() && Token::simpleMatch(tok2, "final"))
202  tok2 = tok2->next();
203 
204  // make sure we have valid code
205  if (!Token::Match(tok2, "{|:")) {
206  // check for qualified variable
207  if (tok2 && tok2->next()) {
208  if (tok2->next()->str() == ";")
209  tok = tok2->next();
210  else if (Token::simpleMatch(tok2->next(), "= {") &&
211  Token::simpleMatch(tok2->linkAt(2), "} ;"))
212  tok = tok2->linkAt(2)->next();
213  else if (Token::Match(tok2->next(), "(|{") &&
214  tok2->next()->link()->strAt(1) == ";")
215  tok = tok2->next()->link()->next();
216  // skip variable declaration
217  else if (Token::Match(tok2, "*|&|>"))
218  continue;
219  else if (Token::Match(tok2, "%name% (") && Tokenizer::isFunctionHead(tok2->next(), "{;"))
220  continue;
221  else if (Token::Match(tok2, "%name% [|="))
222  continue;
223  // skip template
224  else if (Token::simpleMatch(tok2, ";") &&
225  Token::Match(tok->previous(), "template|> class|struct")) {
226  tok = tok2;
227  continue;
228  }
229  // forward declaration
230  else if (Token::simpleMatch(tok2, ";") &&
231  Token::Match(tok, "class|struct|union")) {
232  // TODO: see if it can be used
233  tok = tok2;
234  continue;
235  }
236  // skip constructor
237  else if (Token::simpleMatch(tok2, "(") &&
238  Token::simpleMatch(tok2->link(), ") ;")) {
239  tok = tok2->link()->next();
240  continue;
241  } else
242  throw InternalError(tok2, "SymbolDatabase bailout; unhandled code", InternalError::SYNTAX);
243  continue;
244  }
245  break; // bail
246  }
247 
248  const Token * name = tok->next();
249 
250  if (name->str() == "class" && name->strAt(-1) == "enum")
251  name = name->next();
252 
253  Scope *new_scope = findScope(name, scope);
254 
255  if (new_scope) {
256  // only create base list for classes and structures
257  if (new_scope->isClassOrStruct()) {
258  // goto initial '{'
259  if (!new_scope->definedType)
260  mTokenizer.syntaxError(nullptr); // #6808
261  tok2 = new_scope->definedType->initBaseInfo(tok, tok2);
262  // make sure we have valid code
263  if (!tok2) {
264  break;
265  }
266  }
267 
268  // definition may be different than declaration
269  if (tok->isCpp() && tok->str() == "class") {
270  access[new_scope] = AccessControl::Private;
271  new_scope->type = Scope::eClass;
272  } else if (tok->str() == "struct") {
273  access[new_scope] = AccessControl::Public;
274  new_scope->type = Scope::eStruct;
275  }
276 
277  new_scope->classDef = tok;
278  new_scope->setBodyStartEnd(tok2);
279  // make sure we have valid code
280  if (!new_scope->bodyEnd) {
281  mTokenizer.syntaxError(tok);
282  }
283  scope = new_scope;
284  tok = tok2;
285  } else {
286  scopeList.emplace_back(this, tok, scope);
287  new_scope = &scopeList.back();
288 
289  if (tok->str() == "class")
290  access[new_scope] = AccessControl::Private;
291  else if (tok->str() == "struct" || tok->str() == "union")
292  access[new_scope] = AccessControl::Public;
293 
294  // fill typeList...
295  if (new_scope->isClassOrStructOrUnion() || new_scope->type == Scope::eEnum) {
296  Type* new_type = findType(name, scope);
297  if (!new_type) {
298  typeList.emplace_back(new_scope->classDef, new_scope, scope);
299  new_type = &typeList.back();
300  scope->definedTypesMap[new_type->name()] = new_type;
301  } else
302  new_type->classScope = new_scope;
303  new_scope->definedType = new_type;
304  }
305 
306  // only create base list for classes and structures
307  if (new_scope->isClassOrStruct()) {
308  // goto initial '{'
309  tok2 = new_scope->definedType->initBaseInfo(tok, tok2);
310 
311  // make sure we have valid code
312  if (!tok2) {
313  mTokenizer.syntaxError(tok);
314  }
315  } else if (new_scope->type == Scope::eEnum) {
316  if (tok2->str() == ":") {
317  tok2 = tok2->tokAt(2);
318  while (Token::Match(tok2, "%name%|::"))
319  tok2 = tok2->next();
320  }
321  }
322 
323  new_scope->setBodyStartEnd(tok2);
324 
325  // make sure we have valid code
326  if (!new_scope->bodyEnd) {
327  mTokenizer.syntaxError(tok);
328  }
329 
330  if (new_scope->type == Scope::eEnum) {
331  tok2 = new_scope->addEnum(tok);
332  scope->nestedList.push_back(new_scope);
333 
334  if (!tok2)
335  mTokenizer.syntaxError(tok);
336  } else {
337  // make the new scope the current scope
338  scope->nestedList.push_back(new_scope);
339  scope = new_scope;
340  }
341 
342  tok = tok2;
343  }
344  }
345 
346  // Namespace and unknown macro (#3854)
347  else if (tok->isCpp() && tok->isKeyword() &&
348  Token::Match(tok, "namespace %name% %type% (") &&
349  tok->tokAt(2)->isUpperCaseName() &&
350  Token::simpleMatch(tok->linkAt(3), ") {")) {
351  scopeList.emplace_back(this, tok, scope);
352 
353  Scope *new_scope = &scopeList.back();
354  access[new_scope] = AccessControl::Public;
355 
356  const Token *tok2 = tok->linkAt(3)->next();
357 
358  new_scope->setBodyStartEnd(tok2);
359 
360  // make sure we have valid code
361  if (!new_scope->bodyEnd) {
362  scopeList.pop_back();
363  break;
364  }
365 
366  // make the new scope the current scope
367  scope->nestedList.push_back(new_scope);
368  scope = &scopeList.back();
369 
370  tok = tok2;
371  }
372 
373  // forward declaration
374  else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;") &&
375  tok->strAt(-1) != "friend") {
376  if (!findType(tok->next(), scope)) {
377  // fill typeList..
378  typeList.emplace_back(tok, nullptr, scope);
379  Type* new_type = &typeList.back();
380  scope->definedTypesMap[new_type->name()] = new_type;
381  }
382  tok = tok->tokAt(2);
383  }
384 
385  // using namespace
386  else if (tok->isCpp() && tok->isKeyword() && Token::Match(tok, "using namespace ::| %type% ;|::")) {
387  Scope::UsingInfo using_info;
388 
389  using_info.start = tok; // save location
390  using_info.scope = findNamespace(tok->tokAt(2), scope);
391 
392  scope->usingList.push_back(using_info);
393 
394  // check for global namespace
395  if (tok->strAt(2) == "::")
396  tok = tok->tokAt(4);
397  else
398  tok = tok->tokAt(3);
399 
400  // skip over qualification
401  while (Token::Match(tok, "%type% ::"))
402  tok = tok->tokAt(2);
403  }
404 
405  // using type alias
406  else if (tok->isCpp() && tok->isKeyword() && Token::Match(tok, "using %name% =") && !tok->tokAt(2)->isSimplifiedTypedef()) {
407  if (tok->strAt(-1) != ">" && !findType(tok->next(), scope)) {
408  // fill typeList..
409  typeList.emplace_back(tok, nullptr, scope);
410  Type* new_type = &typeList.back();
411  scope->definedTypesMap[new_type->name()] = new_type;
412  }
413 
414  tok = tok->tokAt(3);
415 
416  while (tok && tok->str() != ";") {
417  if (Token::simpleMatch(tok, "decltype ("))
418  tok = tok->linkAt(1);
419  else
420  tok = tok->next();
421  }
422  }
423 
424  // unnamed struct and union
425  else if (tok->isKeyword() && Token::Match(tok, "struct|union {") &&
426  Token::Match(tok->next()->link(), "} *|&| %name% ;|[|=")) {
427  scopeList.emplace_back(this, tok, scope);
428 
429  Scope *new_scope = &scopeList.back();
430  access[new_scope] = AccessControl::Public;
431 
432  const Token* varNameTok = tok->next()->link()->next();
433  if (varNameTok->str() == "*") {
434  varNameTok = varNameTok->next();
435  } else if (varNameTok->str() == "&") {
436  varNameTok = varNameTok->next();
437  }
438 
439  typeList.emplace_back(tok, new_scope, scope);
440  {
441  Type* new_type = &typeList.back();
442  new_scope->definedType = new_type;
443  scope->definedTypesMap[new_type->name()] = new_type;
444  }
445 
446  scope->addVariable(varNameTok, tok, tok, access[scope], new_scope->definedType, scope, mSettings);
447 
448  const Token *tok2 = tok->next();
449 
450  new_scope->setBodyStartEnd(tok2);
451 
452  // make sure we have valid code
453  if (!new_scope->bodyEnd) {
454  scopeList.pop_back();
455  break;
456  }
457 
458  // make the new scope the current scope
459  scope->nestedList.push_back(new_scope);
460  scope = new_scope;
461 
462  tok = tok2;
463  }
464 
465  // anonymous struct, union and namespace
466  else if (tok->isKeyword() && ((Token::Match(tok, "struct|union {") &&
467  Token::simpleMatch(tok->next()->link(), "} ;")) ||
468  Token::simpleMatch(tok, "namespace {"))) {
469  scopeList.emplace_back(this, tok, scope);
470 
471  Scope *new_scope = &scopeList.back();
472  access[new_scope] = AccessControl::Public;
473 
474  const Token *tok2 = tok->next();
475 
476  new_scope->setBodyStartEnd(tok2);
477 
478  typeList.emplace_back(tok, new_scope, scope);
479  {
480  Type* new_type = &typeList.back();
481  new_scope->definedType = new_type;
482  scope->definedTypesMap[new_type->name()] = new_type;
483  }
484 
485  // make sure we have valid code
486  if (!new_scope->bodyEnd) {
487  scopeList.pop_back();
488  break;
489  }
490 
491  // make the new scope the current scope
492  scope->nestedList.push_back(new_scope);
493  scope = new_scope;
494 
495  tok = tok2;
496  }
497 
498  // forward declared enum
499  else if (tok->isKeyword() && (Token::Match(tok, "enum class| %name% ;") || Token::Match(tok, "enum class| %name% : %name% ;"))) {
500  typeList.emplace_back(tok, nullptr, scope);
501  Type* new_type = &typeList.back();
502  scope->definedTypesMap[new_type->name()] = new_type;
503  tok = tok->tokAt(2);
504  }
505 
506  // check for end of scope
507  else if (tok == scope->bodyEnd) {
508  do {
509  access.erase(scope);
510  scope = const_cast<Scope*>(scope->nestedIn);
511  } while (scope->type != Scope::eGlobal && succeeds(tok, scope->bodyEnd));
512  continue;
513  }
514  // check for end of init list
515  else if (inInitList() && tok == endInitList.top().first) {
516  endInitList.pop();
517  continue;
518  }
519 
520  // check if in class or structure or union
521  else if (scope->isClassOrStructOrUnion()) {
522  const Token *funcStart = nullptr;
523  const Token *argStart = nullptr;
524  const Token *declEnd = nullptr;
525 
526  // What section are we in..
527  if (tok->str() == "private:")
528  access[scope] = AccessControl::Private;
529  else if (tok->str() == "protected:")
530  access[scope] = AccessControl::Protected;
531  else if (tok->str() == "public:" || tok->str() == "__published:")
532  access[scope] = AccessControl::Public;
533  else if (Token::Match(tok, "public|protected|private %name% :")) {
534  if (tok->str() == "private")
535  access[scope] = AccessControl::Private;
536  else if (tok->str() == "protected")
537  access[scope] = AccessControl::Protected;
538  else
539  access[scope] = AccessControl::Public;
540 
541  tok = tok->tokAt(2);
542  }
543 
544  // class function?
545  else if (isFunction(tok, scope, funcStart, argStart, declEnd)) {
546  if (tok->previous()->str() != "::" || tok->strAt(-2) == scope->className) {
547  Function function(tok, scope, funcStart, argStart);
548 
549  // save the access type
550  function.access = access[scope];
551 
552  const Token *end = function.argDef->link();
553 
554  // count the number of constructors
555  if (function.isConstructor())
556  scope->numConstructors++;
557 
558  // assume implementation is inline (definition and implementation same)
559  function.token = function.tokenDef;
560  function.arg = function.argDef;
561 
562  // out of line function
563  if (const Token *endTok = Tokenizer::isFunctionHead(end, ";")) {
564  tok = endTok;
565  scope->addFunction(std::move(function));
566  }
567 
568  // inline function
569  else {
570  // find start of function '{'
571  bool foundInitList = false;
572  while (end && end->str() != "{" && end->str() != ";") {
573  if (end->link() && Token::Match(end, "(|<")) {
574  end = end->link();
575  } else if (foundInitList &&
576  Token::Match(end, "%name%|> {") &&
577  Token::Match(end->linkAt(1), "} ,|{")) {
578  end = end->linkAt(1);
579  } else {
580  if (end->str() == ":")
581  foundInitList = true;
582  end = end->next();
583  }
584  }
585 
586  if (!end || end->str() == ";")
587  continue;
588 
589  scope->addFunction(function);
590 
591  Function* funcptr = &scope->functionList.back();
592  const Token *tok2 = funcStart;
593 
594  addNewFunction(scope, tok2);
595  if (scope) {
596  scope->functionOf = function.nestedIn;
597  scope->function = funcptr;
598  scope->function->functionScope = scope;
599  }
600 
601  tok = tok2;
602  }
603  }
604 
605  // nested class or friend function?
606  else {
607  /** @todo check entire qualification for match */
608  const Scope * const nested = scope->findInNestedListRecursive(tok->strAt(-2));
609 
610  if (nested)
611  addClassFunction(scope, tok, argStart);
612  else {
613  /** @todo handle friend functions */
614  }
615  }
616  }
617 
618  // friend class declaration?
619  else if (tok->isCpp() && tok->isKeyword() && Token::Match(tok, "friend class|struct| ::| %any% ;|::")) {
620  Type::FriendInfo friendInfo;
621 
622  // save the name start
623  friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->next();
624  friendInfo.nameEnd = friendInfo.nameStart;
625 
626  // skip leading "::"
627  if (friendInfo.nameEnd->str() == "::")
628  friendInfo.nameEnd = friendInfo.nameEnd->next();
629 
630  // skip qualification "name ::"
631  while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::")
632  friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2);
633 
634  // fill this in after parsing is complete
635  friendInfo.type = nullptr;
636 
637  if (!scope->definedType)
638  mTokenizer.syntaxError(tok);
639 
640  scope->definedType->friendList.push_back(friendInfo);
641  }
642  } else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) {
643  const Token *funcStart = nullptr;
644  const Token *argStart = nullptr;
645  const Token *declEnd = nullptr;
646 
647  // function?
648  if (isFunction(tok, scope, funcStart, argStart, declEnd)) {
649  // has body?
650  if (declEnd && declEnd->str() == "{") {
651  tok = funcStart;
652 
653  // class function
654  if (tok->previous() && tok->previous()->str() == "::")
655  addClassFunction(scope, tok, argStart);
656 
657  // class destructor
658  else if (tok->previous() &&
659  tok->previous()->str() == "~" &&
660  tok->strAt(-2) == "::")
661  addClassFunction(scope, tok, argStart);
662 
663  // regular function
664  else {
665  const Function* const function = addGlobalFunction(scope, tok, argStart, funcStart);
666 
667  if (!function)
668  mTokenizer.syntaxError(tok);
669  }
670 
671  // syntax error?
672  if (!scope)
673  mTokenizer.syntaxError(tok);
674  }
675  // function prototype?
676  else if (declEnd && declEnd->str() == ";") {
677  if (tok->astParent() && tok->astParent()->str() == "::" &&
678  Token::Match(declEnd->previous(), "default|delete")) {
679  addClassFunction(scope, tok, argStart);
680  continue;
681  }
682 
683  bool newFunc = true; // Is this function already in the database?
684  auto range = scope->functionMap.equal_range(tok->str());
685  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
686  if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) {
687  newFunc = false;
688  break;
689  }
690  }
691 
692  // save function prototype in database
693  if (newFunc) {
694  addGlobalFunctionDecl(scope, tok, argStart, funcStart);
695  }
696 
697  tok = declEnd;
698  continue;
699  }
700  } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
701  tok = addLambda(tok, lambdaEndToken);
702  }
703  } else if (scope->isExecutable()) {
704  if (tok->isKeyword() && Token::Match(tok, "else|try|do {")) {
705  const Token* tok1 = tok->next();
706  if (tok->str() == "else")
707  scopeList.emplace_back(this, tok, scope, Scope::eElse, tok1);
708  else if (tok->str() == "do")
709  scopeList.emplace_back(this, tok, scope, Scope::eDo, tok1);
710  else //if (tok->str() == "try")
711  scopeList.emplace_back(this, tok, scope, Scope::eTry, tok1);
712 
713  tok = tok1;
714  scope->nestedList.push_back(&scopeList.back());
715  scope = &scopeList.back();
716  } else if (tok->isKeyword() && Token::Match(tok, "if|for|while|catch|switch (") && Token::simpleMatch(tok->next()->link(), ") {")) {
717  const Token *scopeStartTok = tok->next()->link()->next();
718  if (tok->str() == "if")
719  scopeList.emplace_back(this, tok, scope, Scope::eIf, scopeStartTok);
720  else if (tok->str() == "for") {
721  scopeList.emplace_back(this, tok, scope, Scope::eFor, scopeStartTok);
722  } else if (tok->str() == "while")
723  scopeList.emplace_back(this, tok, scope, Scope::eWhile, scopeStartTok);
724  else if (tok->str() == "catch") {
725  scopeList.emplace_back(this, tok, scope, Scope::eCatch, scopeStartTok);
726  } else // if (tok->str() == "switch")
727  scopeList.emplace_back(this, tok, scope, Scope::eSwitch, scopeStartTok);
728 
729  scope->nestedList.push_back(&scopeList.back());
730  scope = &scopeList.back();
731  if (scope->type == Scope::eFor)
732  scope->checkVariable(tok->tokAt(2), AccessControl::Local, mSettings); // check for variable declaration and add it to new scope if found
733  else if (scope->type == Scope::eCatch)
734  scope->checkVariable(tok->tokAt(2), AccessControl::Throw, mSettings); // check for variable declaration and add it to new scope if found
735  tok = scopeStartTok;
736  } else if (Token::Match(tok, "%var% {")) {
737  endInitList.emplace(tok->next()->link(), scope);
738  tok = tok->next();
739  } else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
740  tok = addLambda(tok, lambdaEndToken);
741  } else if (tok->str() == "{") {
742  if (inInitList()) {
743  endInitList.emplace(tok->link(), scope);
744  } else if (isExecutableScope(tok)) {
745  scopeList.emplace_back(this, tok, scope, Scope::eUnconditional, tok);
746  scope->nestedList.push_back(&scopeList.back());
747  scope = &scopeList.back();
748  } else if (scope->isExecutable()) {
749  endInitList.emplace(tok->link(), scope);
750  } else {
751  tok = tok->link();
752  }
753  } else if (Token::Match(tok, "extern %type%")) {
754  const Token * ftok = tok->next();
755  while (Token::Match(ftok, "%name%|*|&"))
756  ftok = ftok->next();
757  if (!ftok || ftok->str() != "(")
758  continue;
759  ftok = ftok->previous();
760  if (Token::simpleMatch(ftok->linkAt(1), ") ;")) {
761  const Token *funcStart = nullptr;
762  const Token *argStart = nullptr;
763  const Token *declEnd = nullptr;
764  if (isFunction(ftok, scope, funcStart, argStart, declEnd)) {
765  if (declEnd && declEnd->str() == ";") {
766  bool newFunc = true; // Is this function already in the database?
767  auto range = scope->functionMap.equal_range(ftok->str());
768  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
769  if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) {
770  newFunc = false;
771  break;
772  }
773  }
774  // save function prototype in database
775  if (newFunc) {
776  Function function(ftok, scope, funcStart, argStart);
777  if (function.isExtern()) {
778  scope->addFunction(std::move(function));
779  tok = declEnd;
780  }
781  }
782  }
783  }
784  }
785  }
786  // syntax error?
787  if (!scope)
788  mTokenizer.syntaxError(tok);
789  // End of scope or list should be handled above
790  if (tok->str() == "}")
791  mTokenizer.syntaxError(tok);
792  }
793  }
794 }
795 
797 {
798  if (mTokenizer.isC())
799  return;
800 
801  // fill in using info
802  for (Scope& scope : scopeList) {
803  for (Scope::UsingInfo& usingInfo : scope.usingList) {
804  // only find if not already found
805  if (usingInfo.scope == nullptr) {
806  // check scope for match
807  const Scope * const found = findScope(usingInfo.start->tokAt(2), &scope);
808  if (found) {
809  // set found scope
810  usingInfo.scope = found;
811  break;
812  }
813  }
814  }
815  }
816 
817  // fill in base class info
818  for (Type& type : typeList) {
819  // finish filling in base class info
820  for (Type::BaseInfo & i : type.derivedFrom) {
821  const Type* found = findType(i.nameTok, type.enclosingScope, /*lookOutside*/ true);
822  if (found && found->findDependency(&type)) {
823  // circular dependency
824  //mTokenizer.syntaxError(nullptr);
825  } else {
826  i.type = found;
827  }
828  }
829  }
830 
831  // fill in friend info
832  for (Type & type : typeList) {
833  for (Type::FriendInfo &friendInfo : type.friendList) {
834  friendInfo.type = findType(friendInfo.nameStart, type.enclosingScope);
835  }
836  }
837 }
838 
839 
841 {
842  // fill in variable info
843  for (Scope& scope : scopeList) {
844  // find variables
845  scope.getVariableList(mSettings);
846  }
847 
848  // fill in function arguments
849  for (Scope& scope : scopeList) {
850  std::list<Function>::iterator func;
851 
852  for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
853  // add arguments
854  func->addArguments(this, &scope);
855  }
856  }
857 }
858 
860 {
861  // fill in class and struct copy/move constructors
862  for (Scope& scope : scopeList) {
863  if (!scope.isClassOrStruct())
864  continue;
865 
866  std::list<Function>::iterator func;
867  for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
868  if (!func->isConstructor() || func->minArgCount() != 1)
869  continue;
870 
871  const Variable* firstArg = func->getArgumentVar(0);
872  if (firstArg->type() == scope.definedType) {
873  if (firstArg->isRValueReference())
875  else if (firstArg->isReference() && !firstArg->isPointer())
876  func->type = Function::eCopyConstructor;
877  }
878 
879  if (func->type == Function::eCopyConstructor ||
880  func->type == Function::eMoveConstructor)
881  scope.numCopyOrMoveConstructors++;
882  }
883  }
884 }
885 
887 {
888  // fill in function scopes
889  for (const Scope & scope : scopeList) {
890  if (scope.type == Scope::eFunction)
891  functionScopes.push_back(&scope);
892  }
893 }
894 
896 {
897  // fill in class and struct scopes
898  for (const Scope& scope : scopeList) {
899  if (scope.isClassOrStruct())
900  classAndStructScopes.push_back(&scope);
901  }
902 }
903 
905 {
906  // fill in function return types
907  for (Scope& scope : scopeList) {
908  std::list<Function>::iterator func;
909 
910  for (func = scope.functionList.begin(); func != scope.functionList.end(); ++func) {
911  // add return types
912  if (func->retDef) {
913  const Token *type = func->retDef;
914  while (Token::Match(type, "static|const|struct|union|enum"))
915  type = type->next();
916  if (type) {
917  func->retType = findVariableTypeInBase(&scope, type);
918  if (!func->retType)
919  func->retType = findTypeInNested(type, func->nestedIn);
920  }
921  }
922  }
923  }
924 }
925 
927 {
928  if (mTokenizer.isC()) {
929  // For C code it is easy, as there are no constructors and no default values
930  for (const Scope& scope : scopeList) {
931  if (scope.definedType)
932  scope.definedType->needInitialization = Type::NeedInitialization::True;
933  }
934  } else {
935  // For C++, it is more difficult: Determine if user defined type needs initialization...
936  unsigned int unknowns = 0; // stop checking when there are no unknowns
937  unsigned int retry = 0; // bail if we don't resolve all the variable types for some reason
938 
939  do {
940  unknowns = 0;
941 
942  for (Scope& scope : scopeList) {
943  if (!scope.isClassOrStructOrUnion())
944  continue;
945  if (scope.classDef && Token::simpleMatch(scope.classDef->previous(), ">")) // skip uninstantiated template
946  continue;
947 
948  if (!scope.definedType) {
949  mBlankTypes.emplace_back();
950  scope.definedType = &mBlankTypes.back();
951  }
952 
953  if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown) {
954  // check for default constructor
955  bool hasDefaultConstructor = false;
956 
957  for (const Function& func : scope.functionList) {
958  if (func.type == Function::eConstructor) {
959  // check for no arguments: func ( )
960  if (func.argCount() == 0) {
961  hasDefaultConstructor = true;
962  break;
963  }
964 
965  /** check for arguments with default values */
966  if (func.argCount() == func.initializedArgCount()) {
967  hasDefaultConstructor = true;
968  break;
969  }
970  }
971  }
972 
973  // User defined types with user defined default constructor doesn't need initialization.
974  // We assume the default constructor initializes everything.
975  // Another check will figure out if the constructor actually initializes everything.
976  if (hasDefaultConstructor)
977  scope.definedType->needInitialization = Type::NeedInitialization::False;
978 
979  // check each member variable to see if it needs initialization
980  else {
981  bool needInitialization = false;
982  bool unknown = false;
983 
984  for (const Variable& var: scope.varlist) {
985  if (var.isStatic())
986  continue;
987  if (var.isClass() && !var.isReference()) {
988  if (var.type()) {
989  // does this type need initialization?
991  needInitialization = true;
993  if (!(var.valueType() && var.valueType()->type == ValueType::CONTAINER))
994  unknown = true;
995  }
996  }
997  } else if (!var.hasDefault()) {
998  needInitialization = true;
999  break;
1000  }
1001  }
1002 
1003  if (needInitialization)
1004  scope.definedType->needInitialization = Type::NeedInitialization::True;
1005  else if (!unknown)
1006  scope.definedType->needInitialization = Type::NeedInitialization::False;
1007  else {
1008  if (scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
1009  unknowns++;
1010  }
1011  }
1012  } else if (scope.type == Scope::eUnion && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
1013  scope.definedType->needInitialization = Type::NeedInitialization::True;
1014  }
1015 
1016  retry++;
1017  } while (unknowns && retry < 100);
1018 
1019  // this shouldn't happen so output a debug warning
1020  if (retry == 100 && mSettings.debugwarnings) {
1021  for (const Scope& scope : scopeList) {
1022  if (scope.isClassOrStruct() && scope.definedType->needInitialization == Type::NeedInitialization::Unknown)
1023  debugMessage(scope.classDef, "debug", "SymbolDatabase couldn't resolve all user defined types.");
1024  }
1025  }
1026  }
1027 }
1028 
1030 {
1031  // create variable symbol table
1032  mVariableList.resize(mTokenizer.varIdCount() + 1);
1033  std::fill_n(mVariableList.begin(), mVariableList.size(), nullptr);
1034 
1035  // check all scopes for variables
1036  for (Scope& scope : scopeList) {
1037  // add all variables
1038  for (Variable& var: scope.varlist) {
1039  const unsigned int varId = var.declarationId();
1040  if (varId)
1041  mVariableList[varId] = &var;
1042  // fix up variables without type
1043  if (!var.type() && !var.typeStartToken()->isStandardType()) {
1044  const Type *type = findType(var.typeStartToken(), &scope);
1045  if (type)
1046  var.type(type);
1047  }
1048  }
1049 
1050  // add all function parameters
1051  for (Function& func : scope.functionList) {
1052  for (Variable& arg: func.argumentList) {
1053  // check for named parameters
1054  if (arg.nameToken() && arg.declarationId()) {
1055  const unsigned int declarationId = arg.declarationId();
1056  mVariableList[declarationId] = &arg;
1057  // fix up parameters without type
1058  if (!arg.type() && !arg.typeStartToken()->isStandardType()) {
1059  const Type *type = findTypeInNested(arg.typeStartToken(), &scope);
1060  if (type)
1061  arg.type(type);
1062  }
1063  }
1064  }
1065  }
1066  }
1067 
1068  // fill in missing variables if possible
1069  for (const Scope *func: functionScopes) {
1070  for (const Token *tok = func->bodyStart->next(); tok && tok != func->bodyEnd; tok = tok->next()) {
1071  // check for member variable
1072  if (!Token::Match(tok, "%var% .|["))
1073  continue;
1074  const Token* tokDot = tok->next();
1075  while (Token::simpleMatch(tokDot, "["))
1076  tokDot = tokDot->link()->next();
1077  if (!Token::Match(tokDot, ". %var%"))
1078  continue;
1079  const Token *member = tokDot->next();
1080  if (mVariableList[member->varId()] == nullptr) {
1081  const Variable *var1 = mVariableList[tok->varId()];
1082  if (var1 && var1->typeScope()) {
1083  const Variable* memberVar = var1->typeScope()->getVariable(member->str());
1084  if (memberVar) {
1085  // add this variable to the look up table
1086  mVariableList[member->varId()] = memberVar;
1087  }
1088  }
1089  }
1090  }
1091  }
1092 }
1093 
1095 {
1096  auto setScopePointers = [](const Scope &scope, const Token *bodyStart, const Token *bodyEnd) {
1097  assert(bodyStart);
1098  assert(bodyEnd);
1099 
1100  const_cast<Token *>(bodyEnd)->scope(&scope);
1101 
1102  for (auto* tok = const_cast<Token *>(bodyStart); tok != bodyEnd; tok = tok->next()) {
1103  if (bodyStart != bodyEnd && tok->str() == "{") {
1104  bool isEndOfScope = false;
1105  for (Scope* innerScope: scope.nestedList) {
1106  const auto &list = innerScope->bodyStartList;
1107  if (std::find(list.cbegin(), list.cend(), tok) != list.cend()) { // Is begin of inner scope
1108  tok = tok->link();
1109  if (tok->next() == bodyEnd || !tok->next()) {
1110  isEndOfScope = true;
1111  break;
1112  }
1113  tok = tok->next();
1114  break;
1115  }
1116  }
1117  if (isEndOfScope)
1118  break;
1119  }
1120  tok->scope(&scope);
1121  }
1122  };
1123 
1124  // Set scope pointers
1125  for (const Scope& scope: scopeList) {
1126  if (scope.type == Scope::eGlobal)
1127  setScopePointers(scope, mTokenizer.list.front(), mTokenizer.list.back());
1128  else {
1129  for (const Token *bodyStart: scope.bodyStartList)
1130  setScopePointers(scope, bodyStart, bodyStart->link());
1131  }
1132  }
1133 }
1134 
1136 {
1137  if (firstPass) {
1138  // Set function definition and declaration pointers
1139  for (const Scope& scope: scopeList) {
1140  for (const Function& func: scope.functionList) {
1141  if (func.tokenDef)
1142  const_cast<Token *>(func.tokenDef)->function(&func);
1143 
1144  if (func.token)
1145  const_cast<Token *>(func.token)->function(&func);
1146  }
1147  }
1148  }
1149 
1150  // Set function call pointers
1151  const Token* inTemplateArg = nullptr;
1152  for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1153  if (inTemplateArg == nullptr && tok->link() && tok->str() == "<")
1154  inTemplateArg = tok->link();
1155  if (inTemplateArg == tok)
1156  inTemplateArg = nullptr;
1157  if (tok->isName() && !tok->function() && tok->varId() == 0 && ((tok->astParent() && tok->astParent()->isComparisonOp()) || Token::Match(tok, "%name% [{(,)>;]")) && !isReservedName(tok)) {
1158  if (tok->next()->str() == ">" && !tok->next()->link())
1159  continue;
1160 
1161  const Function *function = findFunction(tok);
1162  if (!function || (inTemplateArg && function->isConstructor()))
1163  continue;
1164 
1165  tok->function(function);
1166 
1167  if (tok->next()->str() != "(")
1168  const_cast<Function *>(function)->functionPointerUsage = tok;
1169  }
1170  }
1171 
1172  // Set C++ 11 delegate constructor function call pointers
1173  for (const Scope& scope: scopeList) {
1174  for (const Function& func: scope.functionList) {
1175  // look for initializer list
1176  if (func.isConstructor() && func.functionScope && func.functionScope->functionOf && func.arg) {
1177  const Token * tok = func.arg->link()->next();
1178  if (tok->str() == "noexcept") {
1179  const Token * closingParenTok = tok->linkAt(1);
1180  if (!closingParenTok || !closingParenTok->next()) {
1181  continue;
1182  }
1183  tok = closingParenTok->next();
1184  }
1185  if (tok->str() != ":") {
1186  continue;
1187  }
1188  tok = tok->next();
1189  while (tok && tok != func.functionScope->bodyStart) {
1190  if (Token::Match(tok, "%name% {|(")) {
1191  if (tok->str() == func.tokenDef->str()) {
1192  const Function *function = func.functionScope->functionOf->findFunction(tok);
1193  if (function)
1194  const_cast<Token *>(tok)->function(function);
1195  break;
1196  }
1197  tok = tok->linkAt(1);
1198  }
1199  tok = tok->next();
1200  }
1201  }
1202  }
1203  }
1204 }
1205 
1207 {
1208  std::unordered_set<std::string> typenames;
1209  for (const Type &t : typeList) {
1210  typenames.insert(t.name());
1211  }
1212 
1213  // Set type pointers
1214  for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1215  if (!tok->isName() || tok->varId() || tok->function() || tok->type() || tok->enumerator())
1216  continue;
1217 
1218  if (typenames.find(tok->str()) == typenames.end())
1219  continue;
1220 
1221  const Type *type = findVariableType(tok->scope(), tok);
1222  if (type)
1223  tok->type(type);
1224  }
1225 }
1226 
1228 {
1229  for (Scope &scope: scopeList) {
1230  for (Variable &var: scope.varlist) {
1231  if (var.valueType() && var.valueType()->smartPointerTypeToken && !var.valueType()->smartPointerType) {
1232  ValueType vt(*var.valueType());
1234  var.setValueType(vt);
1235  }
1236  }
1237  }
1238 }
1239 
1240 void SymbolDatabase::fixVarId(VarIdMap & varIds, const Token * vartok, Token * membertok, const Variable * membervar)
1241 {
1242  VarIdMap::iterator varId = varIds.find(vartok->varId());
1243  if (varId == varIds.end()) {
1244  MemberIdMap memberId;
1245  if (membertok->varId() == 0) {
1246  memberId[membervar->nameToken()->varId()] = mTokenizer.newVarId();
1247  mVariableList.push_back(membervar);
1248  } else
1249  mVariableList[membertok->varId()] = membervar;
1250  varIds.insert(std::make_pair(vartok->varId(), memberId));
1251  varId = varIds.find(vartok->varId());
1252  }
1253  MemberIdMap::iterator memberId = varId->second.find(membervar->nameToken()->varId());
1254  if (memberId == varId->second.end()) {
1255  if (membertok->varId() == 0) {
1256  varId->second.insert(std::make_pair(membervar->nameToken()->varId(), mTokenizer.newVarId()));
1257  mVariableList.push_back(membervar);
1258  memberId = varId->second.find(membervar->nameToken()->varId());
1259  } else
1260  mVariableList[membertok->varId()] = membervar;
1261  }
1262  if (membertok->varId() == 0)
1263  membertok->varId(memberId->second);
1264 }
1265 
1267 
1269 {
1270  VarIdMap varIds;
1271 
1272  auto setMemberVar = [&](const Variable* membervar, Token* membertok, const Token* vartok) -> void {
1273  if (membervar) {
1274  membertok->variable(membervar);
1275  if (vartok && (membertok->varId() == 0 || mVariableList[membertok->varId()] == nullptr))
1276  fixVarId(varIds, vartok, membertok, membervar);
1277  }
1278  };
1279 
1280  // Set variable pointers
1281  for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1282  if (!tok->isName() || tok->isKeyword() || tok->isStandardType())
1283  continue;
1284  if (tok->varId())
1285  tok->variable(getVariableFromVarId(tok->varId()));
1286 
1287  // Set Token::variable pointer for array member variable
1288  // Since it doesn't point at a fixed location it doesn't have varid
1289  const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() ||
1290  (tok->valueType() && (tok->valueType()->type == ValueType::CONTAINER || tok->valueType()->type == ValueType::ITERATOR)));
1291  const bool isArrayAccess = isVar && Token::simpleMatch(tok->astParent(), "[");
1292  const bool isDirectAccess = isVar && !isArrayAccess && Token::simpleMatch(tok->astParent(), ".");
1293  const bool isDerefAccess = isVar && !isDirectAccess && Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astParent()->astParent(), ".");
1294  if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) {
1295  Token* membertok{};
1296  if (isArrayAccess) {
1297  membertok = tok->astParent();
1298  while (Token::simpleMatch(membertok, "["))
1299  membertok = membertok->astParent();
1300  if (membertok)
1301  membertok = membertok->astOperand2();
1302  }
1303  else if (isDirectAccess) {
1304  membertok = tok->astParent()->astOperand2();
1305  if (membertok == tok) {
1306  Token* gptok = tok->astParent()->astParent();
1307  if (Token::simpleMatch(gptok, ".")) // chained access
1308  membertok = gptok->astOperand2();
1309  else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), "."))
1310  membertok = gptok->astParent()->astOperand2();
1311  }
1312  }
1313  else { // isDerefAccess
1314  membertok = tok->astParent();
1315  while (Token::simpleMatch(membertok, "*"))
1316  membertok = membertok->astParent();
1317  if (membertok)
1318  membertok = membertok->astOperand2();
1319  }
1320 
1321  if (membertok && membertok != tok) {
1322  const Variable *var = tok->variable();
1323  if (var->typeScope()) {
1324  const Variable *membervar = var->typeScope()->getVariable(membertok->str());
1325  setMemberVar(membervar, membertok, tok);
1326  } else if (const ::Type *type = var->smartPointerType()) {
1327  const Scope *classScope = type->classScope;
1328  const Variable *membervar = classScope ? classScope->getVariable(membertok->str()) : nullptr;
1329  setMemberVar(membervar, membertok, tok);
1330  } else if (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER) {
1331  if (const Token* ctt = tok->valueType()->containerTypeToken) {
1332  while (ctt && ctt->isKeyword())
1333  ctt = ctt->next();
1334  const Type* ct = findTypeInNested(ctt, tok->scope());
1335  if (ct && ct->classScope && ct->classScope->definedType) {
1336  const Variable *membervar = ct->classScope->getVariable(membertok->str());
1337  setMemberVar(membervar, membertok, tok);
1338  }
1339  }
1340  } else if (const Type* iterType = var->iteratorType()) {
1341  if (iterType->classScope && iterType->classScope->definedType) {
1342  const Variable *membervar = iterType->classScope->getVariable(membertok->str());
1343  setMemberVar(membervar, membertok, tok);
1344  }
1345  }
1346  }
1347  }
1348 
1349  // check for function returning record type
1350  // func(...).var
1351  // func(...)[...].var
1352  else if (tok->function() && tok->next()->str() == "(" &&
1353  (Token::Match(tok->next()->link(), ") . %name% !!(") ||
1354  (Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
1355  const Type *type = tok->function()->retType;
1356  Token* membertok;
1357  if (tok->next()->link()->next()->str() == ".")
1358  membertok = tok->next()->link()->next()->next();
1359  else
1360  membertok = tok->next()->link()->next()->link()->next()->next();
1361  if (type) {
1362  const Variable *membervar = membertok->variable();
1363  if (!membervar) {
1364  if (type->classScope) {
1365  membervar = type->classScope->getVariable(membertok->str());
1366  setMemberVar(membervar, membertok, tok->function()->retDef);
1367  }
1368  }
1369  } else if (mSettings.library.detectSmartPointer(tok->function()->retDef)) {
1370  if (const Token* templateArg = Token::findsimplematch(tok->function()->retDef, "<")) {
1371  if (const Type* spType = findTypeInNested(templateArg->next(), tok->scope())) {
1372  if (spType->classScope) {
1373  const Variable* membervar = spType->classScope->getVariable(membertok->str());
1374  setMemberVar(membervar, membertok, tok->function()->retDef);
1375  }
1376  }
1377  }
1378  }
1379  }
1380  else if (Token::simpleMatch(tok->astParent(), ".") && tok->next()->str() == "(" &&
1381  astIsContainer(tok->astParent()->astOperand1()) && Token::Match(tok->next()->link(), ") . %name% !!(")) {
1382  const ValueType* vt = tok->astParent()->astOperand1()->valueType();
1383  const Library::Container* cont = vt->container;
1384  auto it = cont->functions.find(tok->str());
1385  if (it != cont->functions.end() && isContainerYieldElement(it->second.yield) && vt->containerTypeToken) {
1386  Token* memberTok = tok->next()->link()->tokAt(2);
1387  const Scope* scope = vt->containerTypeToken->scope();
1388  const Type* contType{};
1389  const std::string& typeStr = vt->containerTypeToken->str(); // TODO: handle complex type expressions
1390  while (scope && !contType) {
1391  contType = scope->findType(typeStr); // find the type stored in the container
1392  scope = scope->nestedIn;
1393  }
1394  if (contType && contType->classScope) {
1395  const Variable* membervar = contType->classScope->getVariable(memberTok->str());
1396  setMemberVar(membervar, memberTok, vt->containerTypeToken);
1397  }
1398  }
1399  }
1400  }
1401 }
1402 
1404 {
1405  // fill in enumerators in enum
1406  for (const Scope &scope : scopeList) {
1407  if (scope.type != Scope::eEnum)
1408  continue;
1409 
1410  // add enumerators to enumerator tokens
1411  for (const Enumerator & i : scope.enumeratorList)
1412  const_cast<Token *>(i.name)->enumerator(&i);
1413  }
1414 
1415  std::set<std::string> tokensThatAreNotEnumeratorValues;
1416 
1417  for (const Scope &scope : scopeList) {
1418  if (scope.type != Scope::eEnum)
1419  continue;
1420 
1421  for (const Enumerator & enumerator : scope.enumeratorList) {
1422  // look for initialization tokens that can be converted to enumerators and convert them
1423  if (enumerator.start) {
1424  if (!enumerator.end)
1425  mTokenizer.syntaxError(enumerator.start);
1426  for (const Token * tok3 = enumerator.start; tok3 && tok3 != enumerator.end->next(); tok3 = tok3->next()) {
1427  if (tok3->tokType() == Token::eName) {
1428  const Enumerator * e = findEnumerator(tok3, tokensThatAreNotEnumeratorValues);
1429  if (e)
1430  const_cast<Token *>(tok3)->enumerator(e);
1431  }
1432  }
1433  }
1434  }
1435  }
1436 
1437  // find enumerators
1438  for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1439  const bool isVariable = (tok->tokType() == Token::eVariable && !tok->variable());
1440  if (tok->tokType() != Token::eName && !isVariable)
1441  continue;
1442  const Enumerator * enumerator = findEnumerator(tok, tokensThatAreNotEnumeratorValues);
1443  if (enumerator) {
1444  if (isVariable)
1445  tok->varId(0);
1446  tok->enumerator(enumerator);
1447  }
1448  }
1449 }
1450 
1452 {
1453  for (Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1454  const Scope * scope = tok->scope();
1455  if (!scope)
1456  continue;
1457  if (!scope->isExecutable())
1458  continue;
1459  if (tok->varId() != 0)
1460  continue;
1461  if (tok->isCast() && !isCPPCast(tok) && tok->link() && tok->str() == "(") {
1462  tok = tok->link();
1463  continue;
1464  }
1465  if (tok->isCpp() && (Token::Match(tok, "catch|typeid (") ||
1466  Token::Match(tok, "static_cast|dynamic_cast|const_cast|reinterpret_cast"))) {
1467  tok = tok->linkAt(1);
1468  continue;
1469  }
1470  if (tok->str() == "NULL")
1471  continue;
1472  if (tok->isKeyword() || !tok->isNameOnly())
1473  continue;
1474  if (tok->type())
1475  continue;
1476  if (Token::Match(tok->next(), "::|.|(|{|:|%var%"))
1477  continue;
1478  if (Token::Match(tok->next(), "&|&&|* *| *| )|,|%var%|const"))
1479  continue;
1480  // Very likely a typelist
1481  if (Token::Match(tok->tokAt(-2), "%type% ,") || Token::Match(tok->next(), ", %type%"))
1482  continue;
1483  // Inside template brackets
1484  if (Token::simpleMatch(tok->next(), "<") && tok->linkAt(1)) {
1485  tok = tok->linkAt(1);
1486  continue;
1487  }
1488  // Skip goto labels
1489  if (Token::simpleMatch(tok->previous(), "goto"))
1490  continue;
1491  std::string fstr = tok->str();
1492  const Token* ftok = tok->previous();
1493  while (Token::simpleMatch(ftok, "::")) {
1494  if (!Token::Match(ftok->previous(), "%name%"))
1495  break;
1496  fstr.insert(0, ftok->previous()->str() + "::");
1497  ftok = ftok->tokAt(-2);
1498  }
1499  if (mSettings.library.functions.find(fstr) != mSettings.library.functions.end())
1500  continue;
1501  if (tok->isCpp()) {
1502  const Token* parent = tok->astParent();
1503  while (Token::Match(parent, "::|[|{"))
1504  parent = parent->astParent();
1505  if (Token::simpleMatch(parent, "new"))
1506  continue;
1507  // trailing return type
1508  if (Token::simpleMatch(ftok, ".") && ftok->originalName() == "->" && Token::Match(ftok->tokAt(-1), "[])]"))
1509  continue;
1510  }
1511  tok->isIncompleteVar(true);
1512  }
1513 }
1514 
1516 {
1517  for (const Scope& scope : scopeList) {
1518  if (scope.type != Scope::eFunction)
1519  continue;
1520  Function * function = scope.function;
1521  if (!function)
1522  continue;
1523  if (Token::findsimplematch(scope.bodyStart, "return", scope.bodyEnd))
1524  continue;
1525  function->isEscapeFunction(isReturnScope(scope.bodyEnd, mSettings.library, nullptr, true));
1526  }
1527 }
1528 
1529 static bool isExpression(const Token* tok)
1530 {
1531  if (!tok)
1532  return false;
1533  if (Token::simpleMatch(tok, "{") && tok->scope() && tok->scope()->bodyStart != tok &&
1534  (tok->astOperand1() || tok->astOperand2()))
1535  return true;
1536  if (!Token::Match(tok, "(|.|[|::|?|:|++|--|%cop%|%assign%"))
1537  return false;
1538  if (Token::Match(tok, "*|&|&&")) {
1539  const Token* vartok = findAstNode(tok, [&](const Token* tok2) {
1540  const Variable* var = tok2->variable();
1541  if (!var)
1542  return false;
1543  return var->nameToken() == tok2;
1544  });
1545  if (vartok)
1546  return false;
1547  }
1548  return true;
1549 }
1550 
1551 static std::string getIncompleteNameID(const Token* tok)
1552 {
1553  std::string result = tok->str() + "@";
1554  while (Token::Match(tok->astParent(), ".|::"))
1555  tok = tok->astParent();
1556  return result + tok->expressionString();
1557 }
1558 
1559 namespace {
1560  struct ExprIdKey {
1561  std::string parentOp;
1562  nonneg int operand1;
1563  nonneg int operand2;
1564  bool operator<(const ExprIdKey& k) const {
1565  return std::tie(parentOp, operand1, operand2) < std::tie(k.parentOp, k.operand1, k.operand2);
1566  }
1567  };
1568  using ExprIdMap = std::map<ExprIdKey, nonneg int>;
1569  void setParentExprId(Token* tok, ExprIdMap& exprIdMap, nonneg int &id) {
1570  if (!tok->astParent() || tok->astParent()->isControlFlowKeyword())
1571  return;
1572  const Token* op1 = tok->astParent()->astOperand1();
1573  if (op1 && op1->exprId() == 0)
1574  return;
1575  const Token* op2 = tok->astParent()->astOperand2();
1576  if (op2 && op2->exprId() == 0 &&
1577  !((tok->astParent()->astParent() && tok->astParent()->isAssignmentOp() && tok->astParent()->astParent()->isAssignmentOp()) ||
1578  isLambdaCaptureList(op2) ||
1579  (op2->str() == "(" && isLambdaCaptureList(op2->astOperand1())) ||
1580  Token::simpleMatch(op2, "{ }")))
1581  return;
1582 
1583  if (tok->astParent()->isExpandedMacro() || Token::Match(tok->astParent(), "++|--")) {
1584  tok->astParent()->exprId(id);
1585  ++id;
1586  setParentExprId(tok->astParent(), exprIdMap, id);
1587  return;
1588  }
1589 
1590  ExprIdKey key;
1591  key.parentOp = tok->astParent()->str();
1592  key.operand1 = op1 ? op1->exprId() : 0;
1593  key.operand2 = op2 ? op2->exprId() : 0;
1594 
1595  if (tok->astParent()->isCast() && tok->astParent()->str() == "(") {
1596  const Token* typeStartToken;
1597  const Token* typeEndToken;
1598  if (tok->astParent()->astOperand2()) {
1599  typeStartToken = tok->astParent()->astOperand1();
1600  typeEndToken = tok;
1601  } else {
1602  typeStartToken = tok->astParent()->next();
1603  typeEndToken = tok->astParent()->link();
1604  }
1605  std::string type;
1606  for (const Token* t = typeStartToken; t != typeEndToken; t = t->next()) {
1607  type += " " + t->str();
1608  }
1609  key.parentOp += type;
1610  }
1611 
1612  for (const auto& ref: followAllReferences(op1)) {
1613  if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
1614  key.operand1 = ref.token->exprId();
1615  break;
1616  }
1617  }
1618  for (const auto& ref: followAllReferences(op2)) {
1619  if (ref.token->exprId() != 0) { // cppcheck-suppress useStlAlgorithm
1620  key.operand2 = ref.token->exprId();
1621  break;
1622  }
1623  }
1624 
1625  if (key.operand1 > key.operand2 && key.operand2 &&
1626  Token::Match(tok->astParent(), "%or%|%oror%|+|*|&|&&|^|==|!=")) {
1627  // In C++ the order of operands of + might matter
1628  if (!tok->isCpp() ||
1629  key.parentOp != "+" ||
1630  !tok->astParent()->valueType() ||
1631  tok->astParent()->valueType()->isIntegral() ||
1632  tok->astParent()->valueType()->isFloat() ||
1633  tok->astParent()->valueType()->pointer > 0)
1634  std::swap(key.operand1, key.operand2);
1635  }
1636 
1637  const auto it = exprIdMap.find(key);
1638  if (it == exprIdMap.end()) {
1639  exprIdMap[key] = id;
1640  tok->astParent()->exprId(id);
1641  ++id;
1642  } else {
1643  tok->astParent()->exprId(it->second);
1644  }
1645  setParentExprId(tok->astParent(), exprIdMap, id);
1646  }
1647 }
1648 
1650 {
1651  // Find highest varId
1652  nonneg int maximumVarId = 0;
1653  for (const Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
1654  if (tok->varId() > maximumVarId)
1655  maximumVarId = tok->varId();
1656  }
1657  nonneg int id = maximumVarId + 1;
1658  // Find incomplete vars that are used in constant context
1659  std::unordered_map<std::string, nonneg int> unknownConstantIds;
1660  const Token* inConstExpr = nullptr;
1661  for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
1662  if (Token::Match(tok, "decltype|sizeof|typeof (") && tok->next()->link()) {
1663  tok = tok->next()->link()->previous();
1664  } else if (tok == inConstExpr) {
1665  inConstExpr = nullptr;
1666  } else if (inConstExpr) {
1667  if (!tok->isIncompleteVar())
1668  continue;
1669  if (!isExpression(tok->astParent()))
1670  continue;
1671  const std::string& name = getIncompleteNameID(tok);
1672  if (unknownConstantIds.count(name) > 0)
1673  continue;
1674  unknownConstantIds[name] = id++;
1675  } else if (tok->link() && tok->str() == "<") {
1676  inConstExpr = tok->link();
1677  } else if (Token::Match(tok, "%var% [") && tok->variable() && tok->variable()->nameToken() == tok) {
1678  inConstExpr = tok->next()->link();
1679  }
1680  }
1681 
1682  auto exprScopes = functionScopes; // functions + global lambdas
1683  std::copy_if(scopeList.front().nestedList.begin(), scopeList.front().nestedList.end(), std::back_inserter(exprScopes), [](const Scope* scope) {
1684  return scope && scope->type == Scope::eLambda;
1685  });
1686 
1687  for (const Scope * scope : exprScopes) {
1688  std::unordered_map<std::string, std::vector<Token*>> exprs;
1689 
1690  std::unordered_map<std::string, nonneg int> unknownIds;
1691  // Assign IDs to incomplete vars which are part of an expression
1692  // Such variables should be assumed global
1693  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1694  if (!tok->isIncompleteVar())
1695  continue;
1696  if (!isExpression(tok->astParent()))
1697  continue;
1698  const std::string& name = getIncompleteNameID(tok);
1699  nonneg int sid = 0;
1700  if (unknownConstantIds.count(name) > 0) {
1701  sid = unknownConstantIds.at(name);
1702  tok->isIncompleteConstant(true);
1703  } else if (unknownIds.count(name) == 0) {
1704  sid = id++;
1705  unknownIds[name] = sid;
1706  } else {
1707  sid = unknownIds.at(name);
1708  }
1709  assert(sid > 0);
1710  tok->exprId(sid);
1711  }
1712 
1713  // Assign IDs
1714  ExprIdMap exprIdMap;
1715  std::map<std::string, std::pair<nonneg int, const Token*>> baseIds;
1716  for (auto* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1717  if (tok->varId() > 0) {
1718  tok->exprId(tok->varId());
1719  if (tok->astParent() && tok->astParent()->exprId() == 0)
1720  setParentExprId(tok, exprIdMap, id);
1721  } else if (tok->astParent() && !tok->astOperand1() && !tok->astOperand2()) {
1722  if (tok->tokType() == Token::Type::eBracket)
1723  continue;
1724  if (tok->astParent()->str() == "=")
1725  continue;
1726  if (tok->isControlFlowKeyword())
1727  continue;
1728 
1729  if (Token::Match(tok, "%name% <") && tok->next()->link()) {
1730  tok->exprId(id);
1731  ++id;
1732  } else {
1733  const auto it = baseIds.find(tok->str());
1734  if (it != baseIds.end() && compareTokenFlags(tok, it->second.second, /*macro*/ true)) {
1735  tok->exprId(it->second.first);
1736  } else {
1737  baseIds[tok->str()] = { id, tok };
1738  tok->exprId(id);
1739  ++id;
1740  }
1741  }
1742 
1743  setParentExprId(tok, exprIdMap, id);
1744  }
1745  }
1746  for (Token* tok = const_cast<Token*>(scope->bodyStart); tok != scope->bodyEnd; tok = tok->next()) {
1747  if (tok->varId() == 0 && tok->exprId() > 0 && tok->astParent() && !tok->astOperand1() && !tok->astOperand2()) {
1748  if (tok->isNumber() || tok->isKeyword() || Token::Match(tok->astParent(), ".|::") ||
1749  (Token::simpleMatch(tok->astParent(), "(") && precedes(tok, tok->astParent())))
1750  tok->exprId(0);
1751  }
1752  }
1753  }
1754 
1755  // Mark expressions that are unique
1756  std::vector<std::pair<Token*, int>> uniqueExprId(id);
1757  for (Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
1758  const auto id2 = tok->exprId();
1759  if (id2 == 0 || id2 <= maximumVarId)
1760  continue;
1761  uniqueExprId[id2].first = tok;
1762  uniqueExprId[id2].second++;
1763  }
1764  for (const auto& p : uniqueExprId) {
1765  if (!p.first || p.second != 1)
1766  continue;
1767  if (p.first->variable()) {
1768  const Variable* var = p.first->variable();
1769  if (var->nameToken() != p.first)
1770  continue;
1771  }
1772  p.first->setUniqueExprId();
1773  }
1774 }
1775 
1777 {
1778  // set all unknown array dimensions
1779  for (const Variable *var : mVariableList) {
1780  // check each array variable
1781  if (!var || !var->isArray())
1782  continue;
1783  // check each array dimension
1784  for (const Dimension &const_dimension : var->dimensions()) {
1785  auto &dimension = const_cast<Dimension &>(const_dimension);
1786  if (dimension.num != 0 || !dimension.tok)
1787  continue;
1788 
1789  if (Token::Match(dimension.tok->previous(), "[<,]")) {
1790  if (dimension.known)
1791  continue;
1792  if (!Token::Match(dimension.tok->previous(), "[<,]"))
1793  continue;
1794 
1795  // In template arguments, there might not be AST
1796  // Determine size by using the "raw tokens"
1797  TokenList tokenList(&mSettings);
1798  tokenList.addtoken(";", 0, 0, 0, false);
1799  bool fail = false;
1800  for (const Token *tok = dimension.tok; tok && !Token::Match(tok, "[,>]"); tok = tok->next()) {
1801  if (!tok->isName())
1802  tokenList.addtoken(tok->str(), 0, 0, 0, false);
1803 
1804  else if (tok->hasKnownIntValue())
1805  tokenList.addtoken(std::to_string(tok->getKnownIntValue()), 0, 0, 0, false);
1806 
1807  else {
1808  fail = true;
1809  break;
1810  }
1811  }
1812 
1813  if (fail)
1814  continue;
1815 
1816  tokenList.addtoken(";", 0, 0, 0, false);
1817 
1818  for (Token *tok = tokenList.front(); tok;) {
1820  tok = tokenList.front();
1821  else
1822  tok = tok->next();
1823  }
1824 
1825  if (Token::Match(tokenList.front(), "; %num% ;")) {
1826  dimension.known = true;
1827  dimension.num = MathLib::toBigNumber(tokenList.front()->next()->str());
1828  }
1829 
1830  continue;
1831  }
1832 
1833  // Normal array [..dimension..]
1834  dimension.known = false;
1835 
1836  // check for a single token dimension
1837  if (dimension.tok->hasKnownIntValue()) {
1838  dimension.known = true;
1839  dimension.num = dimension.tok->getKnownIntValue();
1840  continue;
1841  }
1842 
1843  if (dimension.tok->valueType() && dimension.tok->valueType()->pointer == 0) {
1844  int bits = 0;
1845  switch (dimension.tok->valueType()->type) {
1846  case ValueType::Type::CHAR:
1847  bits = mSettings.platform.char_bit;
1848  break;
1849  case ValueType::Type::SHORT:
1850  bits = mSettings.platform.short_bit;
1851  break;
1852  case ValueType::Type::INT:
1853  bits = mSettings.platform.int_bit;
1854  break;
1855  case ValueType::Type::LONG:
1856  bits = mSettings.platform.long_bit;
1857  break;
1858  case ValueType::Type::LONGLONG:
1860  break;
1861  default:
1862  break;
1863  }
1864 
1865  if (bits > 0 && bits <= 62) {
1866  if (dimension.tok->valueType()->sign == ValueType::Sign::UNSIGNED)
1867  dimension.num = 1LL << bits;
1868  else
1869  dimension.num = 1LL << (bits - 1);
1870  }
1871  }
1872  }
1873  }
1874 }
1875 
1877 {
1878  // Clear scope, type, function and variable pointers
1879  for (Token* tok = mTokenizer.list.front(); tok; tok = tok->next()) {
1880  tok->scope(nullptr);
1881  tok->type(nullptr);
1882  tok->function(nullptr);
1883  tok->variable(nullptr);
1884  tok->enumerator(nullptr);
1885  tok->setValueType(nullptr);
1886  }
1887 }
1888 
1889 bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token *&funcStart, const Token *&argStart, const Token*& declEnd) const
1890 {
1891  if (tok->varId())
1892  return false;
1893 
1894  // function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
1895  // function returning reference to array '... ( & %name% ( ... ))[ ... ] {'
1896  // TODO: Activate this again
1897  if ((false) && tok->str() == "(" && tok->strAt(1) != "*" && // NOLINT(readability-simplify-boolean-expr)
1898  (tok->link()->previous()->str() == ")" || Token::simpleMatch(tok->link()->tokAt(-2), ") const"))) {
1899  const Token* tok2 = tok->link()->next();
1900  if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) {
1901  const Token* argStartTok;
1902  if (tok->link()->previous()->str() == "const")
1903  argStartTok = tok->link()->linkAt(-2);
1904  else
1905  argStartTok = tok->link()->linkAt(-1);
1906  funcStart = argStartTok->previous();
1907  argStart = argStartTok;
1908  declEnd = Token::findmatch(tok2->link()->next(), "{|;");
1909  return true;
1910  }
1911  if (tok2 && tok2->str() == "[") {
1912  while (tok2 && tok2->str() == "[")
1913  tok2 = tok2->link()->next();
1914  if (Token::Match(tok2, "{|;|const|=")) {
1915  const Token* argStartTok;
1916  if (tok->link()->previous()->str() == "const")
1917  argStartTok = tok->link()->linkAt(-2);
1918  else
1919  argStartTok = tok->link()->linkAt(-1);
1920  funcStart = argStartTok->previous();
1921  argStart = argStartTok;
1922  declEnd = Token::findmatch(tok2, "{|;");
1923  return true;
1924  }
1925  }
1926  }
1927 
1928  else if (!tok->isName() || !tok->next() || !tok->next()->link())
1929  return false;
1930 
1931  // regular function?
1932  else if (Token::Match(tok, "%name% (") && !isReservedName(tok) && tok->previous() &&
1933  (Token::Match(tok->previous(), "%name%|>|&|&&|*|::|~") || // Either a return type or scope qualifier in front of tok
1934  outerScope->isClassOrStructOrUnion())) { // or a ctor/dtor
1935  const Token* tok1 = tok->previous();
1936  const Token* tok2 = tok->next()->link()->next();
1937 
1938  if (!Tokenizer::isFunctionHead(tok->next(), ";:{"))
1939  return false;
1940 
1941  // skip over destructor "~"
1942  if (tok1->str() == "~")
1943  tok1 = tok1->previous();
1944 
1945  // skip over qualification
1946  while (Token::simpleMatch(tok1, "::")) {
1947  tok1 = tok1->previous();
1948  if (tok1 && tok1->isName())
1949  tok1 = tok1->previous();
1950  else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
1951  tok1 = tok1->link()->tokAt(-2);
1952  }
1953 
1954  // skip over const, noexcept, throw, override, final and volatile specifiers
1955  while (Token::Match(tok2, "const|noexcept|throw|override|final|volatile|&|&&")) {
1956  tok2 = tok2->next();
1957  if (tok2 && tok2->str() == "(")
1958  tok2 = tok2->link()->next();
1959  }
1960 
1961  // skip over trailing return type
1962  bool hasTrailingRet = false;
1963  if (tok2 && tok2->str() == ".") {
1964  hasTrailingRet = true;
1965  for (tok2 = tok2->next(); tok2; tok2 = tok2->next()) {
1966  if (Token::Match(tok2, ";|{|=|override|final"))
1967  break;
1968  if (tok2->link() && Token::Match(tok2, "<|[|("))
1969  tok2 = tok2->link();
1970  }
1971  }
1972 
1973  // done if constructor or destructor
1974  if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
1975  // skip over pointers and references
1976  while (Token::Match(tok1, "%type%|*|&|&&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1) || tok1->str() == "const"))
1977  tok1 = tok1->previous();
1978 
1979  // skip over decltype
1980  if (Token::simpleMatch(tok1, ")") && tok1->link() &&
1981  Token::simpleMatch(tok1->link()->previous(), "decltype ("))
1982  tok1 = tok1->link()->tokAt(-2);
1983 
1984  // skip over template
1985  if (tok1 && tok1->str() == ">") {
1986  if (tok1->link())
1987  tok1 = tok1->link()->previous();
1988  else
1989  return false;
1990  }
1991 
1992  // function can't have number or variable as return type
1993  if (tok1 && (tok1->isNumber() || tok1->varId()))
1994  return false;
1995 
1996  // skip over return type
1997  if (tok1 && tok1->isName()) {
1998  if (tok1->str() == "return")
1999  return false;
2000  if (tok1->str() != "friend")
2001  tok1 = tok1->previous();
2002  }
2003 
2004  // skip over qualification
2005  while (Token::simpleMatch(tok1, "::")) {
2006  tok1 = tok1->previous();
2007  if (tok1 && tok1->isName())
2008  tok1 = tok1->previous();
2009  else if (tok1 && tok1->str() == ">" && tok1->link() && Token::Match(tok1->link()->previous(), "%name%"))
2010  tok1 = tok1->link()->tokAt(-2);
2011  else if (Token::simpleMatch(tok1, ")") && tok1->link() &&
2012  Token::simpleMatch(tok1->link()->previous(), "decltype ("))
2013  tok1 = tok1->link()->tokAt(-2);
2014  }
2015 
2016  // skip over modifiers and other stuff
2017  while (Token::Match(tok1, "const|static|extern|template|virtual|struct|class|enum|%name%")) {
2018  // friend type func(); is not a function
2019  if (tok1->isCpp() && tok1->str() == "friend" && tok2->str() == ";")
2020  return false;
2021  tok1 = tok1->previous();
2022  }
2023 
2024  // should be at a sequence point if this is a function
2025  if (!Token::Match(tok1, ">|{|}|;|public:|protected:|private:") && tok1)
2026  return false;
2027  }
2028 
2029  if (tok2 &&
2030  (Token::Match(tok2, ";|{|=") ||
2031  (tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
2032  (tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
2033  Token::Match(tok2, ": ::| %name% (|::|<|{") ||
2034  Token::Match(tok2, "&|&&| ;|{") ||
2035  Token::Match(tok2, "= delete|default ;") ||
2036  (hasTrailingRet && Token::Match(tok2, "final|override")))) {
2037  funcStart = tok;
2038  argStart = tok->next();
2039  declEnd = Token::findmatch(tok2, "{|;");
2040  return true;
2041  }
2042  }
2043 
2044  // UNKNOWN_MACRO(a,b) { ... }
2045  else if (outerScope->type == Scope::eGlobal &&
2046  Token::Match(tok, "%name% (") &&
2047  tok->isUpperCaseName() &&
2048  Token::simpleMatch(tok->linkAt(1), ") {") &&
2049  (!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
2050  funcStart = tok;
2051  argStart = tok->next();
2052  declEnd = tok->linkAt(1)->next();
2053  return true;
2054  }
2055 
2056  // template constructor?
2057  else if (Token::Match(tok, "%name% <") && Token::simpleMatch(tok->next()->link(), "> (")) {
2058  if (tok->isKeyword() || tok->isStandardType() || !outerScope->isClassOrStructOrUnion())
2059  return false;
2060  const Token* tok2 = tok->next()->link()->next()->link();
2061  if (Token::Match(tok2, ") const| ;|{|=") ||
2062  Token::Match(tok2, ") : ::| %name% (|::|<|{") ||
2063  Token::Match(tok2, ") const| noexcept {|;|(")) {
2064  funcStart = tok;
2065  argStart = tok2->link();
2066  declEnd = Token::findmatch(tok2->next(), "{|;");
2067  return true;
2068  }
2069  }
2070 
2071  // regular C function with missing return or invalid C++ ?
2072  else if (Token::Match(tok, "%name% (") && !isReservedName(tok) &&
2073  Token::simpleMatch(tok->linkAt(1), ") {") &&
2074  (!tok->previous() || Token::Match(tok->previous(), ";|}"))) {
2075  if (tok->isC()) {
2077  funcStart = tok;
2078  argStart = tok->next();
2079  declEnd = tok->linkAt(1)->next();
2080  return true;
2081  }
2082  mTokenizer.syntaxError(tok);
2083  }
2084 
2085  return false;
2086 }
2087 
2089 {
2090  const std::size_t functions = functionScopes.size();
2091  for (std::size_t i = 0; i < functions; ++i) {
2092  const Scope* const scope = functionScopes[i];
2093  const Function* const function = scope->function;
2094  if (scope->isExecutable() && !function) {
2095  const std::list<const Token*> callstack(1, scope->classDef);
2096  const std::string msg = std::string("Executable scope '") + scope->classDef->str() + "' with unknown function.";
2097  const ErrorMessage errmsg(callstack, &mTokenizer.list, Severity::debug,
2098  "symbolDatabaseWarning",
2099  msg,
2101  mErrorLogger.reportErr(errmsg);
2102  }
2103  }
2104 }
2105 
2106 namespace {
2107  const Function* getFunctionForArgumentvariable(const Variable * const var)
2108  {
2109  if (const Scope* scope = var->nameToken()->scope()) {
2110  auto it = std::find_if(scope->functionList.begin(), scope->functionList.end(), [&](const Function& function) {
2111  for (std::size_t arg = 0; arg < function.argCount(); ++arg) {
2112  if (var == function.getArgumentVar(arg))
2113  return true;
2114  }
2115  return false;
2116  });
2117  if (it != scope->functionList.end())
2118  return &*it;
2119  }
2120  return nullptr;
2121  }
2122 }
2123 
2125 {
2126  for (std::vector<const Variable *>::const_iterator iter = mVariableList.cbegin(); iter!=mVariableList.cend(); ++iter) {
2127  const Variable * const var = *iter;
2128  if (var) {
2129  if (!var->scope()) {
2130  const Function* function = getFunctionForArgumentvariable(var);
2131  if (!var->isArgument() || (!function || function->hasBody())) { // variables which only appear in a function declaration do not have a scope
2132  throw InternalError(var->nameToken(), "Analysis failed (variable without scope). If the code is valid then please report this failure.", InternalError::INTERNAL);
2133  }
2134  }
2135  }
2136  }
2137 }
2138 
2140 {
2141  if (mSettings.debugwarnings) {
2143  }
2145 }
2146 
2147 void SymbolDatabase::clangSetVariables(const std::vector<const Variable *> &variableList)
2148 {
2150 }
2151 
2153 {
2155  return;
2156  for (const Token* tok = mTokenizer.list.front(); tok != mTokenizer.list.back(); tok = tok->next()) {
2157  if (tok->astParent() && tok->astParent()->getTokenDebug() == tok->getTokenDebug())
2158  continue;
2159  if (tok->getTokenDebug() == TokenDebug::ValueType) {
2160 
2161  std::string msg = "Value type is ";
2162  ErrorPath errorPath;
2163  if (tok->valueType()) {
2164  msg += tok->valueType()->str();
2165  errorPath.insert(errorPath.end(), tok->valueType()->debugPath.cbegin(), tok->valueType()->debugPath.cend());
2166 
2167  } else {
2168  msg += "missing";
2169  }
2170  errorPath.emplace_back(tok, "");
2172  {errorPath, &mTokenizer.list, Severity::debug, "valueType", msg, CWE{0}, Certainty::normal});
2173  }
2174  }
2175 }
2176 
2177 Variable::Variable(const Token *name_, const std::string &clangType, const Token *typeStart,
2178  const Token *typeEnd, nonneg int index_, AccessControl access_,
2179  const Type *type_, const Scope *scope_)
2180  : mNameToken(name_),
2181  mTypeStartToken(typeStart),
2182  mTypeEndToken(typeEnd),
2183  mIndex(index_),
2184  mAccess(access_),
2185  mFlags(0),
2186  mType(type_),
2187  mScope(scope_)
2188 {
2189  if (!mTypeStartToken && mTypeEndToken) {
2191  while (Token::Match(mTypeStartToken->previous(), "%type%|*|&"))
2193  }
2194 
2195  while (Token::Match(mTypeStartToken, "const|struct|static")) {
2196  if (mTypeStartToken->str() == "static")
2197  setFlag(fIsStatic, true);
2199  }
2200 
2202  setFlag(fIsReference, true);
2203  else if (Token::simpleMatch(mTypeEndToken, "&&")) {
2204  setFlag(fIsReference, true);
2205  setFlag(fIsRValueRef, true);
2206  }
2207 
2208  std::string::size_type pos = clangType.find('[');
2209  if (pos != std::string::npos) {
2210  setFlag(fIsArray, true);
2211  do {
2212  const std::string::size_type pos1 = pos+1;
2213  pos = clangType.find(']', pos1);
2214  Dimension dim;
2215  dim.tok = nullptr;
2216  dim.known = pos > pos1;
2217  if (pos > pos1)
2218  dim.num = MathLib::toBigNumber(clangType.substr(pos1, pos - pos1));
2219  else
2220  dim.num = 0;
2221  mDimensions.push_back(dim);
2222  ++pos;
2223  } while (pos < clangType.size() && clangType[pos] == '[');
2224  }
2225 
2226  // Is there initialization in variable declaration
2227  const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
2228  while (initTok && initTok->str() == "[")
2229  initTok = initTok->link()->next();
2230  if (Token::Match(initTok, "=|{") || (initTok && initTok->isSplittedVarDeclEq()))
2231  setFlag(fIsInit, true);
2232 }
2233 
2234 Variable::Variable(const Variable &var, const Scope *scope)
2235 {
2236  *this = var;
2237  mScope = scope;
2238 }
2239 
2241 {
2242  *this = var;
2243 }
2244 
2246 {
2247  delete mValueType;
2248 }
2249 
2251 {
2252  if (this == &var)
2253  return *this;
2254 
2255  ValueType* vt = nullptr;
2256  if (var.mValueType)
2257  vt = new ValueType(*var.mValueType);
2258 
2259  mNameToken = var.mNameToken;
2262  mIndex = var.mIndex;
2263  mAccess = var.mAccess;
2264  mFlags = var.mFlags;
2265  mType = var.mType;
2266  mScope = var.mScope;
2267  mDimensions = var.mDimensions;
2268  delete mValueType;
2269  mValueType = vt;
2270 
2271  return *this;
2272 }
2273 
2274 bool Variable::isMember() const {
2275  return mScope && mScope->isClassOrStructOrUnion();
2276 }
2277 
2279 {
2280  return isArray() && nameToken() && nameToken()->previous() && (nameToken()->previous()->str() == "*");
2281 }
2282 
2284 {
2285  return mValueType ? (mValueType->sign == ValueType::Sign::UNSIGNED) : mTypeStartToken->isUnsigned();
2286 }
2287 
2289 {
2290  Token const * declEnd = typeStartToken();
2291  while (declEnd && !Token::Match(declEnd, "[;,)={]")) {
2292  if (declEnd->link() && Token::Match(declEnd,"(|[|<"))
2293  declEnd = declEnd->link();
2294  declEnd = declEnd->next();
2295  }
2296  return declEnd;
2297 }
2298 
2299 void Variable::evaluate(const Settings& settings)
2300 {
2301  // Is there initialization in variable declaration
2302  const Token *initTok = mNameToken ? mNameToken->next() : nullptr;
2303  while (Token::Match(initTok, "[")) {
2304  initTok = initTok->link()->next();
2305  if (Token::simpleMatch(initTok, ")"))
2306  initTok = initTok->next();
2307  }
2308  if (Token::Match(initTok, "[={(]") || (initTok && initTok->isSplittedVarDeclEq()))
2309  setFlag(fIsInit, true);
2310 
2311  const Library & lib = settings.library;
2312 
2313  // TODO: ValueType::parseDecl() is also performing a container lookup
2314  bool isContainer = false;
2315  if (mNameToken)
2316  setFlag(fIsArray, arrayDimensions(settings, isContainer));
2317 
2318  if (mTypeStartToken)
2320 
2321  const Token* tok = mTypeStartToken;
2322  while (tok && tok->previous() && tok->previous()->isName())
2323  tok = tok->previous();
2324  const Token* end = mTypeEndToken;
2325  if (end)
2326  end = end->next();
2327  while (tok != end) {
2328  if (tok->str() == "static")
2329  setFlag(fIsStatic, true);
2330  else if (tok->str() == "extern")
2331  setFlag(fIsExtern, true);
2332  else if (tok->str() == "volatile" || Token::simpleMatch(tok, "std :: atomic <"))
2333  setFlag(fIsVolatile, true);
2334  else if (tok->str() == "mutable")
2335  setFlag(fIsMutable, true);
2336  else if (tok->str() == "const")
2337  setFlag(fIsConst, true);
2338  else if (tok->str() == "constexpr") {
2339  setFlag(fIsConst, true);
2340  setFlag(fIsStatic, true);
2341  } else if (tok->str() == "*") {
2342  setFlag(fIsPointer, !isArray() || (isContainer && !Token::Match(tok->next(), "%name% [")) || Token::Match(tok, "* const| %name% )"));
2343  setFlag(fIsConst, false); // Points to const, isn't necessarily const itself
2344  } else if (tok->str() == "&") {
2345  if (isReference())
2346  setFlag(fIsRValueRef, true);
2347  setFlag(fIsReference, true);
2348  } else if (tok->str() == "&&") { // Before simplification, && isn't split up
2349  setFlag(fIsRValueRef, true);
2350  setFlag(fIsReference, true); // Set also fIsReference
2351  }
2352 
2353  if (tok->isAttributeMaybeUnused()) {
2354  setFlag(fIsMaybeUnused, true);
2355  }
2356 
2357  if (tok->str() == "<" && tok->link())
2358  tok = tok->link();
2359  else
2360  tok = tok->next();
2361  }
2362 
2363  while (Token::Match(mTypeStartToken, "static|const|constexpr|volatile %any%"))
2365  while (mTypeEndToken && mTypeEndToken->previous() && Token::Match(mTypeEndToken, "const|volatile"))
2367 
2368  if (mTypeStartToken) {
2369  std::string strtype = mTypeStartToken->str();
2370  for (const Token *typeToken = mTypeStartToken; Token::Match(typeToken, "%type% :: %type%"); typeToken = typeToken->tokAt(2))
2371  strtype += "::" + typeToken->strAt(2);
2372  setFlag(fIsClass, !lib.podtype(strtype) && !mTypeStartToken->isStandardType() && !isEnumType() && !isPointer() && strtype != "...");
2376  }
2378  tok = mNameToken;
2379  if (!tok) {
2380  // Argument without name
2381  tok = mTypeEndToken;
2382  // back up to start of array dimensions
2383  while (tok && tok->str() == "]")
2384  tok = tok->link()->previous();
2385  // add array dimensions if present
2386  if (tok && tok->next()->str() == "[")
2387  setFlag(fIsArray, arrayDimensions(settings, isContainer));
2388  }
2389  if (!tok)
2390  return;
2391  tok = tok->next();
2392  while (tok->str() == "[")
2393  tok = tok->link();
2394  setFlag(fHasDefault, tok->str() == "=");
2395  }
2396  // check for C++11 member initialization
2397  if (mScope && mScope->isClassOrStruct()) {
2398  // type var = x or
2399  // type var = {x}
2400  // type var = x; gets simplified to: type var ; var = x ;
2401  Token const * declEnd = declEndToken();
2402  if ((Token::Match(declEnd, "; %name% =") && declEnd->strAt(1) == mNameToken->str()) ||
2403  Token::Match(declEnd, "=|{"))
2404  setFlag(fHasDefault, true);
2405  }
2406 
2407  if (mTypeStartToken) {
2408  if (Token::Match(mTypeStartToken, "float|double"))
2409  setFlag(fIsFloatType, true);
2410  }
2411 }
2412 
2413 void Variable::setValueType(const ValueType &valueType)
2414 {
2415  if (valueType.type == ValueType::Type::UNKNOWN_TYPE) {
2416  const Token *declType = Token::findsimplematch(mTypeStartToken, "decltype (", mTypeEndToken);
2417  if (declType && !declType->next()->valueType())
2418  return;
2419  }
2420  ValueType* vt = new ValueType(valueType);
2421  delete mValueType;
2422  mValueType = vt;
2423  if ((mValueType->pointer > 0) && (!isArray() || Token::Match(mNameToken->previous(), "( * %name% )")))
2424  setFlag(fIsPointer, true);
2428  setFlag(fIsSmartPointer, true);
2429 }
2430 
2432 {
2433  if (!isSmartPointer())
2434  return nullptr;
2435 
2437  return mValueType->smartPointerType;
2438 
2439  // TODO: Cache result, handle more complex type expression
2440  const Token* typeTok = typeStartToken();
2441  while (Token::Match(typeTok, "%name%|::"))
2442  typeTok = typeTok->next();
2443  if (Token::Match(typeTok, "< %name% >")) {
2444  // cppcheck-suppress shadowFunction - TODO: fix this
2445  const Scope* scope = typeTok->scope();
2446  const Type* ptrType{};
2447  while (scope && !ptrType) {
2448  ptrType = scope->findType(typeTok->next()->str());
2449  scope = scope->nestedIn;
2450  }
2451  return ptrType;
2452  }
2453  return nullptr;
2454 }
2455 
2457 {
2459  return nullptr;
2460 
2462  return mValueType->containerTypeToken->type();
2463 
2464  return nullptr;
2465 }
2466 
2468 {
2470 }
2471 
2472 std::string Variable::getTypeName() const
2473 {
2474  std::string ret;
2475  // TODO: For known types, generate the full type name
2476  for (const Token *typeTok = mTypeStartToken; Token::Match(typeTok, "%name%|::") && typeTok->varId() == 0; typeTok = typeTok->next()) {
2477  ret += typeTok->str();
2478  if (Token::simpleMatch(typeTok->next(), "<") && typeTok->next()->link()) // skip template arguments
2479  typeTok = typeTok->next()->link();
2480  }
2481  return ret;
2482 }
2483 
2484 static bool isOperator(const Token *tokenDef)
2485 {
2486  if (!tokenDef)
2487  return false;
2488  if (tokenDef->isOperatorKeyword())
2489  return true;
2490  const std::string &name = tokenDef->str();
2491  return name.size() > 8 && startsWith(name,"operator") && std::strchr("+-*/%&|~^<>!=[(", name[8]);
2492 }
2493 
2495  const Scope *scope,
2496  const Token *tokDef,
2497  const Token *tokArgDef)
2498  : tokenDef(tokDef),
2499  argDef(tokArgDef),
2500  nestedIn(scope)
2501 {
2502  // operator function
2503  if (::isOperator(tokenDef)) {
2504  isOperator(true);
2505 
2506  // 'operator =' is special
2507  if (tokenDef->str() == "operator=")
2509  }
2510 
2511  else if (tokenDef->str() == "[") {
2513  }
2514 
2515  // class constructor/destructor
2516  else if (scope->isClassOrStructOrUnion() &&
2517  ((tokenDef->str() == scope->className) ||
2518  (tokenDef->str().substr(0, scope->className.size()) == scope->className &&
2519  tokenDef->str().size() > scope->className.size() + 1 &&
2520  tokenDef->str()[scope->className.size() + 1] == '<'))) {
2521  // destructor
2522  if (tokenDef->previous()->str() == "~")
2524  // constructor of any kind
2525  else
2527 
2528  isExplicit(tokenDef->strAt(-1) == "explicit" || tokenDef->strAt(-2) == "explicit");
2529  }
2530 
2531  const Token *tok1 = setFlags(tok, scope);
2532 
2533  // find the return type
2534  if (!isConstructor() && !isDestructor()) {
2535  // @todo auto type deduction should be checked
2536  // @todo attributes and exception specification can also precede trailing return type
2537  if (Token::Match(argDef->link()->next(), "const|volatile| &|&&| .")) { // Trailing return type
2538  hasTrailingReturnType(true);
2539  if (argDef->link()->strAt(1) == ".")
2540  retDef = argDef->link()->tokAt(2);
2541  else if (argDef->link()->strAt(2) == ".")
2542  retDef = argDef->link()->tokAt(3);
2543  else if (argDef->link()->strAt(3) == ".")
2544  retDef = argDef->link()->tokAt(4);
2545  } else if (!isLambda()) {
2546  if (tok1->str() == ">")
2547  tok1 = tok1->next();
2548  while (Token::Match(tok1, "extern|virtual|static|friend|struct|union|enum"))
2549  tok1 = tok1->next();
2550  retDef = tok1;
2551  }
2552  }
2553 
2554  const Token *end = argDef->link();
2555 
2556  // parse function attributes..
2557  tok = end->next();
2558  while (tok) {
2559  if (tok->str() == "const")
2560  isConst(true);
2561  else if (tok->str() == "&")
2562  hasLvalRefQualifier(true);
2563  else if (tok->str() == "&&")
2564  hasRvalRefQualifier(true);
2565  else if (tok->str() == "override")
2567  else if (tok->str() == "final")
2568  setFlag(fHasFinalSpecifier, true);
2569  else if (tok->str() == "volatile")
2570  isVolatile(true);
2571  else if (tok->str() == "noexcept") {
2572  isNoExcept(!Token::simpleMatch(tok->next(), "( false )"));
2573  if (tok->next()->str() == "(")
2574  tok = tok->linkAt(1);
2575  } else if (Token::simpleMatch(tok, "throw (")) {
2576  isThrow(true);
2577  if (tok->strAt(2) != ")")
2578  throwArg = tok->next();
2579  tok = tok->linkAt(1);
2580  } else if (Token::Match(tok, "= 0|default|delete ;")) {
2581  const std::string& modifier = tok->strAt(1);
2582  isPure(modifier == "0");
2583  isDefault(modifier == "default");
2584  isDelete(modifier == "delete");
2585  } else if (tok->str() == ".") { // trailing return type
2586  // skip over return type
2587  while (tok && !Token::Match(tok->next(), ";|{|override|final"))
2588  tok = tok->next();
2589  } else
2590  break;
2591  if (tok)
2592  tok = tok->next();
2593  }
2594 
2595  if (Tokenizer::isFunctionHead(end, ":{")) {
2596  // assume implementation is inline (definition and implementation same)
2597  token = tokenDef;
2598  arg = argDef;
2599  isInline(true);
2600  hasBody(true);
2601  }
2602 }
2603 
2604 Function::Function(const Token *tokenDef, const std::string &clangType)
2605  : tokenDef(tokenDef)
2606 {
2607  // operator function
2608  if (::isOperator(tokenDef)) {
2609  isOperator(true);
2610 
2611  // 'operator =' is special
2612  if (tokenDef->str() == "operator=")
2614  }
2615 
2617 
2618  if (endsWith(clangType, " const"))
2619  isConst(true);
2620 }
2621 
2622 const Token *Function::setFlags(const Token *tok1, const Scope *scope)
2623 {
2624  if (tok1->isInline())
2625  isInlineKeyword(true);
2626 
2627  // look for end of previous statement
2628  while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
2629  tok1 = tok1->previous();
2630 
2631  if (tok1->isInline())
2632  isInlineKeyword(true);
2633 
2634  // extern function
2635  if (tok1->isExternC() || tok1->str() == "extern") {
2636  isExtern(true);
2637  }
2638 
2639  // virtual function
2640  else if (tok1->str() == "virtual") {
2641  hasVirtualSpecifier(true);
2642  }
2643 
2644  // static function
2645  else if (tok1->str() == "static") {
2646  isStatic(true);
2647  if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal)
2648  isStaticLocal(true);
2649  }
2650 
2651  // friend function
2652  else if (tok1->str() == "friend") {
2653  isFriend(true);
2654  }
2655 
2656  // constexpr function
2657  else if (tok1->str() == "constexpr") {
2658  isConstexpr(true);
2659  }
2660 
2661  // decltype
2662  else if (tok1->str() == ")" && Token::simpleMatch(tok1->link()->previous(), "decltype (")) {
2663  tok1 = tok1->link()->previous();
2664  }
2665 
2666  else if (tok1->link() && tok1->str() == ">") {
2667  // Function template
2668  if (Token::simpleMatch(tok1->link()->previous(), "template <")) {
2669  templateDef = tok1->link()->previous();
2670  break;
2671  }
2672  tok1 = tok1->link();
2673  }
2674  }
2675  return tok1;
2676 }
2677 
2678 std::string Function::fullName() const
2679 {
2680  std::string ret = name();
2681  for (const Scope *s = nestedIn; s; s = s->nestedIn) {
2682  if (!s->className.empty())
2683  ret = s->className + "::" + ret;
2684  }
2685  ret += "(";
2686  for (const Variable &a : argumentList)
2687  ret += (a.index() == 0 ? "" : ",") + a.name();
2688  return ret + ")";
2689 }
2690 
2691 static std::string qualifiedName(const Scope *scope)
2692 {
2693  std::string name = scope->className;
2694  while (scope->nestedIn) {
2695  if (!scope->nestedIn->className.empty())
2696  name = (scope->nestedIn->className + " :: ") + name;
2697  scope = scope->nestedIn;
2698  }
2699  return name;
2700 }
2701 
2702 static bool usingNamespace(const Scope *scope, const Token *first, const Token *second, int &offset)
2703 {
2704  // check if qualifications match first before checking if using is needed
2705  const Token *tok1 = first;
2706  const Token *tok2 = second;
2707  bool match = false;
2708  while (Token::Match(tok1, "%type% :: %type%") && Token::Match(tok2, "%type% :: %type%")) {
2709  if (tok1->str() == tok2->str()) {
2710  tok1 = tok1->tokAt(2);
2711  tok2 = tok2->tokAt(2);
2712  match = true;
2713  } else {
2714  match = false;
2715  break;
2716  }
2717  }
2718 
2719  if (match)
2720  return false;
2721 
2722  offset = 0;
2723  std::string name = first->str();
2724 
2725  while (Token::Match(first, "%type% :: %type%")) {
2726  if (offset)
2727  name += (" :: " + first->str());
2728  offset += 2;
2729  first = first->tokAt(2);
2730  if (first->str() == second->str()) {
2731  break;
2732  }
2733  }
2734 
2735  if (offset) {
2736  while (scope) {
2737  for (const auto & info : scope->usingList) {
2738  if (info.scope) {
2739  if (name == qualifiedName(info.scope))
2740  return true;
2741  }
2742  // no scope so get name from using
2743  else {
2744  const Token *start = info.start->tokAt(2);
2745  std::string nsName;
2746  while (start && start->str() != ";") {
2747  if (!nsName.empty())
2748  nsName += " ";
2749  nsName += start->str();
2750  start = start->next();
2751  }
2752  if (nsName == name)
2753  return true;
2754  }
2755  }
2756  scope = scope->nestedIn;
2757  }
2758  }
2759 
2760  return false;
2761 }
2762 
2763 static bool typesMatch(
2764  const Scope *first_scope,
2765  const Token *first_token,
2766  const Scope *second_scope,
2767  const Token *second_token,
2768  const Token *&new_first,
2769  const Token *&new_second)
2770 {
2771  // get first type
2772  const Type* first_type = first_scope->check->findType(first_token, first_scope, /*lookOutside*/ true);
2773  if (first_type) {
2774  // get second type
2775  const Type* second_type = second_scope->check->findType(second_token, second_scope, /*lookOutside*/ true);
2776  // check if types match
2777  if (first_type == second_type) {
2778  const Token* tok1 = first_token;
2779  while (tok1 && tok1->str() != first_type->name())
2780  tok1 = tok1->next();
2781  const Token *tok2 = second_token;
2782  while (tok2 && tok2->str() != second_type->name())
2783  tok2 = tok2->next();
2784  // update parser token positions
2785  if (tok1 && tok2) {
2786  new_first = tok1->previous();
2787  new_second = tok2->previous();
2788  return true;
2789  }
2790  }
2791  }
2792  return false;
2793 }
2794 
2795 bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const
2796 {
2797  if (!first->isCpp()) // C does not support overloads
2798  return true;
2799 
2800  int arg_path_length = path_length;
2801  int offset = 0;
2802  int openParen = 0;
2803 
2804  // check for () == (void) and (void) == ()
2805  if ((Token::simpleMatch(first, "( )") && Token::simpleMatch(second, "( void )")) ||
2806  (Token::simpleMatch(first, "( void )") && Token::simpleMatch(second, "( )")))
2807  return true;
2808 
2809  auto skipTopLevelConst = [](const Token* start) -> const Token* {
2810  const Token* tok = start->next();
2811  if (Token::simpleMatch(tok, "const")) {
2812  tok = tok->next();
2813  while (Token::Match(tok, "%name%|%type%|::"))
2814  tok = tok->next();
2815  if (Token::Match(tok, ",|)|="))
2816  return start->next();
2817  }
2818  return start;
2819  };
2820 
2821  while (first->str() == second->str() &&
2822  first->isLong() == second->isLong() &&
2823  first->isUnsigned() == second->isUnsigned()) {
2824  if (first->str() == "(")
2825  openParen++;
2826 
2827  // at end of argument list
2828  else if (first->str() == ")") {
2829  if (openParen == 1)
2830  return true;
2831  --openParen;
2832  }
2833 
2834  // skip optional type information
2835  if (Token::Match(first->next(), "struct|enum|union|class"))
2836  first = first->next();
2837  if (Token::Match(second->next(), "struct|enum|union|class"))
2838  second = second->next();
2839 
2840  // skip const on type passed by value
2841  const Token* const oldSecond = second;
2842  first = skipTopLevelConst(first);
2843  second = skipTopLevelConst(second);
2844 
2845  // skip default value assignment
2846  if (oldSecond == second && first->next()->str() == "=") {
2847  first = first->nextArgument();
2848  if (first)
2849  first = first->tokAt(-2);
2850  if (second->next()->str() == "=") {
2851  second = second->nextArgument();
2852  if (second)
2853  second = second->tokAt(-2);
2854  if (!first || !second) { // End of argument list (first or second)
2855  return !first && !second;
2856  }
2857  } else if (!first) { // End of argument list (first)
2858  return !second->nextArgument(); // End of argument list (second)
2859  }
2860  } else if (oldSecond == second && second->next()->str() == "=") {
2861  second = second->nextArgument();
2862  if (second)
2863  second = second->tokAt(-2);
2864  if (!second) { // End of argument list (second)
2865  return !first->nextArgument();
2866  }
2867  }
2868 
2869  // definition missing variable name
2870  else if ((first->next()->str() == "," && second->next()->str() != ",") ||
2871  (Token::Match(first, "!!( )") && second->next()->str() != ")")) {
2872  second = second->next();
2873  // skip default value assignment
2874  if (second->next()->str() == "=") {
2875  do {
2876  second = second->next();
2877  } while (!Token::Match(second->next(), ",|)"));
2878  }
2879  } else if (first->next()->str() == "[" && second->next()->str() != "[")
2880  second = second->next();
2881 
2882  // function missing variable name
2883  else if ((second->next()->str() == "," && first->next()->str() != ",") ||
2884  (Token::Match(second, "!!( )") && first->next()->str() != ")")) {
2885  first = first->next();
2886  // skip default value assignment
2887  if (first->next()->str() == "=") {
2888  do {
2889  first = first->next();
2890  } while (!Token::Match(first->next(), ",|)"));
2891  }
2892  } else if (second->next()->str() == "[" && first->next()->str() != "[")
2893  first = first->next();
2894 
2895  // unnamed parameters
2896  else if (Token::Match(first, "(|, %type% ,|)") && Token::Match(second, "(|, %type% ,|)")) {
2897  if (first->next()->expressionString() != second->next()->expressionString())
2898  break;
2899  first = first->next();
2900  second = second->next();
2901  continue;
2902  }
2903 
2904  // argument list has different number of arguments
2905  else if (openParen == 1 && second->str() == ")" && first->str() != ")")
2906  break;
2907 
2908  // check for type * x == type x[]
2909  else if (Token::Match(first->next(), "* %name%| ,|)|=") &&
2910  Token::Match(second->next(), "%name%| [ ] ,|)")) {
2911  do {
2912  first = first->next();
2913  } while (!Token::Match(first->next(), ",|)"));
2914  do {
2915  second = second->next();
2916  } while (!Token::Match(second->next(), ",|)"));
2917  }
2918 
2919  // const after *
2920  else if (first->next()->str() == "*" && second->next()->str() == "*" &&
2921  ((first->strAt(2) != "const" && second->strAt(2) == "const") ||
2922  (first->strAt(2) == "const" && second->strAt(2) != "const"))) {
2923  if (first->strAt(2) != "const") {
2924  if (Token::Match(first->tokAt(2), "%name%| ,|)") && Token::Match(second->tokAt(3), "%name%| ,|)")) {
2925  first = first->tokAt(Token::Match(first->tokAt(2), "%name%") ? 2 : 1);
2926  second = second->tokAt(Token::Match(second->tokAt(3), "%name%") ? 3 : 2);
2927  } else {
2928  first = first->next();
2929  second = second->tokAt(2);
2930  }
2931  } else {
2932  if (Token::Match(second->tokAt(2), "%name%| ,|)") && Token::Match(first->tokAt(3), "%name%| ,|)")) {
2933  first = first->tokAt(Token::Match(first->tokAt(3), "%name%") ? 3 : 2);
2934  second = second->tokAt(Token::Match(second->tokAt(2), "%name%") ? 2 : 1);
2935  } else {
2936  first = first->tokAt(2);
2937  second = second->next();
2938  }
2939  }
2940  }
2941 
2942  // variable names are different
2943  else if ((Token::Match(first->next(), "%name% ,|)|=|[") &&
2944  Token::Match(second->next(), "%name% ,|)|[")) &&
2945  (first->next()->str() != second->next()->str())) {
2946  // skip variable names
2947  first = first->next();
2948  second = second->next();
2949 
2950  // skip default value assignment
2951  if (first->next()->str() == "=") {
2952  do {
2953  first = first->next();
2954  } while (!Token::Match(first->next(), ",|)"));
2955  }
2956  }
2957 
2958  // using namespace
2959  else if (usingNamespace(scope, first->next(), second->next(), offset))
2960  first = first->tokAt(offset);
2961 
2962  // same type with different qualification
2963  else if (typesMatch(scope, first->next(), nestedIn, second->next(), first, second))
2964  ;
2965 
2966  // variable with class path
2967  else if (arg_path_length && Token::Match(first->next(), "%name%") && first->strAt(1) != "const") {
2968  std::string param = path;
2969 
2970  if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
2971  // check for redundant qualification before skipping it
2972  if (!Token::simpleMatch(first->next(), param.c_str(), param.size())) {
2973  second = second->tokAt(arg_path_length);
2974  arg_path_length = 0;
2975  }
2976  }
2977 
2978  // nested or base class variable
2979  else if (arg_path_length <= 2 && Token::Match(first->next(), "%name%") &&
2980  (Token::Match(second->next(), "%name% :: %name%") ||
2981  (Token::Match(second->next(), "%name% <") &&
2982  Token::Match(second->linkAt(1), "> :: %name%"))) &&
2983  ((second->next()->str() == scope->className) ||
2984  (scope->nestedIn && second->next()->str() == scope->nestedIn->className) ||
2985  (scope->definedType && scope->definedType->isDerivedFrom(second->next()->str()))) &&
2986  (first->next()->str() == second->strAt(3))) {
2987  if (Token::Match(second->next(), "%name% <"))
2988  second = second->linkAt(1)->next();
2989  else
2990  second = second->tokAt(2);
2991  }
2992 
2993  // remove class name
2994  else if (arg_path_length > 2 && first->strAt(1) != second->strAt(1)) {
2995  std::string short_path = path;
2996  unsigned int short_path_length = arg_path_length;
2997 
2998  // remove last " :: "
2999  short_path.resize(short_path.size() - 4);
3000  short_path_length--;
3001 
3002  // remove last name
3003  std::string::size_type lastSpace = short_path.find_last_of(' ');
3004  if (lastSpace != std::string::npos) {
3005  short_path.resize(lastSpace+1);
3006  short_path_length--;
3007  if (short_path[short_path.size() - 1] == '>') {
3008  short_path.resize(short_path.size() - 3);
3009  while (short_path[short_path.size() - 1] == '<') {
3010  lastSpace = short_path.find_last_of(' ');
3011  short_path.resize(lastSpace+1);
3012  short_path_length--;
3013  }
3014  }
3015  }
3016 
3017  param = std::move(short_path);
3018  if (Token::simpleMatch(second->next(), param.c_str(), param.size())) {
3019  second = second->tokAt(int(short_path_length));
3020  arg_path_length = 0;
3021  }
3022  }
3023  }
3024 
3025  first = first->next();
3026  second = second->next();
3027 
3028  // reset path length
3029  if (first->str() == "," || second->str() == ",")
3030  arg_path_length = path_length;
3031  }
3032 
3033  return false;
3034 }
3035 
3036 static bool isUnknownType(const Token* start, const Token* end)
3037 {
3038  while (Token::Match(start, "const|volatile"))
3039  start = start->next();
3040  start = skipScopeIdentifiers(start);
3041  if (start->tokAt(1) == end && !start->type() && !start->isStandardType())
3042  return true;
3043  // TODO: Try to deduce the type of the expression
3044  if (Token::Match(start, "decltype|typeof"))
3045  return true;
3046  return false;
3047 }
3048 
3049 static const Token* getEnableIfReturnType(const Token* start)
3050 {
3051  if (!start)
3052  return nullptr;
3053  for (const Token* tok = start->next(); precedes(tok, start->link()); tok = tok->next()) {
3054  if (tok->link() && Token::Match(tok, "(|[|{|<")) {
3055  tok = tok->link();
3056  continue;
3057  }
3058  if (Token::simpleMatch(tok, ","))
3059  return tok->next();
3060  }
3061  return nullptr;
3062 }
3063 
3064 template<class Predicate>
3065 static bool checkReturns(const Function* function, bool unknown, bool emptyEnableIf, Predicate pred)
3066 {
3067  if (!function)
3068  return false;
3069  if (function->type != Function::eFunction && function->type != Function::eOperatorEqual)
3070  return false;
3071  const Token* defStart = function->retDef;
3072  if (!defStart)
3073  return unknown;
3074  const Token* defEnd = function->returnDefEnd();
3075  if (!defEnd)
3076  return unknown;
3077  if (defEnd == defStart)
3078  return unknown;
3079  if (pred(defStart, defEnd))
3080  return true;
3081  if (Token::Match(defEnd->tokAt(-1), "*|&|&&"))
3082  return false;
3083  // void STDCALL foo()
3084  while (defEnd->previous() != defStart && Token::Match(defEnd->tokAt(-2), "%name%|> %name%") &&
3085  !Token::Match(defEnd->tokAt(-2), "const|volatile"))
3086  defEnd = defEnd->previous();
3087  // enable_if
3088  const Token* enableIfEnd = nullptr;
3089  if (Token::simpleMatch(defEnd->previous(), ">"))
3090  enableIfEnd = defEnd->previous();
3091  else if (Token::simpleMatch(defEnd->tokAt(-3), "> :: type"))
3092  enableIfEnd = defEnd->tokAt(-3);
3093  if (enableIfEnd && enableIfEnd->link() &&
3094  Token::Match(enableIfEnd->link()->previous(), "enable_if|enable_if_t|EnableIf")) {
3095  if (const Token* start = getEnableIfReturnType(enableIfEnd->link())) {
3096  defStart = start;
3097  defEnd = enableIfEnd;
3098  } else {
3099  return emptyEnableIf;
3100  }
3101  }
3102  assert(defEnd != defStart);
3103  if (pred(defStart, defEnd))
3104  return true;
3105  if (isUnknownType(defStart, defEnd))
3106  return unknown;
3107  return false;
3108 }
3109 
3110 bool Function::returnsConst(const Function* function, bool unknown)
3111 {
3112  return checkReturns(function, unknown, false, [](const Token* defStart, const Token* defEnd) {
3113  return Token::findsimplematch(defStart, "const", defEnd);
3114  });
3115 }
3116 
3117 bool Function::returnsReference(const Function* function, bool unknown, bool includeRValueRef)
3118 {
3119  return checkReturns(function, unknown, false, [includeRValueRef](const Token* /*defStart*/, const Token* defEnd) {
3120  return includeRValueRef ? Token::Match(defEnd->previous(), "&|&&") : Token::simpleMatch(defEnd->previous(), "&");
3121  });
3122 }
3123 
3124 bool Function::returnsPointer(const Function* function, bool unknown)
3125 {
3126  return checkReturns(function, unknown, false, [](const Token* /*defStart*/, const Token* defEnd) {
3127  return Token::simpleMatch(defEnd->previous(), "*");
3128  });
3129 }
3130 
3131 bool Function::returnsStandardType(const Function* function, bool unknown)
3132 {
3133  return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) {
3134  return defEnd->previous() && defEnd->previous()->isStandardType();
3135  });
3136 }
3137 
3138 bool Function::returnsVoid(const Function* function, bool unknown)
3139 {
3140  return checkReturns(function, unknown, true, [](const Token* /*defStart*/, const Token* defEnd) {
3141  return Token::simpleMatch(defEnd->previous(), "void");
3142  });
3143 }
3144 
3145 std::vector<const Token*> Function::findReturns(const Function* f)
3146 {
3147  std::vector<const Token*> result;
3148  if (!f)
3149  return result;
3150  const Scope* scope = f->functionScope;
3151  if (!scope)
3152  return result;
3153  if (!scope->bodyStart)
3154  return result;
3155  for (const Token* tok = scope->bodyStart->next(); tok && tok != scope->bodyEnd; tok = tok->next()) {
3156  if (tok->str() == "{" && tok->scope() &&
3157  (tok->scope()->type == Scope::eLambda || tok->scope()->type == Scope::eClass)) {
3158  tok = tok->link();
3159  continue;
3160  }
3161  if (Token::simpleMatch(tok->astParent(), "return")) {
3162  result.push_back(tok);
3163  }
3164  // Skip lambda functions since the scope may not be set correctly
3165  const Token* lambdaEndToken = findLambdaEndToken(tok);
3166  if (lambdaEndToken) {
3167  tok = lambdaEndToken;
3168  }
3169  }
3170  return result;
3171 }
3172 
3174 {
3175  if (!isConstructor() || !arg)
3176  return nullptr;
3177  if (Token::simpleMatch(arg->link(), ") :"))
3178  return arg->link()->next();
3179  if (Token::simpleMatch(arg->link(), ") noexcept (") && arg->link()->linkAt(2)->strAt(1) == ":")
3180  return arg->link()->linkAt(2)->next();
3181  return nullptr;
3182 }
3183 
3184 bool Function::isSafe(const Settings &settings) const
3185 {
3186  if (settings.safeChecks.externalFunctions) {
3187  if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() != 0)
3188  return true;
3189  if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() != 0 || !isStatic()))
3190  return true;
3191  }
3192 
3193  if (settings.safeChecks.internalFunctions) {
3194  if (nestedIn->type == Scope::ScopeType::eNamespace && token->fileIndex() == 0)
3195  return true;
3196  if (nestedIn->type == Scope::ScopeType::eGlobal && (token->fileIndex() == 0 || isStatic()))
3197  return true;
3198  }
3199 
3200  if (settings.safeChecks.classes && access == AccessControl::Public && (nestedIn->type == Scope::ScopeType::eClass || nestedIn->type == Scope::ScopeType::eStruct))
3201  return true;
3202 
3203  return false;
3204 }
3205 
3206 Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
3207 {
3208  Function* function = nullptr;
3209  // Lambda functions are always unique
3210  if (tok->str() != "[") {
3211  auto range = scope->functionMap.equal_range(tok->str());
3212  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
3213  const Function *f = it->second;
3214  if (f->hasBody())
3215  continue;
3216  if (f->argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
3217  function = const_cast<Function *>(it->second);
3218  break;
3219  }
3220  }
3221  }
3222 
3223  if (!function)
3224  function = addGlobalFunctionDecl(scope, tok, argStart, funcStart);
3225 
3226  function->arg = argStart;
3227  function->token = funcStart;
3228  function->hasBody(true);
3229 
3230  addNewFunction(scope, tok);
3231 
3232  if (scope) {
3233  scope->function = function;
3234  function->functionScope = scope;
3235  return function;
3236  }
3237  return nullptr;
3238 }
3239 
3240 Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok, const Token *argStart, const Token* funcStart)
3241 {
3242  Function function(tok, scope, funcStart, argStart);
3243  scope->addFunction(std::move(function));
3244  return &scope->functionList.back();
3245 }
3246 
3247 void SymbolDatabase::addClassFunction(Scope *&scope, const Token *&tok, const Token *argStart)
3248 {
3249  const bool destructor(tok->previous()->str() == "~");
3250  const bool has_const(argStart->link()->strAt(1) == "const");
3251  const bool lval(argStart->link()->strAt(has_const ? 2 : 1) == "&");
3252  const bool rval(argStart->link()->strAt(has_const ? 2 : 1) == "&&");
3253  int count = 0;
3254  std::string path;
3255  unsigned int path_length = 0;
3256  const Token *tok1 = tok;
3257 
3258  if (destructor)
3259  tok1 = tok1->previous();
3260 
3261  // back up to head of path
3262  while (tok1 && tok1->previous() && tok1->previous()->str() == "::" && tok1->tokAt(-2) &&
3263  ((tok1->tokAt(-2)->isName() && !tok1->tokAt(-2)->isStandardType()) ||
3264  (tok1->strAt(-2) == ">" && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->previous(), "%name%")))) {
3265  count++;
3266  const Token * tok2 = tok1->tokAt(-2);
3267  if (tok2->str() == ">")
3268  tok2 = tok2->link()->previous();
3269 
3270  if (tok2) {
3271  do {
3272  path = tok1->previous()->str() + " " + path;
3273  tok1 = tok1->previous();
3274  path_length++;
3275  } while (tok1 != tok2);
3276  } else
3277  return; // syntax error ?
3278  }
3279 
3280  // syntax error?
3281  if (!tok1)
3282  return;
3283 
3284  // add global namespace if present
3285  if (tok1->strAt(-1) == "::") {
3286  path_length++;
3287  path.insert(0, ":: ");
3288  }
3289 
3290  // search for match
3291  for (std::list<Scope>::iterator it1 = scopeList.begin(); it1 != scopeList.end(); ++it1) {
3292  Scope *scope1 = &(*it1);
3293 
3294  bool match = false;
3295 
3296  // check in namespace if using found
3297  if (scope == scope1 && !scope1->usingList.empty()) {
3298  std::vector<Scope::UsingInfo>::const_iterator it2;
3299  for (it2 = scope1->usingList.cbegin(); it2 != scope1->usingList.cend(); ++it2) {
3300  if (it2->scope) {
3301  Function * func = findFunctionInScope(tok1, it2->scope, path, path_length);
3302  if (func) {
3303  if (!func->hasBody()) {
3304  const Token *closeParen = tok->next()->link();
3305  if (closeParen) {
3306  const Token *eq = Tokenizer::isFunctionHead(closeParen, ";");
3307  if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
3308  func->isDefault(true);
3309  return;
3310  }
3311  }
3312  func->hasBody(true);
3313  func->token = tok;
3314  func->arg = argStart;
3315  addNewFunction(scope, tok);
3316  if (scope) {
3317  scope->functionOf = func->nestedIn;
3318  scope->function = func;
3319  scope->function->functionScope = scope;
3320  }
3321  return;
3322  }
3323  }
3324  }
3325  }
3326  }
3327 
3328  const bool isAnonymousNamespace = (scope1->type == Scope::eNamespace && scope1->className.empty());
3329  if ((scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) || isAnonymousNamespace) {
3330  // do the scopes match (same scope) or do their names match (multiple namespaces)
3331  if ((scope == scope1->nestedIn) || (scope &&
3332  scope->className == scope1->nestedIn->className &&
3333  !scope->className.empty() &&
3334  scope->type == scope1->nestedIn->type)) {
3335 
3336  // nested scopes => check that they match
3337  {
3338  const Scope *s1 = scope;
3339  const Scope *s2 = scope1->nestedIn;
3340  while (s1 && s2) {
3341  if (s1->className != s2->className)
3342  break;
3343  s1 = s1->nestedIn;
3344  s2 = s2->nestedIn;
3345  }
3346  // Not matching scopes
3347  if (s1 || s2)
3348  continue;
3349  }
3350 
3351  Scope *scope2 = scope1;
3352 
3353  while (scope2 && count > 1) {
3354  count--;
3355  if (tok1->strAt(1) == "<")
3356  tok1 = tok1->linkAt(1)->tokAt(2);
3357  else
3358  tok1 = tok1->tokAt(2);
3359  scope2 = scope2->findRecordInNestedList(tok1->str());
3360  }
3361  if (scope2 && isAnonymousNamespace)
3362  scope2 = scope2->findRecordInNestedList(tok1->str());
3363 
3364  if (count == 1 && scope2) {
3365  match = true;
3366  scope1 = scope2;
3367  }
3368  }
3369  }
3370 
3371  if (match) {
3372  auto range = scope1->functionMap.equal_range(tok->str());
3373  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
3374  auto * func = const_cast<Function *>(it->second);
3375  if (!func->hasBody()) {
3376  if (func->argsMatch(scope1, func->argDef, tok->next(), path, path_length)) {
3377  const Token *closeParen = tok->next()->link();
3378  if (closeParen) {
3379  const Token *eq = Tokenizer::isFunctionHead(closeParen, ";");
3380  if (eq && Token::simpleMatch(eq->tokAt(-2), "= default ;")) {
3381  func->isDefault(true);
3382  return;
3383  }
3384  if (func->type == Function::eDestructor && destructor) {
3385  func->hasBody(true);
3386  } else if (func->type != Function::eDestructor && !destructor) {
3387  // normal function?
3388  const bool hasConstKeyword = closeParen->next()->str() == "const";
3389  if ((func->isConst() == hasConstKeyword) &&
3390  (func->hasLvalRefQualifier() == lval) &&
3391  (func->hasRvalRefQualifier() == rval)) {
3392  func->hasBody(true);
3393  }
3394  }
3395  }
3396 
3397  if (func->hasBody()) {
3398  func->token = tok;
3399  func->arg = argStart;
3400  addNewFunction(scope, tok);
3401  if (scope) {
3402  scope->functionOf = scope1;
3403  scope->function = func;
3404  scope->function->functionScope = scope;
3405  }
3406  return;
3407  }
3408  }
3409  }
3410  }
3411  }
3412  }
3413 
3414  // class function of unknown class
3415  addNewFunction(scope, tok);
3416 }
3417 
3418 void SymbolDatabase::addNewFunction(Scope *&scope, const Token *&tok)
3419 {
3420  const Token *tok1 = tok;
3421  scopeList.emplace_back(this, tok1, scope);
3422  Scope *newScope = &scopeList.back();
3423 
3424  // find start of function '{'
3425  bool foundInitList = false;
3426  while (tok1 && tok1->str() != "{" && tok1->str() != ";") {
3427  if (tok1->link() && Token::Match(tok1, "(|[|<")) {
3428  tok1 = tok1->link();
3429  } else if (foundInitList && Token::Match(tok1, "%name%|> {") && Token::Match(tok1->linkAt(1), "} ,|{")) {
3430  tok1 = tok1->linkAt(1);
3431  } else {
3432  if (tok1->str() == ":")
3433  foundInitList = true;
3434  tok1 = tok1->next();
3435  }
3436  }
3437 
3438  if (tok1 && tok1->str() == "{") {
3439  newScope->setBodyStartEnd(tok1);
3440 
3441  // syntax error?
3442  if (!newScope->bodyEnd) {
3443  mTokenizer.unmatchedToken(tok1);
3444  } else {
3445  scope->nestedList.push_back(newScope);
3446  scope = newScope;
3447  }
3448  } else if (tok1 && Token::Match(tok1->tokAt(-2), "= default|delete ;")) {
3449  scopeList.pop_back();
3450  } else {
3451  throw InternalError(tok, "Analysis failed (function not recognized). If the code is valid then please report this failure.");
3452  }
3453  tok = tok1;
3454 }
3455 
3456 bool Type::isClassType() const
3457 {
3458  return classScope && classScope->type == Scope::ScopeType::eClass;
3459 }
3460 
3461 bool Type::isEnumType() const
3462 {
3463  //We explicitly check for "enum" because a forward declared enum doesn't get its own scope
3464  return (classDef && classDef->str() == "enum") ||
3465  (classScope && classScope->type == Scope::ScopeType::eEnum);
3466 }
3467 
3469 {
3470  return classScope && classScope->type == Scope::ScopeType::eStruct;
3471 }
3472 
3473 bool Type::isUnionType() const
3474 {
3475  return classScope && classScope->type == Scope::ScopeType::eUnion;
3476 }
3477 
3478 const Token *Type::initBaseInfo(const Token *tok, const Token *tok1)
3479 {
3480  // goto initial '{'
3481  const Token *tok2 = tok1;
3482  while (tok2 && tok2->str() != "{") {
3483  // skip unsupported templates
3484  if (tok2->str() == "<")
3485  tok2 = tok2->link();
3486 
3487  // check for base classes
3488  else if (Token::Match(tok2, ":|,")) {
3489  tok2 = tok2->next();
3490 
3491  // check for invalid code
3492  if (!tok2 || !tok2->next())
3493  return nullptr;
3494 
3495  Type::BaseInfo base;
3496 
3497  if (tok2->str() == "virtual") {
3498  base.isVirtual = true;
3499  tok2 = tok2->next();
3500  }
3501 
3502  if (tok2->str() == "public") {
3504  tok2 = tok2->next();
3505  } else if (tok2->str() == "protected") {
3507  tok2 = tok2->next();
3508  } else if (tok2->str() == "private") {
3510  tok2 = tok2->next();
3511  } else {
3512  if (tok->str() == "class")
3514  else if (tok->str() == "struct")
3516  }
3517  if (!tok2)
3518  return nullptr;
3519  if (tok2->str() == "virtual") {
3520  base.isVirtual = true;
3521  tok2 = tok2->next();
3522  }
3523  if (!tok2)
3524  return nullptr;
3525 
3526  base.nameTok = tok2;
3527  // handle global namespace
3528  if (tok2->str() == "::") {
3529  tok2 = tok2->next();
3530  }
3531 
3532  // handle derived base classes
3533  while (Token::Match(tok2, "%name% ::")) {
3534  tok2 = tok2->tokAt(2);
3535  }
3536  if (!tok2)
3537  return nullptr;
3538 
3539  base.name = tok2->str();
3540 
3541  tok2 = tok2->next();
3542  // add unhandled templates
3543  if (tok2 && tok2->link() && tok2->str() == "<") {
3544  for (const Token* const end = tok2->link()->next(); tok2 != end; tok2 = tok2->next()) {
3545  base.name += tok2->str();
3546  }
3547  }
3548 
3549  const Type * baseType = classScope->check->findType(base.nameTok, enclosingScope);
3550  if (baseType && !baseType->findDependency(this))
3551  base.type = baseType;
3552 
3553  // save pattern for base class name
3554  derivedFrom.push_back(std::move(base));
3555  } else
3556  tok2 = tok2->next();
3557  }
3558 
3559  return tok2;
3560 }
3561 
3562 std::string Type::name() const
3563 {
3564  const Token* start = classDef->next();
3566  start = start->tokAt(1);
3567  else if (start->str() == "class")
3568  start = start->tokAt(1);
3569  else if (!start->isName())
3570  return emptyString;
3571  const Token* next = start;
3572  while (Token::Match(next, "::|<|>|(|)|[|]|*|&|&&|%name%")) {
3573  if (Token::Match(next, "<|(|[") && next->link())
3574  next = next->link();
3575  next = next->next();
3576  }
3577  std::string result;
3578  for (const Token* tok = start; tok != next; tok = tok->next()) {
3579  if (!result.empty())
3580  result += ' ';
3581  result += tok->str();
3582  }
3583  return result;
3584 }
3585 
3586 void SymbolDatabase::debugMessage(const Token *tok, const std::string &type, const std::string &msg) const
3587 {
3588  if (tok && mSettings.debugwarnings) {
3589  const std::list<const Token*> locationList(1, tok);
3590  const ErrorMessage errmsg(locationList, &mTokenizer.list,
3592  type,
3593  msg,
3595  mErrorLogger.reportErr(errmsg);
3596  }
3597 }
3598 
3600 {
3602  const std::list<const Token*> locationList(1, tok);
3603  const ErrorMessage errmsg(locationList, &mTokenizer.list,
3605  "returnImplicitInt",
3606  "Omitted return type of function '" + tok->str() + "' defaults to int, this is not supported by ISO C99 and later standards.",
3608  mErrorLogger.reportErr(errmsg);
3609  }
3610 }
3611 
3612 const Function* Type::getFunction(const std::string& funcName) const
3613 {
3614  if (classScope) {
3615  const std::multimap<std::string, const Function *>::const_iterator it = classScope->functionMap.find(funcName);
3616 
3617  if (it != classScope->functionMap.end())
3618  return it->second;
3619  }
3620 
3621  for (const Type::BaseInfo & i : derivedFrom) {
3622  if (i.type) {
3623  const Function* const func = i.type->getFunction(funcName);
3624  if (func)
3625  return func;
3626  }
3627  }
3628  return nullptr;
3629 }
3630 
3631 bool Type::hasCircularDependencies(std::set<BaseInfo>* ancestors) const
3632 {
3633  std::set<BaseInfo> knownAncestors;
3634  if (!ancestors) {
3635  ancestors=&knownAncestors;
3636  }
3637  for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.cbegin(); parent!=derivedFrom.cend(); ++parent) {
3638  if (!parent->type)
3639  continue;
3640  if (this==parent->type)
3641  return true;
3642  if (ancestors->find(*parent)!=ancestors->end())
3643  return true;
3644 
3645  ancestors->insert(*parent);
3646  if (parent->type->hasCircularDependencies(ancestors))
3647  return true;
3648  }
3649  return false;
3650 }
3651 
3652 bool Type::findDependency(const Type* ancestor) const
3653 {
3654  return this == ancestor || std::any_of(derivedFrom.cbegin(), derivedFrom.cend(), [&](const BaseInfo& d) {
3655  return d.type && (d.type == this || d.type->findDependency(ancestor));
3656  });
3657 }
3658 
3659 bool Type::isDerivedFrom(const std::string & ancestor) const
3660 {
3661  for (std::vector<BaseInfo>::const_iterator parent=derivedFrom.cbegin(); parent!=derivedFrom.cend(); ++parent) {
3662  if (parent->name == ancestor)
3663  return true;
3664  if (parent->type && parent->type->isDerivedFrom(ancestor))
3665  return true;
3666  }
3667  return false;
3668 }
3669 
3670 bool Variable::arrayDimensions(const Settings& settings, bool& isContainer)
3671 {
3672  isContainer = false;
3673  const Library::Container* container = (mTypeStartToken && mTypeStartToken->isCpp()) ? settings.library.detectContainer(mTypeStartToken) : nullptr;
3674  if (container && container->arrayLike_indexOp && container->size_templateArgNo > 0) {
3675  const Token* tok = Token::findsimplematch(mTypeStartToken, "<");
3676  if (tok) {
3677  isContainer = true;
3678  Dimension dimension_;
3679  tok = tok->next();
3680  for (int i = 0; i < container->size_templateArgNo && tok; i++) {
3681  tok = tok->nextTemplateArgument();
3682  }
3683  if (Token::Match(tok, "%num% [,>]")) {
3684  dimension_.tok = tok;
3685  dimension_.known = true;
3686  dimension_.num = MathLib::toBigNumber(tok->str());
3687  } else if (tok) {
3688  dimension_.tok = tok;
3689  dimension_.known = false;
3690  }
3691  mDimensions.push_back(dimension_);
3692  return true;
3693  }
3694  }
3695 
3696  const Token *dim = mNameToken;
3697  if (!dim) {
3698  // Argument without name
3699  dim = mTypeEndToken;
3700  // back up to start of array dimensions
3701  while (dim && dim->str() == "]")
3702  dim = dim->link()->previous();
3703  }
3704  if (dim)
3705  dim = dim->next();
3706  if (dim && dim->str() == ")")
3707  dim = dim->next();
3708 
3709  bool arr = false;
3710  while (dim && dim->next() && dim->str() == "[") {
3711  Dimension dimension_;
3712  dimension_.known = false;
3713  // check for empty array dimension []
3714  if (dim->next()->str() != "]") {
3715  dimension_.tok = dim->astOperand2();
3716  ValueFlow::valueFlowConstantFoldAST(const_cast<Token *>(dimension_.tok), settings);
3717  if (dimension_.tok && dimension_.tok->hasKnownIntValue()) {
3718  dimension_.num = dimension_.tok->getKnownIntValue();
3719  dimension_.known = true;
3720  }
3721  }
3722  mDimensions.push_back(dimension_);
3723  dim = dim->link()->next();
3724  arr = true;
3725  }
3726  return arr;
3727 }
3728 
3729 static std::string scopeTypeToString(Scope::ScopeType type)
3730 {
3731  switch (type) {
3732  case Scope::ScopeType::eGlobal:
3733  return "Global";
3734  case Scope::ScopeType::eClass:
3735  return "Class";
3736  case Scope::ScopeType::eStruct:
3737  return "Struct";
3738  case Scope::ScopeType::eUnion:
3739  return "Union";
3740  case Scope::ScopeType::eNamespace:
3741  return "Namespace";
3742  case Scope::ScopeType::eFunction:
3743  return "Function";
3744  case Scope::ScopeType::eIf:
3745  return "If";
3746  case Scope::ScopeType::eElse:
3747  return "Else";
3748  case Scope::ScopeType::eFor:
3749  return "For";
3750  case Scope::ScopeType::eWhile:
3751  return "While";
3752  case Scope::ScopeType::eDo:
3753  return "Do";
3754  case Scope::ScopeType::eSwitch:
3755  return "Switch";
3756  case Scope::ScopeType::eTry:
3757  return "Try";
3758  case Scope::ScopeType::eCatch:
3759  return "Catch";
3760  case Scope::ScopeType::eUnconditional:
3761  return "Unconditional";
3762  case Scope::ScopeType::eLambda:
3763  return "Lambda";
3764  case Scope::ScopeType::eEnum:
3765  return "Enum";
3766  }
3767  return "Unknown";
3768 }
3769 
3770 static std::ostream & operator << (std::ostream & s, Scope::ScopeType type)
3771 {
3772  s << scopeTypeToString(type);
3773  return s;
3774 }
3775 
3776 static std::string accessControlToString(AccessControl access)
3777 {
3778  switch (access) {
3779  case AccessControl::Public:
3780  return "Public";
3782  return "Protected";
3784  return "Private";
3785  case AccessControl::Global:
3786  return "Global";
3788  return "Namespace";
3790  return "Argument";
3791  case AccessControl::Local:
3792  return "Local";
3793  case AccessControl::Throw:
3794  return "Throw";
3795  }
3796  return "Unknown";
3797 }
3798 
3799 static const char* functionTypeToString(Function::Type type)
3800 {
3801  switch (type) {
3803  return "Constructor";
3805  return "CopyConstructor";
3807  return "MoveConstructor";
3809  return "OperatorEqual";
3810  case Function::eDestructor:
3811  return "Destructor";
3812  case Function::eFunction:
3813  return "Function";
3814  case Function::eLambda:
3815  return "Lambda";
3816  default:
3817  return "Unknown";
3818  }
3819 }
3820 
3821 static std::string tokenToString(const Token* tok, const Tokenizer& tokenizer)
3822 {
3823  std::ostringstream oss;
3824  if (tok) {
3825  oss << tok->str() << " ";
3826  oss << tokenizer.list.fileLine(tok) << " ";
3827  }
3828  oss << tok;
3829  return oss.str();
3830 }
3831 
3832 static std::string scopeToString(const Scope* scope, const Tokenizer& tokenizer)
3833 {
3834  std::ostringstream oss;
3835  if (scope) {
3836  oss << scope->type << " ";
3837  if (!scope->className.empty())
3838  oss << scope->className << " ";
3839  if (scope->classDef)
3840  oss << tokenizer.list.fileLine(scope->classDef) << " ";
3841  }
3842  oss << scope;
3843  return oss.str();
3844 }
3845 
3846 static std::string tokenType(const Token * tok)
3847 {
3848  std::ostringstream oss;
3849  if (tok) {
3850  if (tok->isUnsigned())
3851  oss << "unsigned ";
3852  else if (tok->isSigned())
3853  oss << "signed ";
3854  if (tok->isComplex())
3855  oss << "_Complex ";
3856  if (tok->isLong())
3857  oss << "long ";
3858  oss << tok->str();
3859  }
3860  return oss.str();
3861 }
3862 
3863 void SymbolDatabase::printVariable(const Variable *var, const char *indent) const
3864 {
3865  std::cout << indent << "mNameToken: " << tokenToString(var->nameToken(), mTokenizer) << std::endl;
3866  if (var->nameToken()) {
3867  std::cout << indent << " declarationId: " << var->declarationId() << std::endl;
3868  }
3869  std::cout << indent << "mTypeStartToken: " << tokenToString(var->typeStartToken(), mTokenizer) << std::endl;
3870  std::cout << indent << "mTypeEndToken: " << tokenToString(var->typeEndToken(), mTokenizer) << std::endl;
3871 
3872  if (var->typeStartToken()) {
3873  const Token * autoTok = nullptr;
3874  std::cout << indent << " ";
3875  for (const Token * tok = var->typeStartToken(); tok != var->typeEndToken()->next(); tok = tok->next()) {
3876  std::cout << " " << tokenType(tok);
3877  if (tok->str() == "auto")
3878  autoTok = tok;
3879  }
3880  std::cout << std::endl;
3881  if (autoTok) {
3882  const ValueType * valueType = autoTok->valueType();
3883  std::cout << indent << " auto valueType: " << valueType << std::endl;
3884  if (var->typeStartToken()->valueType()) {
3885  std::cout << indent << " " << valueType->str() << std::endl;
3886  }
3887  }
3888  } else if (var->valueType()) {
3889  std::cout << indent << " " << var->valueType()->str() << std::endl;
3890  }
3891  std::cout << indent << "mIndex: " << var->index() << std::endl;
3892  std::cout << indent << "mAccess: " << accessControlToString(var->accessControl()) << std::endl;
3893  std::cout << indent << "mFlags: " << std::endl;
3894  std::cout << indent << " isMutable: " << var->isMutable() << std::endl;
3895  std::cout << indent << " isStatic: " << var->isStatic() << std::endl;
3896  std::cout << indent << " isExtern: " << var->isExtern() << std::endl;
3897  std::cout << indent << " isLocal: " << var->isLocal() << std::endl;
3898  std::cout << indent << " isConst: " << var->isConst() << std::endl;
3899  std::cout << indent << " isClass: " << var->isClass() << std::endl;
3900  std::cout << indent << " isArray: " << var->isArray() << std::endl;
3901  std::cout << indent << " isPointer: " << var->isPointer() << std::endl;
3902  std::cout << indent << " isReference: " << var->isReference() << std::endl;
3903  std::cout << indent << " isRValueRef: " << var->isRValueReference() << std::endl;
3904  std::cout << indent << " hasDefault: " << var->hasDefault() << std::endl;
3905  std::cout << indent << " isStlType: " << var->isStlType() << std::endl;
3906  std::cout << indent << "mType: ";
3907  if (var->type()) {
3908  std::cout << var->type()->type() << " " << var->type()->name();
3909  std::cout << " " << mTokenizer.list.fileLine(var->type()->classDef);
3910  std::cout << " " << var->type() << std::endl;
3911  } else
3912  std::cout << "none" << std::endl;
3913 
3914  if (var->nameToken()) {
3915  const ValueType * valueType = var->nameToken()->valueType();
3916  std::cout << indent << "valueType: " << valueType << std::endl;
3917  if (valueType) {
3918  std::cout << indent << " " << valueType->str() << std::endl;
3919  }
3920  }
3921 
3922  std::cout << indent << "mScope: " << scopeToString(var->scope(), mTokenizer) << std::endl;
3923 
3924  std::cout << indent << "mDimensions:";
3925  for (std::size_t i = 0; i < var->dimensions().size(); i++) {
3926  std::cout << " " << var->dimension(i);
3927  if (!var->dimensions()[i].known)
3928  std::cout << "?";
3929  }
3930  std::cout << std::endl;
3931 }
3932 
3933 void SymbolDatabase::printOut(const char *title) const
3934 {
3935  std::cout << std::setiosflags(std::ios::boolalpha);
3936  if (title)
3937  std::cout << "\n### " << title << " ###\n";
3938 
3939  for (std::list<Scope>::const_iterator scope = scopeList.cbegin(); scope != scopeList.cend(); ++scope) {
3940  std::cout << "Scope: " << &*scope << " " << scope->type << std::endl;
3941  std::cout << " className: " << scope->className << std::endl;
3942  std::cout << " classDef: " << tokenToString(scope->classDef, mTokenizer) << std::endl;
3943  std::cout << " bodyStart: " << tokenToString(scope->bodyStart, mTokenizer) << std::endl;
3944  std::cout << " bodyEnd: " << tokenToString(scope->bodyEnd, mTokenizer) << std::endl;
3945 
3946  // find the function body if not implemented inline
3947  for (auto func = scope->functionList.cbegin(); func != scope->functionList.cend(); ++func) {
3948  std::cout << " Function: " << &*func << std::endl;
3949  std::cout << " name: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
3950  std::cout << " type: " << functionTypeToString(func->type) << std::endl;
3951  std::cout << " access: " << accessControlToString(func->access) << std::endl;
3952  std::cout << " hasBody: " << func->hasBody() << std::endl;
3953  std::cout << " isInline: " << func->isInline() << std::endl;
3954  std::cout << " isConst: " << func->isConst() << std::endl;
3955  std::cout << " hasVirtualSpecifier: " << func->hasVirtualSpecifier() << std::endl;
3956  std::cout << " isPure: " << func->isPure() << std::endl;
3957  std::cout << " isStatic: " << func->isStatic() << std::endl;
3958  std::cout << " isStaticLocal: " << func->isStaticLocal() << std::endl;
3959  std::cout << " isExtern: " << func->isExtern() << std::endl;
3960  std::cout << " isFriend: " << func->isFriend() << std::endl;
3961  std::cout << " isExplicit: " << func->isExplicit() << std::endl;
3962  std::cout << " isDefault: " << func->isDefault() << std::endl;
3963  std::cout << " isDelete: " << func->isDelete() << std::endl;
3964  std::cout << " hasOverrideSpecifier: " << func->hasOverrideSpecifier() << std::endl;
3965  std::cout << " hasFinalSpecifier: " << func->hasFinalSpecifier() << std::endl;
3966  std::cout << " isNoExcept: " << func->isNoExcept() << std::endl;
3967  std::cout << " isThrow: " << func->isThrow() << std::endl;
3968  std::cout << " isOperator: " << func->isOperator() << std::endl;
3969  std::cout << " hasLvalRefQual: " << func->hasLvalRefQualifier() << std::endl;
3970  std::cout << " hasRvalRefQual: " << func->hasRvalRefQualifier() << std::endl;
3971  std::cout << " isVariadic: " << func->isVariadic() << std::endl;
3972  std::cout << " isVolatile: " << func->isVolatile() << std::endl;
3973  std::cout << " hasTrailingReturnType: " << func->hasTrailingReturnType() << std::endl;
3974  std::cout << " attributes:";
3975  if (func->isAttributeConst())
3976  std::cout << " const ";
3977  if (func->isAttributePure())
3978  std::cout << " pure ";
3979  if (func->isAttributeNoreturn())
3980  std::cout << " noreturn ";
3981  if (func->isAttributeNothrow())
3982  std::cout << " nothrow ";
3983  if (func->isAttributeConstructor())
3984  std::cout << " constructor ";
3985  if (func->isAttributeDestructor())
3986  std::cout << " destructor ";
3987  if (func->isAttributeNodiscard())
3988  std::cout << " nodiscard ";
3989  std::cout << std::endl;
3990  std::cout << " noexceptArg: " << (func->noexceptArg ? func->noexceptArg->str() : "none") << std::endl;
3991  std::cout << " throwArg: " << (func->throwArg ? func->throwArg->str() : "none") << std::endl;
3992  std::cout << " tokenDef: " << tokenToString(func->tokenDef, mTokenizer) << std::endl;
3993  std::cout << " argDef: " << tokenToString(func->argDef, mTokenizer) << std::endl;
3994  if (!func->isConstructor() && !func->isDestructor())
3995  std::cout << " retDef: " << tokenToString(func->retDef, mTokenizer) << std::endl;
3996  if (func->retDef) {
3997  std::cout << " ";
3998  for (const Token * tok = func->retDef; tok && tok != func->tokenDef && !Token::Match(tok, "{|;|override|final"); tok = tok->next())
3999  std::cout << " " << tokenType(tok);
4000  std::cout << std::endl;
4001  }
4002  std::cout << " retType: " << func->retType << std::endl;
4003 
4004  if (const ValueType* valueType = func->tokenDef->next()->valueType()) {
4005  std::cout << " valueType: " << valueType << std::endl;
4006  std::cout << " " << valueType->str() << std::endl;
4007  }
4008 
4009  if (func->hasBody()) {
4010  std::cout << " token: " << tokenToString(func->token, mTokenizer) << std::endl;
4011  std::cout << " arg: " << tokenToString(func->arg, mTokenizer) << std::endl;
4012  }
4013  std::cout << " nestedIn: " << scopeToString(func->nestedIn, mTokenizer) << std::endl;
4014  std::cout << " functionScope: " << scopeToString(func->functionScope, mTokenizer) << std::endl;
4015 
4016  for (auto var = func->argumentList.cbegin(); var != func->argumentList.cend(); ++var) {
4017  std::cout << " Variable: " << &*var << std::endl;
4018  printVariable(&*var, " ");
4019  }
4020  }
4021 
4022  for (auto var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var) {
4023  std::cout << " Variable: " << &*var << std::endl;
4024  printVariable(&*var, " ");
4025  }
4026 
4027  if (scope->type == Scope::eEnum) {
4028  std::cout << " enumType: ";
4029  if (scope->enumType) {
4030  std::cout << scope->enumType->stringify(false, true, false);
4031  } else
4032  std::cout << "int";
4033  std::cout << std::endl;
4034  std::cout << " enumClass: " << scope->enumClass << std::endl;
4035  for (const Enumerator &enumerator : scope->enumeratorList) {
4036  std::cout << " Enumerator: " << enumerator.name->str() << " = ";
4037  if (enumerator.value_known)
4038  std::cout << enumerator.value;
4039 
4040  if (enumerator.start) {
4041  const Token * tok = enumerator.start;
4042  std::cout << (enumerator.value_known ? " " : "") << "[" << tok->str();
4043  while (tok && tok != enumerator.end) {
4044  if (tok->next())
4045  std::cout << " " << tok->next()->str();
4046  tok = tok->next();
4047  }
4048 
4049  std::cout << "]";
4050  }
4051 
4052  std::cout << std::endl;
4053  }
4054  }
4055 
4056  std::cout << " nestedIn: " << scope->nestedIn;
4057  if (scope->nestedIn) {
4058  std::cout << " " << scope->nestedIn->type << " "
4059  << scope->nestedIn->className;
4060  }
4061  std::cout << std::endl;
4062 
4063  std::cout << " definedType: " << scope->definedType << std::endl;
4064 
4065  std::cout << " nestedList[" << scope->nestedList.size() << "] = (";
4066 
4067  std::size_t count = scope->nestedList.size();
4068  for (std::vector<Scope*>::const_iterator nsi = scope->nestedList.cbegin(); nsi != scope->nestedList.cend(); ++nsi) {
4069  std::cout << " " << (*nsi) << " " << (*nsi)->type << " " << (*nsi)->className;
4070  if (count-- > 1)
4071  std::cout << ",";
4072  }
4073 
4074  std::cout << " )" << std::endl;
4075 
4076  for (auto use = scope->usingList.cbegin(); use != scope->usingList.cend(); ++use) {
4077  std::cout << " using: " << use->scope << " " << use->start->strAt(2);
4078  const Token *tok1 = use->start->tokAt(3);
4079  while (tok1 && tok1->str() == "::") {
4080  std::cout << "::" << tok1->strAt(1);
4081  tok1 = tok1->tokAt(2);
4082  }
4083  std::cout << " " << mTokenizer.list.fileLine(use->start) << std::endl;
4084  }
4085 
4086  std::cout << " functionOf: " << scopeToString(scope->functionOf, mTokenizer) << std::endl;
4087 
4088  std::cout << " function: " << scope->function;
4089  if (scope->function)
4090  std::cout << " " << scope->function->name();
4091  std::cout << std::endl;
4092  }
4093 
4094  for (std::list<Type>::const_iterator type = typeList.cbegin(); type != typeList.cend(); ++type) {
4095  std::cout << "Type: " << &(*type) << std::endl;
4096  std::cout << " name: " << type->name() << std::endl;
4097  std::cout << " classDef: " << tokenToString(type->classDef, mTokenizer) << std::endl;
4098  std::cout << " classScope: " << type->classScope << std::endl;
4099  std::cout << " enclosingScope: " << type->enclosingScope;
4100  if (type->enclosingScope) {
4101  std::cout << " " << type->enclosingScope->type << " "
4102  << type->enclosingScope->className;
4103  }
4104  std::cout << std::endl;
4105  std::cout << " needInitialization: " << (type->needInitialization == Type::NeedInitialization::Unknown ? "Unknown" :
4106  type->needInitialization == Type::NeedInitialization::True ? "True" :
4107  type->needInitialization == Type::NeedInitialization::False ? "False" :
4108  "Invalid") << std::endl;
4109 
4110  std::cout << " derivedFrom[" << type->derivedFrom.size() << "] = (";
4111  std::size_t count = type->derivedFrom.size();
4112  for (const Type::BaseInfo & i : type->derivedFrom) {
4113  if (i.isVirtual)
4114  std::cout << "Virtual ";
4115 
4116  std::cout << (i.access == AccessControl::Public ? " Public" :
4117  i.access == AccessControl::Protected ? " Protected" :
4118  i.access == AccessControl::Private ? " Private" :
4119  " Unknown");
4120 
4121  if (i.type)
4122  std::cout << " " << i.type;
4123  else
4124  std::cout << " Unknown";
4125 
4126  std::cout << " " << i.name;
4127  if (count-- > 1)
4128  std::cout << ",";
4129  }
4130 
4131  std::cout << " )" << std::endl;
4132 
4133  std::cout << " friendList[" << type->friendList.size() << "] = (";
4134  for (size_t i = 0; i < type->friendList.size(); i++) {
4135  if (type->friendList[i].type)
4136  std::cout << type->friendList[i].type;
4137  else
4138  std::cout << " Unknown";
4139 
4140  std::cout << ' ';
4141  if (type->friendList[i].nameEnd)
4142  std::cout << type->friendList[i].nameEnd->str();
4143  if (i+1 < type->friendList.size())
4144  std::cout << ',';
4145  }
4146 
4147  std::cout << " )" << std::endl;
4148  }
4149 
4150  for (std::size_t i = 1; i < mVariableList.size(); i++) {
4151  std::cout << "mVariableList[" << i << "]: " << mVariableList[i];
4152  if (mVariableList[i]) {
4153  std::cout << " " << mVariableList[i]->name() << " "
4154  << mTokenizer.list.fileLine(mVariableList[i]->nameToken());
4155  }
4156  std::cout << std::endl;
4157  }
4158  std::cout << std::resetiosflags(std::ios::boolalpha);
4159 }
4160 
4161 void SymbolDatabase::printXml(std::ostream &out) const
4162 {
4163  std::string outs;
4164 
4165  std::set<const Variable *> variables;
4166 
4167  // Scopes..
4168  outs += " <scopes>\n";
4169  for (std::list<Scope>::const_iterator scope = scopeList.cbegin(); scope != scopeList.cend(); ++scope) {
4170  outs += " <scope";
4171  outs += " id=\"";
4172  outs += id_string(&*scope);
4173  outs += "\"";
4174  outs += " type=\"";
4175  outs += scopeTypeToString(scope->type);
4176  outs += "\"";
4177  if (!scope->className.empty()) {
4178  outs += " className=\"";
4179  outs += ErrorLogger::toxml(scope->className);
4180  outs += "\"";
4181  }
4182  if (scope->bodyStart) {
4183  outs += " bodyStart=\"";
4184  outs += id_string(scope->bodyStart);
4185  outs += '\"';
4186  }
4187  if (scope->bodyEnd) {
4188  outs += " bodyEnd=\"";
4189  outs += id_string(scope->bodyEnd);
4190  outs += '\"';
4191  }
4192  if (scope->nestedIn) {
4193  outs += " nestedIn=\"";
4194  outs += id_string(scope->nestedIn);
4195  outs += "\"";
4196  }
4197  if (scope->function) {
4198  outs += " function=\"";
4199  outs += id_string(scope->function);
4200  outs += "\"";
4201  }
4202  if (scope->definedType) {
4203  outs += " definedType=\"";
4204  outs += id_string(scope->definedType);
4205  outs += "\"";
4206  }
4207  if (scope->functionList.empty() && scope->varlist.empty())
4208  outs += "/>\n";
4209  else {
4210  outs += ">\n";
4211  if (!scope->functionList.empty()) {
4212  outs += " <functionList>\n";
4213  for (std::list<Function>::const_iterator function = scope->functionList.cbegin(); function != scope->functionList.cend(); ++function) {
4214  outs += " <function id=\"";
4215  outs += id_string(&*function);
4216  outs += "\" token=\"";
4217  outs += id_string(function->token);
4218  outs += "\" tokenDef=\"";
4219  outs += id_string(function->tokenDef);
4220  outs += "\" name=\"";
4221  outs += ErrorLogger::toxml(function->name());
4222  outs += '\"';
4223  outs += " type=\"";
4224  outs += functionTypeToString(function->type);
4225  outs += '\"';
4226  if (function->nestedIn->definedType) {
4227  if (function->hasVirtualSpecifier())
4228  outs += " hasVirtualSpecifier=\"true\"";
4229  else if (function->isImplicitlyVirtual())
4230  outs += " isImplicitlyVirtual=\"true\"";
4231  }
4232  if (function->access == AccessControl::Public || function->access == AccessControl::Protected || function->access == AccessControl::Private) {
4233  outs += " access=\"";
4234  outs += accessControlToString(function->access);
4235  outs +="\"";
4236  }
4237  if (function->isOperator())
4238  outs += " isOperator=\"true\"";
4239  if (function->isExplicit())
4240  outs += " isExplicit=\"true\"";
4241  if (function->hasOverrideSpecifier())
4242  outs += " hasOverrideSpecifier=\"true\"";
4243  if (function->hasFinalSpecifier())
4244  outs += " hasFinalSpecifier=\"true\"";
4245  if (function->isInlineKeyword())
4246  outs += " isInlineKeyword=\"true\"";
4247  if (function->isStatic())
4248  outs += " isStatic=\"true\"";
4249  if (function->isAttributeNoreturn())
4250  outs += " isAttributeNoreturn=\"true\"";
4251  if (const Function* overriddenFunction = function->getOverriddenFunction()) {
4252  outs += " overriddenFunction=\"";
4253  outs += id_string(overriddenFunction);
4254  outs += "\"";
4255  }
4256  if (function->argCount() == 0U)
4257  outs += "/>\n";
4258  else {
4259  outs += ">\n";
4260  for (unsigned int argnr = 0; argnr < function->argCount(); ++argnr) {
4261  const Variable *arg = function->getArgumentVar(argnr);
4262  outs += " <arg nr=\"";
4263  outs += std::to_string(argnr+1);
4264  outs += "\" variable=\"";
4265  outs += id_string(arg);
4266  outs += "\"/>\n";
4267  variables.insert(arg);
4268  }
4269  outs += " </function>\n";
4270  }
4271  }
4272  outs += " </functionList>\n";
4273  }
4274  if (!scope->varlist.empty()) {
4275  outs += " <varlist>\n";
4276  for (std::list<Variable>::const_iterator var = scope->varlist.cbegin(); var != scope->varlist.cend(); ++var) {
4277  outs += " <var id=\"";
4278  outs += id_string(&*var);
4279  outs += "\"/>\n";
4280  }
4281  outs += " </varlist>\n";
4282  }
4283  outs += " </scope>\n";
4284  }
4285  }
4286  outs += " </scopes>\n";
4287 
4288  if (!typeList.empty()) {
4289  outs += " <types>\n";
4290  for (const Type& type:typeList) {
4291  outs += " <type id=\"";
4292  outs += id_string(&type);
4293  outs += "\" classScope=\"";
4294  outs += id_string(type.classScope);
4295  outs += "\"";
4296  if (type.derivedFrom.empty()) {
4297  outs += "/>\n";
4298  continue;
4299  }
4300  outs += ">\n";
4301  for (const Type::BaseInfo& baseInfo: type.derivedFrom) {
4302  outs += " <derivedFrom";
4303  outs += " access=\"";
4304  outs += accessControlToString(baseInfo.access);
4305  outs += "\"";
4306  outs += " type=\"";
4307  outs += id_string(baseInfo.type);
4308  outs += "\"";
4309  outs += " isVirtual=\"";
4310  outs += bool_to_string(baseInfo.isVirtual);
4311  outs += "\"";
4312  outs += " nameTok=\"";
4313  outs += id_string(baseInfo.nameTok);
4314  outs += "\"";
4315  outs += "/>\n";
4316  }
4317  outs += " </type>\n";
4318  }
4319  outs += " </types>\n";
4320  }
4321 
4322  // Variables..
4323  for (const Variable *var : mVariableList)
4324  variables.insert(var);
4325  outs += " <variables>\n";
4326  for (const Variable *var : variables) {
4327  if (!var)
4328  continue;
4329  outs += " <var id=\"";
4330  outs += id_string(var);
4331  outs += '\"';
4332  outs += " nameToken=\"";
4333  outs += id_string(var->nameToken());
4334  outs += '\"';
4335  outs += " typeStartToken=\"";
4336  outs += id_string(var->typeStartToken());
4337  outs += '\"';
4338  outs += " typeEndToken=\"";
4339  outs += id_string(var->typeEndToken());
4340  outs += '\"';
4341  outs += " access=\"";
4342  outs += accessControlToString(var->mAccess);
4343  outs += '\"';
4344  outs += " scope=\"";
4345  outs += id_string(var->scope());
4346  outs += '\"';
4347  if (var->valueType()) {
4348  outs += " constness=\"";
4349  outs += std::to_string(var->valueType()->constness);
4350  outs += '\"';
4351 
4352  outs += " volatileness=\"";
4353  outs += std::to_string(var->valueType()->volatileness);
4354  outs += '\"';
4355  }
4356  outs += " isArray=\"";
4357  outs += bool_to_string(var->isArray());
4358  outs += '\"';
4359  outs += " isClass=\"";
4360  outs += bool_to_string(var->isClass());
4361  outs += '\"';
4362  outs += " isConst=\"";
4363  outs += bool_to_string(var->isConst());
4364  outs += '\"';
4365  outs += " isExtern=\"";
4366  outs += bool_to_string(var->isExtern());
4367  outs += '\"';
4368  outs += " isPointer=\"";
4369  outs += bool_to_string(var->isPointer());
4370  outs += '\"';
4371  outs += " isReference=\"";
4372  outs += bool_to_string(var->isReference());
4373  outs += '\"';
4374  outs += " isStatic=\"";
4375  outs += bool_to_string(var->isStatic());
4376  outs += '\"';
4377  outs += " isVolatile=\"";
4378  outs += bool_to_string(var->isVolatile());
4379  outs += '\"';
4380  outs += "/>\n";
4381  }
4382  outs += " </variables>\n";
4383 
4384  out << outs;
4385 }
4386 
4387 //---------------------------------------------------------------------------
4388 
4389 static const Type* findVariableTypeIncludingUsedNamespaces(const SymbolDatabase* symbolDatabase, const Scope* scope, const Token* typeTok)
4390 {
4391  const Type* argType = symbolDatabase->findVariableType(scope, typeTok);
4392  if (argType)
4393  return argType;
4394 
4395  // look for variable type in any using namespace in this scope or above
4396  while (scope) {
4397  for (const Scope::UsingInfo &ui : scope->usingList) {
4398  if (ui.scope) {
4399  argType = symbolDatabase->findVariableType(ui.scope, typeTok);
4400  if (argType)
4401  return argType;
4402  }
4403  }
4404  scope = scope->nestedIn;
4405  }
4406  return nullptr;
4407 }
4408 
4409 //---------------------------------------------------------------------------
4410 
4411 void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope)
4412 {
4413  // check for non-empty argument list "( ... )"
4414  const Token * start = arg ? arg : argDef;
4415  if (!Token::simpleMatch(start, "("))
4416  return;
4417  if (!(start && start->link() != start->next() && !Token::simpleMatch(start, "( void )")))
4418  return;
4419 
4420  unsigned int count = 0;
4421 
4422  for (const Token* tok = start->next(); tok; tok = tok->next()) {
4423  if (Token::Match(tok, ",|)"))
4424  return; // Syntax error
4425 
4426  const Token* startTok = tok;
4427  const Token* endTok = nullptr;
4428  const Token* nameTok = nullptr;
4429 
4430  do {
4431  if (Token::simpleMatch(tok, "decltype (")) {
4432  tok = tok->linkAt(1)->next();
4433  continue;
4434  }
4435  if (tok != startTok && !nameTok && Token::Match(tok, "( & %var% ) [")) {
4436  nameTok = tok->tokAt(2);
4437  endTok = nameTok->previous();
4438  tok = tok->link();
4439  } else if (tok != startTok && !nameTok && Token::Match(tok, "( * %var% ) (") && Token::Match(tok->link()->linkAt(1), ") [,)]")) {
4440  nameTok = tok->tokAt(2);
4441  endTok = nameTok->previous();
4442  tok = tok->link()->linkAt(1);
4443  } else if (tok != startTok && !nameTok && Token::Match(tok, "( * %var% ) [")) {
4444  nameTok = tok->tokAt(2);
4445  endTok = nameTok->previous();
4446  tok = tok->link();
4447  } else if (tok->varId() != 0) {
4448  nameTok = tok;
4449  endTok = tok->previous();
4450  } else if (tok->str() == "[") {
4451  // skip array dimension(s)
4452  tok = tok->link();
4453  while (tok->next()->str() == "[")
4454  tok = tok->next()->link();
4455  } else if (tok->str() == "<") {
4456  tok = tok->link();
4457  if (!tok) // something is wrong so just bail out
4458  return;
4459  }
4460 
4461  tok = tok->next();
4462 
4463  if (!tok) // something is wrong so just bail
4464  return;
4465  } while (tok->str() != "," && tok->str() != ")" && tok->str() != "=");
4466 
4467  const Token *typeTok = startTok;
4468  // skip over stuff to get to type
4469  while (Token::Match(typeTok, "const|volatile|enum|struct|::"))
4470  typeTok = typeTok->next();
4471  if (Token::Match(typeTok, ",|)")) { // #8333
4472  symbolDatabase->mTokenizer.syntaxError(typeTok);
4473  }
4474  if (Token::Match(typeTok, "%type% <") && Token::Match(typeTok->linkAt(1), "> :: %type%"))
4475  typeTok = typeTok->linkAt(1)->tokAt(2);
4476  // skip over qualification
4477  while (Token::Match(typeTok, "%type% ::")) {
4478  typeTok = typeTok->tokAt(2);
4479  if (Token::Match(typeTok, "%type% <") && Token::Match(typeTok->linkAt(1), "> :: %type%"))
4480  typeTok = typeTok->linkAt(1)->tokAt(2);
4481  }
4482 
4483  // check for argument with no name or missing varid
4484  if (!endTok) {
4485  if (tok->previous()->isName() && !Token::Match(tok->tokAt(-1), "const|volatile")) {
4486  if (tok->previous() != typeTok) {
4487  nameTok = tok->previous();
4488  endTok = nameTok->previous();
4489 
4490  if (hasBody())
4491  symbolDatabase->debugMessage(nameTok, "varid0", "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0.");
4492  } else
4493  endTok = typeTok;
4494  } else
4495  endTok = tok->previous();
4496  }
4497 
4498  const ::Type *argType = nullptr;
4499  if (!typeTok->isStandardType()) {
4500  argType = findVariableTypeIncludingUsedNamespaces(symbolDatabase, scope, typeTok);
4501 
4502  // save type
4503  const_cast<Token *>(typeTok)->type(argType);
4504  }
4505 
4506  // skip default values
4507  if (tok->str() == "=") {
4508  do {
4509  if (tok->link() && Token::Match(tok, "[{[(<]"))
4510  tok = tok->link();
4511  tok = tok->next();
4512  } while (tok->str() != "," && tok->str() != ")");
4513  }
4514 
4515  // skip over stuff before type
4516  while (Token::Match(startTok, "enum|struct|const|volatile"))
4517  startTok = startTok->next();
4518 
4519  if (startTok == nameTok)
4520  break;
4521 
4522  argumentList.emplace_back(nameTok, startTok, endTok, count++, AccessControl::Argument, argType, functionScope, symbolDatabase->mSettings);
4523 
4524  if (tok->str() == ")") {
4525  // check for a variadic function or a variadic template function
4526  if (Token::simpleMatch(endTok, "..."))
4527  isVariadic(true);
4528 
4529  break;
4530  }
4531  }
4532 
4533  // count default arguments
4534  for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) {
4535  if (tok->str() == "=") {
4536  initArgCount++;
4537  if (tok->strAt(1) == "[") {
4538  const Token* lambdaStart = tok->next();
4539  if (type == eLambda)
4540  tok = findLambdaEndTokenWithoutAST(lambdaStart);
4541  else {
4542  tok = findLambdaEndToken(lambdaStart);
4543  if (!tok)
4544  tok = findLambdaEndTokenWithoutAST(lambdaStart);
4545  }
4546  if (!tok)
4547  throw InternalError(lambdaStart, "Analysis failed (lambda not recognized). If the code is valid then please report this failure.", InternalError::INTERNAL);
4548  }
4549  }
4550  }
4551 }
4552 
4553 bool Function::isImplicitlyVirtual(bool defaultVal) const
4554 {
4555  if (hasVirtualSpecifier()) //If it has the virtual specifier it's definitely virtual
4556  return true;
4557  if (hasOverrideSpecifier()) //If it has the override specifier then it's either virtual or not going to compile
4558  return true;
4559  bool foundAllBaseClasses = true;
4560  if (getOverriddenFunction(&foundAllBaseClasses)) //If it overrides a base class's method then it's virtual
4561  return true;
4562  if (foundAllBaseClasses) //If we've seen all the base classes and none of the above were true then it must not be virtual
4563  return false;
4564  return defaultVal; //If we can't see all the bases classes then we can't say conclusively
4565 }
4566 
4567 std::vector<const Function*> Function::getOverloadedFunctions() const
4568 {
4569  std::vector<const Function*> result;
4570  const Scope* scope = nestedIn;
4571 
4572  while (scope) {
4573  const bool isMemberFunction = scope->isClassOrStruct() && !isStatic();
4574  for (std::multimap<std::string, const Function*>::const_iterator it = scope->functionMap.find(tokenDef->str());
4575  it != scope->functionMap.end() && it->first == tokenDef->str();
4576  ++it) {
4577  const Function* func = it->second;
4578  if (isMemberFunction && isMemberFunction == func->isStatic())
4579  continue;
4580  result.push_back(func);
4581  }
4582  if (isMemberFunction)
4583  break;
4584  scope = scope->nestedIn;
4585  }
4586 
4587  return result;
4588 }
4589 
4590 const Function *Function::getOverriddenFunction(bool *foundAllBaseClasses) const
4591 {
4592  if (foundAllBaseClasses)
4593  *foundAllBaseClasses = true;
4594  if (!nestedIn->isClassOrStruct())
4595  return nullptr;
4596  return getOverriddenFunctionRecursive(nestedIn->definedType, foundAllBaseClasses);
4597 }
4598 
4599 // prevent recursion if base is the same except for different template parameters
4600 static bool isDerivedFromItself(const std::string& thisName, const std::string& baseName)
4601 {
4602  if (thisName.back() != '>')
4603  return false;
4604  const auto pos = thisName.find('<');
4605  if (pos == std::string::npos)
4606  return false;
4607  return thisName.compare(0, pos + 1, baseName, 0, pos + 1) == 0;
4608 }
4609 
4610 const Function * Function::getOverriddenFunctionRecursive(const ::Type* baseType, bool *foundAllBaseClasses) const
4611 {
4612  // check each base class
4613  for (const ::Type::BaseInfo & i : baseType->derivedFrom) {
4614  const ::Type* derivedFromType = i.type;
4615  // check if base class exists in database
4616  if (!derivedFromType || !derivedFromType->classScope) {
4617  if (foundAllBaseClasses)
4618  *foundAllBaseClasses = false;
4619  continue;
4620  }
4621 
4622  const Scope *parent = derivedFromType->classScope;
4623 
4624  // check if function defined in base class
4625  auto range = parent->functionMap.equal_range(tokenDef->str());
4626  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
4627  const Function * func = it->second;
4628  if (func->isImplicitlyVirtual()) { // Base is virtual and of same name
4629  const Token *temp1 = func->tokenDef->previous();
4630  const Token *temp2 = tokenDef->previous();
4631  bool match = true;
4632 
4633  // check for matching return parameters
4634  while (!Token::Match(temp1, "virtual|public:|private:|protected:|{|}|;")) {
4635  if (temp1->str() != temp2->str() &&
4636  !(temp1->type() && temp2->type() && temp2->type()->isDerivedFrom(temp1->type()->name()))) {
4637  match = false;
4638  break;
4639  }
4640 
4641  temp1 = temp1->previous();
4642  temp2 = temp2->previous();
4643  }
4644 
4645  // check for matching function parameters
4646  match = match && argsMatch(baseType->classScope, func->argDef, argDef, emptyString, 0);
4647 
4648  // check for matching cv-ref qualifiers
4649  match = match
4650  && isConst() == func->isConst()
4651  && isVolatile() == func->isVolatile()
4653  && hasLvalRefQualifier() == func->hasLvalRefQualifier();
4654 
4655  // it's a match
4656  if (match) {
4657  return func;
4658  }
4659  }
4660  }
4661 
4662  if (isDestructor()) {
4663  auto it = std::find_if(parent->functionList.begin(), parent->functionList.end(), [](const Function& f) {
4664  return f.isDestructor() && f.isImplicitlyVirtual();
4665  });
4666  if (it != parent->functionList.end())
4667  return &*it;
4668  }
4669 
4670  if (!derivedFromType->derivedFrom.empty() && !derivedFromType->hasCircularDependencies() && !isDerivedFromItself(baseType->classScope->className, i.name)) {
4671  // avoid endless recursion, see #5289 Crash: Stack overflow in isImplicitlyVirtual_rec when checking SVN and
4672  // #5590 with a loop within the class hierarchy.
4673  const Function *func = getOverriddenFunctionRecursive(derivedFromType, foundAllBaseClasses);
4674  if (func) {
4675  return func;
4676  }
4677  }
4678  }
4679  return nullptr;
4680 }
4681 
4683 {
4684  if (num < argumentList.size()) {
4685  auto it = argumentList.begin();
4686  std::advance(it, num);
4687  return &*it;
4688  }
4689  return nullptr;
4690 }
4691 
4692 
4693 //---------------------------------------------------------------------------
4694 
4695 Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_) :
4696  check(check_),
4697  classDef(classDef_),
4698  nestedIn(nestedIn_),
4699  type(type_)
4700 {
4701  setBodyStartEnd(start_);
4702 }
4703 
4704 Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_) :
4705  check(check_),
4706  classDef(classDef_),
4707  nestedIn(nestedIn_)
4708 {
4709  const Token *nameTok = classDef;
4710  if (!classDef) {
4711  type = Scope::eGlobal;
4712  } else if (classDef->str() == "class" && classDef->isCpp()) {
4713  type = Scope::eClass;
4714  nameTok = nameTok->next();
4715  } else if (classDef->str() == "struct") {
4716  type = Scope::eStruct;
4717  nameTok = nameTok->next();
4718  } else if (classDef->str() == "union") {
4719  type = Scope::eUnion;
4720  nameTok = nameTok->next();
4721  } else if (classDef->str() == "namespace") {
4723  nameTok = nameTok->next();
4724  } else if (classDef->str() == "enum") {
4725  type = Scope::eEnum;
4726  nameTok = nameTok->next();
4727  if (nameTok->str() == "class") {
4728  enumClass = true;
4729  nameTok = nameTok->next();
4730  }
4731  } else if (classDef->str() == "[") {
4732  type = Scope::eLambda;
4733  } else {
4735  }
4736  // skip over qualification if present
4737  nameTok = skipScopeIdentifiers(nameTok);
4738  if (nameTok && ((type == Scope::eEnum && Token::Match(nameTok, ":|{")) || nameTok->str() != "{")) // anonymous and unnamed structs/unions don't have a name
4739  className = nameTok->str();
4740 }
4741 
4743 {
4744  switch (type) {
4745  case eGlobal:
4746  return AccessControl::Global;
4747  case eClass:
4748  return AccessControl::Private;
4749  case eStruct:
4750  return AccessControl::Public;
4751  case eUnion:
4752  return AccessControl::Public;
4753  case eNamespace:
4754  return AccessControl::Namespace;
4755  default:
4756  return AccessControl::Local;
4757  }
4758 }
4759 
4760 void Scope::addVariable(const Token *token_, const Token *start_, const Token *end_,
4761  AccessControl access_, const Type *type_, const Scope *scope_, const Settings& settings)
4762 {
4763  // keep possible size_t -> int truncation outside emplace_back() to have a single line
4764  // C4267 VC++ warning instead of several dozens lines
4765  const int varIndex = varlist.size();
4766  varlist.emplace_back(token_, start_, end_, varIndex, access_, type_, scope_, settings);
4767 }
4768 
4769 // Get variable list..
4770 void Scope::getVariableList(const Settings& settings)
4771 {
4772  if (!bodyStartList.empty()) {
4773  for (const Token *bs: bodyStartList)
4774  getVariableList(settings, bs->next(), bs->link());
4775  }
4776 
4777  // global scope
4778  else if (type == Scope::eGlobal)
4779  getVariableList(settings, check->mTokenizer.tokens(), nullptr);
4780 
4781  // forward declaration
4782  else
4783  return;
4784 }
4785 
4786 void Scope::getVariableList(const Settings& settings, const Token* start, const Token* end)
4787 {
4788  // Variable declared in condition: if (auto x = bar())
4789  if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) {
4790  checkVariable(classDef->tokAt(2), defaultAccess(), settings);
4791  }
4792 
4793  AccessControl varaccess = defaultAccess();
4794  for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
4795  // syntax error?
4796  if (tok->next() == nullptr)
4797  break;
4798 
4799  // Is it a function?
4800  if (tok->str() == "{") {
4801  tok = tok->link();
4802  continue;
4803  }
4804 
4805  // Is it a nested class or structure?
4806  if (tok->isKeyword() && Token::Match(tok, "class|struct|union|namespace %type% :|{")) {
4807  tok = tok->tokAt(2);
4808  while (tok && tok->str() != "{")
4809  tok = tok->next();
4810  if (tok) {
4811  // skip implementation
4812  tok = tok->link();
4813  continue;
4814  }
4815  break;
4816  }
4817  if (tok->isKeyword() && Token::Match(tok, "struct|union {")) {
4818  if (Token::Match(tok->next()->link(), "} %name% ;|[")) {
4819  tok = tok->next()->link()->tokAt(2);
4820  continue;
4821  }
4822  if (Token::simpleMatch(tok->next()->link(), "} ;")) {
4823  tok = tok->next();
4824  continue;
4825  }
4826  }
4827 
4828  // Borland C++: Skip all variables in the __published section.
4829  // These are automatically initialized.
4830  else if (tok->str() == "__published:") {
4831  for (; tok; tok = tok->next()) {
4832  if (tok->str() == "{")
4833  tok = tok->link();
4834  if (Token::Match(tok->next(), "private:|protected:|public:"))
4835  break;
4836  }
4837  if (tok)
4838  continue;
4839  break;
4840  }
4841 
4842  // "private:" "public:" "protected:" etc
4843  else if (tok->str() == "public:") {
4844  varaccess = AccessControl::Public;
4845  continue;
4846  } else if (tok->str() == "protected:") {
4847  varaccess = AccessControl::Protected;
4848  continue;
4849  } else if (tok->str() == "private:") {
4850  varaccess = AccessControl::Private;
4851  continue;
4852  }
4853 
4854  // Is it a forward declaration?
4855  else if (tok->isKeyword() && Token::Match(tok, "class|struct|union %name% ;")) {
4856  tok = tok->tokAt(2);
4857  continue;
4858  }
4859 
4860  // Borland C++: Ignore properties..
4861  else if (tok->str() == "__property")
4862  continue;
4863 
4864  // skip return, goto and delete
4865  else if (tok->isKeyword() && Token::Match(tok, "return|delete|goto")) {
4866  while (tok->next() &&
4867  tok->next()->str() != ";" &&
4868  tok->next()->str() != "}" /* ticket #4994 */) {
4869  tok = tok->next();
4870  }
4871  continue;
4872  }
4873 
4874  // skip case/default
4875  if (tok->isKeyword() && Token::Match(tok, "case|default")) {
4876  while (tok->next() && !Token::Match(tok->next(), "[:;{}]"))
4877  tok = tok->next();
4878  continue;
4879  }
4880 
4881  // Search for start of statement..
4882  if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|public:|protected:|private:"))
4883  continue;
4884  if (tok->str() == ";")
4885  continue;
4886 
4887  tok = checkVariable(tok, varaccess, settings);
4888 
4889  if (!tok)
4890  break;
4891  }
4892 }
4893 
4894 const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess, const Settings& settings)
4895 {
4896  // Is it a throw..?
4897  if (tok->isKeyword() && Token::Match(tok, "throw %any% (") &&
4898  Token::simpleMatch(tok->linkAt(2), ") ;")) {
4899  return tok->linkAt(2);
4900  }
4901 
4902  if (tok->isKeyword() && Token::Match(tok, "throw %any% :: %any% (") &&
4903  Token::simpleMatch(tok->linkAt(4), ") ;")) {
4904  return tok->linkAt(4);
4905  }
4906 
4907  // friend?
4908  if (tok->isKeyword() && Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) {
4909  const Token *next = Token::findmatch(tok->tokAt(2), ";|{");
4910  if (next && next->str() == "{")
4911  next = next->link();
4912  return next;
4913  }
4914 
4915  // skip const|volatile|static|mutable|extern
4916  while (tok && tok->isKeyword() && Token::Match(tok, "const|constexpr|volatile|static|mutable|extern")) {
4917  tok = tok->next();
4918  }
4919 
4920  // the start of the type tokens does not include the above modifiers
4921  const Token *typestart = tok;
4922 
4923  // C++17 structured bindings
4924  if (tok && tok->isCpp() && (settings.standards.cpp >= Standards::CPP17) && Token::Match(tok, "auto &|&&| [")) {
4925  const Token *typeend = Token::findsimplematch(typestart, "[")->previous();
4926  for (tok = typeend->tokAt(2); Token::Match(tok, "%name%|,"); tok = tok->next()) {
4927  if (tok->varId())
4928  addVariable(tok, typestart, typeend, varaccess, nullptr, this, settings);
4929  }
4930  return typeend->linkAt(1);
4931  }
4932 
4933  while (tok && tok->isKeyword() && Token::Match(tok, "class|struct|union|enum")) {
4934  tok = tok->next();
4935  }
4936 
4937  // This is the start of a statement
4938  const Token *vartok = nullptr;
4939  const Token *typetok = nullptr;
4940 
4941  if (tok && isVariableDeclaration(tok, vartok, typetok)) {
4942  // If the vartok was set in the if-blocks above, create a entry for this variable..
4943  tok = vartok->next();
4944  while (Token::Match(tok, "[|{"))
4945  tok = tok->link()->next();
4946 
4947  if (vartok->varId() == 0) {
4948  if (!vartok->isBoolean())
4949  check->debugMessage(vartok, "varid0", "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0.");
4950  return tok;
4951  }
4952 
4953  const Type *vType = nullptr;
4954 
4955  if (typetok) {
4956  vType = findVariableTypeIncludingUsedNamespaces(check, this, typetok);
4957 
4958  const_cast<Token *>(typetok)->type(vType);
4959  }
4960 
4961  // skip "enum" or "struct"
4962  if (Token::Match(typestart, "enum|struct"))
4963  typestart = typestart->next();
4964 
4965  addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this, settings);
4966  }
4967 
4968  return tok;
4969 }
4970 
4971 const Variable *Scope::getVariable(const std::string &varname) const
4972 {
4973  auto it = std::find_if(varlist.begin(), varlist.end(), [&varname](const Variable& var) {
4974  return var.name() == varname;
4975  });
4976  if (it != varlist.end())
4977  return &*it;
4978 
4979  if (definedType) {
4980  for (const Type::BaseInfo& baseInfo: definedType->derivedFrom) {
4981  if (baseInfo.type && baseInfo.type->classScope) {
4982  if (const Variable* var = baseInfo.type->classScope->getVariable(varname))
4983  return var;
4984  }
4985  }
4986  }
4987  return nullptr;
4988 }
4989 
4990 static const Token* skipPointers(const Token* tok)
4991 {
4992  while (Token::Match(tok, "*|&|&&") || (Token::Match(tok, "( [*&]") && Token::Match(tok->link()->next(), "(|["))) {
4993  tok = tok->next();
4994  if (tok && tok->strAt(-1) == "(" && Token::Match(tok, "%type% ::"))
4995  tok = tok->tokAt(2);
4996  }
4997 
4998  if (Token::simpleMatch(tok, "( *") && Token::simpleMatch(tok->link()->previous(), "] ) ;")) {
4999  const Token *tok2 = skipPointers(tok->next());
5000  if (Token::Match(tok2, "%name% [") && Token::simpleMatch(tok2->linkAt(1), "] ) ;"))
5001  return tok2;
5002  }
5003 
5004  return tok;
5005 }
5006 
5007 static const Token* skipPointersAndQualifiers(const Token* tok)
5008 {
5009  tok = skipPointers(tok);
5010  while (Token::Match(tok, "const|static|volatile")) {
5011  tok = tok->next();
5012  tok = skipPointers(tok);
5013  }
5014 
5015  return tok;
5016 }
5017 
5018 bool Scope::isVariableDeclaration(const Token* const tok, const Token*& vartok, const Token*& typetok) const
5019 {
5020  if (!tok)
5021  return false;
5022 
5023  const bool isCPP = tok->isCpp();
5024 
5025  if (isCPP && Token::Match(tok, "throw|new"))
5026  return false;
5027 
5028  const bool isCPP11 = isCPP && check->mSettings.standards.cpp >= Standards::CPP11;
5029 
5030  if (isCPP11 && tok->str() == "using")
5031  return false;
5032 
5033  const Token* localTypeTok = skipScopeIdentifiers(tok);
5034  const Token* localVarTok = nullptr;
5035 
5036  while (Token::simpleMatch(localTypeTok, "alignas (") && Token::Match(localTypeTok->linkAt(1), ") %name%"))
5037  localTypeTok = localTypeTok->linkAt(1)->next();
5038 
5039  if (Token::Match(localTypeTok, "%type% <")) {
5040  if (Token::Match(tok, "const_cast|dynamic_cast|reinterpret_cast|static_cast <"))
5041  return false;
5042 
5043  const Token* closeTok = localTypeTok->next()->link();
5044  if (closeTok) {
5045  localVarTok = skipPointers(closeTok->next());
5046 
5047  if (Token::Match(localVarTok, ":: %type% %name% [;=({]")) {
5048  if (localVarTok->strAt(3) != "(" ||
5049  Token::Match(localVarTok->linkAt(3), "[)}] ;")) {
5050  localTypeTok = localVarTok->next();
5051  localVarTok = localVarTok->tokAt(2);
5052  }
5053  }
5054  }
5055  } else if (Token::Match(localTypeTok, "%type%")) {
5056 
5057  if (isCPP11 && Token::simpleMatch(localTypeTok, "decltype (") && Token::Match(localTypeTok->linkAt(1), ") %name%|*|&|&&"))
5058  localVarTok = skipPointersAndQualifiers(localTypeTok->linkAt(1)->next());
5059  else {
5060  localVarTok = skipPointersAndQualifiers(localTypeTok->next());
5061  if (isCPP11 && Token::simpleMatch(localVarTok, "decltype (") && Token::Match(localVarTok->linkAt(1), ") %name%|*|&|&&"))
5062  localVarTok = skipPointersAndQualifiers(localVarTok->linkAt(1)->next());
5063  }
5064  }
5065 
5066  if (!localVarTok)
5067  return false;
5068 
5069  while (Token::Match(localVarTok, "const|*|&"))
5070  localVarTok = localVarTok->next();
5071 
5072  if (Token::Match(localVarTok, "%name% ;|=") || (localVarTok && localVarTok->varId() && localVarTok->strAt(1) == ":")) {
5073  vartok = localVarTok;
5074  typetok = localTypeTok;
5075  } else if (Token::Match(localVarTok, "%name% )|[") && localVarTok->str() != "operator") {
5076  vartok = localVarTok;
5077  typetok = localTypeTok;
5078  } else if (localVarTok && localVarTok->varId() && Token::Match(localVarTok, "%name% (|{") &&
5079  Token::Match(localVarTok->next()->link(), ")|} ;")) {
5080  vartok = localVarTok;
5081  typetok = localTypeTok;
5082  } else if (type == eCatch &&
5083  Token::Match(localVarTok, "%name% )")) {
5084  vartok = localVarTok;
5085  typetok = localTypeTok;
5086  }
5087 
5088  return nullptr != vartok;
5089 }
5090 
5091 const Token * Scope::addEnum(const Token * tok)
5092 {
5093  const Token * tok2 = tok->next();
5094 
5095  // skip over class if present
5096  if (tok2->isCpp() && tok2->str() == "class")
5097  tok2 = tok2->next();
5098 
5099  // skip over name
5100  tok2 = tok2->next();
5101 
5102  // save type if present
5103  if (tok2->str() == ":") {
5104  tok2 = tok2->next();
5105 
5106  enumType = tok2;
5107  while (Token::Match(tok2, "%name%|::"))
5108  tok2 = tok2->next();
5109  }
5110 
5111  // add enumerators
5112  if (tok2->str() == "{") {
5113  const Token * end = tok2->link();
5114  tok2 = tok2->next();
5115 
5116  while (Token::Match(tok2, "%name% =|,|}") ||
5117  (Token::Match(tok2, "%name% (") && Token::Match(tok2->linkAt(1), ") ,|}"))) {
5118  Enumerator enumerator(this);
5119 
5120  // save enumerator name
5121  enumerator.name = tok2;
5122 
5123  // skip over name
5124  tok2 = tok2->next();
5125 
5126  if (tok2->str() == "=") {
5127  // skip over "="
5128  tok2 = tok2->next();
5129 
5130  if (tok2->str() == "}")
5131  return nullptr;
5132 
5133  enumerator.start = tok2;
5134 
5135  while (!Token::Match(tok2, ",|}")) {
5136  if (tok2->link())
5137  tok2 = tok2->link();
5138  enumerator.end = tok2;
5139  tok2 = tok2->next();
5140  }
5141  } else if (tok2->str() == "(") {
5142  // skip over unknown macro
5143  tok2 = tok2->link()->next();
5144  }
5145 
5146  if (tok2->str() == ",") {
5147  enumeratorList.push_back(enumerator);
5148  tok2 = tok2->next();
5149  } else if (tok2->str() == "}") {
5150  enumeratorList.push_back(enumerator);
5151  break;
5152  }
5153  }
5154 
5155  if (tok2 == end) {
5156  tok2 = tok2->next();
5157 
5158  if (tok2 && tok2->str() != ";" && (tok2->isCpp() || tok2->str() != ")"))
5159  tok2 = nullptr;
5160  } else
5161  tok2 = nullptr;
5162  } else
5163  tok2 = nullptr;
5164 
5165  return tok2;
5166 }
5167 
5168 static const Scope* findEnumScopeInBase(const Scope* scope, const std::string& tokStr)
5169 {
5170  if (scope->definedType) {
5171  const std::vector<Type::BaseInfo>& derivedFrom = scope->definedType->derivedFrom;
5172  for (const Type::BaseInfo& i : derivedFrom) {
5173  const Type *derivedFromType = i.type;
5174  if (derivedFromType && derivedFromType->classScope) {
5175  if (const Scope* enumScope = derivedFromType->classScope->findRecordInNestedList(tokStr))
5176  return enumScope;
5177  }
5178  }
5179  }
5180  return nullptr;
5181 }
5182 
5183 const Enumerator * SymbolDatabase::findEnumerator(const Token * tok, std::set<std::string>& tokensThatAreNotEnumeratorValues) const
5184 {
5185  if (tok->isKeyword())
5186  return nullptr;
5187 
5188  const std::string& tokStr = tok->str();
5189  const Scope* scope = tok->scope();
5190 
5191  // check for qualified name
5192  if (tok->strAt(-1) == "::") {
5193  // find first scope
5194  const Token *tok1 = tok;
5195  while (Token::Match(tok1->tokAt(-2), "%name% ::"))
5196  tok1 = tok1->tokAt(-2);
5197 
5198  if (tok1->strAt(-1) == "::")
5199  scope = &scopeList.front();
5200  else {
5201  const Scope* temp = nullptr;
5202  if (scope)
5203  temp = scope->findRecordInNestedList(tok1->str());
5204  // find first scope
5205  while (scope && scope->nestedIn) {
5206  if (!temp)
5207  temp = scope->nestedIn->findRecordInNestedList(tok1->str());
5208  if (!temp && scope->functionOf) {
5209  temp = scope->functionOf->findRecordInNestedList(tok1->str());
5210  const Scope* nested = scope->functionOf->nestedIn;
5211  while (!temp && nested) {
5212  temp = nested->findRecordInNestedList(tok1->str());
5213  nested = nested->nestedIn;
5214  }
5215  }
5216  if (!temp)
5217  temp = findEnumScopeInBase(scope, tok1->str());
5218  if (temp) {
5219  scope = temp;
5220  break;
5221  }
5222  scope = scope->nestedIn;
5223  }
5224  }
5225 
5226  if (scope) {
5227  tok1 = tok1->tokAt(2);
5228  while (scope && Token::Match(tok1, "%name% ::")) {
5229  scope = scope->findRecordInNestedList(tok1->str());
5230  tok1 = tok1->tokAt(2);
5231  }
5232 
5233  if (scope) {
5234  const Enumerator * enumerator = scope->findEnumerator(tokStr);
5235 
5236  if (enumerator) // enum class
5237  return enumerator;
5238  // enum
5239  for (std::vector<Scope *>::const_iterator it = scope->nestedList.cbegin(), end = scope->nestedList.cend(); it != end; ++it) {
5240  enumerator = (*it)->findEnumerator(tokStr);
5241 
5242  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5243  return enumerator;
5244  }
5245  }
5246  }
5247  } else { // unqualified name
5248 
5249  if (tokensThatAreNotEnumeratorValues.find(tokStr) != tokensThatAreNotEnumeratorValues.end())
5250  return nullptr;
5251 
5252  if (tok->scope()->type == Scope::eGlobal) {
5253  const Token* astTop = tok->astTop();
5254  if (Token::simpleMatch(astTop, ":") && Token::simpleMatch(astTop->astOperand1(), "(")) { // ctor init list
5255  const Token* ctor = astTop->astOperand1()->previous();
5256  if (ctor && ctor->function() && ctor->function()->nestedIn)
5257  scope = ctor->function()->nestedIn;
5258  }
5259  }
5260  const Enumerator * enumerator = scope->findEnumerator(tokStr);
5261 
5262  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5263  return enumerator;
5264 
5265  if (Token::simpleMatch(tok->astParent(), ".")) {
5266  const Token* varTok = tok->astParent()->astOperand1();
5267  if (varTok && varTok->variable() && varTok->variable()->type() && varTok->variable()->type()->classScope)
5268  scope = varTok->variable()->type()->classScope;
5269  }
5270  else if (Token::simpleMatch(tok->astParent(), "[")) {
5271  const Token* varTok = tok->astParent()->previous();
5272  if (varTok && varTok->variable() && varTok->variable()->scope() && Token::simpleMatch(tok->astParent()->astOperand1(), "::"))
5273  scope = varTok->variable()->scope();
5274  }
5275 
5276  for (std::vector<Scope *>::const_iterator s = scope->nestedList.cbegin(); s != scope->nestedList.cend(); ++s) {
5277  enumerator = (*s)->findEnumerator(tokStr);
5278 
5279  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5280  return enumerator;
5281  }
5282 
5283  if (scope->definedType) {
5284  const std::vector<Type::BaseInfo> & derivedFrom = scope->definedType->derivedFrom;
5285  for (const Type::BaseInfo & i : derivedFrom) {
5286  const Type *derivedFromType = i.type;
5287  if (derivedFromType && derivedFromType->classScope) {
5288  enumerator = derivedFromType->classScope->findEnumerator(tokStr);
5289 
5290  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5291  return enumerator;
5292  }
5293  }
5294  }
5295 
5296  while (scope->nestedIn) {
5297  if (scope->type == Scope::eFunction && scope->functionOf)
5298  scope = scope->functionOf;
5299  else
5300  scope = scope->nestedIn;
5301 
5302  enumerator = scope->findEnumerator(tokStr);
5303 
5304  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5305  return enumerator;
5306 
5307  for (std::vector<Scope*>::const_iterator s = scope->nestedList.cbegin(); s != scope->nestedList.cend(); ++s) {
5308  enumerator = (*s)->findEnumerator(tokStr);
5309 
5310  if (enumerator && !(enumerator->scope && enumerator->scope->enumClass))
5311  return enumerator;
5312  }
5313  }
5314  }
5315 
5316  tokensThatAreNotEnumeratorValues.insert(tokStr);
5317 
5318  return nullptr;
5319 }
5320 
5321 //---------------------------------------------------------------------------
5322 
5323 const Type* SymbolDatabase::findVariableTypeInBase(const Scope* scope, const Token* typeTok)
5324 {
5325  if (scope && scope->definedType && !scope->definedType->derivedFrom.empty()) {
5326  const std::vector<Type::BaseInfo> &derivedFrom = scope->definedType->derivedFrom;
5327  for (const Type::BaseInfo & i : derivedFrom) {
5328  const Type *base = i.type;
5329  if (base && base->classScope) {
5330  if (base->classScope == scope)
5331  return nullptr;
5332  const Type * type = base->classScope->findType(typeTok->str());
5333  if (type)
5334  return type;
5335  type = findVariableTypeInBase(base->classScope, typeTok);
5336  if (type)
5337  return type;
5338  }
5339  }
5340  }
5341 
5342  return nullptr;
5343 }
5344 
5345 //---------------------------------------------------------------------------
5346 
5347 const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const
5348 {
5349  const Scope *scope = start;
5350 
5351  // check if type does not have a namespace
5352  if (typeTok->strAt(-1) != "::" && typeTok->strAt(1) != "::") {
5353  // check if type same as scope
5354  if (start->isClassOrStruct() && typeTok->str() == start->className)
5355  return start->definedType;
5356 
5357  while (scope) {
5358  // look for type in this scope
5359  const Type * type = scope->findType(typeTok->str());
5360 
5361  if (type)
5362  return type;
5363 
5364  // look for type in base classes if possible
5365  if (scope->isClassOrStruct()) {
5366  type = findVariableTypeInBase(scope, typeTok);
5367 
5368  if (type)
5369  return type;
5370  }
5371 
5372  // check if in member function class to see if it's present in class
5373  if (scope->type == Scope::eFunction && scope->functionOf) {
5374  const Scope *scope1 = scope->functionOf;
5375 
5376  type = scope1->findType(typeTok->str());
5377 
5378  if (type)
5379  return type;
5380 
5381  type = findVariableTypeInBase(scope1, typeTok);
5382 
5383  if (type)
5384  return type;
5385  }
5386 
5387  scope = scope->nestedIn;
5388  }
5389  }
5390 
5391  // check for a qualified name and use it when given
5392  else if (typeTok->strAt(-1) == "::") {
5393  // check if type is not part of qualification
5394  if (typeTok->strAt(1) == "::")
5395  return nullptr;
5396 
5397  // find start of qualified function name
5398  const Token *tok1 = typeTok;
5399 
5400  while ((Token::Match(tok1->tokAt(-2), "%type% ::") && !tok1->tokAt(-2)->isKeyword()) ||
5401  (Token::simpleMatch(tok1->tokAt(-2), "> ::") && tok1->linkAt(-2) && Token::Match(tok1->linkAt(-2)->tokAt(-1), "%type%"))) {
5402  if (tok1->strAt(-1) == "::")
5403  tok1 = tok1->tokAt(-2);
5404  else
5405  tok1 = tok1->linkAt(-2)->tokAt(-1);
5406  }
5407 
5408  // check for global scope
5409  if (tok1->strAt(-1) == "::") {
5410  scope = &scopeList.front();
5411 
5412  scope = scope->findRecordInNestedList(tok1->str());
5413  }
5414 
5415  // find start of qualification
5416  else {
5417  while (scope) {
5418  if (scope->className == tok1->str())
5419  break;
5420 
5421  const Scope *scope1 = scope->findRecordInNestedList(tok1->str());
5422 
5423  if (scope1) {
5424  scope = scope1;
5425  break;
5426  }
5427  if (scope->type == Scope::eFunction && scope->functionOf)
5428  scope = scope->functionOf;
5429  else
5430  scope = scope->nestedIn;
5431  }
5432  }
5433 
5434  if (scope) {
5435  // follow qualification
5436  while (scope && (Token::Match(tok1, "%type% ::") ||
5437  (Token::Match(tok1, "%type% <") && Token::simpleMatch(tok1->linkAt(1), "> ::")))) {
5438  if (tok1->strAt(1) == "::")
5439  tok1 = tok1->tokAt(2);
5440  else
5441  tok1 = tok1->linkAt(1)->tokAt(2);
5442  const Scope * temp = scope->findRecordInNestedList(tok1->str());
5443  if (!temp) {
5444  // look in base classes
5445  const Type * type = findVariableTypeInBase(scope, tok1);
5446 
5447  if (type)
5448  return type;
5449  }
5450  scope = temp;
5451  }
5452 
5453  if (scope && scope->definedType)
5454  return scope->definedType;
5455  }
5456  }
5457 
5458  return nullptr;
5459 }
5460 
5461 static bool hasEmptyCaptureList(const Token* tok) {
5462  if (!Token::simpleMatch(tok, "{"))
5463  return false;
5464  const Token* listTok = tok->astParent();
5465  if (Token::simpleMatch(listTok, "("))
5466  listTok = listTok->astParent();
5467  return Token::simpleMatch(listTok, "[ ]");
5468 }
5469 
5471 {
5472  return std::any_of(nestedList.begin(), nestedList.end(), [&](const Scope* s) {
5473  // Inline function
5474  if (s->type == Scope::eUnconditional && Token::simpleMatch(s->bodyStart->previous(), ") {"))
5475  return true;
5476  // Lambda function
5477  if (s->type == Scope::eLambda && !hasEmptyCaptureList(s->bodyStart))
5478  return true;
5479  if (s->hasInlineOrLambdaFunction())
5480  return true;
5481  return false;
5482  });
5483 }
5484 
5485 void Scope::findFunctionInBase(const std::string & name, nonneg int args, std::vector<const Function *> & matches) const
5486 {
5487  if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5488  const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
5489  for (const Type::BaseInfo & i : derivedFrom) {
5490  const Type *base = i.type;
5491  if (base && base->classScope) {
5492  if (base->classScope == this) // Ticket #5120, #5125: Recursive class; tok should have been found already
5493  continue;
5494 
5495  auto range = base->classScope->functionMap.equal_range(name);
5496  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
5497  const Function *func = it->second;
5498  if ((func->isVariadic() && args >= (func->argCount() - 1)) ||
5499  (args == func->argCount() || (args < func->argCount() && args >= func->minArgCount()))) {
5500  matches.push_back(func);
5501  }
5502  }
5503 
5504  base->classScope->findFunctionInBase(name, args, matches);
5505  }
5506  }
5507  }
5508 }
5509 
5510 const Scope *Scope::findRecordInBase(const std::string & name) const
5511 {
5512  if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5513  const std::vector<Type::BaseInfo> &derivedFrom = definedType->derivedFrom;
5514  for (const Type::BaseInfo & i : derivedFrom) {
5515  const Type *base = i.type;
5516  if (base && base->classScope) {
5517  if (base->classScope == this) // Recursive class; tok should have been found already
5518  continue;
5519 
5520  if (base->name() == name) {
5521  return base->classScope;
5522  }
5523 
5524  const ::Type * t = base->classScope->findType(name);
5525  if (t)
5526  return t->classScope;
5527  }
5528  }
5529  }
5530 
5531  return nullptr;
5532 }
5533 
5534 std::vector<const Scope*> Scope::findAssociatedScopes() const
5535 {
5536  std::vector<const Scope*> result = {this};
5537  if (isClassOrStruct() && definedType && !definedType->derivedFrom.empty()) {
5538  const std::vector<Type::BaseInfo>& derivedFrom = definedType->derivedFrom;
5539  for (const Type::BaseInfo& i : derivedFrom) {
5540  const Type* base = i.type;
5541  if (base && base->classScope) {
5542  if (contains(result, base->classScope))
5543  continue;
5544  std::vector<const Scope*> baseScopes = base->classScope->findAssociatedScopes();
5545  result.insert(result.end(), baseScopes.cbegin(), baseScopes.cend());
5546  }
5547  }
5548  }
5549  return result;
5550 }
5551 
5552 //---------------------------------------------------------------------------
5553 
5554 static void checkVariableCallMatch(const Variable* callarg, const Variable* funcarg, size_t& same, size_t& fallback1, size_t& fallback2)
5555 {
5556  if (callarg) {
5557  const ValueType::MatchResult res = ValueType::matchParameter(callarg->valueType(), callarg, funcarg);
5558  if (res == ValueType::MatchResult::SAME) {
5559  same++;
5560  return;
5561  }
5562  if (res == ValueType::MatchResult::FALLBACK1) {
5563  fallback1++;
5564  return;
5565  }
5566  if (res == ValueType::MatchResult::FALLBACK2) {
5567  fallback2++;
5568  return;
5569  }
5571  return;
5572 
5573  const bool ptrequals = callarg->isArrayOrPointer() == funcarg->isArrayOrPointer();
5574  const bool constEquals = !callarg->isArrayOrPointer() || ((callarg->typeStartToken()->strAt(-1) == "const") == (funcarg->typeStartToken()->strAt(-1) == "const"));
5575  if (ptrequals && constEquals &&
5576  callarg->typeStartToken()->str() == funcarg->typeStartToken()->str() &&
5577  callarg->typeStartToken()->isUnsigned() == funcarg->typeStartToken()->isUnsigned() &&
5578  callarg->typeStartToken()->isLong() == funcarg->typeStartToken()->isLong()) {
5579  same++;
5580  } else if (callarg->isArrayOrPointer()) {
5581  if (ptrequals && constEquals && funcarg->typeStartToken()->str() == "void")
5582  fallback1++;
5583  else if (constEquals && funcarg->isStlStringType() && Token::Match(callarg->typeStartToken(), "char|wchar_t"))
5584  fallback2++;
5585  } else if (ptrequals) {
5586  const bool takesInt = Token::Match(funcarg->typeStartToken(), "char|short|int|long");
5587  const bool takesFloat = Token::Match(funcarg->typeStartToken(), "float|double");
5588  const bool passesInt = Token::Match(callarg->typeStartToken(), "char|short|int|long");
5589  const bool passesFloat = Token::Match(callarg->typeStartToken(), "float|double");
5590  if ((takesInt && passesInt) || (takesFloat && passesFloat))
5591  fallback1++;
5592  else if ((takesInt && passesFloat) || (takesFloat && passesInt))
5593  fallback2++;
5594  }
5595  }
5596 }
5597 
5598 static std::string getTypeString(const Token *typeToken)
5599 {
5600  if (!typeToken)
5601  return "";
5602  while (Token::Match(typeToken, "%name%|*|&|::")) {
5603  if (typeToken->str() == "::") {
5604  std::string ret;
5605  while (Token::Match(typeToken, ":: %name%")) {
5606  ret += "::" + typeToken->strAt(1);
5607  typeToken = typeToken->tokAt(2);
5608  if (typeToken->str() == "<") {
5609  for (const Token *tok = typeToken; tok != typeToken->link(); tok = tok->next())
5610  ret += tok->str();
5611  ret += ">";
5612  typeToken = typeToken->link()->next();
5613  }
5614  }
5615  return ret;
5616  }
5617  if (Token::Match(typeToken, "%name% const| %var%|*|&")) {
5618  return typeToken->str();
5619  }
5620  typeToken = typeToken->next();
5621  }
5622  return "";
5623 }
5624 
5625 static bool hasMatchingConstructor(const Scope* classScope, const ValueType* argType) {
5626  if (!classScope || !argType)
5627  return false;
5628  return std::any_of(classScope->functionList.cbegin(),
5629  classScope->functionList.cend(),
5630  [&](const Function& f) {
5631  if (!f.isConstructor() || f.argCount() != 1 || !f.getArgumentVar(0))
5632  return false;
5633  const ValueType* vt = f.getArgumentVar(0)->valueType();
5634  return vt &&
5635  vt->type == argType->type &&
5636  (argType->sign == ValueType::Sign::UNKNOWN_SIGN || vt->sign == argType->sign) &&
5637  vt->pointer == argType->pointer &&
5638  (vt->constness & 1) >= (argType->constness & 1) &&
5639  (vt->volatileness & 1) >= (argType->volatileness & 1);
5640  });
5641 }
5642 
5643 const Function* Scope::findFunction(const Token *tok, bool requireConst) const
5644 {
5645  const bool isCall = Token::Match(tok->next(), "(|{");
5646 
5647  const std::vector<const Token *> arguments = getArguments(tok);
5648 
5649  std::vector<const Function *> matches;
5650 
5651  // find all the possible functions that could match
5652  const std::size_t args = arguments.size();
5653 
5654  auto addMatchingFunctions = [&](const Scope *scope) {
5655  auto range = scope->functionMap.equal_range(tok->str());
5656  for (std::multimap<std::string, const Function *>::const_iterator it = range.first; it != range.second; ++it) {
5657  const Function *func = it->second;
5658  if (!isCall || args == func->argCount() ||
5659  (func->isVariadic() && args >= (func->minArgCount() - 1)) ||
5660  (args < func->argCount() && args >= func->minArgCount())) {
5661  matches.push_back(func);
5662  }
5663  }
5664  };
5665 
5666  addMatchingFunctions(this);
5667 
5668  // check in anonymous namespaces
5669  for (const Scope *nestedScope : nestedList) {
5670  if (nestedScope->type == eNamespace && nestedScope->className.empty())
5671  addMatchingFunctions(nestedScope);
5672  }
5673 
5674  const std::size_t numberOfMatchesNonBase = matches.size();
5675 
5676  // check in base classes
5677  findFunctionInBase(tok->str(), args, matches);
5678 
5679  // Non-call => Do not match parameters
5680  if (!isCall) {
5681  return matches.empty() ? nullptr : matches[0];
5682  }
5683 
5684  std::vector<const Function*> fallback1Func, fallback2Func;
5685 
5686  // check each function against the arguments in the function call for a match
5687  for (std::size_t i = 0; i < matches.size();) {
5688  if (i > 0 && i == numberOfMatchesNonBase && fallback1Func.empty() && !fallback2Func.empty())
5689  break;
5690 
5691  bool constFallback = false;
5692  const Function * func = matches[i];
5693  size_t same = 0;
5694 
5695  if (requireConst && !func->isConst()) {
5696  i++;
5697  continue;
5698  }
5699 
5700  if (!requireConst || !func->isConst()) {
5701  // get the function this call is in
5702  const Scope * scope = tok->scope();
5703 
5704  // check if this function is a member function
5705  if (scope && scope->functionOf && scope->functionOf->isClassOrStruct() && scope->function &&
5706  func->nestedIn == scope->functionOf) {
5707  // check if isConst mismatches
5708  if (scope->function->isConst() != func->isConst()) {
5709  if (scope->function->isConst()) {
5710  ++i;
5711  continue;
5712  }
5713  constFallback = true;
5714  }
5715  }
5716  }
5717 
5718  size_t fallback1 = 0;
5719  size_t fallback2 = 0;
5720  bool erased = false;
5721  for (std::size_t j = 0; j < args; ++j) {
5722 
5723  // don't check variadic arguments
5724  if (func->isVariadic() && j > (func->argCount() - 1)) {
5725  break;
5726  }
5727  const Variable *funcarg = func->getArgumentVar(j);
5728 
5729  if (!arguments[j]->valueType()) {
5730  const Token *vartok = arguments[j];
5731  int pointer = 0;
5732  while (vartok && (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))) {
5733  pointer += vartok->isUnaryOp("&") ? 1 : -1;
5734  vartok = vartok->astOperand1();
5735  }
5736  if (vartok && vartok->variable()) {
5737  const Token *callArgTypeToken = vartok->variable()->typeStartToken();
5738  const Token *funcArgTypeToken = funcarg->typeStartToken();
5739 
5740  auto parseDecl = [](const Token *typeToken) -> ValueType {
5741  ValueType ret;
5742  while (Token::Match(typeToken->previous(), "%name%"))
5743  typeToken = typeToken->previous();
5744  while (Token::Match(typeToken, "%name%|*|&|::|<"))
5745  {
5746  if (typeToken->str() == "const")
5747  ret.constness |= (1 << ret.pointer);
5748  else if (typeToken->str() == "volatile")
5749  ret.volatileness |= (1 << ret.pointer);
5750  else if (typeToken->str() == "*")
5751  ret.pointer++;
5752  else if (typeToken->str() == "<") {
5753  if (!typeToken->link())
5754  break;
5755  typeToken = typeToken->link();
5756  }
5757  typeToken = typeToken->next();
5758  }
5759  return ret;
5760  };
5761 
5762  const std::string type1 = getTypeString(callArgTypeToken);
5763  const std::string type2 = getTypeString(funcArgTypeToken);
5764  if (!type1.empty() && type1 == type2) {
5765  ValueType callArgType = parseDecl(callArgTypeToken);
5766  callArgType.pointer += pointer;
5767  ValueType funcArgType = parseDecl(funcArgTypeToken);
5768 
5769  callArgType.sign = funcArgType.sign = ValueType::Sign::SIGNED;
5770  callArgType.type = funcArgType.type = ValueType::Type::INT;
5771 
5772  const ValueType::MatchResult res = ValueType::matchParameter(&callArgType, &funcArgType);
5773  if (res == ValueType::MatchResult::SAME)
5774  ++same;
5775  else if (res == ValueType::MatchResult::FALLBACK1)
5776  ++fallback1;
5777  else if (res == ValueType::MatchResult::FALLBACK2)
5778  ++fallback2;
5779  continue;
5780  }
5781  }
5782  }
5783 
5784  // check for a match with a variable
5785  if (Token::Match(arguments[j], "%var% ,|)")) {
5786  const Variable * callarg = arguments[j]->variable();
5787  checkVariableCallMatch(callarg, funcarg, same, fallback1, fallback2);
5788  }
5789 
5790  else if (funcarg->isStlStringType() && arguments[j]->valueType() && arguments[j]->valueType()->pointer == 1 && arguments[j]->valueType()->type == ValueType::Type::CHAR)
5791  fallback2++;
5792 
5793  // check for a match with nullptr
5794  else if (funcarg->isPointer() && Token::Match(arguments[j], "nullptr|NULL ,|)"))
5795  same++;
5796 
5797  else if (funcarg->isPointer() && MathLib::isNullValue(arguments[j]->str()))
5798  fallback1++;
5799 
5800  else if (!funcarg->isPointer() && funcarg->type() && hasMatchingConstructor(funcarg->type()->classScope, arguments[j]->valueType()))
5801  fallback2++;
5802 
5803  // Try to evaluate the apparently more complex expression
5804  else if (arguments[j]->isCpp()) {
5805  const Token *vartok = arguments[j];
5806  if (vartok->str() == ".") {
5807  const Token* rml = nextAfterAstRightmostLeaf(vartok);
5808  if (rml)
5809  vartok = rml->previous();
5810  }
5811  while (vartok->isUnaryOp("&") || vartok->isUnaryOp("*"))
5812  vartok = vartok->astOperand1();
5813  const Variable* var = vartok->variable();
5814  // smart pointer deref?
5815  bool unknownDeref = false;
5816  if (var && vartok->astParent() && vartok->astParent()->str() == "*") {
5817  if (var->isSmartPointer() && var->valueType() && var->valueType()->smartPointerTypeToken)
5818  var = var->valueType()->smartPointerTypeToken->variable();
5819  else
5820  unknownDeref = true;
5821  }
5822  const Token* valuetok = arguments[j];
5823  if (valuetok->str() == "::") {
5824  const Token* rml = nextAfterAstRightmostLeaf(valuetok);
5825  if (rml)
5826  valuetok = rml->previous();
5827  }
5828  if (vartok->isEnumerator())
5829  valuetok = vartok;
5830  const ValueType::MatchResult res = ValueType::matchParameter(valuetok->valueType(), var, funcarg);
5831  if (res == ValueType::MatchResult::SAME)
5832  ++same;
5833  else if (res == ValueType::MatchResult::FALLBACK1)
5834  ++fallback1;
5835  else if (res == ValueType::MatchResult::FALLBACK2)
5836  ++fallback2;
5837  else if (res == ValueType::MatchResult::NOMATCH) {
5838  if (unknownDeref)
5839  continue;
5840  // can't match so remove this function from possible matches
5841  matches.erase(matches.begin() + i);
5842  erased = true;
5843  break;
5844  }
5845  }
5846 
5847  else
5848  // C code: if number of arguments match then do not match types
5849  fallback1++;
5850  }
5851 
5852  const size_t hasToBe = func->isVariadic() ? (func->argCount() - 1) : args;
5853 
5854  // check if all arguments matched
5855  if (same == hasToBe) {
5856  if (constFallback || (!requireConst && func->isConst()))
5857  fallback1Func.emplace_back(func);
5858  else
5859  return func;
5860  }
5861 
5862  else {
5863  if (same + fallback1 == hasToBe)
5864  fallback1Func.emplace_back(func);
5865  else if (same + fallback2 + fallback1 == hasToBe)
5866  fallback2Func.emplace_back(func);
5867  }
5868 
5869  if (!erased)
5870  ++i;
5871  }
5872 
5873  // Fallback cases
5874  for (const auto& fb : { fallback1Func, fallback2Func }) {
5875  if (fb.size() == 1)
5876  return fb.front();
5877  if (fb.size() == 2) {
5878  if (fb[0]->isConst() && !fb[1]->isConst())
5879  return fb[1];
5880  if (fb[1]->isConst() && !fb[0]->isConst())
5881  return fb[0];
5882  }
5883  }
5884 
5885  // remove pure virtual function if there is an overrider
5886  auto itPure = std::find_if(matches.begin(), matches.end(), [](const Function* m) {
5887  return m->isPure();
5888  });
5889  if (itPure != matches.end() && std::any_of(matches.begin(), matches.end(), [&](const Function* m) {
5890  return m->isImplicitlyVirtual() && m != *itPure;
5891  }))
5892  matches.erase(itPure);
5893 
5894  // Only one candidate left
5895  if (matches.size() == 1)
5896  return matches[0];
5897 
5898  // Prioritize matches in derived scopes
5899  for (const auto& fb : { fallback1Func, fallback2Func }) {
5900  const Function* ret = nullptr;
5901  for (int i = 0; i < fb.size(); ++i) {
5902  if (std::find(matches.cbegin(), matches.cend(), fb[i]) == matches.cend())
5903  continue;
5904  if (this == fb[i]->nestedIn) {
5905  if (!ret)
5906  ret = fb[i];
5907  else {
5908  ret = nullptr;
5909  break;
5910  }
5911  }
5912  }
5913  if (ret)
5914  return ret;
5915  }
5916 
5917  return nullptr;
5918 }
5919 
5920 //---------------------------------------------------------------------------
5921 
5922 const Function* SymbolDatabase::findFunction(const Token* const tok) const
5923 {
5924  // find the scope this function is in
5925  const Scope *currScope = tok->scope();
5926  while (currScope && currScope->isExecutable()) {
5927  if (const Function* f = currScope->findFunction(tok)) {
5928  return f;
5929  }
5930  if (currScope->functionOf)
5931  currScope = currScope->functionOf;
5932  else
5933  currScope = currScope->nestedIn;
5934  }
5935 
5936  // check for a qualified name and use it when given
5937  if (tok->strAt(-1) == "::") {
5938  // find start of qualified function name
5939  const Token *tok1 = tok;
5940 
5941  while (Token::Match(tok1->tokAt(-2), ">|%type% ::")) {
5942  if (tok1->strAt(-2) == ">") {
5943  if (tok1->linkAt(-2))
5944  tok1 = tok1->linkAt(-2)->tokAt(-1);
5945  else
5946  break;
5947  } else
5948  tok1 = tok1->tokAt(-2);
5949  }
5950 
5951  // check for global scope
5952  if (tok1->strAt(-1) == "::") {
5953  currScope = &scopeList.front();
5954 
5955  if (const Function* f = currScope->findFunction(tok))
5956  return f;
5957 
5958  currScope = currScope->findRecordInNestedList(tok1->str());
5959  }
5960 
5961  // find start of qualification
5962  else {
5963  while (currScope) {
5964  if (currScope->className == tok1->str())
5965  break;
5966 
5967  const Scope *scope = currScope->findRecordInNestedList(tok1->str());
5968 
5969  if (scope) {
5970  currScope = scope;
5971  break;
5972  }
5973  currScope = currScope->nestedIn;
5974  }
5975  }
5976 
5977  if (currScope) {
5978  while (currScope && tok1 && !(Token::Match(tok1, "%type% :: %name% [(),>]") ||
5979  (Token::Match(tok1, "%type% <") && Token::Match(tok1->linkAt(1), "> :: %name% (")))) {
5980  if (tok1->strAt(1) == "::")
5981  tok1 = tok1->tokAt(2);
5982  else if (tok1->strAt(1) == "<")
5983  tok1 = tok1->linkAt(1)->tokAt(2);
5984  else
5985  tok1 = nullptr;
5986 
5987  if (tok1) {
5988  const Function* func = currScope->findFunction(tok1);
5989  if (func)
5990  return func;
5991 
5992  currScope = currScope->findRecordInNestedList(tok1->str());
5993  }
5994  }
5995 
5996  if (tok1)
5997  tok1 = tok1->tokAt(2);
5998 
5999  if (currScope && tok1) {
6000  const Function* func = currScope->findFunction(tok1);
6001  if (func)
6002  return func;
6003  }
6004  }
6005  }
6006 
6007  // check for member function
6008  else if (Token::Match(tok->tokAt(-2), "!!this .")) {
6009  const Token* tok1 = tok->previous()->astOperand1();
6010  if (tok1 && tok1->valueType() && tok1->valueType()->typeScope)
6011  return tok1->valueType()->typeScope->findFunction(tok, tok1->valueType()->constness == 1);
6012  if (tok1 && Token::Match(tok1->previous(), "%name% (") && tok1->previous()->function() &&
6013  tok1->previous()->function()->retDef) {
6014  ValueType vt = ValueType::parseDecl(tok1->previous()->function()->retDef, mSettings);
6015  if (vt.typeScope)
6016  return vt.typeScope->findFunction(tok, vt.constness == 1);
6017  } else if (Token::Match(tok1, "%var% .")) {
6018  const Variable *var = getVariableFromVarId(tok1->varId());
6019  if (var && var->typeScope())
6020  return var->typeScope()->findFunction(tok, var->valueType()->constness == 1);
6021  if (var && var->smartPointerType() && var->smartPointerType()->classScope && tok1->next()->originalName() == "->")
6022  return var->smartPointerType()->classScope->findFunction(tok, var->valueType()->constness == 1);
6023  if (var && var->iteratorType() && var->iteratorType()->classScope && tok1->next()->originalName() == "->")
6024  return var->iteratorType()->classScope->findFunction(tok, var->valueType()->constness == 1);
6025  } else if (Token::simpleMatch(tok->previous()->astOperand1(), "(")) {
6026  const Token *castTok = tok->previous()->astOperand1();
6027  if (castTok->isCast()) {
6028  ValueType vt = ValueType::parseDecl(castTok->next(),mSettings);
6029  if (vt.typeScope)
6030  return vt.typeScope->findFunction(tok, vt.constness == 1);
6031  }
6032  }
6033  }
6034 
6035  // check in enclosing scopes
6036  else {
6037  while (currScope) {
6038  const Function *func = currScope->findFunction(tok);
6039  if (func)
6040  return func;
6041  currScope = currScope->nestedIn;
6042  }
6043  // check using namespace
6044  currScope = tok->scope();
6045  while (currScope) {
6046  for (const auto& ul : currScope->usingList) {
6047  if (ul.scope) {
6048  const Function* func = ul.scope->findFunction(tok);
6049  if (func)
6050  return func;
6051  }
6052  }
6053  currScope = currScope->nestedIn;
6054  }
6055  }
6056  // Check for constructor
6057  if (Token::Match(tok, "%name% (|{")) {
6059  if (vt.typeScope)
6060  return vt.typeScope->findFunction(tok, false);
6061  }
6062  return nullptr;
6063 }
6064 
6065 //---------------------------------------------------------------------------
6066 
6067 const Scope *SymbolDatabase::findScopeByName(const std::string& name) const
6068 {
6069  auto it = std::find_if(scopeList.cbegin(), scopeList.cend(), [&](const Scope& s) {
6070  return s.className == name;
6071  });
6072  return it == scopeList.end() ? nullptr : &*it;
6073 }
6074 
6075 //---------------------------------------------------------------------------
6076 
6077 template<class S, class T, REQUIRES("S must be a Scope class", std::is_convertible<S*, const Scope*> ), REQUIRES("T must be a Type class", std::is_convertible<T*, const Type*> )>
6078 S* findRecordInNestedListImpl(S& thisScope, const std::string & name, bool isC)
6079 {
6080  for (S* scope: thisScope.nestedList) {
6081  if (scope->className == name && scope->type != Scope::eFunction)
6082  return scope;
6083  if (isC) {
6084  S* nestedScope = scope->findRecordInNestedList(name, isC);
6085  if (nestedScope)
6086  return nestedScope;
6087  }
6088  }
6089 
6090  T * nested_type = thisScope.findType(name);
6091 
6092  if (nested_type) {
6093  if (nested_type->isTypeAlias()) {
6094  if (nested_type->typeStart == nested_type->typeEnd)
6095  return thisScope.findRecordInNestedList(nested_type->typeStart->str()); // TODO: pass isC?
6096  } else
6097  return const_cast<S*>(nested_type->classScope);
6098  }
6099 
6100  return nullptr;
6101 }
6102 
6103 const Scope* Scope::findRecordInNestedList(const std::string & name, bool isC) const
6104 {
6105  return findRecordInNestedListImpl<const Scope, const Type>(*this, name, isC);
6106 }
6107 
6108 Scope* Scope::findRecordInNestedList(const std::string & name, bool isC)
6109 {
6110  return findRecordInNestedListImpl<Scope, Type>(*this, name, isC);
6111 }
6112 
6113 //---------------------------------------------------------------------------
6114 
6115 template<class S, class T, REQUIRES("S must be a Scope class", std::is_convertible<S*, const Scope*> ), REQUIRES("T must be a Type class", std::is_convertible<T*, const Type*> )>
6116 T* findTypeImpl(S& thisScope, const std::string & name)
6117 {
6118  auto it = thisScope.definedTypesMap.find(name);
6119 
6120  // Type was found
6121  if (thisScope.definedTypesMap.end() != it)
6122  return it->second;
6123 
6124  // is type defined in anonymous namespace..
6125  it = thisScope.definedTypesMap.find(emptyString);
6126  if (it != thisScope.definedTypesMap.end()) {
6127  for (S *scope : thisScope.nestedList) {
6128  if (scope->className.empty() && (scope->type == thisScope.eNamespace || scope->isClassOrStructOrUnion())) {
6129  T *t = scope->findType(name);
6130  if (t)
6131  return t;
6132  }
6133  }
6134  }
6135 
6136  // Type was not found
6137  return nullptr;
6138 }
6139 
6140 const Type* Scope::findType(const std::string& name) const
6141 {
6142  return findTypeImpl<const Scope, const Type>(*this, name);
6143 }
6144 
6145 Type* Scope::findType(const std::string& name)
6146 {
6147  return findTypeImpl<Scope, Type>(*this, name);
6148 }
6149 
6150 //---------------------------------------------------------------------------
6151 
6152 Scope *Scope::findInNestedListRecursive(const std::string & name)
6153 {
6154  auto it = std::find_if(nestedList.cbegin(), nestedList.cend(), [&](const Scope* s) {
6155  return s->className == name;
6156  });
6157  if (it != nestedList.end())
6158  return *it;
6159 
6160  for (Scope* scope: nestedList) {
6161  Scope *child = scope->findInNestedListRecursive(name);
6162  if (child)
6163  return child;
6164  }
6165  return nullptr;
6166 }
6167 
6168 //---------------------------------------------------------------------------
6169 
6171 {
6172  auto it = std::find_if(functionList.cbegin(), functionList.cend(), [](const Function& f) {
6173  return f.type == Function::eDestructor;
6174  });
6175  return it == functionList.end() ? nullptr : &*it;
6176 }
6177 
6178 //---------------------------------------------------------------------------
6179 
6180 const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const
6181 {
6182  const Scope *scope = nullptr;
6183  // absolute path
6184  if (tok->str() == "::") {
6185  tok = tok->next();
6186  scope = &scopeList.front();
6187  }
6188  // relative path
6189  else if (tok->isName()) {
6190  scope = startScope;
6191  }
6192 
6193  while (scope && tok && tok->isName()) {
6194  if (tok->strAt(1) == "::") {
6195  scope = scope->findRecordInNestedList(tok->str());
6196  tok = tok->tokAt(2);
6197  } else if (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::")) {
6198  scope = scope->findRecordInNestedList(tok->str());
6199  tok = tok->linkAt(1)->tokAt(2);
6200  } else
6201  return scope->findRecordInNestedList(tok->str());
6202  }
6203 
6204  // not a valid path
6205  return nullptr;
6206 }
6207 
6208 //---------------------------------------------------------------------------
6209 
6210 const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startScope, bool lookOutside) const
6211 {
6212  // skip over struct or union
6213  if (Token::Match(startTok, "struct|union"))
6214  startTok = startTok->next();
6215 
6216  // type same as scope
6217  if (startTok->str() == startScope->className && startScope->isClassOrStruct() && startTok->strAt(1) != "::")
6218  return startScope->definedType;
6219 
6220  if (startTok->isC()) {
6221  const Scope* scope = startScope;
6222  while (scope) {
6223  if (startTok->str() == scope->className && scope->isClassOrStruct())
6224  return scope->definedType;
6225  const Scope* typeScope = scope->findRecordInNestedList(startTok->str(), /*isC*/ true);
6226  if (typeScope) {
6227  if (startTok->str() == typeScope->className && typeScope->isClassOrStruct()) {
6228  if (const Type* type = typeScope->definedType)
6229  return type;
6230  }
6231  }
6232  scope = scope->nestedIn;
6233  }
6234  return nullptr;
6235  }
6236 
6237  const Scope* start_scope = startScope;
6238 
6239  // absolute path - directly start in global scope
6240  if (startTok->str() == "::") {
6241  startTok = startTok->next();
6242  start_scope = &scopeList.front();
6243  }
6244 
6245  const Token* tok = startTok;
6246  const Scope* scope = start_scope;
6247 
6248  while (scope && tok && tok->isName()) {
6249  if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6250  scope = scope->findRecordInNestedList(tok->str());
6251  if (scope) {
6252  if (tok->strAt(1) == "::")
6253  tok = tok->tokAt(2);
6254  else
6255  tok = tok->linkAt(1)->tokAt(2);
6256  } else {
6257  start_scope = start_scope->nestedIn;
6258  if (!start_scope)
6259  break;
6260  scope = start_scope;
6261  tok = startTok;
6262  }
6263  } else {
6264  const Scope* scope1{};
6265  const Type* type = scope->findType(tok->str());
6266  if (type)
6267  return type;
6268  if (lookOutside && (scope1 = scope->findRecordInBase(tok->str()))) {
6269  type = scope1->definedType;
6270  if (type)
6271  return type;
6272  } else if (lookOutside && scope->type == Scope::ScopeType::eNamespace) {
6273  scope = scope->nestedIn;
6274  continue;
6275  } else
6276  break;
6277  }
6278  }
6279 
6280  // check using namespaces
6281  while (startScope) {
6282  for (std::vector<Scope::UsingInfo>::const_iterator it = startScope->usingList.cbegin();
6283  it != startScope->usingList.cend(); ++it) {
6284  tok = startTok;
6285  scope = it->scope;
6286  start_scope = startScope;
6287 
6288  while (scope && tok && tok->isName()) {
6289  if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6290  scope = scope->findRecordInNestedList(tok->str());
6291  if (scope) {
6292  if (tok->strAt(1) == "::")
6293  tok = tok->tokAt(2);
6294  else
6295  tok = tok->linkAt(1)->tokAt(2);
6296  } else {
6297  start_scope = start_scope->nestedIn;
6298  if (!start_scope)
6299  break;
6300  scope = start_scope;
6301  tok = startTok;
6302  }
6303  } else {
6304  const Type * type = scope->findType(tok->str());
6305  if (type)
6306  return type;
6307  if (const Scope *scope1 = scope->findRecordInBase(tok->str())) {
6308  type = scope1->definedType;
6309  if (type)
6310  return type;
6311  } else
6312  break;
6313  }
6314  }
6315  }
6316  startScope = startScope->nestedIn;
6317  }
6318 
6319  // not a valid path
6320  return nullptr;
6321 }
6322 
6323 //---------------------------------------------------------------------------
6324 
6325 const Type* SymbolDatabase::findTypeInNested(const Token *startTok, const Scope *startScope) const
6326 {
6327  // skip over struct or union
6328  if (Token::Match(startTok, "struct|union|enum"))
6329  startTok = startTok->next();
6330 
6331  // type same as scope
6332  if (startScope->isClassOrStruct() && startTok->str() == startScope->className && !Token::simpleMatch(startTok->next(), "::"))
6333  return startScope->definedType;
6334 
6335  bool hasPath = false;
6336 
6337  // absolute path - directly start in global scope
6338  if (startTok->str() == "::") {
6339  hasPath = true;
6340  startTok = startTok->next();
6341  startScope = &scopeList.front();
6342  }
6343 
6344  const Token* tok = startTok;
6345  const Scope* scope = startScope;
6346 
6347  while (scope && tok && tok->isName()) {
6348  if (tok->strAt(1) == "::" || (tok->strAt(1) == "<" && Token::simpleMatch(tok->linkAt(1), "> ::"))) {
6349  hasPath = true;
6350  scope = scope->findRecordInNestedList(tok->str());
6351  if (scope) {
6352  if (tok->strAt(1) == "::")
6353  tok = tok->tokAt(2);
6354  else
6355  tok = tok->linkAt(1)->tokAt(2);
6356  } else {
6357  startScope = startScope->nestedIn;
6358  if (!startScope)
6359  break;
6360  scope = startScope;
6361  tok = startTok;
6362  }
6363  } else {
6364  const Type * type = scope->findType(tok->str());
6365  if (hasPath || type)
6366  return type;
6367 
6368  scope = scope->nestedIn;
6369  if (!scope)
6370  break;
6371  }
6372  }
6373 
6374  // not a valid path
6375  return nullptr;
6376 }
6377 
6378 //---------------------------------------------------------------------------
6379 
6380 const Scope * SymbolDatabase::findNamespace(const Token * tok, const Scope * scope) const
6381 {
6382  const Scope * s = findScope(tok, scope);
6383 
6384  if (s)
6385  return s;
6386  if (scope->nestedIn)
6387  return findNamespace(tok, scope->nestedIn);
6388 
6389  return nullptr;
6390 }
6391 
6392 //---------------------------------------------------------------------------
6393 
6394 Function * SymbolDatabase::findFunctionInScope(const Token *func, const Scope *ns, const std::string & path, nonneg int path_length)
6395 {
6396  const Function * function = nullptr;
6397  const bool destructor = func->strAt(-1) == "~";
6398 
6399  auto range = ns->functionMap.equal_range(func->str());
6400  for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
6401  if (it->second->argsMatch(ns, it->second->argDef, func->next(), path, path_length) &&
6402  it->second->isDestructor() == destructor) {
6403  function = it->second;
6404  break;
6405  }
6406  }
6407 
6408  if (!function) {
6409  const Scope * scope = ns->findRecordInNestedList(func->str());
6410  if (scope && Token::Match(func->tokAt(1), "::|<")) {
6411  if (func->strAt(1) == "::")
6412  func = func->tokAt(2);
6413  else if (func->linkAt(1))
6414  func = func->linkAt(1)->tokAt(2);
6415  else
6416  return nullptr;
6417  if (func->str() == "~")
6418  func = func->next();
6419  function = findFunctionInScope(func, scope, path, path_length);
6420  }
6421  }
6422 
6423  return const_cast<Function *>(function);
6424 }
6425 
6426 //---------------------------------------------------------------------------
6427 
6429 {
6430  const std::string& iName = tok->str();
6431  if (tok->isCpp()) {
6432  static const auto& cpp_keywords = Keywords::getAll(Standards::cppstd_t::CPPLatest);
6433  return cpp_keywords.find(iName) != cpp_keywords.cend();
6434  }
6435  static const auto& c_keywords = Keywords::getAll(Standards::cstd_t::CLatest);
6436  return c_keywords.find(iName) != c_keywords.cend();
6437 }
6438 
6440 {
6441  int size = mTokenizer.sizeOfType(type);
6442 
6443  if (size == 0 && type->type() && type->type()->isEnumType() && type->type()->classScope) {
6444  size = mSettings.platform.sizeof_int;
6445  const Token * enum_type = type->type()->classScope->enumType;
6446  if (enum_type)
6447  size = mTokenizer.sizeOfType(enum_type);
6448  }
6449 
6450  return size;
6451 }
6452 
6453 static const Token* parsedecl(const Token* type,
6454  ValueType* const valuetype,
6455  ValueType::Sign defaultSignedness,
6456  const Settings& settings,
6458 
6459 void SymbolDatabase::setValueType(Token* tok, const Variable& var, const SourceLocation &loc)
6460 {
6461  ValueType valuetype;
6463  valuetype.setDebugPath(tok, loc);
6464  if (var.nameToken())
6465  valuetype.bits = var.nameToken()->bits();
6466 
6467  valuetype.pointer = var.dimensions().size();
6468  // HACK: don't set pointer for plain std::array
6469  if (var.valueType() && var.valueType()->container && Token::simpleMatch(var.typeStartToken(), "std :: array") && !Token::simpleMatch(var.nameToken()->next(), "["))
6470  valuetype.pointer = 0;
6471 
6472  valuetype.typeScope = var.typeScope();
6473  if (var.valueType()) {
6474  valuetype.container = var.valueType()->container;
6475  valuetype.containerTypeToken = var.valueType()->containerTypeToken;
6476  }
6477  valuetype.smartPointerType = var.smartPointerType();
6478  if (parsedecl(var.typeStartToken(), &valuetype, mDefaultSignedness, mSettings)) {
6479  if (tok->str() == "." && tok->astOperand1()) {
6480  const ValueType * const vt = tok->astOperand1()->valueType();
6481  if (vt && (vt->constness & 1) != 0)
6482  valuetype.constness |= 1;
6483  if (vt && (vt->volatileness & 1) != 0)
6484  valuetype.volatileness |= 1;
6485  }
6486  setValueType(tok, valuetype);
6487  }
6488 }
6489 
6490 static ValueType::Type getEnumType(const Scope* scope, const Platform& platform);
6491 
6492 void SymbolDatabase::setValueType(Token* tok, const Enumerator& enumerator, const SourceLocation &loc)
6493 {
6494  ValueType valuetype;
6496  valuetype.setDebugPath(tok, loc);
6497  valuetype.typeScope = enumerator.scope;
6498  const Token * type = enumerator.scope->enumType;
6499  if (type) {
6500  valuetype.type = ValueType::typeFromString(type->str(), type->isLong());
6501  if (valuetype.type == ValueType::Type::UNKNOWN_TYPE && type->isStandardType())
6502  valuetype.fromLibraryType(type->str(), mSettings);
6503 
6504  if (valuetype.isIntegral()) {
6505  if (type->isSigned())
6506  valuetype.sign = ValueType::Sign::SIGNED;
6507  else if (type->isUnsigned())
6508  valuetype.sign = ValueType::Sign::UNSIGNED;
6509  else if (valuetype.type == ValueType::Type::CHAR)
6510  valuetype.sign = mDefaultSignedness;
6511  else
6512  valuetype.sign = ValueType::Sign::SIGNED;
6513  }
6514 
6515  setValueType(tok, valuetype);
6516  } else {
6517  valuetype.sign = ValueType::SIGNED;
6518  valuetype.type = getEnumType(enumerator.scope, mSettings.platform);
6519  setValueType(tok, valuetype);
6520  }
6521 }
6522 
6523 static void setAutoTokenProperties(Token * const autoTok)
6524 {
6525  const ValueType *valuetype = autoTok->valueType();
6526  if (valuetype->isIntegral() || valuetype->isFloat())
6527  autoTok->isStandardType(true);
6528 }
6529 
6531 {
6534 }
6535 
6537 {
6539 }
6540 
6541 void SymbolDatabase::setValueType(Token* tok, const ValueType& valuetype, const SourceLocation &loc)
6542 {
6543  auto* valuetypePtr = new ValueType(valuetype);
6545  valuetypePtr->setDebugPath(tok, loc);
6546  tok->setValueType(valuetypePtr);
6547  Token *parent = tok->astParent();
6548  if (!parent || parent->valueType())
6549  return;
6550  if (!parent->astOperand1())
6551  return;
6552 
6553  const ValueType *vt1 = parent->astOperand1()->valueType();
6554  const ValueType *vt2 = parent->astOperand2() ? parent->astOperand2()->valueType() : nullptr;
6555 
6556  if (vt1 && Token::Match(parent, "<<|>>")) {
6557  if (!parent->isCpp() || (vt2 && vt2->isIntegral())) {
6558  if (vt1->type < ValueType::Type::BOOL || vt1->type >= ValueType::Type::INT) {
6559  ValueType vt(*vt1);
6561  setValueType(parent, vt);
6562  } else {
6563  ValueType vt(*vt1);
6564  vt.type = ValueType::Type::INT; // Integer promotion
6565  vt.sign = ValueType::Sign::SIGNED;
6567  setValueType(parent, vt);
6568  }
6569 
6570  }
6571  return;
6572  }
6573 
6574  if (vt1 && vt1->container && vt1->containerTypeToken && Token::Match(parent, ". %name% (") &&
6575  isContainerYieldElement(vt1->container->getYield(parent->next()->str()))) {
6576  ValueType item;
6578  if (item.constness == 0)
6579  item.constness = vt1->constness;
6580  if (item.volatileness == 0)
6581  item.volatileness = vt1->volatileness;
6582  if (isContainerYieldPointer(vt1->container->getYield(parent->next()->str())))
6583  item.pointer += 1;
6584  else
6586  setValueType(parent->tokAt(2), item);
6587  }
6588  }
6589 
6590  if (vt1 && vt1->smartPointerType && Token::Match(parent, ". %name% (") && parent->originalName() == "->" && !parent->next()->function()) {
6591  const Scope *scope = vt1->smartPointerType->classScope;
6592  const Function *f = scope ? scope->findFunction(parent->next(), false) : nullptr;
6593  if (f)
6594  parent->next()->function(f);
6595  }
6596 
6597  if (parent->isAssignmentOp()) {
6598  if (vt1) {
6599  auto vt = *vt1;
6601  setValueType(parent, vt);
6602  } else if (parent->isCpp() && ((Token::Match(parent->tokAt(-3), "%var% ; %var% =") && parent->strAt(-3) == parent->strAt(-1)) ||
6603  Token::Match(parent->tokAt(-1), "%var% ="))) {
6604  Token *var1Tok = parent->strAt(-2) == ";" ? parent->tokAt(-3) : parent->tokAt(-1);
6605  Token *autoTok = nullptr;
6606  if (Token::simpleMatch(var1Tok->tokAt(-1), "auto"))
6607  autoTok = var1Tok->previous();
6608  else if (Token::Match(var1Tok->tokAt(-2), "auto *|&|&&"))
6609  autoTok = var1Tok->tokAt(-2);
6610  else if (Token::simpleMatch(var1Tok->tokAt(-3), "auto * const"))
6611  autoTok = var1Tok->tokAt(-3);
6612  if (autoTok) {
6613  ValueType vt(*vt2);
6614  if (vt.constness & (1 << vt.pointer))
6615  vt.constness &= ~(1 << vt.pointer);
6616  if (vt.volatileness & (1 << vt.pointer))
6617  vt.volatileness &= ~(1 << vt.pointer);
6618  if (autoTok->strAt(1) == "*" && vt.pointer)
6619  vt.pointer--;
6620  if (Token::Match(autoTok->tokAt(-1), "const|constexpr"))
6621  vt.constness |= (1 << vt.pointer);
6622  if (Token::simpleMatch(autoTok->tokAt(-1), "volatile"))
6623  vt.volatileness |= (1 << vt.pointer);
6624  setValueType(autoTok, vt);
6625  setAutoTokenProperties(autoTok);
6626  if (vt2->pointer > vt.pointer)
6627  vt.pointer++;
6628  setValueType(var1Tok, vt);
6629  if (var1Tok != parent->previous())
6630  setValueType(parent->previous(), vt);
6631  auto *var = const_cast<Variable *>(parent->previous()->variable());
6632  if (var) {
6633  ValueType vt2_(*vt2);
6634  if (vt2_.pointer == 0 && autoTok->strAt(1) == "*")
6635  vt2_.pointer = 1;
6636  if ((vt.constness & (1 << vt2->pointer)) != 0)
6637  vt2_.constness |= (1 << vt2->pointer);
6638  if ((vt.volatileness & (1 << vt2->pointer)) != 0)
6639  vt2_.volatileness |= (1 << vt2->pointer);
6640  if (!Token::Match(autoTok->tokAt(1), "*|&")) {
6641  vt2_.constness = vt.constness;
6642  vt2_.volatileness = vt.volatileness;
6643  }
6644  if (Token::simpleMatch(autoTok->tokAt(1), "* const"))
6645  vt2_.constness |= (1 << vt2->pointer);
6646  if (Token::simpleMatch(autoTok->tokAt(1), "* volatile"))
6647  vt2_.volatileness |= (1 << vt2->pointer);
6648  var->setValueType(vt2_);
6649  if (vt2->typeScope && vt2->typeScope->definedType) {
6650  var->type(vt2->typeScope->definedType);
6651  if (autoTok->valueType()->pointer == 0)
6652  autoTok->type(vt2->typeScope->definedType);
6653  }
6654  }
6655  }
6656  }
6657  return;
6658  }
6659 
6660  if (parent->str() == "[" && (!parent->isCpp() || parent->astOperand1() == tok) && valuetype.pointer > 0U && !Token::Match(parent->previous(), "[{,]")) {
6661  const Token *op1 = parent->astOperand1();
6662  while (op1 && op1->str() == "[")
6663  op1 = op1->astOperand1();
6664 
6665  ValueType vt(valuetype);
6666  // the "[" is a dereference unless this is a variable declaration
6667  if (!(op1 && op1->variable() && op1->variable()->nameToken() == op1))
6668  vt.pointer -= 1U;
6669  setValueType(parent, vt);
6670  return;
6671  }
6672  if (Token::Match(parent->previous(), "%name% (") && parent->astOperand1() == tok && valuetype.pointer > 0U) {
6673  ValueType vt(valuetype);
6674  vt.pointer -= 1U;
6675  setValueType(parent, vt);
6676  return;
6677  }
6678  // std::move
6679  if (vt2 && parent->str() == "(" && Token::simpleMatch(parent->tokAt(-3), "std :: move (")) {
6680  ValueType vt = valuetype;
6682  setValueType(parent, vt);
6683  return;
6684  }
6685  if (parent->str() == "*" && !parent->astOperand2() && valuetype.pointer > 0U) {
6686  ValueType vt(valuetype);
6687  vt.pointer -= 1U;
6688  setValueType(parent, vt);
6689  return;
6690  }
6691  // Dereference iterator
6692  if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::ITERATOR &&
6693  valuetype.containerTypeToken) {
6694  ValueType vt;
6695  if (parsedecl(valuetype.containerTypeToken, &vt, mDefaultSignedness, mSettings)) {
6696  if (vt.constness == 0)
6697  vt.constness = valuetype.constness;
6698  if (vt.volatileness == 0)
6699  vt.volatileness = valuetype.volatileness;
6701  setValueType(parent, vt);
6702  return;
6703  }
6704  }
6705  // Dereference smart pointer
6706  if (parent->str() == "*" && !parent->astOperand2() && valuetype.type == ValueType::Type::SMART_POINTER &&
6707  valuetype.smartPointerTypeToken) {
6708  ValueType vt;
6710  if (vt.constness == 0)
6711  vt.constness = valuetype.constness;
6712  if (vt.volatileness == 0)
6713  vt.volatileness = valuetype.volatileness;
6714  setValueType(parent, vt);
6715  return;
6716  }
6717  }
6718  if (parent->str() == "*" && Token::simpleMatch(parent->astOperand2(), "[") && valuetype.pointer > 0U) {
6719  const Token *op1 = parent->astOperand2()->astOperand1();
6720  while (op1 && op1->str() == "[")
6721  op1 = op1->astOperand1();
6722  const ValueType& vt(valuetype);
6723  if (op1 && op1->variable() && op1->variable()->nameToken() == op1) {
6724  setValueType(parent, vt);
6725  return;
6726  }
6727  }
6728  if (parent->str() == "&" && !parent->astOperand2()) {
6729  ValueType vt(valuetype);
6730  vt.reference = Reference::None; //Given int& x; the type of &x is int* not int&*
6731  bool isArrayToPointerDecay = false;
6732  for (const Token* child = parent->astOperand1(); child;) {
6733  if (Token::Match(child, ".|::"))
6734  child = child->astOperand2();
6735  else {
6736  isArrayToPointerDecay = child->variable() && child->variable()->isArray();
6737  break;
6738  }
6739  }
6740  if (!isArrayToPointerDecay)
6741  vt.pointer += 1U;
6742  setValueType(parent, vt);
6743  return;
6744  }
6745 
6746  if ((parent->str() == "." || parent->str() == "::") &&
6747  parent->astOperand2() && parent->astOperand2()->isName()) {
6748  const Variable* var = parent->astOperand2()->variable();
6749  if (!var && valuetype.typeScope && vt1) {
6750  const std::string &name = parent->astOperand2()->str();
6751  const Scope *typeScope = vt1->typeScope;
6752  if (!typeScope)
6753  return;
6754  auto it = std::find_if(typeScope->varlist.begin(), typeScope->varlist.end(), [&name](const Variable& v) {
6755  return v.nameToken()->str() == name;
6756  });
6757  if (it != typeScope->varlist.end())
6758  var = &*it;
6759  }
6760  if (var) {
6761  setValueType(parent, *var);
6762  return;
6763  }
6764  if (const Enumerator* enu = parent->astOperand2()->enumerator())
6765  setValueType(parent, *enu);
6766  return;
6767  }
6768 
6769  // range for loop, auto
6770  if (vt2 &&
6771  parent->str() == ":" &&
6772  Token::Match(parent->astParent(), "( const| auto *|&|&&| %var% :") && // TODO: east-const, multiple const, ref to ptr
6773  !parent->previous()->valueType() &&
6774  Token::simpleMatch(parent->astParent()->astOperand1(), "for")) {
6775  const bool isconst = Token::simpleMatch(parent->astParent()->next(), "const");
6776  const bool isvolatile = Token::simpleMatch(parent->astParent()->next(), "volatile");
6777  Token * const autoToken = parent->astParent()->tokAt(isconst ? 2 : 1);
6778  if (vt2->pointer) {
6779  ValueType autovt(*vt2);
6780  autovt.pointer--;
6781  autovt.constness = 0;
6782  autovt.volatileness = 0;
6783  setValueType(autoToken, autovt);
6784  setAutoTokenProperties(autoToken);
6785  ValueType varvt(*vt2);
6786  varvt.pointer--;
6787  if (Token::simpleMatch(autoToken->next(), "&"))
6788  varvt.reference = Reference::LValue;
6789  if (isconst) {
6790  if (varvt.pointer && varvt.reference != Reference::None)
6791  varvt.constness |= (1 << varvt.pointer);
6792  else
6793  varvt.constness |= 1;
6794  }
6795  if (isvolatile) {
6796  if (varvt.pointer && varvt.reference != Reference::None)
6797  varvt.volatileness |= (1 << varvt.pointer);
6798  else
6799  varvt.volatileness |= 1;
6800  }
6801  setValueType(parent->previous(), varvt);
6802  auto *var = const_cast<Variable *>(parent->previous()->variable());
6803  if (var) {
6804  var->setValueType(varvt);
6805  if (vt2->typeScope && vt2->typeScope->definedType) {
6806  var->type(vt2->typeScope->definedType);
6807  autoToken->type(vt2->typeScope->definedType);
6808  }
6809  }
6810  } else if (vt2->container) {
6811  // TODO: Determine exact type of RHS
6812  const Token *typeStart = parent->astOperand2();
6813  while (typeStart) {
6814  if (typeStart->variable())
6815  typeStart = typeStart->variable()->typeStartToken();
6816  else if (typeStart->str() == "(" && typeStart->previous() && typeStart->previous()->function())
6817  typeStart = typeStart->previous()->function()->retDef;
6818  else
6819  break;
6820  }
6821 
6822  // Try to determine type of "auto" token.
6823  // TODO: Get type better
6824  bool setType = false;
6825  ValueType autovt;
6826  const Type *templateArgType = nullptr; // container element type / smart pointer type
6827  if (!vt2->container->rangeItemRecordType.empty()) {
6828  setType = true;
6829  autovt.type = ValueType::Type::RECORD;
6830  } else if (vt2->containerTypeToken) {
6832  const Token *smartPointerTypeTok = vt2->containerTypeToken;
6833  while (Token::Match(smartPointerTypeTok, "%name%|::"))
6834  smartPointerTypeTok = smartPointerTypeTok->next();
6835  if (Token::simpleMatch(smartPointerTypeTok, "<")) {
6836  if ((templateArgType = findTypeInNested(smartPointerTypeTok->next(), tok->scope()))) {
6837  setType = true;
6838  autovt.smartPointerType = templateArgType;
6839  autovt.type = ValueType::Type::NONSTD;
6840  }
6841  }
6842  } else if (parsedecl(vt2->containerTypeToken, &autovt, mDefaultSignedness, mSettings)) {
6843  setType = true;
6844  templateArgType = vt2->containerTypeToken->type();
6845  if (Token::simpleMatch(autoToken->next(), "&"))
6846  autovt.reference = Reference::LValue;
6847  else if (Token::simpleMatch(autoToken->next(), "&&"))
6848  autovt.reference = Reference::RValue;
6849  if (autoToken->previous()->str() == "const") {
6850  if (autovt.pointer && autovt.reference != Reference::None)
6851  autovt.constness |= 2;
6852  else
6853  autovt.constness |= 1;
6854  }
6855  if (autoToken->previous()->str() == "volatile") {
6856  if (autovt.pointer && autovt.reference != Reference::None)
6857  autovt.volatileness |= 2;
6858  else
6859  autovt.volatileness |= 1;
6860  }
6861  }
6862  }
6863 
6864  if (setType) {
6865  // Type of "auto" has been determined.. set type information for "auto" and variable tokens
6866  setValueType(autoToken, autovt);
6867  setAutoTokenProperties(autoToken);
6868  ValueType varvt(autovt);
6869  if (autoToken->strAt(1) == "*" && autovt.pointer)
6870  autovt.pointer--;
6871  if (isconst)
6872  varvt.constness |= (1 << autovt.pointer);
6873  if (isvolatile)
6874  varvt.volatileness |= (1 << autovt.pointer);
6875  setValueType(parent->previous(), varvt);
6876  auto * var = const_cast<Variable *>(parent->previous()->variable());
6877  if (var) {
6878  var->setValueType(varvt);
6879  if (templateArgType && templateArgType->classScope && templateArgType->classScope->definedType) {
6880  autoToken->type(templateArgType->classScope->definedType);
6881  var->type(templateArgType->classScope->definedType);
6882  }
6883  }
6884  }
6885  }
6886  }
6887 
6888  if (vt1 && vt1->containerTypeToken && parent->str() == "[") {
6889  ValueType vtParent;
6890  if (parsedecl(vt1->containerTypeToken, &vtParent, mDefaultSignedness, mSettings)) {
6891  setValueType(parent, vtParent);
6892  return;
6893  }
6894  }
6895 
6896  if (parent->isCpp() && vt2 && Token::simpleMatch(parent->previous(), "decltype (")) {
6897  setValueType(parent, *vt2);
6898  return;
6899  }
6900 
6901  // c++17 auto type deduction of braced init list
6902  if (parent->isCpp() && mSettings.standards.cpp >= Standards::CPP17 && vt2 && Token::Match(parent->tokAt(-2), "auto %var% {")) {
6903  Token *autoTok = parent->tokAt(-2);
6904  setValueType(autoTok, *vt2);
6905  setAutoTokenProperties(autoTok);
6906  if (parent->previous()->variable())
6907  const_cast<Variable*>(parent->previous()->variable())->setValueType(*vt2);
6908  else
6909  debugMessage(parent->previous(), "debug", "Missing variable class for variable with varid");
6910  return;
6911  }
6912 
6913  if (!vt1)
6914  return;
6915  if (parent->astOperand2() && !vt2)
6916  return;
6917 
6918  const bool ternary = parent->str() == ":" && parent->astParent() && parent->astParent()->str() == "?";
6919  if (ternary) {
6920  if (vt2 && vt1->pointer == vt2->pointer && vt1->type == vt2->type && vt1->sign == vt2->sign)
6921  setValueType(parent, *vt2);
6922  parent = parent->astParent();
6923  }
6924 
6925  if (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eIncDecOp) {
6926 
6927  // CONTAINER + x => CONTAINER
6928  if (parent->str() == "+" && vt1->type == ValueType::Type::CONTAINER && vt2 && vt2->isIntegral()) {
6929  setValueType(parent, *vt1);
6930  return;
6931  }
6932  // x + CONTAINER => CONTAINER
6933  if (parent->str() == "+" && vt1->isIntegral() && vt2 && vt2->type == ValueType::Type::CONTAINER) {
6934  setValueType(parent, *vt2);
6935  return;
6936  }
6937 
6938  if (parent->isArithmeticalOp()) {
6939  if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
6940  setValueType(parent, *vt1);
6941  return;
6942  }
6943 
6944  if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
6945  setValueType(parent, *vt2);
6946  return;
6947  }
6948  } else if (ternary) {
6949  if (vt1->pointer != 0U && vt2 && vt2->pointer == 0U) {
6950  if (vt2->isPrimitive())
6951  setValueType(parent, *vt1);
6952  else
6953  setValueType(parent, *vt2);
6954  return;
6955  }
6956 
6957  if (vt1->pointer == 0U && vt2 && vt2->pointer != 0U) {
6958  if (vt1->isPrimitive())
6959  setValueType(parent, *vt2);
6960  else
6961  setValueType(parent, *vt1);
6962  return;
6963  }
6964 
6965  if (vt1->isTypeEqual(vt2)) {
6966  setValueType(parent, *vt1);
6967  return;
6968  }
6969  }
6970 
6971  if (vt1->pointer != 0U) {
6972  if (ternary || parent->tokType() == Token::eIncDecOp) // result is pointer
6973  setValueType(parent, *vt1);
6974  else // result is pointer diff
6975  setValueType(parent, ValueType(ValueType::Sign::SIGNED, ValueType::Type::INT, 0U, 0U, "ptrdiff_t"));
6976  return;
6977  }
6978 
6979  if (vt1->type == ValueType::Type::LONGDOUBLE || (vt2 && vt2->type == ValueType::Type::LONGDOUBLE)) {
6980  setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::LONGDOUBLE, 0U));
6981  return;
6982  }
6983  if (vt1->type == ValueType::Type::DOUBLE || (vt2 && vt2->type == ValueType::Type::DOUBLE)) {
6984  setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::DOUBLE, 0U));
6985  return;
6986  }
6987  if (vt1->type == ValueType::Type::FLOAT || (vt2 && vt2->type == ValueType::Type::FLOAT)) {
6988  setValueType(parent, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::FLOAT, 0U));
6989  return;
6990  }
6991 
6992  // iterator +/- integral = iterator
6993  if (vt1->type == ValueType::Type::ITERATOR && vt2 && vt2->isIntegral() &&
6994  (parent->str() == "+" || parent->str() == "-")) {
6995  setValueType(parent, *vt1);
6996  return;
6997  }
6998 
6999  if (parent->str() == "+" && vt1->type == ValueType::Type::CONTAINER && vt2 && vt2->type == ValueType::Type::CONTAINER && vt1->container == vt2->container) {
7000  setValueType(parent, *vt1);
7001  return;
7002  }
7003  }
7004 
7005  if (vt1->isIntegral() && vt1->pointer == 0U &&
7006  (!vt2 || (vt2->isIntegral() && vt2->pointer == 0U)) &&
7007  (ternary || parent->isArithmeticalOp() || parent->tokType() == Token::eBitOp || parent->tokType() == Token::eIncDecOp || parent->isAssignmentOp())) {
7008 
7009  ValueType vt;
7010  if (!vt2 || vt1->type > vt2->type) {
7011  vt.type = vt1->type;
7012  vt.sign = vt1->sign;
7014  } else if (vt1->type == vt2->type) {
7015  vt.type = vt1->type;
7016  if (vt1->sign == ValueType::Sign::UNSIGNED || vt2->sign == ValueType::Sign::UNSIGNED)
7017  vt.sign = ValueType::Sign::UNSIGNED;
7018  else if (vt1->sign == ValueType::Sign::UNKNOWN_SIGN || vt2->sign == ValueType::Sign::UNKNOWN_SIGN)
7019  vt.sign = ValueType::Sign::UNKNOWN_SIGN;
7020  else
7021  vt.sign = ValueType::Sign::SIGNED;
7022  vt.originalTypeName = (vt1->originalTypeName.empty() ? vt2 : vt1)->originalTypeName;
7023  } else {
7024  vt.type = vt2->type;
7025  vt.sign = vt2->sign;
7027  }
7028  if (vt.type < ValueType::Type::INT && !(ternary && vt.type==ValueType::Type::BOOL)) {
7029  vt.type = ValueType::Type::INT;
7030  vt.sign = ValueType::Sign::SIGNED;
7031  vt.originalTypeName.clear();
7032  }
7033 
7034  setValueType(parent, vt);
7035  return;
7036  }
7037 }
7038 
7039 static ValueType::Type getEnumType(const Scope* scope, const Platform& platform) // TODO: also determine sign?
7040 {
7041  ValueType::Type type = ValueType::Type::INT;
7042  for (const Token* tok = scope->bodyStart; tok && tok != scope->bodyEnd; tok = tok->next()) {
7043  if (!tok->isAssignmentOp())
7044  continue;
7045  const Token* vTok = tok->astOperand2();
7046  if (!vTok->hasKnownIntValue()) {
7047  if (!vTok->isLiteral())
7048  continue;
7049  if (const ValueType* vt = vTok->valueType()) {
7050  if ((vt->type > type && (vt->type == ValueType::Type::LONG || vt->type == ValueType::Type::LONGLONG)))
7051  type = vt->type;
7052  }
7053  continue;
7054  }
7055  const MathLib::bigint value = vTok->getKnownIntValue();
7056  if (!platform.isIntValue(value)) {
7057  type = ValueType::Type::LONG;
7058  if (!platform.isLongValue(value))
7059  type = ValueType::Type::LONGLONG;
7060  }
7061  }
7062  return type;
7063 }
7064 
7065 static const Token* parsedecl(const Token* type,
7066  ValueType* const valuetype,
7067  ValueType::Sign defaultSignedness,
7068  const Settings& settings,
7069  SourceLocation loc)
7070 {
7071  if (settings.debugnormal || settings.debugwarnings)
7072  valuetype->setDebugPath(type, loc);
7073  const Token * const previousType = type;
7074  const unsigned int pointer0 = valuetype->pointer;
7075  while (Token::Match(type->previous(), "%name%") && !endsWith(type->previous()->str(), ':'))
7076  type = type->previous();
7077  valuetype->sign = ValueType::Sign::UNKNOWN_SIGN;
7078  if (!valuetype->typeScope && !valuetype->smartPointerType)
7079  valuetype->type = ValueType::Type::UNKNOWN_TYPE;
7080  else if (valuetype->smartPointerType)
7081  valuetype->type = ValueType::Type::SMART_POINTER;
7082  else if (valuetype->typeScope->type == Scope::eEnum) {
7083  const Token * enum_type = valuetype->typeScope->enumType;
7084  if (enum_type) {
7085  if (enum_type->isSigned())
7086  valuetype->sign = ValueType::Sign::SIGNED;
7087  else if (enum_type->isUnsigned())
7088  valuetype->sign = ValueType::Sign::UNSIGNED;
7089  else
7090  valuetype->sign = defaultSignedness;
7091  const ValueType::Type t = ValueType::typeFromString(enum_type->str(), enum_type->isLong());
7092  if (t != ValueType::Type::UNKNOWN_TYPE)
7093  valuetype->type = t;
7094  else if (enum_type->isStandardType())
7095  valuetype->fromLibraryType(enum_type->str(), settings);
7096  } else
7097  valuetype->type = getEnumType(valuetype->typeScope, settings.platform);
7098  } else
7099  valuetype->type = ValueType::Type::RECORD;
7100  bool par = false;
7101  while (Token::Match(type, "%name%|*|&|&&|::|(") && !Token::Match(type, "typename|template") && type->varId() == 0 &&
7102  !type->variable() && !type->function()) {
7103  bool isIterator = false;
7104  if (type->str() == "(") {
7105  if (Token::Match(type->link(), ") const| {"))
7106  break;
7107  if (par)
7108  break;
7109  par = true;
7110  }
7111  if (Token::simpleMatch(type, "decltype (") && type->next()->valueType()) {
7112  const ValueType *vt2 = type->next()->valueType();
7113  if (valuetype->sign == ValueType::Sign::UNKNOWN_SIGN)
7114  valuetype->sign = vt2->sign;
7115  if (valuetype->type == ValueType::Type::UNKNOWN_TYPE)
7116  valuetype->type = vt2->type;
7117  valuetype->constness += vt2->constness;
7118  valuetype->pointer += vt2->pointer;
7119  valuetype->reference = vt2->reference;
7120  type = type->linkAt(1)->next();
7121  continue;
7122  }
7123  if (type->isSigned())
7124  valuetype->sign = ValueType::Sign::SIGNED;
7125  else if (type->isUnsigned())
7126  valuetype->sign = ValueType::Sign::UNSIGNED;
7127  if (valuetype->type == ValueType::Type::UNKNOWN_TYPE &&
7128  type->type() && type->type()->isTypeAlias() && type->type()->typeStart &&
7129  type->type()->typeStart->str() != type->str() && type->type()->typeStart != previousType)
7130  parsedecl(type->type()->typeStart, valuetype, defaultSignedness, settings);
7131  else if (Token::Match(type, "const|constexpr"))
7132  valuetype->constness |= (1 << (valuetype->pointer - pointer0));
7133  else if (Token::simpleMatch(type, "volatile"))
7134  valuetype->volatileness |= (1 << (valuetype->pointer - pointer0));
7135  else if (settings.clang && type->str().size() > 2 && type->str().find("::") < type->str().find('<')) {
7136  TokenList typeTokens(&settings);
7137  std::string::size_type pos1 = 0;
7138  do {
7139  const std::string::size_type pos2 = type->str().find("::", pos1);
7140  if (pos2 == std::string::npos) {
7141  typeTokens.addtoken(type->str().substr(pos1), 0, 0, 0, false);
7142  break;
7143  }
7144  typeTokens.addtoken(type->str().substr(pos1, pos2 - pos1), 0, 0, 0, false);
7145  typeTokens.addtoken("::", 0, 0, 0, false);
7146  pos1 = pos2 + 2;
7147  } while (pos1 < type->str().size());
7148  const Library::Container* container =
7149  settings.library.detectContainerOrIterator(typeTokens.front(), &isIterator);
7150  if (container) {
7151  if (isIterator)
7152  valuetype->type = ValueType::Type::ITERATOR;
7153  else
7154  valuetype->type = ValueType::Type::CONTAINER;
7155  valuetype->container = container;
7156  } else {
7157  const Scope *scope = type->scope();
7158  valuetype->typeScope = scope->check->findScope(typeTokens.front(), scope);
7159  if (valuetype->typeScope)
7160  valuetype->type = (scope->type == Scope::ScopeType::eClass) ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
7161  }
7162  } else if (const Library::Container* container = (type->isCpp() ? settings.library.detectContainerOrIterator(type, &isIterator) : nullptr)) {
7163  if (isIterator)
7164  valuetype->type = ValueType::Type::ITERATOR;
7165  else
7166  valuetype->type = ValueType::Type::CONTAINER;
7167  valuetype->container = container;
7168  while (Token::Match(type, "%type%|::|<") && type->str() != "const") {
7169  if (type->str() == "<" && type->link()) {
7170  if (container->type_templateArgNo >= 0) {
7171  const Token *templateType = type->next();
7172  for (int j = 0; templateType && j < container->type_templateArgNo; j++)
7173  templateType = templateType->nextTemplateArgument();
7174  valuetype->containerTypeToken = templateType;
7175  }
7176  type = type->link();
7177  }
7178  type = type->next();
7179  }
7180  if (type && type->str() == "(" && type->previous()->function())
7181  // we are past the end of the type
7182  type = type->previous();
7183  continue;
7184  } else if (const Library::SmartPointer* smartPointer = (type->isCpp() ? settings.library.detectSmartPointer(type) : nullptr)) {
7185  const Token* argTok = Token::findsimplematch(type, "<");
7186  if (!argTok)
7187  break;
7188  valuetype->smartPointer = smartPointer;
7189  valuetype->smartPointerTypeToken = argTok->next();
7190  valuetype->smartPointerType = argTok->next()->type();
7191  valuetype->type = ValueType::Type::SMART_POINTER;
7192  type = argTok->link();
7193  if (type)
7194  type = type->next();
7195  continue;
7196  } else if (Token::Match(type, "%name% :: %name%")) {
7197  std::string typestr;
7198  const Token *end = type;
7199  while (Token::Match(end, "%name% :: %name%")) {
7200  typestr += end->str() + "::";
7201  end = end->tokAt(2);
7202  }
7203  typestr += end->str();
7204  if (valuetype->fromLibraryType(typestr, settings))
7205  type = end;
7206  } else if (ValueType::Type::UNKNOWN_TYPE != ValueType::typeFromString(type->str(), type->isLong())) {
7207  const ValueType::Type t0 = valuetype->type;
7208  valuetype->type = ValueType::typeFromString(type->str(), type->isLong());
7209  if (t0 == ValueType::Type::LONG) {
7210  if (valuetype->type == ValueType::Type::LONG)
7211  valuetype->type = ValueType::Type::LONGLONG;
7212  else if (valuetype->type == ValueType::Type::DOUBLE)
7213  valuetype->type = ValueType::Type::LONGDOUBLE;
7214  }
7215  } else if (type->str() == "auto") {
7216  const ValueType *vt = type->valueType();
7217  if (!vt)
7218  return nullptr;
7219  valuetype->type = vt->type;
7220  valuetype->pointer = vt->pointer;
7221  valuetype->reference = vt->reference;
7222  if (vt->sign != ValueType::Sign::UNKNOWN_SIGN)
7223  valuetype->sign = vt->sign;
7224  valuetype->constness = vt->constness;
7225  valuetype->volatileness = vt->volatileness;
7226  valuetype->originalTypeName = vt->originalTypeName;
7227  const bool hasConst = Token::simpleMatch(type->previous(), "const");
7228  const bool hasVolatile = Token::simpleMatch(type->previous(), "volatile");
7229  while (Token::Match(type, "%name%|*|&|&&|::") && !type->variable()) {
7230  if (type->str() == "*") {
7231  valuetype->pointer = 1;
7232  if (hasConst)
7233  valuetype->constness = 1;
7234  if (hasVolatile)
7235  valuetype->volatileness = 1;
7236  } else if (type->str() == "&") {
7237  valuetype->reference = Reference::LValue;
7238  } else if (type->str() == "&&") {
7239  valuetype->reference = Reference::RValue;
7240  }
7241  if (type->str() == "const")
7242  valuetype->constness |= (1 << valuetype->pointer);
7243  if (type->str() == "volatile")
7244  valuetype->volatileness |= (1 << valuetype->pointer);
7245  type = type->next();
7246  }
7247  break;
7248  } else if (!valuetype->typeScope && (type->str() == "struct" || type->str() == "enum"))
7249  valuetype->type = type->str() == "struct" ? ValueType::Type::RECORD : ValueType::Type::NONSTD;
7250  else if (!valuetype->typeScope && type->type() && type->type()->classScope) {
7251  if (type->type()->classScope->type == Scope::ScopeType::eEnum) {
7252  valuetype->sign = ValueType::Sign::SIGNED;
7253  valuetype->type = getEnumType(type->type()->classScope, settings.platform);
7254  } else {
7255  valuetype->type = ValueType::Type::RECORD;
7256  }
7257  valuetype->typeScope = type->type()->classScope;
7258  } else if (type->isName() && valuetype->sign != ValueType::Sign::UNKNOWN_SIGN && valuetype->pointer == 0U)
7259  return nullptr;
7260  else if (type->str() == "*")
7261  valuetype->pointer++;
7262  else if (type->str() == "&")
7263  valuetype->reference = Reference::LValue;
7264  else if (type->str() == "&&")
7265  valuetype->reference = Reference::RValue;
7266  else if (type->isStandardType())
7267  valuetype->fromLibraryType(type->str(), settings);
7268  else if (Token::Match(type->previous(), "!!:: %name% !!::"))
7269  valuetype->fromLibraryType(type->str(), settings);
7270  if (!type->originalName().empty())
7271  valuetype->originalTypeName = type->originalName();
7272  type = type->next();
7273  if (type && type->link() && type->str() == "<")
7274  type = type->link()->next();
7275  }
7276 
7277  // Set signedness for integral types..
7278  if (valuetype->isIntegral() && valuetype->sign == ValueType::Sign::UNKNOWN_SIGN) {
7279  if (valuetype->type == ValueType::Type::CHAR)
7280  valuetype->sign = defaultSignedness;
7281  else if (valuetype->type >= ValueType::Type::SHORT)
7282  valuetype->sign = ValueType::Sign::SIGNED;
7283  }
7284 
7285  return (type && (valuetype->type != ValueType::Type::UNKNOWN_TYPE || valuetype->pointer > 0 || valuetype->reference != Reference::None)) ? type : nullptr;
7286 }
7287 
7288 static const Scope *getClassScope(const Token *tok)
7289 {
7290  return tok && tok->valueType() && tok->valueType()->typeScope && tok->valueType()->typeScope->isClassOrStruct() ?
7291  tok->valueType()->typeScope :
7292  nullptr;
7293 }
7294 
7295 static const Function *getOperatorFunction(const Token * const tok)
7296 {
7297  const std::string functionName("operator" + tok->str());
7298  std::multimap<std::string, const Function *>::const_iterator it;
7299 
7300  const Scope *classScope = getClassScope(tok->astOperand1());
7301  if (classScope) {
7302  it = classScope->functionMap.find(functionName);
7303  if (it != classScope->functionMap.end())
7304  return it->second;
7305  }
7306 
7307  classScope = getClassScope(tok->astOperand2());
7308  if (classScope) {
7309  it = classScope->functionMap.find(functionName);
7310  if (it != classScope->functionMap.end())
7311  return it->second;
7312  }
7313 
7314  return nullptr;
7315 }
7316 
7317 static const Function* getFunction(const Token* tok) {
7318  if (!tok)
7319  return nullptr;
7320  if (tok->function() && tok->function()->retDef)
7321  return tok->function();
7322  if (const Variable* lvar = tok->variable()) { // lambda
7323  const Function* lambda{};
7324  if (Token::Match(lvar->nameToken()->next(), "; %varid% = [", lvar->declarationId()))
7325  lambda = lvar->nameToken()->tokAt(4)->function();
7326  else if (Token::simpleMatch(lvar->nameToken()->next(), "{ ["))
7327  lambda = lvar->nameToken()->tokAt(2)->function();
7328  if (lambda && lambda->retDef)
7329  return lambda;
7330  }
7331  return nullptr;
7332 }
7333 
7334 void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens)
7335 {
7336  if (!tokens)
7337  tokens = mTokenizer.list.front();
7338 
7339  for (Token *tok = tokens; tok; tok = tok->next())
7340  tok->setValueType(nullptr);
7341 
7342  for (Token *tok = tokens; tok; tok = tok->next()) {
7343  if (tok->isNumber()) {
7344  if (MathLib::isFloat(tok->str())) {
7345  ValueType::Type type = ValueType::Type::DOUBLE;
7346  const char suffix = tok->str()[tok->str().size() - 1];
7347  if (suffix == 'f' || suffix == 'F')
7348  type = ValueType::Type::FLOAT;
7349  else if (suffix == 'L' || suffix == 'l')
7350  type = ValueType::Type::LONGDOUBLE;
7351  setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, type, 0U));
7352  } else if (MathLib::isInt(tok->str())) {
7353  const std::string tokStr = MathLib::abs(tok->str());
7354  const bool unsignedSuffix = (tokStr.find_last_of("uU") != std::string::npos);
7355  ValueType::Sign sign = unsignedSuffix ? ValueType::Sign::UNSIGNED : ValueType::Sign::SIGNED;
7356  ValueType::Type type = ValueType::Type::INT;
7357  const MathLib::biguint value = MathLib::toBigUNumber(tokStr);
7358  for (std::size_t pos = tokStr.size() - 1U; pos > 0U; --pos) {
7359  const char suffix = tokStr[pos];
7360  if (suffix == 'u' || suffix == 'U')
7361  sign = ValueType::Sign::UNSIGNED;
7362  else if (suffix == 'l' || suffix == 'L')
7363  type = (type == ValueType::Type::INT) ? ValueType::Type::LONG : ValueType::Type::LONGLONG;
7364  else if (pos > 2U && suffix == '4' && tokStr[pos - 1] == '6' && tokStr[pos - 2] == 'i') {
7365  type = ValueType::Type::LONGLONG;
7366  pos -= 2;
7367  } else break;
7368  }
7369  if (mSettings.platform.type != Platform::Type::Unspecified) {
7370  if (type <= ValueType::Type::INT && mSettings.platform.isIntValue(unsignedSuffix ? (value >> 1) : value))
7371  type = ValueType::Type::INT;
7372  else if (type <= ValueType::Type::INT && !MathLib::isDec(tokStr) && mSettings.platform.isIntValue(value >> 2)) {
7373  type = ValueType::Type::INT;
7374  sign = ValueType::Sign::UNSIGNED;
7375  } else if (type <= ValueType::Type::LONG && mSettings.platform.isLongValue(unsignedSuffix ? (value >> 1) : value))
7376  type = ValueType::Type::LONG;
7377  else if (type <= ValueType::Type::LONG && !MathLib::isDec(tokStr) && mSettings.platform.isLongValue(value >> 2)) {
7378  type = ValueType::Type::LONG;
7379  sign = ValueType::Sign::UNSIGNED;
7380  } else if (mSettings.platform.isLongLongValue(unsignedSuffix ? (value >> 1) : value))
7381  type = ValueType::Type::LONGLONG;
7382  else {
7383  type = ValueType::Type::LONGLONG;
7384  sign = ValueType::Sign::UNSIGNED;
7385  }
7386  }
7387 
7388  setValueType(tok, ValueType(sign, type, 0U));
7389  }
7390  } else if (tok->isComparisonOp() || tok->tokType() == Token::eLogicalOp) {
7391  if (tok->isCpp() && tok->isComparisonOp() && (getClassScope(tok->astOperand1()) || getClassScope(tok->astOperand2()))) {
7392  const Function *function = getOperatorFunction(tok);
7393  if (function) {
7394  ValueType vt;
7395  parsedecl(function->retDef, &vt, mDefaultSignedness, mSettings);
7396  setValueType(tok, vt);
7397  continue;
7398  }
7399  }
7400  setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
7401  } else if (tok->isBoolean()) {
7402  setValueType(tok, ValueType(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::BOOL, 0U));
7403  } else if (tok->tokType() == Token::eChar || tok->tokType() == Token::eString) {
7404  nonneg int const pointer = tok->tokType() == Token::eChar ? 0U : 1U;
7405  nonneg int const constness = tok->tokType() == Token::eChar ? 0U : 1U;
7406  nonneg int const volatileness = 0U;
7407  ValueType valuetype(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::CHAR, pointer, constness, volatileness);
7408 
7409  if (tok->isCpp() && mSettings.standards.cpp >= Standards::CPP20 && tok->isUtf8()) {
7410  valuetype.originalTypeName = "char8_t";
7411  valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7412  } else if (tok->isUtf16()) {
7413  valuetype.originalTypeName = "char16_t";
7414  valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7415  } else if (tok->isUtf32()) {
7416  valuetype.originalTypeName = "char32_t";
7417  valuetype.fromLibraryType(valuetype.originalTypeName, mSettings);
7418  } else if (tok->isLong()) {
7419  valuetype.originalTypeName = "wchar_t";
7420  valuetype.type = ValueType::Type::WCHAR_T;
7421  } else if ((tok->tokType() == Token::eChar) && ((!tok->isCpp() && tok->isCChar()) || (tok->isCMultiChar()))) {
7422  valuetype.type = ValueType::Type::INT;
7423  valuetype.sign = ValueType::Sign::SIGNED;
7424  }
7425  setValueType(tok, valuetype);
7426  } else if (tok->link() && Token::Match(tok, "(|{")) {
7427  const Token* start = tok->astOperand1() ? tok->astOperand1()->findExpressionStartEndTokens().first : nullptr;
7428  // cast
7429  if (tok->isCast() && !tok->astOperand2() && Token::Match(tok, "( %name%")) {
7430  ValueType valuetype;
7431  if (Token::simpleMatch(parsedecl(tok->next(), &valuetype, mDefaultSignedness, mSettings), ")"))
7432  setValueType(tok, valuetype);
7433  }
7434 
7435  // C++ cast
7436  else if (tok->astOperand2() && Token::Match(tok->astOperand1(), "static_cast|const_cast|dynamic_cast|reinterpret_cast < %name%") && tok->astOperand1()->linkAt(1)) {
7437  ValueType valuetype;
7438  if (Token::simpleMatch(parsedecl(tok->astOperand1()->tokAt(2), &valuetype, mDefaultSignedness, mSettings), ">"))
7439  setValueType(tok, valuetype);
7440  }
7441 
7442  // Construct smart pointer
7443  else if (start && start->isCpp() && mSettings.library.isSmartPointer(start)) {
7444  ValueType valuetype;
7445  if (parsedecl(start, &valuetype, mDefaultSignedness, mSettings)) {
7446  setValueType(tok, valuetype);
7447  setValueType(tok->astOperand1(), valuetype);
7448  }
7449 
7450  }
7451 
7452  // function or lambda
7453  else if (const Function* f = getFunction(tok->previous())) {
7454  ValueType valuetype;
7455  if (parsedecl(f->retDef, &valuetype, mDefaultSignedness, mSettings))
7456  setValueType(tok, valuetype);
7457  }
7458 
7459  else if (Token::simpleMatch(tok->previous(), "sizeof (")) {
7460  ValueType valuetype(ValueType::Sign::UNSIGNED, ValueType::Type::LONG, 0U);
7461  if (mSettings.platform.type == Platform::Type::Win64)
7462  valuetype.type = ValueType::Type::LONGLONG;
7463 
7464  valuetype.originalTypeName = "size_t";
7465  setValueType(tok, valuetype);
7466 
7467  if (Token::Match(tok, "( %type% %type%| *| *| )")) {
7468  ValueType vt;
7469  if (parsedecl(tok->next(), &vt, mDefaultSignedness, mSettings)) {
7470  setValueType(tok->next(), vt);
7471  }
7472  }
7473  }
7474 
7475  // function style cast
7476  else if (tok->previous() && tok->previous()->isStandardType()) {
7477  ValueType valuetype;
7478  if (tok->astOperand1() && valuetype.fromLibraryType(tok->astOperand1()->expressionString(), mSettings)) {
7479  setValueType(tok, valuetype);
7480  continue;
7481  }
7482 
7483  valuetype.type = ValueType::typeFromString(tok->previous()->str(), tok->previous()->isLong());
7484  if (tok->previous()->isUnsigned())
7485  valuetype.sign = ValueType::Sign::UNSIGNED;
7486  else if (tok->previous()->isSigned())
7487  valuetype.sign = ValueType::Sign::SIGNED;
7488  else if (valuetype.isIntegral() && valuetype.type != ValueType::UNKNOWN_INT)
7489  valuetype.sign = mDefaultSignedness;
7490  setValueType(tok, valuetype);
7491  }
7492 
7493  // constructor call
7494  else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->isConstructor()) {
7495  ValueType valuetype;
7496  valuetype.type = ValueType::RECORD;
7497  valuetype.typeScope = tok->previous()->function()->token->scope();
7498  setValueType(tok, valuetype);
7499  }
7500 
7501  else if (Token::simpleMatch(tok->previous(), "= {") && tok->tokAt(-2) && tok->tokAt(-2)->valueType()) {
7502  ValueType vt = *tok->tokAt(-2)->valueType();
7503  setValueType(tok, vt);
7504  }
7505 
7506  // library type/function
7507  else if (tok->previous()) {
7508  // Aggregate constructor
7509  if (Token::Match(tok->previous(), "%name%")) {
7510  ValueType valuetype;
7511  if (parsedecl(tok->previous(), &valuetype, mDefaultSignedness, mSettings)) {
7512  if (valuetype.typeScope) {
7513  setValueType(tok, valuetype);
7514  continue;
7515  }
7516  }
7517  }
7518  if (tok->isCpp() && tok->astParent() && Token::Match(tok->astOperand1(), "%name%|::")) {
7519  const Token *typeStartToken = tok->astOperand1();
7520  while (typeStartToken && typeStartToken->str() == "::")
7521  typeStartToken = typeStartToken->astOperand1();
7522  if (mSettings.library.detectContainerOrIterator(typeStartToken) ||
7523  mSettings.library.detectSmartPointer(typeStartToken)) {
7524  ValueType vt;
7525  if (parsedecl(typeStartToken, &vt, mDefaultSignedness, mSettings)) {
7526  setValueType(tok, vt);
7527  continue;
7528  }
7529  }
7530 
7531  const std::string e = tok->astOperand1()->expressionString();
7532 
7533  if ((e == "std::make_shared" || e == "std::make_unique") && Token::Match(tok->astOperand1(), ":: %name% < %name%")) {
7534  ValueType vt;
7535  parsedecl(tok->astOperand1()->tokAt(3), &vt, mDefaultSignedness, mSettings);
7536  if (vt.typeScope) {
7538  vt.typeScope = nullptr;
7539  }
7540  if (e == "std::make_shared" && mSettings.library.smartPointers.count("std::shared_ptr") > 0)
7541  vt.smartPointer = &mSettings.library.smartPointers.at("std::shared_ptr");
7542  if (e == "std::make_unique" && mSettings.library.smartPointers.count("std::unique_ptr") > 0)
7543  vt.smartPointer = &mSettings.library.smartPointers.at("std::unique_ptr");
7544  vt.type = ValueType::Type::SMART_POINTER;
7545  vt.smartPointerTypeToken = tok->astOperand1()->tokAt(3);
7546  setValueType(tok, vt);
7547  continue;
7548  }
7549 
7550  ValueType podtype;
7551  if (podtype.fromLibraryType(e, mSettings)) {
7552  setValueType(tok, podtype);
7553  continue;
7554  }
7555  }
7556 
7557  const std::string& typestr(mSettings.library.returnValueType(tok->previous()));
7558  if (!typestr.empty()) {
7559  ValueType valuetype;
7560  TokenList tokenList(&mSettings);
7561  std::istringstream istr(typestr+";");
7562  tokenList.createTokens(istr, tok->isCpp() ? Standards::Language::CPP : Standards::Language::C); // TODO: check result?
7563  tokenList.simplifyStdType();
7564  if (parsedecl(tokenList.front(), &valuetype, mDefaultSignedness, mSettings)) {
7565  valuetype.originalTypeName = typestr;
7566  setValueType(tok, valuetype);
7567  }
7568  }
7569 
7570  //Is iterator fetching function invoked on container?
7571  const bool isReturnIter = typestr == "iterator";
7572  if (typestr.empty() || isReturnIter) {
7573  if (Token::simpleMatch(tok->astOperand1(), ".") &&
7574  tok->astOperand1()->astOperand1() &&
7575  tok->astOperand1()->astOperand2() &&
7576  tok->astOperand1()->astOperand1()->valueType() &&
7577  tok->astOperand1()->astOperand1()->valueType()->container) {
7578  const Library::Container *cont = tok->astOperand1()->astOperand1()->valueType()->container;
7579  const auto it = cont->functions.find(tok->astOperand1()->astOperand2()->str());
7580  if (it != cont->functions.end()) {
7581  if (it->second.yield == Library::Container::Yield::START_ITERATOR ||
7582  it->second.yield == Library::Container::Yield::END_ITERATOR ||
7583  it->second.yield == Library::Container::Yield::ITERATOR) {
7584  ValueType vt;
7585  vt.type = ValueType::Type::ITERATOR;
7586  vt.container = cont;
7587  vt.containerTypeToken =
7588  tok->astOperand1()->astOperand1()->valueType()->containerTypeToken;
7589  setValueType(tok, vt);
7590  continue;
7591  }
7592  }
7593  //Is iterator fetching function called?
7594  } else if (Token::simpleMatch(tok->astOperand1(), "::") &&
7595  tok->astOperand2() &&
7596  tok->astOperand2()->isVariable()) {
7597  const auto* const paramVariable = tok->astOperand2()->variable();
7598  if (!paramVariable ||
7599  !paramVariable->valueType() ||
7600  !paramVariable->valueType()->container) {
7601  continue;
7602  }
7603 
7604  const auto yield = astFunctionYield(tok->previous(), mSettings);
7608  ValueType vt;
7609  vt.type = ValueType::Type::ITERATOR;
7610  vt.container = paramVariable->valueType()->container;
7611  vt.containerTypeToken = paramVariable->valueType()->containerTypeToken;
7612  setValueType(tok, vt);
7613  }
7614  }
7615  if (isReturnIter) {
7616  const std::vector<const Token*> args = getArguments(tok);
7617  if (!args.empty()) {
7619  if (info && info->it) {
7620  const Token* contTok = args[0];
7621  if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1()) // .begin()
7622  contTok = args[0]->astOperand1()->astOperand1();
7623  else if (Token::simpleMatch(args[0], "(") && args[0]->astOperand2()) // std::begin()
7624  contTok = args[0]->astOperand2();
7625  while (Token::simpleMatch(contTok, "[")) // move to container token
7626  contTok = contTok->astOperand1();
7627  if (Token::simpleMatch(contTok, "."))
7628  contTok = contTok->astOperand2();
7629  if (contTok && contTok->variable() && contTok->variable()->valueType() && contTok->variable()->valueType()->container) {
7630  ValueType vt;
7631  vt.type = ValueType::Type::ITERATOR;
7632  vt.container = contTok->variable()->valueType()->container;
7633  vt.containerTypeToken = contTok->variable()->valueType()->containerTypeToken;
7634  setValueType(tok, vt);
7635  } else if (Token::simpleMatch(contTok, "(") && contTok->astOperand1() && contTok->astOperand1()->function()) {
7636  const Function* func = contTok->astOperand1()->function();
7637  if (const ValueType* funcVt = func->tokenDef->next()->valueType()) {
7638  ValueType vt;
7639  vt.type = ValueType::Type::ITERATOR;
7640  vt.container = funcVt->container;
7641  vt.containerTypeToken = funcVt->containerTypeToken;
7642  setValueType(tok, vt);
7643  }
7644  }
7645  }
7646  }
7647  }
7648  continue;
7649  }
7650  TokenList tokenList(&mSettings);
7651  std::istringstream istr(typestr+";");
7652  if (tokenList.createTokens(istr, tok->isCpp() ? Standards::Language::CPP : Standards::Language::C)) {
7653  ValueType vt;
7654  tokenList.simplifyPlatformTypes();
7655  tokenList.simplifyStdType();
7656  if (parsedecl(tokenList.front(), &vt, mDefaultSignedness, mSettings)) {
7657  vt.originalTypeName = typestr;
7658  setValueType(tok, vt);
7659  }
7660  }
7661  }
7662  } else if (tok->str() == "return") {
7663  const Scope *functionScope = tok->scope();
7664  while (functionScope && functionScope->isExecutable() && functionScope->type != Scope::eLambda && functionScope->type != Scope::eFunction)
7665  functionScope = functionScope->nestedIn;
7666  if (functionScope && functionScope->type == Scope::eFunction && functionScope->function &&
7667  functionScope->function->retDef) {
7668  ValueType vt = ValueType::parseDecl(functionScope->function->retDef, mSettings);
7669  setValueType(tok, vt);
7670  if (Token::simpleMatch(tok, "return {"))
7671  setValueType(tok->next(), vt);
7672  }
7673  } else if (tok->variable()) {
7674  setValueType(tok, *tok->variable());
7675  if (!tok->variable()->valueType() && tok->valueType())
7676  const_cast<Variable*>(tok->variable())->setValueType(*tok->valueType());
7677  } else if (tok->enumerator()) {
7678  setValueType(tok, *tok->enumerator());
7679  } else if (tok->isKeyword() && tok->str() == "new") {
7680  const Token *typeTok = tok->next();
7681  if (Token::Match(typeTok, "( std| ::| nothrow )"))
7682  typeTok = typeTok->link()->next();
7683  bool isIterator = false;
7685  ValueType vt;
7686  vt.pointer = 1;
7687  vt.container = c;
7688  vt.type = isIterator ? ValueType::Type::ITERATOR : ValueType::Type::CONTAINER;
7689  setValueType(tok, vt);
7690  continue;
7691  }
7692  std::string typestr;
7693  while (Token::Match(typeTok, "%name% :: %name%")) {
7694  typestr += typeTok->str() + "::";
7695  typeTok = typeTok->tokAt(2);
7696  }
7697  if (!Token::Match(typeTok, "%type% ;|[|("))
7698  continue;
7699  typestr += typeTok->str();
7700  ValueType vt;
7701  vt.pointer = 1;
7702  if (typeTok->type() && typeTok->type()->classScope) {
7703  vt.type = ValueType::Type::RECORD;
7704  vt.typeScope = typeTok->type()->classScope;
7705  } else {
7706  vt.type = ValueType::typeFromString(typestr, typeTok->isLong());
7707  if (vt.type == ValueType::Type::UNKNOWN_TYPE)
7708  vt.fromLibraryType(typestr, mSettings);
7709  if (vt.type == ValueType::Type::UNKNOWN_TYPE)
7710  continue;
7711  if (typeTok->isUnsigned())
7712  vt.sign = ValueType::Sign::UNSIGNED;
7713  else if (typeTok->isSigned())
7714  vt.sign = ValueType::Sign::SIGNED;
7715  if (vt.sign == ValueType::Sign::UNKNOWN_SIGN && vt.isIntegral())
7716  vt.sign = (vt.type == ValueType::Type::CHAR) ? mDefaultSignedness : ValueType::Sign::SIGNED;
7717  }
7718  setValueType(tok, vt);
7719  if (Token::simpleMatch(tok->astOperand1(), "(")) {
7720  vt.pointer--;
7721  setValueType(tok->astOperand1(), vt);
7722  }
7723  } else if (tok->isKeyword() && tok->str() == "return" && tok->scope()) {
7724  const Scope* fscope = tok->scope();
7725  while (fscope && !fscope->function)
7726  fscope = fscope->nestedIn;
7727  if (fscope && fscope->function && fscope->function->retDef) {
7728  ValueType vt;
7730  setValueType(tok, vt);
7731  }
7732  } else if (tok->isKeyword() && tok->str() == "this" && tok->scope()->isExecutable()) {
7733  const Scope* fscope = tok->scope();
7734  while (fscope && !fscope->function)
7735  fscope = fscope->nestedIn;
7736  const Scope* defScope = fscope && fscope->function->tokenDef ? fscope->function->tokenDef->scope() : nullptr;
7737  if (defScope && defScope->isClassOrStruct()) {
7738  ValueType vt(ValueType::Sign::UNKNOWN_SIGN, ValueType::Type::RECORD, 1);
7739  vt.typeScope = defScope;
7740  if (fscope->function->isConst())
7741  vt.constness = 1;
7742  if (fscope->function->isVolatile())
7743  vt.volatileness = 1;
7744  setValueType(tok, vt);
7745  }
7746  }
7747  }
7748 
7749  if (reportDebugWarnings && mSettings.debugwarnings) {
7750  for (Token *tok = tokens; tok; tok = tok->next()) {
7751  if (tok->str() == "auto" && !tok->valueType()) {
7752  if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
7753  continue;
7754  if (Token::Match(tok->next(), "%name% {|= [") && isLambdaCaptureList(tok->tokAt(3)))
7755  continue;
7756  debugMessage(tok, "autoNoType", "auto token with no type.");
7757  }
7758  }
7759  }
7760 
7761  // Update functions with new type information.
7763 
7764  // Update auto variables with new type information.
7766 }
7767 
7768 ValueType ValueType::parseDecl(const Token *type, const Settings &settings)
7769 {
7770  ValueType vt;
7771  parsedecl(type, &vt, settings.platform.defaultSign == 'u' ? Sign::UNSIGNED : Sign::SIGNED, settings);
7772  return vt;
7773 }
7774 
7775 ValueType::Type ValueType::typeFromString(const std::string &typestr, bool longType)
7776 {
7777  if (typestr == "void")
7778  return ValueType::Type::VOID;
7779  if (typestr == "bool" || typestr == "_Bool")
7780  return ValueType::Type::BOOL;
7781  if (typestr== "char")
7782  return ValueType::Type::CHAR;
7783  if (typestr == "short")
7784  return ValueType::Type::SHORT;
7785  if (typestr == "wchar_t")
7786  return ValueType::Type::WCHAR_T;
7787  if (typestr == "int")
7788  return ValueType::Type::INT;
7789  if (typestr == "long")
7790  return longType ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
7791  if (typestr == "float")
7792  return ValueType::Type::FLOAT;
7793  if (typestr == "double")
7794  return longType ? ValueType::Type::LONGDOUBLE : ValueType::Type::DOUBLE;
7795  return ValueType::Type::UNKNOWN_TYPE;
7796 }
7797 
7798 bool ValueType::fromLibraryType(const std::string &typestr, const Settings &settings)
7799 {
7800  const Library::PodType* podtype = settings.library.podtype(typestr);
7801  if (podtype && (podtype->sign == 's' || podtype->sign == 'u')) {
7802  if (podtype->size == 1)
7803  type = ValueType::Type::CHAR;
7804  else if (podtype->size == settings.platform.sizeof_int)
7805  type = ValueType::Type::INT;
7806  else if (podtype->size == settings.platform.sizeof_short)
7807  type = ValueType::Type::SHORT;
7808  else if (podtype->size == settings.platform.sizeof_long)
7809  type = ValueType::Type::LONG;
7810  else if (podtype->size == settings.platform.sizeof_long_long)
7811  type = ValueType::Type::LONGLONG;
7812  else if (podtype->stdtype == Library::PodType::Type::BOOL)
7813  type = ValueType::Type::BOOL;
7814  else if (podtype->stdtype == Library::PodType::Type::CHAR)
7815  type = ValueType::Type::CHAR;
7816  else if (podtype->stdtype == Library::PodType::Type::SHORT)
7817  type = ValueType::Type::SHORT;
7818  else if (podtype->stdtype == Library::PodType::Type::INT)
7819  type = ValueType::Type::INT;
7820  else if (podtype->stdtype == Library::PodType::Type::LONG)
7821  type = ValueType::Type::LONG;
7822  else if (podtype->stdtype == Library::PodType::Type::LONGLONG)
7823  type = ValueType::Type::LONGLONG;
7824  else
7825  type = ValueType::Type::UNKNOWN_INT;
7826  sign = (podtype->sign == 'u') ? ValueType::UNSIGNED : ValueType::SIGNED;
7827  return true;
7828  }
7829  if (podtype && podtype->stdtype == Library::PodType::Type::NO) {
7830  type = ValueType::Type::POD;
7832  return true;
7833  }
7834 
7835  const Library::PlatformType *platformType = settings.library.platform_type(typestr, settings.platform.toString());
7836  if (platformType) {
7837  if (platformType->mType == "char")
7838  type = ValueType::Type::CHAR;
7839  else if (platformType->mType == "short")
7840  type = ValueType::Type::SHORT;
7841  else if (platformType->mType == "wchar_t")
7842  type = ValueType::Type::WCHAR_T;
7843  else if (platformType->mType == "int")
7844  type = platformType->mLong ? ValueType::Type::LONG : ValueType::Type::INT;
7845  else if (platformType->mType == "long")
7846  type = platformType->mLong ? ValueType::Type::LONGLONG : ValueType::Type::LONG;
7847  if (platformType->mSigned)
7849  else if (platformType->mUnsigned)
7851  if (platformType->mPointer)
7852  pointer = 1;
7853  if (platformType->mPtrPtr)
7854  pointer = 2;
7855  if (platformType->mConstPtr)
7856  constness = 1;
7857  return true;
7858  }
7859  if (!podtype && (typestr == "size_t" || typestr == "std::size_t")) {
7860  originalTypeName = "size_t";
7862  if (settings.platform.sizeof_size_t == settings.platform.sizeof_long)
7863  type = ValueType::Type::LONG;
7864  else if (settings.platform.sizeof_size_t == settings.platform.sizeof_long_long)
7865  type = ValueType::Type::LONGLONG;
7866  else if (settings.platform.sizeof_size_t == settings.platform.sizeof_int)
7867  type = ValueType::Type::INT;
7868  else
7869  type = ValueType::Type::UNKNOWN_INT;
7870  return true;
7871  }
7872 
7873  return false;
7874 }
7875 
7876 std::string ValueType::dump() const
7877 {
7878  std::string ret;
7879  switch (type) {
7880  case UNKNOWN_TYPE:
7881  return "";
7882  case NONSTD:
7883  ret += "valueType-type=\"nonstd\"";
7884  break;
7885  case POD:
7886  ret += "valueType-type=\"pod\"";
7887  break;
7888  case RECORD:
7889  ret += "valueType-type=\"record\"";
7890  break;
7891  case SMART_POINTER:
7892  ret += "valueType-type=\"smart-pointer\"";
7893  break;
7894  case CONTAINER: {
7895  ret += "valueType-type=\"container\"";
7896  ret += " valueType-containerId=\"";
7897  ret += id_string(container);
7898  ret += "\"";
7899  break;
7900  }
7901  case ITERATOR:
7902  ret += "valueType-type=\"iterator\"";
7903  break;
7904  case VOID:
7905  ret += "valueType-type=\"void\"";
7906  break;
7907  case BOOL:
7908  ret += "valueType-type=\"bool\"";
7909  break;
7910  case CHAR:
7911  ret += "valueType-type=\"char\"";
7912  break;
7913  case SHORT:
7914  ret += "valueType-type=\"short\"";
7915  break;
7916  case WCHAR_T:
7917  ret += "valueType-type=\"wchar_t\"";
7918  break;
7919  case INT:
7920  ret += "valueType-type=\"int\"";
7921  break;
7922  case LONG:
7923  ret += "valueType-type=\"long\"";
7924  break;
7925  case LONGLONG:
7926  ret += "valueType-type=\"long long\"";
7927  break;
7928  case UNKNOWN_INT:
7929  ret += "valueType-type=\"unknown int\"";
7930  break;
7931  case FLOAT:
7932  ret += "valueType-type=\"float\"";
7933  break;
7934  case DOUBLE:
7935  ret += "valueType-type=\"double\"";
7936  break;
7937  case LONGDOUBLE:
7938  ret += "valueType-type=\"long double\"";
7939  break;
7940  }
7941 
7942  switch (sign) {
7943  case Sign::UNKNOWN_SIGN:
7944  break;
7945  case Sign::SIGNED:
7946  ret += " valueType-sign=\"signed\"";
7947  break;
7948  case Sign::UNSIGNED:
7949  ret += " valueType-sign=\"unsigned\"";
7950  break;
7951  }
7952 
7953  if (bits > 0) {
7954  ret += " valueType-bits=\"";
7955  ret += std::to_string(bits);
7956  ret += '\"';
7957  }
7958 
7959  if (pointer > 0) {
7960  ret += " valueType-pointer=\"";
7961  ret += std::to_string(pointer);
7962  ret += '\"';
7963  }
7964 
7965  if (constness > 0) {
7966  ret += " valueType-constness=\"";
7967  ret += std::to_string(constness);
7968  ret += '\"';
7969  }
7970 
7971  if (volatileness > 0) {
7972  ret += " valueType-volatileness=\"";
7973  ret += std::to_string(volatileness);
7974  ret += '\"';
7975  }
7976 
7977  if (reference == Reference::None)
7978  ret += " valueType-reference=\"None\"";
7979  else if (reference == Reference::LValue)
7980  ret += " valueType-reference=\"LValue\"";
7981  else if (reference == Reference::RValue)
7982  ret += " valueType-reference=\"RValue\"";
7983 
7984  if (typeScope) {
7985  ret += " valueType-typeScope=\"";
7986  ret += id_string(typeScope);
7987  ret += '\"';
7988  }
7989 
7990  if (!originalTypeName.empty()) {
7991  ret += " valueType-originalTypeName=\"";
7993  ret += '\"';
7994  }
7995 
7996  return ret;
7997 }
7998 
7999 bool ValueType::isConst(nonneg int indirect) const
8000 {
8001  if (indirect > pointer)
8002  return false;
8003  return constness & (1 << (pointer - indirect));
8004 }
8005 
8006 bool ValueType::isVolatile(nonneg int indirect) const
8007 {
8008  if (indirect > pointer)
8009  return false;
8010  return volatileness & (1 << (pointer - indirect));
8011 }
8012 MathLib::bigint ValueType::typeSize(const Platform &platform, bool p) const
8013 {
8014  if (p && pointer)
8015  return platform.sizeof_pointer;
8016 
8018  return typeScope->definedType->sizeOf;
8019 
8020  switch (type) {
8021  case ValueType::Type::BOOL:
8022  return platform.sizeof_bool;
8023  case ValueType::Type::CHAR:
8024  return 1;
8025  case ValueType::Type::SHORT:
8026  return platform.sizeof_short;
8027  case ValueType::Type::WCHAR_T:
8028  return platform.sizeof_wchar_t;
8029  case ValueType::Type::INT:
8030  return platform.sizeof_int;
8031  case ValueType::Type::LONG:
8032  return platform.sizeof_long;
8033  case ValueType::Type::LONGLONG:
8034  return platform.sizeof_long_long;
8035  case ValueType::Type::FLOAT:
8036  return platform.sizeof_float;
8037  case ValueType::Type::DOUBLE:
8038  return platform.sizeof_double;
8039  case ValueType::Type::LONGDOUBLE:
8040  return platform.sizeof_long_double;
8041  default:
8042  break;
8043  }
8044 
8045  // Unknown invalid size
8046  return 0;
8047 }
8048 
8049 bool ValueType::isTypeEqual(const ValueType* that) const
8050 {
8051  if (!that)
8052  return false;
8053  auto tie = [](const ValueType* vt) {
8054  return std::tie(vt->type, vt->container, vt->pointer, vt->typeScope, vt->smartPointer);
8055  };
8056  return tie(this) == tie(that);
8057 }
8058 
8059 std::string ValueType::str() const
8060 {
8061  std::string ret;
8062  if (constness & 1)
8063  ret = " const";
8064  if (volatileness & 1)
8065  ret = " volatile";
8066  if (type == VOID)
8067  ret += " void";
8068  else if (isIntegral()) {
8069  if (sign == SIGNED)
8070  ret += " signed";
8071  else if (sign == UNSIGNED)
8072  ret += " unsigned";
8073  if (type == BOOL)
8074  ret += " bool";
8075  else if (type == CHAR)
8076  ret += " char";
8077  else if (type == SHORT)
8078  ret += " short";
8079  else if (type == WCHAR_T)
8080  ret += " wchar_t";
8081  else if (type == INT)
8082  ret += " int";
8083  else if (type == LONG)
8084  ret += " long";
8085  else if (type == LONGLONG)
8086  ret += " long long";
8087  else if (type == UNKNOWN_INT)
8088  ret += " unknown_int";
8089  } else if (type == FLOAT)
8090  ret += " float";
8091  else if (type == DOUBLE)
8092  ret += " double";
8093  else if (type == LONGDOUBLE)
8094  ret += " long double";
8095  else if ((type == ValueType::Type::NONSTD || type == ValueType::Type::RECORD) && typeScope) {
8096  std::string className(typeScope->className);
8098  while (scope && scope->type != Scope::eGlobal) {
8099  if (scope->type == Scope::eClass || scope->type == Scope::eStruct || scope->type == Scope::eNamespace)
8100  className = scope->className + "::" + className;
8101  scope = (scope->definedType && scope->definedType->enclosingScope) ? scope->definedType->enclosingScope : scope->nestedIn;
8102  }
8103  ret += ' ' + className;
8104  } else if (type == ValueType::Type::CONTAINER && container) {
8105  ret += " container(" + container->startPattern + ')';
8106  } else if (type == ValueType::Type::ITERATOR && container) {
8107  ret += " iterator(" + container->startPattern + ')';
8108  } else if (type == ValueType::Type::SMART_POINTER && smartPointer) {
8109  ret += " smart-pointer(" + smartPointer->name + ")";
8110  }
8111  for (unsigned int p = 0; p < pointer; p++) {
8112  ret += " *";
8113  if (constness & (2 << p))
8114  ret += " const";
8115  if (volatileness & (2 << p))
8116  ret += " volatile";
8117  }
8119  ret += " &";
8120  else if (reference == Reference::RValue)
8121  ret += " &&";
8122  if (ret.empty())
8123  return ret;
8124  return ret.substr(1);
8125 }
8126 
8127 void ValueType::setDebugPath(const Token* tok, SourceLocation ctx, const SourceLocation &local)
8128 {
8129  std::string file = ctx.file_name();
8130  if (file.empty())
8131  return;
8132  std::string s = Path::stripDirectoryPart(file) + ":" + std::to_string(ctx.line()) + ": " + ctx.function_name() +
8133  " => " + local.function_name();
8134  debugPath.emplace_back(tok, std::move(s));
8135 }
8136 
8138 {
8139  if (!call || !func)
8141  if (call->pointer != func->pointer) {
8142  if (call->pointer > 1 && func->pointer == 1 && func->type == ValueType::Type::VOID)
8144  if (call->pointer == 1 && func->pointer == 0 && func->isIntegral() && func->sign != ValueType::Sign::SIGNED)
8146  if (call->pointer == 1 && call->type == ValueType::Type::CHAR && func->pointer == 0 && func->container && func->container->stdStringLike)
8148  return ValueType::MatchResult::NOMATCH; // TODO
8149  }
8150  if (call->pointer > 0) {
8151  if ((call->constness | func->constness) != func->constness)
8153  if ((call->volatileness | func->volatileness) != func->volatileness)
8155  if (call->constness == 0 && func->constness != 0 && func->reference != Reference::None)
8157  if (call->volatileness == 0 && func->volatileness != 0 && func->reference != Reference::None)
8159  }
8160  if (call->type != func->type || (call->isEnum() && !func->isEnum())) {
8161  if (call->type == ValueType::Type::VOID || func->type == ValueType::Type::VOID)
8163  if (call->pointer > 0)
8165  if (call->isIntegral() && func->isIntegral())
8166  return call->type < func->type ?
8169  if (call->isFloat() && func->isFloat())
8171  if (call->isIntegral() && func->isFloat())
8173  if (call->isFloat() && func->isIntegral())
8175  return ValueType::MatchResult::UNKNOWN; // TODO
8176  }
8177 
8178  if (call->typeScope != nullptr || func->typeScope != nullptr) {
8179  if (call->typeScope != func->typeScope &&
8180  !(call->typeScope && func->typeScope && call->typeScope->definedType && call->typeScope->definedType->isDerivedFrom(func->typeScope->className)))
8182  }
8183 
8184  if (call->container != nullptr || func->container != nullptr) {
8185  if (call->container != func->container)
8187  }
8188 
8189  if (func->typeScope != nullptr && func->container != nullptr) {
8190  if (func->type < ValueType::Type::VOID || func->type == ValueType::Type::UNKNOWN_INT)
8192  }
8193 
8194  if (call->isIntegral() && func->isIntegral() && call->sign != ValueType::Sign::UNKNOWN_SIGN && func->sign != ValueType::Sign::UNKNOWN_SIGN && call->sign != func->sign)
8196 
8197  if (func->reference != Reference::None && (func->constness > call->constness || func->volatileness > call->volatileness))
8199 
8201 }
8202 
8204 {
8205  ValueType vt;
8206  const ValueType* pvt = funcVar->valueType();
8207  if (pvt && funcVar->isArray() && !(funcVar->isStlType() && Token::simpleMatch(funcVar->typeStartToken(), "std :: array"))) { // std::array doesn't decay to a pointer
8208  vt = *pvt;
8209  if (vt.pointer == 0) // don't bump array of pointers
8210  ++vt.pointer;
8211  pvt = &vt;
8212  }
8213  const ValueType::MatchResult res = ValueType::matchParameter(call, pvt);
8214  if (callVar && ((res == ValueType::MatchResult::SAME && call->container) || res == ValueType::MatchResult::UNKNOWN)) {
8215  const std::string type1 = getTypeString(callVar->typeStartToken());
8216  const std::string type2 = getTypeString(funcVar->typeStartToken());
8217  const bool templateVar =
8218  funcVar->scope() && funcVar->scope()->function && funcVar->scope()->function->templateDef;
8219  if (type1 == type2)
8221  if (!templateVar && type1.find("auto") == std::string::npos && type2.find("auto") == std::string::npos)
8223  }
8224  return res;
8225 }
bool astIsContainer(const Token *tok)
Definition: astutils.cpp:244
std::vector< const Token * > getArguments(const Token *ftok)
Get arguments (AST)
Definition: astutils.cpp:3078
bool precedes(const Token *tok1, const Token *tok2)
If tok2 comes after tok1.
Definition: astutils.cpp:987
bool compareTokenFlags(const Token *tok1, const Token *tok2, bool macro)
Are the tokens' flags equal?
Definition: astutils.cpp:1530
static bool match(const Token *tok, const std::string &rhs)
Definition: astutils.cpp:342
Library::Container::Yield astFunctionYield(const Token *tok, const Settings &settings, const Token **ftok)
Definition: astutils.cpp:307
const Token * findLambdaStartToken(const Token *last)
Definition: astutils.cpp:3140
const Token * findLambdaEndToken(const Token *first)
find lambda function end token
Definition: astutils.cpp:3190
const Token * nextAfterAstRightmostLeaf(const Token *tok)
Definition: astutils.cpp:548
bool isReturnScope(const Token *const endToken, const Library &library, const Token **unknownFunc, bool functionScope)
Is scope a return scope (scope will unconditionally return)
Definition: astutils.cpp:2197
bool isCPPCast(const Token *tok)
Definition: astutils.cpp:3242
SmallVector< ReferenceToken > followAllReferences(const Token *tok, bool temporary, bool inconclusive, ErrorPath errors, int depth)
Definition: astutils.cpp:1229
bool succeeds(const Token *tok1, const Token *tok2)
If tok1 comes after tok2.
Definition: astutils.cpp:999
const Token * findAstNode(const Token *ast, const TFunc &pred)
Definition: astutils.h:88
static int sign(const T v)
static bool isIterator(const Variable *var, bool &inconclusiveType)
Definition: checkstl.cpp:419
This is an interface, which the class responsible of error logging should implement.
Definition: errorlogger.h:214
virtual void reportErr(const ErrorMessage &msg)=0
Information about found errors and warnings is directed here.
static std::string toxml(const std::string &str)
Convert XML-sensitive characters into XML entities.
virtual void reportProgress(const std::string &filename, const char stage[], const std::size_t value)
Report progress to client.
Definition: errorlogger.h:241
Wrapper for error messages, provided by reportErr()
Definition: errorlogger.h:48
bool isInlineKeyword() const
bool isStatic() const
AccessControl access
public/protected/private
Function(const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef)
nonneg int initializedArgCount() const
nonneg int minArgCount() const
static std::vector< const Token * > findReturns(const Function *f)
const std::string & name() const
std::vector< const Function * > getOverloadedFunctions() const
void addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope)
const Token * argDef
function argument start '(' in class definition
bool isPure() const
const Scope * functionScope
scope of function body
const Function * getOverriddenFunction(bool *foundAllBaseClasses=nullptr) const
get function in base class that is overridden
bool hasRvalRefQualifier() const
static bool returnsConst(const Function *function, bool unknown=false)
bool hasLvalRefQualifier() const
bool isVolatile() const
bool isInline() const
bool hasBody() const
Type type
constructor, destructor, ...
bool isThrow() const
bool isSafe(const Settings &settings) const
bool isOperator() const
static bool returnsPointer(const Function *function, bool unknown=false)
bool isConstexpr() const
static bool returnsReference(const Function *function, bool unknown=false, bool includeRValueRef=false)
bool isExplicit() const
bool argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, nonneg int path_length) const
bool isExtern() const
@ fHasFinalSpecifier
does declaration contain 'final' specifier?
@ fHasOverrideSpecifier
does declaration contain 'override' specifier?
const Token * setFlags(const Token *tok1, const Scope *scope)
nonneg int initArgCount
number of args with default values
bool isLambda() const
const Variable * getArgumentVar(nonneg int num) const
nonneg int argCount() const
const Token * throwArg
throw token
const Token * retDef
function return type token
bool isImplicitlyVirtual(bool defaultVal=false) const
check if this function is virtual in the base classes
bool hasTrailingReturnType() const
static bool returnsStandardType(const Function *function, bool unknown=false)
bool isDefault() const
std::string fullName() const
bool isVariadic() const
const Token * constructorMemberInitialization() const
const Function * getOverriddenFunctionRecursive(const ::Type *baseType, bool *foundAllBaseClasses) const
Recursively determine if this function overrides a virtual function in a base class.
bool isEscapeFunction() const
const Token * token
function name token in implementation
const Token * arg
function argument start '('
const Scope * nestedIn
Scope the function is declared in.
bool hasOverrideSpecifier() const
bool hasVirtualSpecifier() const
const Token * tokenDef
function name token in class definition
bool isDelete() const
const Token * templateDef
points to 'template <' before function
bool isFriend() const
std::list< Variable > argumentList
argument list, must remain list due to clangimport usage!
void setFlag(unsigned int flag, bool state)
Set specified flag state.
static bool returnsVoid(const Function *function, bool unknown=false)
bool isDestructor() const
bool isConstructor() const
bool isStaticLocal() const
bool isNoExcept() const
bool isConst() const
static const std::unordered_set< std::string > & getAll(Standards::cstd_t cStd)
Definition: keywords.cpp:152
int size_templateArgNo
Definition: library.h:238
bool arrayLike_indexOp
Definition: library.h:239
std::vector< RangeItemRecordTypeItem > rangeItemRecordType
Definition: library.h:237
std::map< std::string, Function > functions
Definition: library.h:235
std::string startPattern
Definition: library.h:234
Yield getYield(const std::string &function) const
Definition: library.h:255
Library definitions handling.
Definition: library.h:52
const Container * detectContainerOrIterator(const Token *typeStart, bool *isIterator=nullptr, bool withoutStd=false) const
Definition: library.cpp:1241
const SmartPointer * detectSmartPointer(const Token *tok, bool withoutStd=false) const
Definition: library.cpp:1702
bool isSmartPointer(const Token *tok) const
Definition: library.cpp:1697
const PodType * podtype(const std::string &name) const
Definition: library.h:447
const ArgumentChecks::IteratorInfo * getArgIteratorInfo(const Token *ftok, int argnr) const
Definition: library.h:362
std::unordered_map< std::string, SmartPointer > smartPointers
Definition: library.h:438
const Container * detectContainer(const Token *typeStart) const
Definition: library.cpp:1231
const std::string & returnValueType(const Token *ftok) const
Definition: library.cpp:1428
std::unordered_map< std::string, Function > functions
Definition: library.h:330
const PlatformType * platform_type(const std::string &name, const std::string &platform) const
Definition: library.h:482
static biguint toBigUNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:289
long long bigint
Definition: mathlib.h:68
static bigint toBigNumber(const std::string &str)
for conversion of numeric literals - for atoi-like conversions please use strToInt()
Definition: mathlib.cpp:368
static bool isFloat(const std::string &str)
Definition: mathlib.cpp:535
static bool isDec(const std::string &str)
Definition: mathlib.cpp:978
static bool isNullValue(const std::string &str)
Does the string represent the numerical value of 0? In case leading or trailing white space is provid...
Definition: mathlib.cpp:1253
static std::string abs(const std::string &tok)
Definition: mathlib.cpp:1202
static bool isInt(const std::string &str)
Definition: mathlib.cpp:1007
unsigned long long biguint
Definition: mathlib.h:69
static std::string stripDirectoryPart(const std::string &file)
Get filename without a directory path part.
Definition: path.cpp:302
Platform settings.
Definition: platform.h:43
nonneg int short_bit
bits in char
Definition: platform.h:86
nonneg int int_bit
bits in short
Definition: platform.h:87
std::size_t sizeof_bool
bits in long long
Definition: platform.h:92
std::size_t sizeof_long_long
Definition: platform.h:96
char defaultSign
Definition: platform.h:104
bool isLongLongValue(unsigned long long value) const
Definition: platform.h:80
std::size_t sizeof_long_double
Definition: platform.h:99
nonneg int long_bit
bits in int
Definition: platform.h:88
bool isLongValue(long long value) const
Definition: platform.h:71
bool isIntValue(long long value) const
Definition: platform.h:62
std::size_t sizeof_short
Definition: platform.h:93
std::size_t sizeof_int
Definition: platform.h:94
std::size_t sizeof_pointer
Definition: platform.h:102
std::size_t sizeof_size_t
Definition: platform.h:101
nonneg int char_bit
Definition: platform.h:85
std::size_t sizeof_float
Definition: platform.h:97
const char * toString() const
Definition: platform.h:148
nonneg int long_long_bit
bits in long
Definition: platform.h:89
Type type
platform type
Definition: platform.h:118
std::size_t sizeof_double
Definition: platform.h:98
std::size_t sizeof_long
Definition: platform.h:95
std::size_t sizeof_wchar_t
Definition: platform.h:100
std::list< Function > functionList
bool hasInlineOrLambdaFunction() const
std::vector< UsingInfo > usingList
const Token * enumType
std::map< std::string, Type * > definedTypesMap
const Scope * findRecordInNestedList(const std::string &name, bool isC=false) const
std::list< Variable > varlist
const Token * checkVariable(const Token *tok, AccessControl varaccess, const Settings &settings)
check if statement is variable declaration and add it if it is
const Scope * findRecordInBase(const std::string &name) const
std::multimap< std::string, const Function * > functionMap
bool isVariableDeclaration(const Token *const tok, const Token *&vartok, const Token *&typetok) const
helper function for getVariableList()
std::vector< Scope * > nestedList
ScopeType type
const Token * addEnum(const Token *tok)
Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_)
const Function * getDestructor() const
std::vector< Enumerator > enumeratorList
Type * definedType
Function * function
function info for this function
const SymbolDatabase * check
@ eUnconditional
void addVariable(const Token *token_, const Token *start_, const Token *end_, AccessControl access_, const Type *type_, const Scope *scope_, const Settings &settings)
const Function * findFunction(const Token *tok, bool requireConst=false) const
find a function
const Type * findType(const std::string &name) const
std::vector< const Token * > bodyStartList
const Scope * nestedIn
const Token * classDef
class/struct/union/namespace token
void getVariableList(const Settings &settings)
initialize varlist
Scope * findInNestedListRecursive(const std::string &name)
find if name is in nested list
void setBodyStartEnd(const Token *start)
AccessControl defaultAccess() const
const Token * bodyStart
'{' token
const Token * bodyEnd
'}' token
void findFunctionInBase(const std::string &name, nonneg int args, std::vector< const Function * > &matches) const
std::string className
const Scope * functionOf
scope this function belongs to
const Enumerator * findEnumerator(const std::string &name) const
void addFunction(Function func)
std::vector< const Scope * > findAssociatedScopes() const
bool isClassOrStructOrUnion() const
const Variable * getVariable(const std::string &varname) const
get variable from name
bool isExecutable() const
bool isClassOrStruct() const
bool enumClass
This is just a container for general settings so that we don't need to pass individual values to func...
Definition: settings.h:95
Library library
Library.
Definition: settings.h:237
SafeChecks safeChecks
Definition: settings.h:356
bool clang
Use Clang.
Definition: settings.h:150
Platform platform
Definition: settings.h:255
bool debugnormal
Is –debug-normal given?
Definition: settings.h:174
SimpleEnableGroup< Severity > severity
Definition: settings.h:358
bool debugwarnings
Is –debug-warnings given?
Definition: settings.h:183
Standards standards
Struct contains standards settings.
Definition: settings.h:366
bool isEnabled(T flag) const
Definition: settings.h:66
void createSymbolDatabaseNeedInitialization()
void debugSymbolDatabase() const
const Scope * findScopeByName(const std::string &name) const
For unit testing only.
void createSymbolDatabaseSetFunctionPointers(bool firstPass)
static bool isReservedName(const Token *tok)
Whether the token is a keyword as defined in http://en.cppreference.com/w/c/keyword and http://en....
const Variable * getVariableFromVarId(nonneg int varId) const
std::vector< const Variable * > mVariableList
variable symbol table
void createSymbolDatabaseFunctionReturnTypes()
void createSymbolDatabaseSetScopePointers()
const std::vector< const Variable * > & variableList() const
SymbolDatabase(Tokenizer &tokenizer, const Settings &settings, ErrorLogger &errorLogger)
const Settings & mSettings
void addNewFunction(Scope *&scope, const Token *&tok)
void createSymbolDatabaseClassAndStructScopes()
void createSymbolDatabaseExprIds()
void validateExecutableScopes() const
const Function * findFunction(const Token *tok) const
find a function
Tokenizer & mTokenizer
static const Type * findVariableTypeInBase(const Scope *scope, const Token *typeTok)
void createSymbolDatabaseVariableSymbolTable()
void debugMessage(const Token *tok, const std::string &type, const std::string &msg) const
output a debug message
std::list< Type > typeList
Fast access to types.
void createSymbolDatabaseVariableInfo()
void clangSetVariables(const std::vector< const Variable * > &variableList)
void createSymbolDatabaseSetTypePointers()
void createSymbolDatabaseCopyAndMoveConstructors()
std::map< unsigned int, MemberIdMap > VarIdMap
std::list< Type > mBlankTypes
list for missing types
void createSymbolDatabaseFunctionScopes()
const Type * findTypeInNested(const Token *startTok, const Scope *startScope) const
const Scope * findScope(const Token *tok, const Scope *startScope) const
void setValueTypeInTokenList(bool reportDebugWarnings, Token *tokens=nullptr)
Set valuetype in provided tokenlist.
void createSymbolDatabaseSetVariablePointers()
ValueType::Sign mDefaultSignedness
void createSymbolDatabaseFindAllScopes()
const Type * findType(const Token *startTok, const Scope *startScope, bool lookOutside=false) const
void validate() const
void createSymbolDatabaseEscapeFunctions()
void validateVariables() const
Check variable list, e.g.
void printXml(std::ostream &out) const
const Enumerator * findEnumerator(const Token *tok, std::set< std::string > &tokensThatAreNotEnumeratorValues) const
void returnImplicitIntError(const Token *tok) const
void setValueType(Token *tok, const ValueType &valuetype, const SourceLocation &loc=SourceLocation::current())
void setArrayDimensionsUsingValueFlow()
Set array dimensions when valueflow analysis is completed.
void createSymbolDatabaseSetSmartPointerType()
std::vector< const Scope * > functionScopes
Fast access to function scopes.
std::map< unsigned int, unsigned int > MemberIdMap
std::list< Scope > scopeList
Information about all namespaces/classes/structures.
const Type * findVariableType(const Scope *start, const Token *typeTok) const
find a variable type if it's a user defined type
bool isFunction(const Token *tok, const Scope *outerScope, const Token *&funcStart, const Token *&argStart, const Token *&declEnd) const
void createSymbolDatabaseClassInfo()
nonneg int sizeOfType(const Token *type) const
Calculates sizeof value for given type.
void printVariable(const Variable *var, const char *indent) const
void createSymbolDatabaseIncompleteVars()
ErrorLogger & mErrorLogger
Function * addGlobalFunction(Scope *&scope, const Token *&tok, const Token *argStart, const Token *funcStart)
void createSymbolDatabaseEnums()
void addClassFunction(Scope *&scope, const Token *&tok, const Token *argStart)
void fixVarId(VarIdMap &varIds, const Token *vartok, Token *membertok, const Variable *membervar)
static Function * addGlobalFunctionDecl(Scope *&scope, const Token *tok, const Token *argStart, const Token *funcStart)
std::vector< const Scope * > classAndStructScopes
Fast access to class and struct scopes.
static Function * findFunctionInScope(const Token *func, const Scope *ns, const std::string &path, nonneg int path_length)
const Scope * findNamespace(const Token *tok, const Scope *scope) const
void printOut(const char *title=nullptr) const
static bool simplifyNumericCalculations(Token *tok, bool isTemplate=true)
Simplify constant calculations such as "1+2" => "3".
std::string fileLine(const Token *tok) const
Get file:line for a given token.
const Token * back() const
get last token of list
Definition: tokenlist.h:128
void simplifyPlatformTypes()
Convert platform dependent types to standard types.
const std::string & getSourceFilePath() const
Definition: tokenlist.cpp:75
void simplifyStdType()
Collapse compound standard types into a single token.
void addtoken(const std::string &str, const nonneg int lineno, const nonneg int column, const nonneg int fileno, bool split=false)
Definition: tokenlist.cpp:145
const Token * front() const
get first token of list
Definition: tokenlist.h:119
bool createTokens(std::istream &code, const std::string &file0)
Create tokens from code.
Definition: tokenlist.cpp:336
The token list that the TokenList generates is a linked-list of this class.
Definition: token.h:150
void str(T &&s)
Definition: token.h:179
bool isUtf16() const
Definition: token.h:712
Token * astTop()
Definition: token.h:1416
static bool Match(const Token *tok, const char pattern[], nonneg int varid=0)
Match given token (or list of tokens) to a pattern list.
Definition: token.cpp:722
nonneg int exprId() const
Definition: token.h:883
bool isEnumerator() const
Definition: token.h:374
bool isKeyword() const
Definition: token.h:358
unsigned char bits() const
Definition: token.h:689
bool isC() const
Definition: token.cpp:2757
bool isCChar() const
Definition: token.h:722
const std::string & originalName() const
Definition: token.h:1193
bool isName() const
Definition: token.h:361
static const Token * findmatch(const Token *const startTok, const char pattern[], const nonneg int varId=0)
Definition: token.cpp:1099
bool isUnsigned() const
Definition: token.h:424
bool hasKnownIntValue() const
Definition: token.cpp:2553
MathLib::bigint getKnownIntValue() const
Definition: token.h:1218
bool isSimplifiedTypedef() const
Definition: token.h:580
const Token * nextTemplateArgument() const
Definition: token.cpp:930
bool isArithmeticalOp() const
Definition: token.h:395
bool isIncompleteVar() const
Definition: token.h:573
bool isBoolean() const
Definition: token.h:404
bool isUpperCaseName() const
Definition: token.cpp:237
bool isCpp() const
Definition: token.cpp:2752
nonneg int progressValue() const
Get progressValue (0 - 100)
Definition: token.h:1150
bool isControlFlowKeyword() const
Definition: token.h:546
void setValueType(ValueType *vt)
Definition: token.cpp:2359
bool isUtf32() const
Definition: token.h:717
const ValueType * valueType() const
Definition: token.h:331
const std::string & strAt(int index) const
Definition: token.cpp:457
const Enumerator * enumerator() const
Definition: token.h:1111
void astOperand1(Token *tok)
Definition: token.cpp:1490
bool isNumber() const
Definition: token.h:371
void function(const Function *f)
Associate this token with given function.
Definition: token.cpp:1127
bool isCMultiChar() const
Definition: token.h:727
bool isExternC() const
Definition: token.h:601
nonneg int varId() const
Definition: token.h:870
std::string expressionString() const
Definition: token.cpp:1681
bool isSigned() const
Definition: token.h:430
bool isCast() const
Definition: token.h:458
bool isUnaryOp(const std::string &s) const
Definition: token.h:413
bool isLiteral() const
Definition: token.h:368
bool isOperatorKeyword() const
Definition: token.h:549
bool isIncompleteConstant() const
Definition: token.h:587
TokenDebug getTokenDebug() const
Definition: token.h:1475
static const Token * findsimplematch(const Token *const startTok, const char(&pattern)[count])
Definition: token.h:763
const Token * tokAt(int index) const
Definition: token.cpp:427
Token::Type tokType() const
Definition: token.h:343
void astOperand2(Token *tok)
Definition: token.cpp:1502
void scope(const Scope *s)
Associate this token with given scope.
Definition: token.h:1042
bool isLong() const
Definition: token.h:443
void link(Token *linkToToken)
Create link to given token.
Definition: token.h:1015
const Token * linkAt(int index) const
Definition: token.cpp:447
@ eName
Definition: token.h:161
@ eString
Definition: token.h:162
@ eChar
Definition: token.h:162
@ eVariable
Definition: token.h:161
@ eLogicalOp
Definition: token.h:163
@ eBitOp
Definition: token.h:163
@ eIncDecOp
Definition: token.h:163
Token * previous()
Definition: token.h:862
bool isComplex() const
Definition: token.h:555
void type(const ::Type *t)
Associate this token with given type.
Definition: token.cpp:2367
bool isAssignmentOp() const
Definition: token.h:401
bool isSplittedVarDeclEq() const
Definition: token.h:615
bool isUtf8() const
Definition: token.h:707
bool isStandardType() const
Definition: token.h:449
void variable(const Variable *v)
Associate this token with given variable.
Definition: token.h:1070
bool isAttributeMaybeUnused() const
Definition: token.h:530
bool isComparisonOp() const
Definition: token.h:398
Token * next()
Definition: token.h:830
bool isInline() const
Definition: token.h:629
const Token * nextArgument() const
Definition: token.cpp:903
static bool simpleMatch(const Token *tok, const char(&pattern)[count])
Match given token (or list of tokens) to a pattern list.
Definition: token.h:252
nonneg int fileIndex() const
Definition: token.h:809
void astParent(Token *tok)
Definition: token.cpp:1471
The main purpose is to tokenize the source code.
Definition: tokenize.h:46
nonneg int sizeOfType(const Token *type) const
Calculates sizeof value for given type.
Definition: tokenize.cpp:191
nonneg int newVarId()
Get new variable id.
Definition: tokenize.h:637
const Token * tokens() const
Definition: tokenize.h:592
nonneg int varIdCount() const
Get variable count.
Definition: tokenize.h:583
TokenList list
Token list: stores all tokens.
Definition: tokenize.h:590
bool isC() const
Is the code C.
Definition: tokenize.h:64
NORETURN void unmatchedToken(const Token *tok) const
Syntax error.
Definition: tokenize.cpp:8049
static const Token * isFunctionHead(const Token *tok, const std::string &endsWith)
is token pointing at function head?
Definition: tokenize.cpp:96
NORETURN void syntaxError(const Token *tok, const std::string &code=emptyString) const
Syntax error.
Definition: tokenize.cpp:8043
Information about a class type.
const Function * getFunction(const std::string &funcName) const
bool findDependency(const Type *ancestor) const
Check for dependency.
const Scope * enclosingScope
bool isDerivedFrom(const std::string &ancestor) const
bool isStructType() const
bool hasCircularDependencies(std::set< BaseInfo > *ancestors=nullptr) const
Check for circulare dependencies, i.e.
bool isEnumType() const
const Token * classDef
Points to "class" token.
const Token * initBaseInfo(const Token *tok, const Token *tok1)
std::vector< BaseInfo > derivedFrom
std::string name() const
std::vector< FriendInfo > friendList
MathLib::bigint sizeOf
enum Type::NeedInitialization needInitialization
bool isClassType() const
const Scope * classScope
bool isUnionType() const
const std::string & type() const
Value type.
bool fromLibraryType(const std::string &typestr, const Settings &settings)
bool isFloat() const
enum ValueType::Type type
const Library::Container * container
If the type is a container defined in a cfg file, this is the used.
bool isConst(nonneg int indirect=0) const
nonneg int constness
bit 0=data, bit 1=*, bit 2=**
static Type typeFromString(const std::string &typestr, bool longType)
nonneg int bits
bitfield bitcount
bool isTypeEqual(const ValueType *that) const
Check if type is the same ignoring const and references.
MathLib::bigint typeSize(const Platform &platform, bool p=false) const
Reference reference
Is the outermost indirection of this type a reference or rvalue.
const Library::SmartPointer * smartPointer
Smart pointer.
bool isIntegral() const
nonneg int pointer
0=>not pointer, 1=>*, 2=>**, 3=>***, etc
const Token * smartPointerTypeToken
Smart pointer type token.
std::string dump() const
static MatchResult matchParameter(const ValueType *call, const ValueType *func)
nonneg int volatileness
bit 0=data, bit 1=*, bit 2=**
bool isEnum() const
std::string originalTypeName
original type name as written in the source code.
const Token * containerTypeToken
The container type token.
const Scope * typeScope
if the type definition is seen this point out the type scope
static ValueType parseDecl(const Token *type, const Settings &settings)
enum ValueType::Sign sign
bool isVolatile(nonneg int indirect=0) const
ErrorPath debugPath
debug path to the type
bool isPrimitive() const
std::string str() const
const ::Type * smartPointerType
Smart pointer type.
void setDebugPath(const Token *tok, SourceLocation ctx, const SourceLocation &local=SourceLocation::current())
Information about a member variable.
@ fIsPointer
array variable
@ fIsReference
pointer variable
@ fIsInit
marked [[maybe_unused]]
@ fIsSmartPointer
volatile
@ fIsClass
extern variable
@ fIsExtern
const variable
@ fIsStlString
STL type ('std::')
@ fIsStlType
function argument with default value
@ fIsRValueRef
reference variable
@ fIsMaybeUnused
std::shared_ptr|unique_ptr
@ fIsVolatile
Floating point type.
@ fIsArray
user defined type
@ fIsFloatType
std::string|wstring|basic_string<T>|u16string|u32string
@ fIsStatic
mutable variable
@ fIsConst
static variable
@ fHasDefault
rvalue reference variable
bool hasDefault() const
Does variable have a default value.
bool isArgument() const
Is variable a function argument.
bool arrayDimensions(const Settings &settings, bool &isContainer)
parse and save array dimension information
const Token * mTypeStartToken
variable type start token
bool isEnumType() const
Determine whether it's an enumeration type.
Variable(const Token *name_, const Token *start_, const Token *end_, nonneg int index_, AccessControl access_, const Type *type_, const Scope *scope_, const Settings &settings)
bool isClass() const
Is variable a user defined (or unknown) type.
Variable & operator=(const Variable &var)
const Type * mType
pointer to user defined type info (for known types)
bool isArrayOrPointer() const
Is array or pointer variable.
bool isExtern() const
Is variable extern.
const Token * mNameToken
variable name token
const Type * smartPointerType() const
const Type * iteratorType() const
bool isReference() const
Is reference variable.
bool isStlStringViewType() const
nonneg int mIndex
order declared
std::string getTypeName() const
bool isRValueReference() const
Is reference variable.
AccessControl accessControl() const
bool isStlType() const
Checks if the variable is an STL type ('std::') E.g.
bool isLocal() const
Is variable local.
bool isSmartPointer() const
const Token * declEndToken() const
Get end token of variable declaration E.g.
const Type * type() const
Get Type pointer of known type.
const Scope * scope() const
Get Scope pointer of enclosing scope.
void setFlag(unsigned int flag_, bool state_)
Set specified flag state.
bool getFlag(unsigned int flag_) const
Get specified flag state.
const Scope * typeScope() const
Get Scope pointer of known type.
const Token * typeEndToken() const
Get type end token.
bool isConst() const
Is variable const.
bool isPointerArray() const
Is variable an array of pointers.
MathLib::bigint dimension(nonneg int index_) const
Get array dimension length.
bool isMember() const
Is variable a member of a user-defined type.
bool isArray() const
Is variable an array.
const Token * nameToken() const
Get name token.
AccessControl mAccess
what section is this variable declared in?
nonneg int index() const
Get index of variable in declared order.
unsigned int mFlags
flags
const Scope * mScope
pointer to scope this variable is in
bool isUnsigned() const
Is variable unsigned.
nonneg int declarationId() const
Get declaration ID (varId used for variable in its declaration).
bool isMutable() const
Is variable mutable.
std::vector< Dimension > mDimensions
array dimensions
const Token * typeStartToken() const
Get type start token.
void evaluate(const Settings &settings)
fill in information, depending on Tokens given at instantiation
bool isVolatile() const
Is variable volatile.
const std::vector< Dimension > & dimensions() const
Get array dimensions.
bool isPointer() const
Is pointer variable.
bool isStlStringType() const
Checks if the variable is an STL type ('std::') E.g.
void setValueType(const ValueType &valueType)
const Token * mTypeEndToken
variable type end token
bool isStatic() const
Is variable static.
const ValueType * valueType() const
const ValueType * mValueType
#define REQUIRES(msg,...)
Definition: config.h:124
static const std::string emptyString
Definition: config.h:127
#define nonneg
Definition: config.h:138
std::list< ErrorPathItem > ErrorPath
Definition: errortypes.h:130
@ portability
Portability warning.
@ debug
Debug message.
const Value * valueFlowConstantFoldAST(Token *expr, const Settings &settings)
Constant folding of expression. This can be used before the full ValueFlow has been executed (ValueFl...
Definition: valueflow.cpp:9408
Array dimension information.
const Token * tok
size token
MathLib::bigint num
(assumed) dimension length when size is a number, 0 if not known
bool known
Known size.
const Token * start
const Token * end
const Scope * scope
const Token * name
MathLib::bigint value
Simple container to be thrown when internal error is detected.
Definition: errortypes.h:36
std::string mType
Definition: library.h:465
enum Library::PodType::Type stdtype
unsigned int size
Definition: library.h:443
std::string name
Definition: library.h:434
const Scope * scope
const Token * start
bool classes
Public interface of classes.
Definition: settings.h:334
bool externalFunctions
External functions.
Definition: settings.h:341
bool internalFunctions
Experimental: assume that internal functions can be used in any way This is only available in the GUI...
Definition: settings.h:347
static SourceLocation current()
const char * function_name() const
const char * file_name() const
std::uint_least32_t line() const
enum Standards::cstd_t c
enum Standards::cppstd_t cpp
AccessControl access
const Token * nameTok
std::string name
const Type * type
const Type * type
const Token * nameStart
const Token * nameEnd
static const Scope * getClassScope(const Token *tok)
static bool isUnknownType(const Token *start, const Token *end)
T * findTypeImpl(S &thisScope, const std::string &name)
static bool isContainerYieldPointer(Library::Container::Yield yield)
static const char * functionTypeToString(Function::Type type)
static bool usingNamespace(const Scope *scope, const Token *first, const Token *second, int &offset)
static bool isContainerYieldElement(Library::Container::Yield yield)
static const Token * skipScopeIdentifiers(const Token *tok)
static const Scope * findEnumScopeInBase(const Scope *scope, const std::string &tokStr)
static std::string getIncompleteNameID(const Token *tok)
S * findRecordInNestedListImpl(S &thisScope, const std::string &name, bool isC)
static bool typesMatch(const Scope *first_scope, const Token *first_token, const Scope *second_scope, const Token *second_token, const Token *&new_first, const Token *&new_second)
static void checkVariableCallMatch(const Variable *callarg, const Variable *funcarg, size_t &same, size_t &fallback1, size_t &fallback2)
static const Token * parsedecl(const Token *type, ValueType *const valuetype, ValueType::Sign defaultSignedness, const Settings &settings, SourceLocation loc=SourceLocation::current())
static bool isExpression(const Token *tok)
static const Token * skipPointers(const Token *tok)
static std::string getTypeString(const Token *typeToken)
static std::string tokenType(const Token *tok)
static bool isExecutableScope(const Token *tok)
static std::string qualifiedName(const Scope *scope)
static void setAutoTokenProperties(Token *const autoTok)
static std::ostream & operator<<(std::ostream &s, Scope::ScopeType type)
static bool isEnumDefinition(const Token *tok)
static const Function * getOperatorFunction(const Token *const tok)
static const Function * getFunction(const Token *tok)
static const Token * skipPointersAndQualifiers(const Token *tok)
static const Token * getEnableIfReturnType(const Token *start)
static bool isDerivedFromItself(const std::string &thisName, const std::string &baseName)
static bool hasMatchingConstructor(const Scope *classScope, const ValueType *argType)
static bool checkReturns(const Function *function, bool unknown, bool emptyEnableIf, Predicate pred)
static bool isOperator(const Token *tokenDef)
static std::string accessControlToString(AccessControl access)
static std::string scopeToString(const Scope *scope, const Tokenizer &tokenizer)
static std::string scopeTypeToString(Scope::ScopeType type)
static ValueType::Type getEnumType(const Scope *scope, const Platform &platform)
static bool hasEmptyCaptureList(const Token *tok)
static const Type * findVariableTypeIncludingUsedNamespaces(const SymbolDatabase *symbolDatabase, const Scope *scope, const Token *typeTok)
static std::string tokenToString(const Token *tok, const Tokenizer &tokenizer)
AccessControl
Access control enumerations.
static void indent(std::string &str, const nonneg int indent1, const nonneg int indent2)
Definition: token.cpp:1742
const Token * findLambdaEndTokenWithoutAST(const Token *tok)
const Token * isLambdaCaptureList(const Token *tok)
static std::string id_string(const void *p)
Definition: utils.h:340
bool startsWith(const std::string &str, const char start[], std::size_t startlen)
Definition: utils.h:94
bool endsWith(const std::string &str, char c)
Definition: utils.h:110
static const char * bool_to_string(bool b)
Definition: utils.h:345
bool contains(const Range &r, const T &x)
Definition: utils.h:62