|
Cppcheck
|
00001 /* 00002 * Cppcheck - A tool for static C/C++ code analysis 00003 * Copyright (C) 2007-2013 Daniel Marjamäki and Cppcheck team. 00004 * 00005 * This program is free software: you can redistribute it and/or modify 00006 * it under the terms of the GNU General Public License as published by 00007 * the Free Software Foundation, either version 3 of the License, or 00008 * (at your option) any later version. 00009 * 00010 * This program is distributed in the hope that it will be useful, 00011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 * GNU General Public License for more details. 00014 * 00015 * You should have received a copy of the GNU General Public License 00016 * along with this program. If not, see <http://www.gnu.org/licenses/>. 00017 */ 00018 00019 //--------------------------------------------------------------------------- 00020 #include "symboldatabase.h" 00021 00022 #include "tokenize.h" 00023 #include "token.h" 00024 #include "settings.h" 00025 #include "errorlogger.h" 00026 #include "check.h" 00027 00028 #include <string> 00029 #include <sstream> 00030 #include <climits> 00031 00032 // Define ULLONG_MAX and LLONG_MAX for Borland 00033 #ifdef __BORLANDC__ 00034 #define ULLONG_MAX ULONG_MAX 00035 #define LLONG_MAX LONG_MAX 00036 #endif 00037 00038 // Define ULLONG_MAX and LLONG_MAX for SunCC on non-Solaris systems 00039 #if (defined(__SUNPRO_C) || defined(__SUNPRO_CC)) && \ 00040 !(defined (__sun) || defined (__sun__)) 00041 #define ULLONG_MAX ULONG_MAX 00042 #define LLONG_MAX LONG_MAX 00043 #endif 00044 00045 //--------------------------------------------------------------------------- 00046 00047 SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger) 00048 : _tokenizer(tokenizer), _settings(settings), _errorLogger(errorLogger) 00049 { 00050 // create global scope 00051 scopeList.push_back(Scope(this, NULL, NULL)); 00052 00053 // pointer to current scope 00054 Scope *scope = &scopeList.back(); 00055 00056 // Store current access in each scope (depends on evaluation progress) 00057 std::map<const Scope*, AccessControl> access; 00058 00059 std::map<const Token *, Scope *> back; 00060 00061 // find all scopes 00062 for (const Token *tok = _tokenizer->tokens(); tok; tok = tok->next()) { 00063 // Locate next class 00064 if (Token::Match(tok, "class|struct|union|namespace ::| %var% {|:|::") && 00065 tok->strAt(-1) != "friend") { 00066 const Token *tok2 = tok->tokAt(2); 00067 00068 if (tok->strAt(1) == "::") 00069 tok2 = tok2->next(); 00070 00071 while (tok2 && tok2->str() == "::") 00072 tok2 = tok2->tokAt(2); 00073 00074 // make sure we have valid code 00075 if (!tok2 || !Token::Match(tok2, "{|:")) { 00076 // check for qualified variable 00077 if (tok2 && tok2->next()) { 00078 if (tok2->next()->str() == ";") 00079 tok = tok2->next(); 00080 else if (Token::Match(tok2->next(), "= {") && 00081 tok2->linkAt(2)->next()->str() == ";") 00082 tok = tok2->linkAt(2)->next(); 00083 else if (Token::Match(tok2->next(), "(|{") && 00084 tok2->next()->link()->next()->str() == ";") 00085 tok = tok2->next()->link()->next(); 00086 else 00087 break; // bail 00088 continue; 00089 } 00090 break; // bail 00091 } 00092 00093 Scope *new_scope = findScope(tok->next(), scope); 00094 00095 if (new_scope) { 00096 // only create base list for classes and structures 00097 if (new_scope->isClassOrStruct()) { 00098 // goto initial '{' 00099 tok2 = new_scope->definedType->initBaseInfo(tok, tok2); 00100 00101 // make sure we have valid code 00102 if (!tok2) { 00103 break; 00104 } 00105 } 00106 00107 // definition may be different than declaration 00108 if (tok->str() == "class") { 00109 access[new_scope] = Private; 00110 new_scope->type = Scope::eClass; 00111 } else if (tok->str() == "struct") { 00112 access[new_scope] = Public; 00113 new_scope->type = Scope::eStruct; 00114 } 00115 00116 back[tok2->link()] = scope; 00117 new_scope->classDef = tok; 00118 new_scope->classStart = tok2; 00119 new_scope->classEnd = tok2->link(); 00120 scope = new_scope; 00121 tok = tok2; 00122 } else { 00123 scopeList.push_back(Scope(this, tok, scope)); 00124 new_scope = &scopeList.back(); 00125 00126 if (tok->str() == "class") 00127 access[new_scope] = Private; 00128 else if (tok->str() == "struct") 00129 access[new_scope] = Public; 00130 00131 // fill typeList... 00132 if (new_scope->isClassOrStruct() || new_scope->type == Scope::eUnion) { 00133 Type* new_type = findType(tok->next(), scope); 00134 if (!new_type) { 00135 typeList.push_back(Type(new_scope->classDef, new_scope, scope)); 00136 new_type = &typeList.back(); 00137 scope->definedTypes.push_back(new_type); 00138 } else 00139 new_type->classScope = new_scope; 00140 new_scope->definedType = new_type; 00141 } 00142 00143 // only create base list for classes and structures 00144 if (new_scope->isClassOrStruct()) { 00145 // goto initial '{' 00146 tok2 = new_scope->definedType->initBaseInfo(tok, tok2); 00147 00148 // make sure we have valid code 00149 if (!tok2) { 00150 scopeList.pop_back(); 00151 break; 00152 } 00153 } 00154 00155 new_scope->classStart = tok2; 00156 new_scope->classEnd = tok2->link(); 00157 00158 // make sure we have valid code 00159 if (!new_scope->classEnd) { 00160 scopeList.pop_back(); 00161 break; 00162 } 00163 00164 // make the new scope the current scope 00165 scope->nestedList.push_back(new_scope); 00166 scope = new_scope; 00167 00168 tok = tok2; 00169 } 00170 } 00171 00172 // Namespace and unknown macro (#3854) 00173 else if (Token::Match(tok, "namespace %var% %type% (") && 00174 _tokenizer->isCPP() && 00175 tok->tokAt(2)->isUpperCaseName() && 00176 Token::simpleMatch(tok->linkAt(3), ") {")) { 00177 scopeList.push_back(Scope(this, tok, scope)); 00178 00179 Scope *new_scope = &scopeList.back(); 00180 access[new_scope] = Public; 00181 00182 const Token *tok2 = tok->linkAt(3)->next(); 00183 00184 new_scope->classStart = tok2; 00185 new_scope->classEnd = tok2->link(); 00186 00187 // make sure we have valid code 00188 if (!new_scope->classEnd) { 00189 scopeList.pop_back(); 00190 break; 00191 } 00192 00193 // make the new scope the current scope 00194 scope->nestedList.push_back(new_scope); 00195 scope = &scopeList.back(); 00196 00197 tok = tok2; 00198 } 00199 00200 // forward declaration 00201 else if (Token::Match(tok, "class|struct|union %var% ;") && 00202 tok->strAt(-1) != "friend") { 00203 if (!findType(tok->next(), scope)) { 00204 // fill typeList.. 00205 typeList.push_back(Type(tok, 0, scope)); 00206 scope->definedTypes.push_back(&typeList.back()); 00207 } 00208 tok = tok->tokAt(2); 00209 } 00210 00211 // using namespace 00212 else if (Token::Match(tok, "using namespace ::| %type% ;|::")) { 00213 Scope::UsingInfo using_info; 00214 00215 using_info.start = tok; // save location 00216 using_info.scope = 0; // fill in later 00217 00218 scope->usingList.push_back(using_info); 00219 00220 // check for global namespace 00221 if (tok->strAt(2) == "::") 00222 tok = tok->tokAt(4); 00223 else 00224 tok = tok->tokAt(3); 00225 00226 // skip over qualification 00227 while (tok && Token::Match(tok, "%type% ::")) 00228 tok = tok->tokAt(2); 00229 } 00230 00231 // unnamed struct and union 00232 else if (Token::Match(tok, "struct|union {") && 00233 Token::Match(tok->next()->link(), "} *|&| %var% ;|[")) { 00234 scopeList.push_back(Scope(this, tok, scope)); 00235 00236 Scope *new_scope = &scopeList.back(); 00237 access[new_scope] = Public; 00238 00239 const Token* varNameTok = tok->next()->link()->next(); 00240 if (varNameTok->str() == "*") { 00241 varNameTok = varNameTok->next(); 00242 } else if (varNameTok->str() == "&") { 00243 varNameTok = varNameTok->next(); 00244 } 00245 00246 typeList.push_back(Type(tok, new_scope, scope)); 00247 new_scope->definedType = &typeList.back(); 00248 scope->definedTypes.push_back(&typeList.back()); 00249 00250 scope->addVariable(varNameTok, tok, tok, access[scope], new_scope->definedType, scope); 00251 00252 const Token *tok2 = tok->next(); 00253 00254 new_scope->classStart = tok2; 00255 new_scope->classEnd = tok2->link(); 00256 00257 // make sure we have valid code 00258 if (!new_scope->classEnd) { 00259 scopeList.pop_back(); 00260 break; 00261 } 00262 00263 // make the new scope the current scope 00264 scope->nestedList.push_back(new_scope); 00265 scope = new_scope; 00266 00267 tok = tok2; 00268 } 00269 00270 // anonymous struct and union 00271 else if (Token::Match(tok, "struct|union {") && 00272 Token::simpleMatch(tok->next()->link(), "} ;")) { 00273 scopeList.push_back(Scope(this, tok, scope)); 00274 00275 Scope *new_scope = &scopeList.back(); 00276 access[new_scope] = Public; 00277 00278 const Token *tok2 = tok->next(); 00279 00280 new_scope->classStart = tok2; 00281 new_scope->classEnd = tok2->link(); 00282 00283 typeList.push_back(Type(tok, new_scope, scope)); 00284 new_scope->definedType = &typeList.back(); 00285 scope->definedTypes.push_back(&typeList.back()); 00286 00287 // make sure we have valid code 00288 if (!new_scope->classEnd) { 00289 scopeList.pop_back(); 00290 break; 00291 } 00292 00293 // make the new scope the current scope 00294 scope->nestedList.push_back(new_scope); 00295 scope = new_scope; 00296 00297 tok = tok2; 00298 } 00299 00300 else { 00301 // check for end of scope 00302 if (tok == scope->classEnd) { 00303 if (back.find(tok) != back.end()) { 00304 scope = back[tok]; 00305 back.erase(tok); 00306 } else 00307 scope = const_cast<Scope*>(scope->nestedIn); 00308 continue; 00309 } 00310 00311 // check if in class or structure 00312 else if (scope->type == Scope::eClass || scope->type == Scope::eStruct) { 00313 const Token *funcStart = 0; 00314 const Token *argStart = 0; 00315 00316 // What section are we in.. 00317 if (tok->str() == "private:") 00318 access[scope] = Private; 00319 else if (tok->str() == "protected:") 00320 access[scope] = Protected; 00321 else if (tok->str() == "public:" || tok->str() == "__published:") 00322 access[scope] = Public; 00323 else if (Token::Match(tok, "public|protected|private %var% :")) { 00324 if (tok->str() == "private") 00325 access[scope] = Private; 00326 else if (tok->str() == "protected") 00327 access[scope] = Protected; 00328 else 00329 access[scope] = Public; 00330 00331 tok = tok->tokAt(2); 00332 } 00333 00334 // class function? 00335 else if (tok->previous()->str() != "::" && isFunction(tok, scope, &funcStart, &argStart)) { 00336 Function function; 00337 00338 // save the function definition argument start '(' 00339 function.argDef = argStart; 00340 00341 // save the access type 00342 function.access = access[scope]; 00343 00344 // save the function name location 00345 function.tokenDef = funcStart; 00346 00347 // save the function parent scope 00348 function.nestedIn = scope; 00349 00350 // operator function 00351 if (function.tokenDef->str().find("operator") == 0) { 00352 function.isOperator = true; 00353 00354 // 'operator =' is special 00355 if (function.tokenDef->str() == "operator=") 00356 function.type = Function::eOperatorEqual; 00357 } 00358 00359 // class constructor/destructor 00360 else if (function.tokenDef->str() == scope->className) { 00361 // destructor 00362 if (function.tokenDef->previous()->str() == "~") 00363 function.type = Function::eDestructor; 00364 00365 // copy constructor 00366 else if ((Token::Match(function.tokenDef, "%var% ( const %var% & %var%| )") || 00367 (Token::Match(function.tokenDef, "%var% ( const %var% <") && 00368 Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) && 00369 function.tokenDef->strAt(3) == scope->className) 00370 function.type = Function::eCopyConstructor; 00371 00372 else if ((Token::Match(function.tokenDef, "%var% <") && 00373 Token::Match(function.tokenDef->linkAt(1), "> (const %var% & %var%| )")) && 00374 function.tokenDef->linkAt(1)->strAt(3) == scope->className) 00375 function.type = Function::eCopyConstructor; 00376 00377 // copy constructor with non-const argument 00378 else if ((Token::Match(function.tokenDef, "%var% ( %var% & %var%| )") || 00379 (Token::Match(function.tokenDef, "%var% ( %var% <") && 00380 Token::Match(function.tokenDef->linkAt(4), "> & %var%| )"))) && 00381 function.tokenDef->strAt(2) == scope->className) 00382 function.type = Function::eCopyConstructor; 00383 00384 else if ((Token::Match(function.tokenDef, "%var% <") && 00385 Token::Match(function.tokenDef->linkAt(1), "> ( %var% & %var%| )")) && 00386 function.tokenDef->strAt(2) == scope->className) 00387 function.type = Function::eCopyConstructor; 00388 00389 // regular constructor 00390 else 00391 function.type = Function::eConstructor; 00392 00393 if (function.tokenDef->previous()->str() == "explicit") 00394 function.isExplicit = true; 00395 } 00396 00397 // function returning function pointer 00398 else if (tok->str() == "(") { 00399 function.retFuncPtr = true; 00400 } 00401 00402 const Token *tok1 = tok; 00403 00404 // look for end of previous statement 00405 while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) { 00406 // virtual function 00407 if (tok1->previous()->str() == "virtual") { 00408 function.isVirtual = true; 00409 break; 00410 } 00411 00412 // static function 00413 else if (tok1->previous()->str() == "static") { 00414 function.isStatic = true; 00415 break; 00416 } 00417 00418 // friend function 00419 else if (tok1->previous()->str() == "friend") { 00420 function.isFriend = true; 00421 break; 00422 } 00423 00424 tok1 = tok1->previous(); 00425 } 00426 00427 const Token *end; 00428 00429 if (!function.retFuncPtr) 00430 end = function.argDef->link(); 00431 else 00432 end = tok->link()->next()->link(); 00433 00434 // const function 00435 if (end->next()->str() == "const") 00436 function.isConst = true; 00437 00438 // count the number of constructors 00439 if (function.type == Function::eConstructor) 00440 scope->numConstructors++; 00441 else if (function.type == Function::eCopyConstructor) { 00442 scope->numConstructors++; 00443 scope->numCopyConstructors++; 00444 } 00445 00446 // assume implementation is inline (definition and implementation same) 00447 function.token = function.tokenDef; 00448 function.arg = function.argDef; 00449 00450 // out of line function 00451 if (Token::Match(end, ") const| ;")) { 00452 // find the function implementation later 00453 tok = end->next(); 00454 if (tok->str() != ";") 00455 tok = tok->next(); 00456 00457 scope->functionList.push_back(function); 00458 } 00459 00460 // default or delete 00461 else if (Token::Match(end, ") = default|delete ;")) { 00462 if (end->strAt(2) == "default") 00463 function.isDefault = true; 00464 else 00465 function.isDelete = true; 00466 00467 tok = end->tokAt(3); 00468 00469 scope->functionList.push_back(function); 00470 } 00471 00472 // pure virtual function 00473 else if (Token::Match(end, ") const| = %any% ;")) { 00474 function.isPure = true; 00475 00476 if (end->next()->str() == "const") 00477 tok = end->tokAt(4); 00478 else 00479 tok = end->tokAt(3); 00480 00481 scope->functionList.push_back(function); 00482 } 00483 00484 // inline function 00485 else { 00486 function.isInline = true; 00487 function.hasBody = true; 00488 00489 // find start of function '{' 00490 while (end && end->str() != "{") 00491 end = end->next(); 00492 if (!end) 00493 continue; 00494 00495 scope->functionList.push_back(function); 00496 00497 Function* funcptr = &scope->functionList.back(); 00498 const Token *tok2 = funcStart; 00499 00500 addNewFunction(&scope, &tok2); 00501 if (scope) { 00502 scope->functionOf = function.nestedIn; 00503 scope->function = funcptr; 00504 scope->function->functionScope = scope; 00505 } 00506 00507 tok = tok2; 00508 } 00509 } 00510 00511 // nested class or friend function? 00512 else if (tok->previous()->str() == "::" && isFunction(tok, scope, &funcStart, &argStart)) { 00513 /** @todo check entire qualification for match */ 00514 Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2)); 00515 00516 if (nested) 00517 addClassFunction(&scope, &tok, argStart); 00518 else { 00519 /** @todo handle friend functions */ 00520 } 00521 } 00522 00523 // friend class declaration? 00524 else if (Token::Match(tok, "friend class| ::| %any% ;|::")) { 00525 Type::FriendInfo friendInfo; 00526 00527 // save the name start 00528 friendInfo.nameStart = tok->strAt(1) == "class" ? tok->tokAt(2) : tok->next(); 00529 friendInfo.nameEnd = friendInfo.nameStart; 00530 00531 // skip leading "::" 00532 if (friendInfo.nameEnd->str() == "::") 00533 friendInfo.nameEnd = friendInfo.nameEnd->next(); 00534 00535 // skip qualification "name ::" 00536 while (friendInfo.nameEnd && friendInfo.nameEnd->strAt(1) == "::") 00537 friendInfo.nameEnd = friendInfo.nameEnd->tokAt(2); 00538 00539 // save the name 00540 if (friendInfo.nameEnd) 00541 friendInfo.name = friendInfo.nameEnd->str(); 00542 00543 // fill this in after parsing is complete 00544 friendInfo.type = 0; 00545 00546 scope->definedType->friendList.push_back(friendInfo); 00547 } 00548 } else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) { 00549 const Token *funcStart = 0; 00550 const Token *argStart = 0; 00551 00552 // function? 00553 if (isFunction(tok, scope, &funcStart, &argStart)) { 00554 // has body? 00555 if (Token::Match(argStart->link(), ") const| {|:")) { 00556 Scope *old_scope = scope; 00557 00558 // class function 00559 if (tok->previous() && tok->previous()->str() == "::") 00560 addClassFunction(&scope, &tok, argStart); 00561 00562 // class destructor 00563 else if (tok->previous() && tok->previous()->str() == "~" && 00564 tok->tokAt(-2) && tok->strAt(-2) == "::") 00565 addClassFunction(&scope, &tok, argStart); 00566 00567 // regular function 00568 else 00569 addGlobalFunction(scope, tok, argStart, funcStart); 00570 00571 // syntax error 00572 if (!scope) { 00573 scope = old_scope; 00574 break; 00575 } 00576 } 00577 00578 // function returning function pointer with body 00579 else if (Token::simpleMatch(argStart->link(), ") ) (") && 00580 Token::Match(argStart->link()->linkAt(2), ") const| {")) { 00581 tok = funcStart; 00582 Scope *old_scope = scope; 00583 00584 // class function 00585 if (tok->previous()->str() == "::") 00586 addClassFunction(&scope, &tok, argStart); 00587 00588 // regular function 00589 else { 00590 Function* function = addGlobalFunction(scope, tok, argStart, funcStart); 00591 function->retFuncPtr = true; 00592 } 00593 00594 // syntax error? 00595 if (!scope) { 00596 scope = old_scope; 00597 break; 00598 } 00599 } 00600 00601 // function prototype 00602 else if (Token::simpleMatch(argStart->link(), ") ;")) { 00603 bool newFunc = true; // Is this function already in the database? 00604 for (std::list<Function>::const_iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) { 00605 if (i->tokenDef->str() == tok->str() && Function::argsMatch(scope, i->argDef->next(), argStart->next(), "", 0)) { 00606 newFunc = false; 00607 break; 00608 } 00609 } 00610 // save function prototype in database 00611 if (newFunc) 00612 addGlobalFunctionDecl(scope, argStart, funcStart); 00613 00614 tok = argStart->link()->next(); 00615 continue; 00616 } 00617 00618 // function returning function pointer prototype 00619 else if (Token::simpleMatch(argStart->link(), ") ) (") && 00620 Token::simpleMatch(argStart->link()->linkAt(2), ") ;")) { 00621 bool newFunc = true; // Is this function already in the database? 00622 for (std::list<Function>::const_iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) { 00623 if (i->tokenDef->str() == tok->str() && Function::argsMatch(scope, i->argDef, argStart, "", 0)) 00624 newFunc = false; 00625 } 00626 // save function prototype in database 00627 if (newFunc) { 00628 Function* func = addGlobalFunctionDecl(scope, argStart, funcStart); 00629 func->retFuncPtr = true; 00630 } 00631 00632 tok = argStart->link()->linkAt(2)->next(); 00633 continue; 00634 } 00635 } 00636 } else if (scope->isExecutable()) { 00637 if (Token::Match(tok, "else|try|do {")) { 00638 const Token* tok1 = tok->next(); 00639 if (tok->str() == "else") 00640 scopeList.push_back(Scope(this, tok, scope, Scope::eElse, tok1)); 00641 if (tok->str() == "do") 00642 scopeList.push_back(Scope(this, tok, scope, Scope::eDo, tok1)); 00643 else if (tok->str() == "try") 00644 scopeList.push_back(Scope(this, tok, scope, Scope::eTry, tok1)); 00645 00646 tok = tok1; 00647 scope->nestedList.push_back(&scopeList.back()); 00648 scope = &scopeList.back(); 00649 } else if (Token::Match(tok, "if|for|while|catch|switch (") && Token::simpleMatch(tok->next()->link(), ") {")) { 00650 const Token *tok1 = tok->next()->link()->next(); 00651 if (tok->str() == "if" && tok->strAt(-1) == "else") 00652 scopeList.push_back(Scope(this, tok->previous(), scope, Scope::eElseIf, tok1)); 00653 else if (tok->str() == "if") 00654 scopeList.push_back(Scope(this, tok, scope, Scope::eIf, tok1)); 00655 else if (tok->str() == "for") { 00656 scopeList.push_back(Scope(this, tok, scope, Scope::eFor, tok1)); 00657 } else if (tok->str() == "while") 00658 scopeList.push_back(Scope(this, tok, scope, Scope::eWhile, tok1)); 00659 else if (tok->str() == "catch") { 00660 scopeList.push_back(Scope(this, tok, scope, Scope::eCatch, tok1)); 00661 } else if (tok->str() == "switch") 00662 scopeList.push_back(Scope(this, tok, scope, Scope::eSwitch, tok1)); 00663 00664 scope->nestedList.push_back(&scopeList.back()); 00665 scope = &scopeList.back(); 00666 if (scope->type == Scope::eFor) 00667 scope->checkVariable(tok->tokAt(2), Local); // check for variable declaration and add it to new scope if found 00668 else if (scope->type == Scope::eCatch) 00669 scope->checkVariable(tok->tokAt(2), Throw); // check for variable declaration and add it to new scope if found 00670 tok = tok1; 00671 } else if (tok->str() == "{") { 00672 if (!Token::Match(tok->previous(), "=|,")) { 00673 scopeList.push_back(Scope(this, tok, scope, Scope::eUnconditional, tok)); 00674 scope->nestedList.push_back(&scopeList.back()); 00675 scope = &scopeList.back(); 00676 } else { 00677 tok = tok->link(); 00678 } 00679 } 00680 } 00681 } 00682 } 00683 00684 // fill in base class info 00685 for (std::list<Type>::iterator it = typeList.begin(); it != typeList.end(); ++it) { 00686 // finish filling in base class info 00687 for (unsigned int i = 0; i < it->derivedFrom.size(); ++i) 00688 it->derivedFrom[i].type = findType(it->derivedFrom[i].nameTok, it->enclosingScope); 00689 } 00690 00691 // fill in friend info 00692 for (std::list<Type>::iterator it = typeList.begin(); it != typeList.end(); ++it) { 00693 for (std::list<Type::FriendInfo>::iterator i = it->friendList.begin(); i != it->friendList.end(); ++i) { 00694 i->type = findType(i->nameStart, it->enclosingScope); 00695 } 00696 } 00697 00698 // fill in using info 00699 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00700 for (std::list<Scope::UsingInfo>::iterator i = it->usingList.begin(); i != it->usingList.end(); ++i) { 00701 // check scope for match 00702 scope = findScope(i->start->tokAt(2), &(*it)); 00703 if (scope) { 00704 // set found scope 00705 i->scope = scope; 00706 break; 00707 } 00708 } 00709 } 00710 00711 // fill in variable info 00712 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00713 // find variables 00714 it->getVariableList(); 00715 } 00716 00717 // fill in function arguments 00718 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00719 std::list<Function>::iterator func; 00720 00721 for (func = it->functionList.begin(); func != it->functionList.end(); ++func) { 00722 // add arguments 00723 func->addArguments(this, scope); 00724 } 00725 } 00726 00727 // fill in function scopes 00728 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00729 if (it->type == Scope::eFunction) 00730 functionScopes.push_back(&*it); 00731 } 00732 00733 // fill in class and struct scopes 00734 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00735 if (it->isClassOrStruct()) 00736 classAndStructScopes.push_back(&*it); 00737 } 00738 00739 // determine if user defined type needs initialization 00740 unsigned int unknowns = 0; // stop checking when there are no unknowns 00741 unsigned int retry = 0; // bail if we don't resolve all the variable types for some reason 00742 00743 do { 00744 unknowns = 0; 00745 00746 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00747 scope = &(*it); 00748 00749 if (scope->isClassOrStruct() && scope->definedType->needInitialization == Type::Unknown) { 00750 // check for default constructor 00751 bool hasDefaultConstructor = false; 00752 00753 std::list<Function>::const_iterator func; 00754 00755 for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { 00756 if (func->type == Function::eConstructor) { 00757 // check for no arguments: func ( ) 00758 if (func->argCount() == 0) { 00759 hasDefaultConstructor = true; 00760 break; 00761 } 00762 00763 /** check for arguments with default values */ 00764 else if (func->argCount() == func->initializedArgCount()) { 00765 hasDefaultConstructor = true; 00766 break; 00767 } 00768 } 00769 } 00770 00771 // User defined types with user defined default constructor doesn't need initialization. 00772 // We assume the default constructor initializes everything. 00773 // Another check will figure out if the constructor actually initializes everything. 00774 if (hasDefaultConstructor) 00775 scope->definedType->needInitialization = Type::False; 00776 00777 // check each member variable to see if it needs initialization 00778 else { 00779 bool needInitialization = false; 00780 bool unknown = false; 00781 00782 std::list<Variable>::const_iterator var; 00783 for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) { 00784 if (var->isClass()) { 00785 if (var->type()) { 00786 // does this type need initialization? 00787 if (var->type()->needInitialization == Type::True) 00788 needInitialization = true; 00789 else if (var->type()->needInitialization == Type::Unknown) 00790 unknown = true; 00791 } 00792 } else 00793 needInitialization = true; 00794 } 00795 00796 if (!unknown) { 00797 if (needInitialization) 00798 scope->definedType->needInitialization = Type::True; 00799 else 00800 scope->definedType->needInitialization = Type::False; 00801 } 00802 00803 if (scope->definedType->needInitialization == Type::Unknown) 00804 unknowns++; 00805 } 00806 } else if (scope->type == Scope::eUnion && scope->definedType->needInitialization == Type::Unknown) 00807 scope->definedType->needInitialization = Type::True; 00808 } 00809 00810 retry++; 00811 } while (unknowns && retry < 100); 00812 00813 // this shouldn't happen so output a debug warning 00814 if (retry == 100 && _settings->debugwarnings) { 00815 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00816 scope = &(*it); 00817 00818 if (scope->isClassOrStruct() && scope->definedType->needInitialization == Type::Unknown) 00819 debugMessage(scope->classDef, "SymbolDatabase::SymbolDatabase couldn't resolve all user defined types."); 00820 } 00821 } 00822 00823 // create variable symbol table 00824 _variableList.resize(_tokenizer->varIdCount() + 1); 00825 std::fill_n(_variableList.begin(), _variableList.size(), (const Variable*)NULL); 00826 00827 // check all scopes for variables 00828 for (std::list<Scope>::iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 00829 scope = &(*it); 00830 00831 // add all variables 00832 std::list<Variable>::const_iterator var; 00833 for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) { 00834 unsigned int varId = var->varId(); 00835 if (varId) 00836 _variableList[varId] = &(*var); 00837 } 00838 00839 // add all function parameters 00840 std::list<Function>::const_iterator func; 00841 for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { 00842 // ignore function without implementations 00843 if (!func->hasBody) 00844 continue; 00845 00846 std::list<Variable>::const_iterator arg; 00847 for (arg = func->argumentList.begin(); arg != func->argumentList.end(); ++arg) { 00848 // check for named parameters 00849 if (arg->nameToken() && arg->varId()) { 00850 unsigned int varId = arg->varId(); 00851 if (varId) 00852 _variableList[varId] = &(*arg); 00853 } 00854 } 00855 } 00856 } 00857 00858 // fill in missing variables if possible 00859 const std::size_t functions = functionScopes.size(); 00860 for (std::size_t i = 0; i < functions; ++i) { 00861 const Scope *func = functionScopes[i]; 00862 for (const Token *tok = func->classStart->next(); tok != func->classEnd; tok = tok->next()) { 00863 // check for member variable 00864 if (tok && tok->varId() && tok->next() && tok->next()->str() == ".") { 00865 const Token *tok1 = tok->tokAt(2); 00866 if (tok1 && tok1->varId() && _variableList[tok1->varId()] == 0) { 00867 const Variable *var = _variableList[tok->varId()]; 00868 if (var && var->typeScope()) { 00869 // find the member variable of this variable 00870 const Variable *var1 = var->typeScope()->getVariable(tok1->str()); 00871 if (var1) { 00872 // add this variable to the look up table 00873 _variableList[tok1->varId()] = var1; 00874 } 00875 } 00876 } 00877 } 00878 } 00879 } 00880 00881 /* set all unknown array dimensions that are set by a variable to the maximum size of that variable type */ 00882 for (std::size_t i = 1; i <= _tokenizer->varIdCount(); i++) { 00883 // check each array variable 00884 if (_variableList[i] && _variableList[i]->isArray()) { 00885 // check each array dimension 00886 for (std::size_t j = 0; j < _variableList[i]->dimensions().size(); j++) { 00887 Dimension &dimension = const_cast<Dimension &>(_variableList[i]->dimensions()[j]); 00888 // check for a single token dimension that is a variable 00889 if (dimension.num == 0) { 00890 dimension.known = false; 00891 if (!dimension.start || (dimension.start != dimension.end) || !dimension.start->varId()) 00892 continue; 00893 00894 // get maximum size from type 00895 // find where this type is defined 00896 const Variable *var = getVariableFromVarId(dimension.start->varId()); 00897 00898 // make sure it is in the database 00899 if (!var) 00900 break; 00901 00902 // get type token 00903 const Token *index_type = var->typeEndToken(); 00904 00905 if (index_type->str() == "char") { 00906 if (index_type->isUnsigned()) 00907 dimension.num = UCHAR_MAX + 1; 00908 else if (index_type->isSigned()) 00909 dimension.num = SCHAR_MAX + 1; 00910 else 00911 dimension.num = CHAR_MAX + 1; 00912 } else if (index_type->str() == "short") { 00913 if (index_type->isUnsigned()) 00914 dimension.num = USHRT_MAX + 1; 00915 else 00916 dimension.num = SHRT_MAX + 1; 00917 } 00918 00919 // checkScope assumes size is signed int so we limit the following sizes to INT_MAX 00920 else if (index_type->str() == "int") { 00921 if (index_type->isUnsigned()) 00922 dimension.num = UINT_MAX + 1ULL; 00923 else 00924 dimension.num = INT_MAX + 1ULL; 00925 } else if (index_type->str() == "long") { 00926 if (index_type->isUnsigned()) { 00927 if (index_type->isLong()) 00928 dimension.num = ULLONG_MAX; // should be ULLONG_MAX + 1ULL 00929 else 00930 dimension.num = ULONG_MAX; // should be ULONG_MAX + 1ULL 00931 } else { 00932 if (index_type->isLong()) 00933 dimension.num = LLONG_MAX; // should be LLONG_MAX + 1LL 00934 else 00935 dimension.num = LONG_MAX; // should be LONG_MAX + 1LL 00936 } 00937 } 00938 } 00939 } 00940 } 00941 } 00942 } 00943 00944 bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart) 00945 { 00946 // function returning function pointer? '... ( ... %var% ( ... ))( ... ) {' 00947 if (tok->str() == "(" && 00948 tok->link()->previous()->str() == ")" && 00949 tok->link()->next() && 00950 tok->link()->next()->str() == "(" && 00951 tok->link()->next()->link()->next() && 00952 Token::Match(tok->link()->next()->link()->next(), "{|;|const|=")) { 00953 *funcStart = tok->link()->previous()->link()->previous(); 00954 *argStart = tok->link()->previous()->link(); 00955 return true; 00956 } 00957 00958 // regular function? 00959 else if (Token::Match(tok, "%var% (") && tok->previous() && 00960 (tok->previous()->isName() || tok->strAt(-1) == ">" || tok->strAt(-1) == "&" || tok->strAt(-1) == "*" || // Either a return type in front of tok 00961 tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok 00962 outerScope->isClassOrStruct()) && // or a ctor/dtor 00963 (Token::Match(tok->next()->link(), ") const| ;|{|=") || 00964 Token::Match(tok->next()->link(), ") : ::| %var% (|::|<|{") || 00965 Token::Match(tok->next()->link(), ") = delete|default ;"))) { 00966 *funcStart = tok; 00967 *argStart = tok->next(); 00968 return true; 00969 } 00970 00971 // template constructor? 00972 else if (Token::Match(tok, "%var% <") && Token::simpleMatch(tok->next()->link(), "> (") && 00973 (Token::Match(tok->next()->link()->next()->link(), ") const| ;|{|=") || 00974 Token::Match(tok->next()->link()->next()->link(), ") : ::| %var% (|::|<|{"))) { 00975 *funcStart = tok; 00976 *argStart = tok->next()->link()->next(); 00977 return true; 00978 } 00979 00980 return false; 00981 } 00982 00983 void Variable::evaluate() 00984 { 00985 const Token* tok = _start; 00986 while (tok && tok->previous() && tok->previous()->isName()) 00987 tok = tok->previous(); 00988 for (const Token* const end = _name?_name:_end; tok != end;) { 00989 if (tok->str() == "static") 00990 setFlag(fIsStatic, true); 00991 else if (tok->str() == "extern") 00992 setFlag(fIsExtern, true); 00993 else if (tok->str() == "mutable") 00994 setFlag(fIsMutable, true); 00995 else if (tok->str() == "const") 00996 setFlag(fIsConst, true); 00997 else if (tok->str() == "*") { 00998 setFlag(fIsPointer, true); 00999 setFlag(fIsConst, false); // Points to const, isn't necessarily const itself 01000 } else if (tok->str() == "&") 01001 setFlag(fIsReference, true); 01002 01003 if (tok->str() == "<") 01004 tok->findClosingBracket(tok); 01005 else 01006 tok = tok->next(); 01007 } 01008 01009 while (_start && _start->next() && (_start->str() == "static" || _start->str() == "const")) 01010 _start = _start->next(); 01011 while (_end && _end->previous() && _end->str() == "const") 01012 _end = _end->previous(); 01013 01014 if (_name) 01015 setFlag(fIsArray, arrayDimensions(_dimensions, _name->next())); 01016 if (_start) 01017 setFlag(fIsClass, !_start->isStandardType() && !isPointer() && !isReference()); 01018 if (_access == Argument) { 01019 tok = _name; 01020 if (!tok) { 01021 // Argument without name 01022 tok = _end; 01023 // back up to start of array dimensions 01024 while (tok && tok->str() == "]") 01025 tok = tok->link()->previous(); 01026 // add array dimensions if present 01027 if (tok && tok->next()->str() == "[") 01028 setFlag(fIsArray, arrayDimensions(_dimensions, tok->next())); 01029 } 01030 if (!tok) 01031 return; 01032 tok = tok->next(); 01033 while (tok->str() == "[") 01034 tok = tok->link(); 01035 setFlag(fHasDefault, tok->str() == "="); 01036 } 01037 // check for C++11 member initialization 01038 if (_scope && _scope->isClassOrStruct()) { 01039 // type var = x; gets simplified to: type var ; var = x ; 01040 if (Token::Match(_name, "%var% ; %var% = %any% ;") && _name->strAt(2) == _name->str()) 01041 setFlag(fHasDefault, true); 01042 } 01043 } 01044 01045 bool Function::argsMatch(const Scope *scope, const Token *first, const Token *second, const std::string &path, unsigned int depth) 01046 { 01047 const bool isCPP = scope->check->isCPP(); 01048 01049 // skip "struct" if it is C++ 01050 if (isCPP) { 01051 if (first->str() == "struct") 01052 first = first->next(); 01053 if (second->str() == "struct") 01054 second = second->next(); 01055 } 01056 01057 // skip const on type passed by value 01058 if (Token::Match(first, "const %type% %var%|,|)")) 01059 first = first->next(); 01060 if (Token::Match(second, "const %type% %var%|,|)")) 01061 second = second->next(); 01062 01063 while (first->str() == second->str() && 01064 first->isLong() == second->isLong() && 01065 first->isUnsigned() == second->isUnsigned()) { 01066 // at end of argument list 01067 if (first->str() == ")") { 01068 return true; 01069 } 01070 01071 // skip default value assignment 01072 else if (first->next()->str() == "=") { 01073 first = first->nextArgument(); 01074 01075 if (second->next()->str() == "=") { 01076 second = second->nextArgument(); 01077 if (!first || !second) { // End of argument list (first or second) 01078 return !first && !second; 01079 } 01080 } else if (!first) { // End of argument list (first) 01081 return second->next() && second->next()->str() == ")"; 01082 } 01083 } 01084 01085 // definition missing variable name 01086 else if (first->next()->str() == "," && second->next()->str() != ",") 01087 second = second->next(); 01088 else if (first->next()->str() == ")" && second->next()->str() != ")") 01089 second = second->next(); 01090 else if (first->next()->str() == "[" && second->next()->str() != "[") 01091 second = second->next(); 01092 01093 // function missing variable name 01094 else if (second->next()->str() == "," && first->next()->str() != ",") 01095 first = first->next(); 01096 else if (second->next()->str() == ")" && first->next()->str() != ")") 01097 first = first->next(); 01098 else if (second->next()->str() == "[" && first->next()->str() != "[") 01099 first = first->next(); 01100 01101 // argument list has different number of arguments 01102 else if (second->str() == ")") 01103 break; 01104 01105 // variable names are different 01106 else if ((Token::Match(first->next(), "%var% ,|)|=") && 01107 Token::Match(second->next(), "%var% ,|)")) && 01108 (first->next()->str() != second->next()->str())) { 01109 // skip variable names 01110 first = first->next(); 01111 second = second->next(); 01112 } 01113 01114 // variable with class path 01115 else if (depth && Token::Match(first->next(), "%var%")) { 01116 std::string param = path + first->next()->str(); 01117 01118 if (Token::Match(second->next(), param.c_str())) { 01119 second = second->tokAt(int(depth) * 2); 01120 } else if (depth > 1) { 01121 std::string short_path = path; 01122 01123 // remove last " :: " 01124 short_path.resize(short_path.size() - 4); 01125 01126 // remove last name 01127 while (!short_path.empty() && short_path[short_path.size() - 1] != ' ') 01128 short_path.resize(short_path.size() - 1); 01129 01130 param = short_path + first->next()->str(); 01131 if (Token::Match(second->next(), param.c_str())) { 01132 second = second->tokAt((int(depth) - 1) * 2); 01133 } 01134 } 01135 } 01136 01137 // nested class variable 01138 else if (depth == 0 && Token::Match(first->next(), "%var%") && 01139 second->next()->str() == scope->className && second->strAt(2) == "::" && 01140 first->next()->str() == second->strAt(3)) { 01141 second = second->tokAt(2); 01142 } 01143 01144 first = first->next(); 01145 second = second->next(); 01146 01147 // skip "struct" if it is C++ 01148 if (isCPP) { 01149 if (first->str() == "struct") 01150 first = first->next(); 01151 if (second->str() == "struct") 01152 second = second->next(); 01153 } 01154 01155 // skip const on type passed by value 01156 if (Token::Match(first, "const %type% %var%|,|)")) 01157 first = first->next(); 01158 if (Token::Match(second, "const %type% %var%|,|)")) 01159 second = second->next(); 01160 } 01161 01162 return false; 01163 } 01164 01165 Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart) 01166 { 01167 Function* function = 0; 01168 for (std::list<Function>::iterator i = scope->functionList.begin(); i != scope->functionList.end(); ++i) { 01169 if (i->tokenDef->str() == tok->str() && Function::argsMatch(scope, i->argDef->next(), argStart->next(), "", 0)) 01170 function = &*i; 01171 } 01172 01173 if (!function) 01174 function = addGlobalFunctionDecl(scope, argStart, funcStart); 01175 01176 function->arg = argStart; 01177 function->token = funcStart; 01178 function->hasBody = true; 01179 01180 addNewFunction(&scope, &tok); 01181 01182 if (scope) { 01183 scope->function = function; 01184 function->functionScope = scope; 01185 return function; 01186 } 01187 return 0; 01188 } 01189 01190 Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *argStart, const Token* funcStart) 01191 { 01192 Function function; 01193 01194 // save the function definition argument start '(' 01195 function.argDef = argStart; 01196 01197 // save the access type 01198 function.access = Public; 01199 01200 // save the function name location 01201 function.tokenDef = funcStart; 01202 01203 function.isInline = false; 01204 function.hasBody = false; 01205 function.type = Function::eFunction; 01206 function.nestedIn = scope; 01207 01208 scope->functionList.push_back(function); 01209 return &scope->functionList.back(); 01210 } 01211 01212 void SymbolDatabase::addClassFunction(Scope **scope, const Token **tok, const Token *argStart) 01213 { 01214 int count = 0; 01215 std::string path; 01216 unsigned int path_length = 0; 01217 const Token *tok1; 01218 01219 const bool destructor((*tok)->previous()->str() == "~"); 01220 01221 // skip class/struct name 01222 if (destructor) 01223 tok1 = (*tok)->tokAt(-3); 01224 else 01225 tok1 = (*tok)->tokAt(-2); 01226 01227 // syntax error? 01228 if (!tok1) 01229 return; 01230 01231 // back up to head of path 01232 while (tok1 && tok1->previous() && tok1->previous()->str() == "::" && 01233 tok1->tokAt(-2) && tok1->tokAt(-2)->isName()) { 01234 path = tok1->str() + " :: " + path; 01235 tok1 = tok1->tokAt(-2); 01236 count++; 01237 path_length++; 01238 } 01239 01240 if (tok1 && count) { 01241 path = tok1->str() + " :: " + path; 01242 path_length++; 01243 } 01244 01245 std::list<Scope>::iterator it1; 01246 01247 // search for match 01248 for (it1 = scopeList.begin(); it1 != scopeList.end(); ++it1) { 01249 Scope *scope1 = &(*it1); 01250 01251 bool match = false; 01252 if (scope1->className == tok1->str() && (scope1->type != Scope::eFunction)) { 01253 // do the scopes match (same scope) or do their names match (multiple namespaces) 01254 if ((*scope == scope1->nestedIn) || (*scope && scope1 && 01255 (*scope)->className == scope1->nestedIn->className && 01256 !(*scope)->className.empty() && 01257 (*scope)->type == scope1->nestedIn->type)) { 01258 01259 // nested scopes => check that they match 01260 { 01261 const Scope *s1 = *scope; 01262 const Scope *s2 = scope1->nestedIn; 01263 while (s1 && s2) { 01264 if (s1->className != s2->className) 01265 break; 01266 s1 = s1->nestedIn; 01267 s2 = s2->nestedIn; 01268 } 01269 // Not matching scopes 01270 if (s1 || s2) 01271 continue; 01272 } 01273 01274 Scope *scope2 = scope1; 01275 01276 while (scope2 && count > 0) { 01277 count--; 01278 tok1 = tok1->tokAt(2); 01279 scope2 = scope2->findInNestedList(tok1->str()); 01280 } 01281 01282 if (count == 0 && scope2) { 01283 match = true; 01284 scope1 = scope2; 01285 } 01286 } 01287 } 01288 01289 if (match) { 01290 std::list<Function>::iterator func; 01291 01292 for (func = scope1->functionList.begin(); func != scope1->functionList.end(); ++func) { 01293 if (!func->hasBody && func->tokenDef->str() == (*tok)->str()) { 01294 if (Function::argsMatch(scope1, func->argDef, (*tok)->next(), path, path_length)) { 01295 if (func->type == Function::eDestructor && destructor) { 01296 func->hasBody = true; 01297 } else if (func->type != Function::eDestructor && !destructor) { 01298 // normal function? 01299 if (!func->retFuncPtr && (*tok)->next()->link()) { 01300 if ((func->isConst && (*tok)->next()->link()->next()->str() == "const") || 01301 (!func->isConst && (*tok)->next()->link()->next()->str() != "const")) { 01302 func->hasBody = true; 01303 } 01304 } 01305 01306 // function returning function pointer? 01307 else if (func->retFuncPtr) { 01308 // todo check for const 01309 func->hasBody = true; 01310 } 01311 } 01312 01313 if (func->hasBody) { 01314 func->token = *tok; 01315 func->arg = argStart; 01316 addNewFunction(scope, tok); 01317 if (*scope) { 01318 (*scope)->functionOf = scope1; 01319 (*scope)->function = &*func; 01320 (*scope)->function->functionScope = *scope; 01321 } 01322 return; 01323 } 01324 } 01325 } 01326 } 01327 } 01328 } 01329 01330 // class function of unknown class 01331 addNewFunction(scope, tok); 01332 } 01333 01334 void SymbolDatabase::addNewFunction(Scope **scope, const Token **tok) 01335 { 01336 const Token *tok1 = *tok; 01337 scopeList.push_back(Scope(this, tok1, *scope)); 01338 Scope *new_scope = &scopeList.back(); 01339 01340 // skip to start of function 01341 while (tok1 && ((tok1->str() != "{") || (tok1->previous() && tok1->previous()->isName() && tok1->strAt(-1) != "const" && Token::Match(tok1->link()->next(), ",|{|%type%")))) { 01342 if (tok1->str() == "(" || tok1->str() == "{") 01343 tok1 = tok1->link(); 01344 tok1 = tok1->next(); 01345 } 01346 01347 if (tok1) { 01348 new_scope->classStart = tok1; 01349 new_scope->classEnd = tok1->link(); 01350 01351 // syntax error? 01352 if (!new_scope->classEnd) { 01353 scopeList.pop_back(); 01354 while (tok1->next()) 01355 tok1 = tok1->next(); 01356 *scope = NULL; 01357 *tok = tok1; 01358 return; 01359 } 01360 01361 (*scope)->nestedList.push_back(new_scope); 01362 *scope = new_scope; 01363 *tok = tok1; 01364 } else { 01365 scopeList.pop_back(); 01366 *scope = NULL; 01367 *tok = NULL; 01368 } 01369 } 01370 01371 const Token *Type::initBaseInfo(const Token *tok, const Token *tok1) 01372 { 01373 // goto initial '{' 01374 const Token *tok2 = tok1; 01375 while (tok2 && tok2->str() != "{") { 01376 // skip unsupported templates 01377 if (tok2->str() == "<") 01378 tok2->findClosingBracket(tok2); 01379 01380 // check for base classes 01381 else if (Token::Match(tok2, ":|,")) { 01382 Type::BaseInfo base; 01383 01384 base.isVirtual = false; 01385 01386 tok2 = tok2->next(); 01387 01388 // check for invalid code 01389 if (!tok2 || !tok2->next()) 01390 return NULL; 01391 01392 if (tok2->str() == "virtual") { 01393 base.isVirtual = true; 01394 tok2 = tok2->next(); 01395 } 01396 01397 if (tok2->str() == "public") { 01398 base.access = Public; 01399 tok2 = tok2->next(); 01400 } else if (tok2->str() == "protected") { 01401 base.access = Protected; 01402 tok2 = tok2->next(); 01403 } else if (tok2->str() == "private") { 01404 base.access = Private; 01405 tok2 = tok2->next(); 01406 } else { 01407 if (tok->str() == "class") 01408 base.access = Private; 01409 else if (tok->str() == "struct") 01410 base.access = Public; 01411 } 01412 01413 if (tok2->str() == "virtual") { 01414 base.isVirtual = true; 01415 tok2 = tok2->next(); 01416 } 01417 01418 base.nameTok = tok2; 01419 01420 // handle global namespace 01421 if (tok2->str() == "::") { 01422 tok2 = tok2->next(); 01423 } 01424 01425 // handle derived base classes 01426 while (Token::Match(tok2, "%var% ::")) { 01427 tok2 = tok2->tokAt(2); 01428 } 01429 01430 base.name = tok2->str(); 01431 base.type = NULL; 01432 01433 // add unhandled templates 01434 if (tok2->next() && tok2->next()->str() == "<") { 01435 tok2 = tok2->next(); 01436 base.name += tok2->str(); 01437 01438 int level1 = 1; 01439 while (tok2->next()) { 01440 base.name += tok2->next()->str(); 01441 01442 if (tok2->next()->str() == ">") { 01443 level1--; 01444 if (level1 == 0) 01445 break; 01446 } else if (tok2->next()->str() == "<") 01447 level1++; 01448 01449 tok2 = tok2->next(); 01450 } 01451 } 01452 01453 // save pattern for base class name 01454 derivedFrom.push_back(base); 01455 } 01456 tok2 = tok2->next(); 01457 } 01458 01459 return tok2; 01460 } 01461 01462 void SymbolDatabase::debugMessage(const Token *tok, const std::string &msg) const 01463 { 01464 if (tok && _settings->debugwarnings) { 01465 const std::list<const Token*> locationList(1, tok); 01466 const ErrorLogger::ErrorMessage errmsg(locationList, &_tokenizer->list, 01467 Severity::debug, 01468 "debug", 01469 msg, 01470 false); 01471 if (_errorLogger) 01472 _errorLogger->reportErr(errmsg); 01473 } 01474 } 01475 01476 const Function* Type::getFunction(const std::string& funcName) const 01477 { 01478 if (classScope) { 01479 for (std::list<Function>::const_iterator i = classScope->functionList.begin(); i != classScope->functionList.end(); ++i) 01480 if (i->name() == funcName) 01481 return &*i; 01482 } 01483 01484 for (std::size_t i = 0; i < derivedFrom.size(); i++) { 01485 if (derivedFrom[i].type) { 01486 const Function* func = derivedFrom[i].type->getFunction(funcName); 01487 if (func) 01488 return func; 01489 } 01490 } 01491 return 0; 01492 } 01493 01494 bool Variable::arrayDimensions(std::vector<Dimension> &dimensions, const Token *tok) 01495 { 01496 bool isArray = false; 01497 01498 const Token *dim = tok; 01499 01500 while (dim && dim->next() && dim->str() == "[") { 01501 Dimension dimension; 01502 // check for empty array dimension [] 01503 if (dim->next()->str() != "]") { 01504 dimension.start = dim->next(); 01505 dimension.end = dim->link()->previous(); 01506 if (dimension.start == dimension.end && dimension.start->isNumber()) 01507 dimension.num = MathLib::toLongNumber(dimension.start->str()); 01508 } 01509 dimensions.push_back(dimension); 01510 dim = dim->link()->next(); 01511 isArray = true; 01512 } 01513 return isArray; 01514 } 01515 01516 static std::ostream & operator << (std::ostream & s, Scope::ScopeType type) 01517 { 01518 s << (type == Scope::eGlobal ? "Global" : 01519 type == Scope::eClass ? "Class" : 01520 type == Scope::eStruct ? "Struct" : 01521 type == Scope::eUnion ? "Union" : 01522 type == Scope::eNamespace ? "Namespace" : 01523 type == Scope::eFunction ? "Function" : 01524 type == Scope::eIf ? "If" : 01525 type == Scope::eElse ? "Else" : 01526 type == Scope::eElseIf ? "ElseIf" : 01527 type == Scope::eFor ? "For" : 01528 type == Scope::eWhile ? "While" : 01529 type == Scope::eDo ? "Do" : 01530 type == Scope::eSwitch ? "Switch" : 01531 type == Scope::eTry ? "Try" : 01532 type == Scope::eCatch ? "Catch" : 01533 type == Scope::eUnconditional ? "Unconditional" : 01534 "Unknown"); 01535 return s; 01536 } 01537 01538 void SymbolDatabase::printVariable(const Variable *var, const char *indent) const 01539 { 01540 std::cout << indent << "_name: " << var->nameToken(); 01541 if (var->nameToken()) { 01542 std::cout << " " << var->name() << " " << _tokenizer->list.fileLine(var->nameToken()) << std::endl; 01543 std::cout << indent << " varId: " << var->varId() << std::endl; 01544 } else 01545 std::cout << std::endl; 01546 std::cout << indent << "_start: " << var->typeStartToken() << " " << var->typeStartToken()->str() 01547 << " " << _tokenizer->list.fileLine(var->typeStartToken()) << std::endl; 01548 std::cout << indent << "_end: " << var->typeEndToken() << " " << var->typeEndToken()->str() 01549 << " " << _tokenizer->list.fileLine(var->typeEndToken()) << std::endl; 01550 std::cout << indent << "_index: " << var->index() << std::endl; 01551 std::cout << indent << "_access: " << 01552 (var->isPublic() ? "Public" : 01553 var->isProtected() ? "Protected" : 01554 var->isPrivate() ? "Private" : 01555 var->isGlobal() ? "Global" : 01556 var->isNamespace() ? "Namespace" : 01557 var->isArgument() ? "Argument" : 01558 var->isLocal() ? "Local" : 01559 var->isThrow() ? "Throw" : 01560 "???") << std::endl; 01561 std::cout << indent << "_flags: " << std::endl; 01562 std::cout << indent << " isMutable: " << (var->isMutable() ? "true" : "false") << std::endl; 01563 std::cout << indent << " isStatic: " << (var->isStatic() ? "true" : "false") << std::endl; 01564 std::cout << indent << " isExtern: " << (var->isExtern() ? "true" : "false") << std::endl; 01565 std::cout << indent << " isConst: " << (var->isConst() ? "true" : "false") << std::endl; 01566 std::cout << indent << " isClass: " << (var->isClass() ? "true" : "false") << std::endl; 01567 std::cout << indent << " isArray: " << (var->isArray() ? "true" : "false") << std::endl; 01568 std::cout << indent << " isPointer: " << (var->isPointer() ? "true" : "false") << std::endl; 01569 std::cout << indent << " isReference: " << (var->isReference() ? "true" : "false") << std::endl; 01570 std::cout << indent << " hasDefault: " << (var->hasDefault() ? "true" : "false") << std::endl; 01571 std::cout << indent << "_type: "; 01572 if (var->type()) { 01573 std::cout << var->type()->name(); 01574 if (var->typeScope()) 01575 std::cout << " " << var->typeScope()->type; 01576 std::cout << " " << _tokenizer->list.fileLine(var->type()->classDef) << std::endl; 01577 } else 01578 std::cout << "none" << std::endl; 01579 01580 std::cout << indent << "_scope: "; 01581 if (var->scope()) { 01582 std::cout << var->scope()->className << " " << var->scope()->type; 01583 if (var->scope()->classDef) 01584 std::cout << " " << _tokenizer->list.fileLine(var->scope()->classDef) << std::endl; 01585 else 01586 std::cout << std::endl; 01587 } else 01588 std::cout << "none" << std::endl; 01589 01590 std::cout << indent << "_dimensions:"; 01591 for (std::size_t i = 0; i < var->dimensions().size(); i++) { 01592 std::cout << " " << var->dimension(i); 01593 if (!var->dimensions()[i].known) 01594 std::cout << "?"; 01595 } 01596 std::cout << std::endl; 01597 } 01598 01599 void SymbolDatabase::printOut(const char *title) const 01600 { 01601 if (title) 01602 std::cout << "\n### " << title << " ###\n"; 01603 01604 for (std::list<Scope>::const_iterator scope = scopeList.begin(); scope != scopeList.end(); ++scope) { 01605 std::cout << "Scope: " << &*scope << std::endl; 01606 std::cout << " type: " << scope->type << std::endl; 01607 std::cout << " className: " << scope->className << std::endl; 01608 std::cout << " classDef: " << scope->classDef; 01609 if (scope->classDef) 01610 std::cout << " " << scope->classDef->str() << " " << _tokenizer->list.fileLine(scope->classDef) << std::endl; 01611 else 01612 std::cout << std::endl; 01613 01614 std::cout << " classStart: " << scope->classStart; 01615 if (scope->classStart) 01616 std::cout << " " << scope->classStart->str() << " " << _tokenizer->list.fileLine(scope->classStart) << std::endl; 01617 else 01618 std::cout << std::endl; 01619 01620 std::cout << " classEnd: " << scope->classEnd; 01621 if (scope->classEnd) 01622 std::cout << " " << scope->classEnd->str() << " " << _tokenizer->list.fileLine(scope->classEnd) << std::endl; 01623 else 01624 std::cout << std::endl; 01625 01626 std::list<Function>::const_iterator func; 01627 01628 // find the function body if not implemented inline 01629 for (func = scope->functionList.begin(); func != scope->functionList.end(); ++func) { 01630 std::cout << " Function: " << &*func << std::endl; 01631 std::cout << " name: " << func->tokenDef->str() << " " 01632 << _tokenizer->list.fileLine(func->tokenDef) << std::endl; 01633 std::cout << " type: " << (func->type == Function::eConstructor? "Constructor" : 01634 func->type == Function::eCopyConstructor ? "CopyConstructor" : 01635 func->type == Function::eOperatorEqual ? "OperatorEqual" : 01636 func->type == Function::eDestructor ? "Destructor" : 01637 func->type == Function::eFunction ? "Function" : 01638 "???") << std::endl; 01639 std::cout << " access: " << (func->access == Public ? "Public" : 01640 func->access == Protected ? "Protected" : 01641 func->access == Private ? "Private" : 01642 "???") << std::endl; 01643 std::cout << " hasBody: " << (func->hasBody ? "true" : "false") << std::endl; 01644 std::cout << " isInline: " << (func->isInline ? "true" : "false") << std::endl; 01645 std::cout << " isConst: " << (func->isConst ? "true" : "false") << std::endl; 01646 std::cout << " isVirtual: " << (func->isVirtual ? "true" : "false") << std::endl; 01647 std::cout << " isPure: " << (func->isPure ? "true" : "false") << std::endl; 01648 std::cout << " isStatic: " << (func->isStatic ? "true" : "false") << std::endl; 01649 std::cout << " isFriend: " << (func->isFriend ? "true" : "false") << std::endl; 01650 std::cout << " isExplicit: " << (func->isExplicit ? "true" : "false") << std::endl; 01651 std::cout << " isDefault: " << (func->isDefault ? "true" : "false") << std::endl; 01652 std::cout << " isDelete: " << (func->isDelete ? "true" : "false") << std::endl; 01653 std::cout << " isOperator: " << (func->isOperator ? "true" : "false") << std::endl; 01654 std::cout << " retFuncPtr: " << (func->retFuncPtr ? "true" : "false") << std::endl; 01655 std::cout << " tokenDef: " << _tokenizer->list.fileLine(func->tokenDef) << std::endl; 01656 std::cout << " argDef: " << _tokenizer->list.fileLine(func->argDef) << std::endl; 01657 if (func->hasBody) { 01658 std::cout << " token: " << _tokenizer->list.fileLine(func->token) << std::endl; 01659 std::cout << " arg: " << _tokenizer->list.fileLine(func->arg) << std::endl; 01660 } 01661 std::cout << " nestedIn: "; 01662 if (func->nestedIn) { 01663 std::cout << func->nestedIn->className << " " << func->nestedIn->type; 01664 if (func->nestedIn->classDef) 01665 std::cout << " " << _tokenizer->list.fileLine(func->nestedIn->classDef) << std::endl; 01666 else 01667 std::cout << std::endl; 01668 } else 01669 std::cout << "Unknown" << std::endl; 01670 std::cout << " functionScope: "; 01671 if (func->functionScope) { 01672 std::cout << func->functionScope->className << " " 01673 << _tokenizer->list.fileLine(func->functionScope->classDef) << std::endl; 01674 } else 01675 std::cout << "Unknown" << std::endl; 01676 01677 std::list<Variable>::const_iterator var; 01678 01679 for (var = func->argumentList.begin(); var != func->argumentList.end(); ++var) { 01680 std::cout << " Variable: " << &*var << std::endl; 01681 printVariable(&*var, " "); 01682 } 01683 } 01684 01685 std::list<Variable>::const_iterator var; 01686 01687 for (var = scope->varlist.begin(); var != scope->varlist.end(); ++var) { 01688 std::cout << " Variable: " << &*var << std::endl; 01689 printVariable(&*var, " "); 01690 } 01691 01692 std::cout << " nestedIn: " << scope->nestedIn; 01693 if (scope->nestedIn) { 01694 std::cout << " " << scope->nestedIn->type << " " 01695 << scope->nestedIn->className; 01696 } 01697 std::cout << std::endl; 01698 01699 std::cout << " definedType: " << scope->definedType << std::endl; 01700 01701 std::cout << " nestedList[" << scope->nestedList.size() << "] = ("; 01702 01703 std::list<Scope *>::const_iterator nsi; 01704 01705 std::size_t count = scope->nestedList.size(); 01706 for (nsi = scope->nestedList.begin(); nsi != scope->nestedList.end(); ++nsi) { 01707 std::cout << " " << (*nsi) << " " << (*nsi)->type << " " << (*nsi)->className; 01708 if (count-- > 1) 01709 std::cout << ","; 01710 } 01711 01712 std::cout << " )" << std::endl; 01713 01714 std::list<Scope::UsingInfo>::const_iterator use; 01715 01716 for (use = scope->usingList.begin(); use != scope->usingList.end(); ++use) { 01717 std::cout << " using: " << use->scope << " " << use->start->strAt(2); 01718 const Token *tok1 = use->start->tokAt(3); 01719 while (tok1 && tok1->str() == "::") { 01720 std::cout << "::" << tok1->strAt(1); 01721 tok1 = tok1->tokAt(2); 01722 } 01723 std::cout << " " << _tokenizer->list.fileLine(use->start) << std::endl; 01724 } 01725 01726 std::cout << " functionOf: " << scope->functionOf; 01727 if (scope->functionOf) { 01728 std::cout << " " << scope->functionOf->type << " " << scope->functionOf->className; 01729 if (scope->functionOf->classDef) 01730 std::cout << " " << _tokenizer->list.fileLine(scope->functionOf->classDef); 01731 } 01732 std::cout << std::endl; 01733 01734 std::cout << " function: " << scope->function; 01735 if (scope->function) { 01736 std::cout << " " << scope->function->tokenDef->str() << " " 01737 << _tokenizer->list.fileLine(scope->function->tokenDef); 01738 } 01739 std::cout << std::endl; 01740 } 01741 01742 for (std::list<Type>::const_iterator type = typeList.begin(); type != typeList.end(); ++type) { 01743 std::cout << "Type: " << type->name() << std::endl; 01744 std::cout << " classDef: " << _tokenizer->list.fileLine(type->classDef) << std::endl; 01745 std::cout << " classScope: " << type->classScope << std::endl; 01746 std::cout << " enclosingScope: " << type->enclosingScope << std::endl; 01747 std::cout << " needInitialization: " << (type->needInitialization == Type::Unknown ? "Unknown" : 01748 type->needInitialization == Type::True ? "True" : 01749 type->needInitialization == Type::False ? "False" : 01750 "Invalid") << std::endl; 01751 01752 std::cout << " derivedFrom[" << type->derivedFrom.size() << "] = ("; 01753 std::size_t count = type->derivedFrom.size(); 01754 for (std::size_t i = 0; i < type->derivedFrom.size(); ++i) { 01755 if (type->derivedFrom[i].isVirtual) 01756 std::cout << "Virtual "; 01757 01758 std::cout << (type->derivedFrom[i].access == Public ? " Public " : 01759 type->derivedFrom[i].access == Protected ? " Protected " : 01760 type->derivedFrom[i].access == Private ? " Private " : 01761 " Unknown"); 01762 01763 if (type->derivedFrom[i].type) 01764 std::cout << type->derivedFrom[i].type; 01765 else 01766 std::cout << " Unknown"; 01767 01768 std::cout << " " << type->derivedFrom[i].name; 01769 if (count-- > 1) 01770 std::cout << ","; 01771 } 01772 01773 std::cout << " )" << std::endl; 01774 01775 std::cout << " friendList[" << type->friendList.size() << "] = ("; 01776 01777 std::list<Type::FriendInfo>::const_iterator fii; 01778 01779 count = type->friendList.size(); 01780 for (fii = type->friendList.begin(); fii != type->friendList.end(); ++fii) { 01781 if (fii->type) 01782 std::cout << fii->type; 01783 else 01784 std::cout << " Unknown"; 01785 01786 std::cout << " " << fii->name; 01787 if (count-- > 1) 01788 std::cout << ","; 01789 } 01790 01791 std::cout << " )" << std::endl; 01792 } 01793 01794 for (std::size_t i = 1; i < _variableList.size(); i++) { 01795 std::cout << "_variableList[" << i << "]: " << _variableList[i]; 01796 if (_variableList[i]) { 01797 std::cout << " " << _variableList[i]->name() << " " 01798 << _tokenizer->list.fileLine(_variableList[i]->nameToken()); 01799 } 01800 std::cout << std::endl; 01801 } 01802 } 01803 01804 //--------------------------------------------------------------------------- 01805 01806 void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope) 01807 { 01808 // check for non-empty argument list "( ... )" 01809 const Token * start = arg ? arg : argDef; 01810 if (start && start->link() != start->next() && !Token::simpleMatch(start, "( void )")) { 01811 unsigned int count = 0; 01812 01813 for (const Token* tok = start->next(); tok; tok = tok->next()) { 01814 const Token* startTok = tok; 01815 const Token* endTok = NULL; 01816 const Token* nameTok = NULL; 01817 01818 if (tok->str() == "," || tok->str() == ")") 01819 return; // Syntax error 01820 01821 do { 01822 if (tok->varId() != 0) { 01823 nameTok = tok; 01824 endTok = tok->previous(); 01825 } else if (tok->str() == "[") { 01826 // skip array dimension(s) 01827 tok = tok->link(); 01828 while (tok->next()->str() == "[") 01829 tok = tok->next()->link(); 01830 } else if (tok->str() == "<") { 01831 bool success = tok->findClosingBracket(tok); 01832 if (!tok || !success) // something is wrong so just bail out 01833 return; 01834 } 01835 01836 tok = tok->next(); 01837 01838 if (!tok) // something is wrong so just bail 01839 return; 01840 } while (tok->str() != "," && tok->str() != ")" && tok->str() != "="); 01841 01842 const Token *typeTok = startTok->tokAt(startTok->str() == "const" ? 1 : 0); 01843 if (typeTok->str() == "struct") 01844 typeTok = typeTok->next(); 01845 01846 // check for argument with no name or missing varid 01847 if (!endTok) { 01848 if (tok->previous()->isName()) { 01849 if (tok->previous() != typeTok) { 01850 nameTok = tok->previous(); 01851 endTok = nameTok->previous(); 01852 01853 if (hasBody) 01854 symbolDatabase->debugMessage(nameTok, "Function::addArguments found argument \'" + nameTok->str() + "\' with varid 0."); 01855 } else 01856 endTok = startTok; 01857 } else 01858 endTok = tok->previous(); 01859 } 01860 01861 const ::Type *argType = NULL; 01862 if (!typeTok->isStandardType()) { 01863 argType = symbolDatabase->findVariableType(scope, typeTok); 01864 if (!argType) { 01865 // look for variable type in any using namespace in this scope or above 01866 const Scope *parent = scope; 01867 while (parent) { 01868 for (std::list<Scope::UsingInfo>::const_iterator ui = scope->usingList.begin(); 01869 ui != scope->usingList.end(); ++ui) { 01870 if (ui->scope) { 01871 argType = symbolDatabase->findVariableType(ui->scope, typeTok); 01872 if (argType) 01873 break; 01874 } 01875 } 01876 parent = parent->nestedIn; 01877 } 01878 } 01879 } 01880 01881 // skip default values 01882 if (tok->str() == "=") { 01883 while (tok->str() != "," && tok->str() != ")") { 01884 if (tok->link() && Token::Match(tok, "[{[(<]")) 01885 tok = tok->link(); 01886 tok = tok->next(); 01887 } 01888 } 01889 01890 argumentList.push_back(Variable(nameTok, startTok, endTok, count++, Argument, argType, functionScope)); 01891 01892 if (tok->str() == ")") 01893 break; 01894 } 01895 01896 // count deafult arguments 01897 for (const Token* tok = argDef->next(); tok && tok != argDef->link(); tok = tok->next()) { 01898 if (tok->str() == "=") 01899 initArgCount++; 01900 } 01901 } 01902 } 01903 01904 bool Function::isImplicitlyVirtual(bool defaultVal) const 01905 { 01906 if (isVirtual) 01907 return true; 01908 else if (access == Private || access == Public || access == Protected) { 01909 bool safe = true; 01910 bool hasVirt = isImplicitlyVirtual_rec(nestedIn->definedType, safe); 01911 if (hasVirt) 01912 return true; 01913 else if (safe) 01914 return false; 01915 else 01916 return defaultVal; 01917 } else 01918 return false; 01919 } 01920 01921 bool Function::isImplicitlyVirtual_rec(const ::Type* baseType, bool& safe) const 01922 { 01923 // check each base class 01924 for (unsigned int i = 0; i < baseType->derivedFrom.size(); ++i) { 01925 // check if base class exists in database 01926 if (baseType->derivedFrom[i].type && baseType->derivedFrom[i].type->classScope) { 01927 const Scope *parent = baseType->derivedFrom[i].type->classScope; 01928 01929 std::list<Function>::const_iterator func; 01930 01931 // check if function defined in base class 01932 for (func = parent->functionList.begin(); func != parent->functionList.end(); ++func) { 01933 if (func->isVirtual && func->tokenDef->str() == tokenDef->str()) { // Base is virtual and of same name 01934 const Token *temp1 = func->tokenDef->previous(); 01935 const Token *temp2 = tokenDef->previous(); 01936 bool returnMatch = true; 01937 01938 // check for matching return parameters 01939 while (temp1->str() != "virtual") { 01940 if (temp1->str() != temp2->str()) { 01941 returnMatch = false; 01942 break; 01943 } 01944 01945 temp1 = temp1->previous(); 01946 temp2 = temp2->previous(); 01947 } 01948 01949 // check for matching function parameters 01950 if (returnMatch && argsMatch(baseType->classScope, func->argDef, argDef, "", 0)) { 01951 return true; 01952 } 01953 } 01954 } 01955 01956 if (!baseType->derivedFrom[i].type->derivedFrom.empty()) 01957 if (isImplicitlyVirtual_rec(baseType->derivedFrom[i].type, safe)) 01958 return true; 01959 } else { 01960 // unable to find base class so assume it has no virtual function 01961 safe = false; 01962 return false; 01963 } 01964 } 01965 return false; 01966 } 01967 01968 const Variable* Function::getArgumentVar(unsigned int num) const 01969 { 01970 for (std::list<Variable>::const_iterator i = argumentList.begin(); i != argumentList.end(); ++i) { 01971 if (i->index() == num) 01972 return(&*i); 01973 else if (i->index() > num) 01974 return 0; 01975 } 01976 return 0; 01977 } 01978 01979 01980 //--------------------------------------------------------------------------- 01981 01982 Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_) : 01983 check(check_), 01984 classDef(classDef_), 01985 classStart(start_), 01986 classEnd(start_->link()), 01987 nestedIn(nestedIn_), 01988 numConstructors(0), 01989 numCopyConstructors(0), 01990 type(type_), 01991 definedType(NULL), 01992 functionOf(NULL), 01993 function(NULL) 01994 { 01995 } 01996 01997 Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_) : 01998 check(check_), 01999 classDef(classDef_), 02000 classStart(NULL), 02001 classEnd(NULL), 02002 nestedIn(nestedIn_), 02003 numConstructors(0), 02004 numCopyConstructors(0), 02005 definedType(NULL), 02006 functionOf(NULL), 02007 function(NULL) 02008 { 02009 const Token *nameTok = classDef; 02010 if (!classDef) { 02011 type = Scope::eGlobal; 02012 } else if (classDef->str() == "class") { 02013 type = Scope::eClass; 02014 nameTok = nameTok->next(); 02015 } else if (classDef->str() == "struct") { 02016 type = Scope::eStruct; 02017 nameTok = nameTok->next(); 02018 } else if (classDef->str() == "union") { 02019 type = Scope::eUnion; 02020 nameTok = nameTok->next(); 02021 } else if (classDef->str() == "namespace") { 02022 type = Scope::eNamespace; 02023 nameTok = nameTok->next(); 02024 } else { 02025 type = Scope::eFunction; 02026 } 02027 // skip over qualification if present 02028 if (nameTok && nameTok->str() == "::") 02029 nameTok = nameTok->next(); 02030 while (nameTok && Token::Match(nameTok, "%type% ::")) 02031 nameTok = nameTok->tokAt(2); 02032 if (nameTok && nameTok->str() != "{") // anonymous and unnamed structs/unions don't have a name 02033 className = nameTok->str(); 02034 } 02035 02036 bool Scope::hasDefaultConstructor() const 02037 { 02038 if (numConstructors) { 02039 std::list<Function>::const_iterator func; 02040 02041 for (func = functionList.begin(); func != functionList.end(); ++func) { 02042 if (func->type == Function::eConstructor && func->argCount() == 0) 02043 return true; 02044 } 02045 } 02046 return false; 02047 } 02048 02049 AccessControl Scope::defaultAccess() const 02050 { 02051 switch (type) { 02052 case eGlobal: 02053 return Global; 02054 case eClass: 02055 return Private; 02056 case eStruct: 02057 return Public; 02058 case eUnion: 02059 return Public; 02060 case eNamespace: 02061 return Namespace; 02062 default: 02063 return Local; 02064 } 02065 } 02066 02067 // Get variable list.. 02068 void Scope::getVariableList() 02069 { 02070 AccessControl varaccess = defaultAccess(); 02071 const Token *start; 02072 unsigned int level = 1; 02073 02074 if (classStart) 02075 start = classStart->next(); 02076 02077 // global scope 02078 else if (className.empty()) 02079 start = check->_tokenizer->tokens(); 02080 02081 // forward declaration 02082 else 02083 return; 02084 02085 for (const Token *tok = start; tok; tok = tok->next()) { 02086 // end of scope? 02087 if (tok->str() == "}") { 02088 level--; 02089 if (level == 0) 02090 break; 02091 } 02092 02093 // syntax error? 02094 else if (tok->next() == NULL) 02095 break; 02096 02097 // Is it a function? 02098 else if (tok->str() == "{") { 02099 tok = tok->link(); 02100 // syntax error? 02101 if (!tok) 02102 return; 02103 continue; 02104 } 02105 02106 // Is it a nested class or structure? 02107 else if (Token::Match(tok, "class|struct|union|namespace %type% :|{")) { 02108 tok = tok->tokAt(2); 02109 while (tok && tok->str() != "{") 02110 tok = tok->next(); 02111 if (tok) { 02112 // skip implementation 02113 tok = tok->link(); 02114 continue; 02115 } else 02116 break; 02117 } else if (Token::Match(tok, "struct|union {") && Token::Match(tok->next()->link(), "} %var% ;|[")) { 02118 tok = tok->next()->link()->tokAt(2); 02119 continue; 02120 } else if (Token::Match(tok, "struct|union {") && Token::simpleMatch(tok->next()->link(), "} ;")) { 02121 level++; 02122 tok = tok->next(); 02123 continue; 02124 } 02125 02126 // Borland C++: Skip all variables in the __published section. 02127 // These are automatically initialized. 02128 else if (tok->str() == "__published:") { 02129 for (; tok; tok = tok->next()) { 02130 if (tok->str() == "{") 02131 tok = tok->link(); 02132 if (Token::Match(tok->next(), "private:|protected:|public:")) 02133 break; 02134 } 02135 if (tok) 02136 continue; 02137 else 02138 break; 02139 } 02140 02141 // "private:" "public:" "protected:" etc 02142 else if (tok->str() == "public:") { 02143 varaccess = Public; 02144 continue; 02145 } else if (tok->str() == "protected:") { 02146 varaccess = Protected; 02147 continue; 02148 } else if (tok->str() == "private:") { 02149 varaccess = Private; 02150 continue; 02151 } 02152 02153 // Is it a forward declaration? 02154 else if (Token::Match(tok, "class|struct|union %var% ;")) { 02155 tok = tok->tokAt(2); 02156 continue; 02157 } 02158 02159 // Borland C++: Ignore properties.. 02160 else if (tok->str() == "__property") 02161 continue; 02162 02163 // skip return and delete 02164 else if (Token::Match(tok, "return|delete")) { 02165 while (tok->next() && tok->next()->str() != ";") 02166 tok = tok->next(); 02167 continue; 02168 } 02169 02170 // Search for start of statement.. 02171 else if (tok->previous() && !Token::Match(tok->previous(), ";|{|}|public:|protected:|private:")) 02172 continue; 02173 else if (Token::Match(tok, ";|{|}")) 02174 continue; 02175 else if (Token::Match(tok, "goto %var% ;")) { 02176 tok = tok->tokAt(2); 02177 continue; 02178 } 02179 02180 tok = checkVariable(tok, varaccess); 02181 02182 if (!tok) 02183 break; 02184 } 02185 } 02186 02187 const Token *Scope::checkVariable(const Token *tok, AccessControl varaccess) 02188 { 02189 // This is the start of a statement 02190 const Token *vartok = NULL; 02191 const Token *typetok = NULL; 02192 02193 // Is it a throw..? 02194 if (Token::Match(tok, "throw %any% (") && 02195 Token::simpleMatch(tok->linkAt(2), ") ;")) { 02196 return tok->linkAt(2); 02197 } else if ((Token::Match(tok, "throw %any% :: %any% (") && 02198 Token::simpleMatch(tok->linkAt(4), ") ;"))) { 02199 return tok->linkAt(4); 02200 } 02201 02202 // friend? 02203 if (Token::Match(tok, "friend %type%") && tok->next()->varId() == 0) { 02204 const Token *next = Token::findmatch(tok->tokAt(2), ";|{"); 02205 if (next && next->str() == "{") 02206 next = next->link(); 02207 return next; 02208 } 02209 02210 // skip const|static|mutable|extern 02211 while (Token::Match(tok, "const|static|mutable|extern")) { 02212 tok = tok->next(); 02213 } 02214 02215 // the start of the type tokens does not include the above modifiers 02216 const Token *typestart = tok; 02217 02218 if (Token::Match(tok, "struct|union")) { 02219 tok = tok->next(); 02220 } 02221 02222 if (tok && isVariableDeclaration(tok, vartok, typetok)) { 02223 // If the vartok was set in the if-blocks above, create a entry for this variable.. 02224 tok = vartok->next(); 02225 while (tok && tok->str() == "[") 02226 tok = tok->link()->next(); 02227 02228 if (vartok->varId() == 0 && !vartok->isBoolean()) 02229 check->debugMessage(vartok, "Scope::checkVariable found variable \'" + vartok->str() + "\' with varid 0."); 02230 02231 const Type *vType = NULL; 02232 02233 if (typetok) { 02234 vType = check->findVariableType(this, typetok); 02235 if (!vType) { 02236 // look for variable type in any using namespace in this scope or above 02237 const Scope *parent = this; 02238 while (parent) { 02239 for (std::list<Scope::UsingInfo>::const_iterator ui = parent->usingList.begin(); 02240 ui != parent->usingList.end(); ++ui) { 02241 if (ui->scope) { 02242 vType = check->findVariableType(ui->scope, typetok); 02243 if (vType) 02244 break; 02245 } 02246 } 02247 parent = parent->nestedIn; 02248 } 02249 } 02250 } 02251 02252 addVariable(vartok, typestart, vartok->previous(), varaccess, vType, this); 02253 } 02254 02255 return tok; 02256 } 02257 02258 const Variable *Scope::getVariable(const std::string &varname) const 02259 { 02260 std::list<Variable>::const_iterator iter; 02261 02262 for (iter = varlist.begin(); iter != varlist.end(); ++iter) { 02263 if (iter->name() == varname) 02264 return &*iter; 02265 } 02266 02267 return NULL; 02268 } 02269 02270 static const Token* skipScopeIdentifiers(const Token* tok) 02271 { 02272 if (tok && tok->str() == "::") { 02273 tok = tok->next(); 02274 } 02275 while (Token::Match(tok, "%type% ::")) { 02276 tok = tok->tokAt(2); 02277 } 02278 02279 return tok; 02280 } 02281 02282 static const Token* skipPointers(const Token* tok) 02283 { 02284 while (Token::Match(tok, "*|&")) { 02285 tok = tok->next(); 02286 } 02287 02288 return tok; 02289 } 02290 02291 bool Scope::isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const 02292 { 02293 if (tok && tok->str() == "throw" && check->_tokenizer->isCPP()) 02294 return false; 02295 02296 const Token* localTypeTok = skipScopeIdentifiers(tok); 02297 const Token* localVarTok = NULL; 02298 02299 if (Token::Match(localTypeTok, "%type% <")) { 02300 const Token* closeTok = NULL; 02301 bool found = localTypeTok->next()->findClosingBracket(closeTok); 02302 if (found) { 02303 localVarTok = skipPointers(closeTok->next()); 02304 02305 if (Token::Match(localVarTok, ":: %type% %var% ;|=")) { 02306 localTypeTok = localVarTok->next(); 02307 localVarTok = localVarTok->tokAt(2); 02308 } 02309 } 02310 } else if (Token::Match(localTypeTok, "%type%")) { 02311 localVarTok = skipPointers(localTypeTok->strAt(1)=="const"?localTypeTok->tokAt(2):localTypeTok->next()); 02312 } 02313 02314 if (localVarTok && localVarTok->str() == "const") 02315 localVarTok = localVarTok->next(); 02316 02317 if (Token::Match(localVarTok, "%var% ;|=")) { 02318 vartok = localVarTok; 02319 typetok = localTypeTok; 02320 } else if (Token::Match(localVarTok, "%var% [") && localVarTok->str() != "operator") { 02321 vartok = localVarTok; 02322 typetok = localTypeTok; 02323 } else if ((isLocal() || type == Scope::eFunction) && 02324 Token::Match(localVarTok, "%var% (") && 02325 Token::simpleMatch(localVarTok->next()->link(), ") ;")) { 02326 vartok = localVarTok; 02327 typetok = localTypeTok; 02328 } else if (type == eCatch && 02329 (Token::Match(localTypeTok, "%var% )") || 02330 Token::Match(localTypeTok, "%var% &| %var% )"))) { 02331 vartok = localVarTok; 02332 typetok = localTypeTok; 02333 } 02334 02335 return NULL != vartok; 02336 } 02337 02338 02339 02340 //--------------------------------------------------------------------------- 02341 02342 const Type* SymbolDatabase::findVariableType(const Scope *start, const Token *typeTok) const 02343 { 02344 std::list<Type>::const_iterator type; 02345 02346 for (type = typeList.begin(); type != typeList.end(); ++type) { 02347 // do the names match? 02348 if (type->name() == typeTok->str()) { 02349 // check if type does not have a namespace 02350 if (typeTok->strAt(-1) != "::") { 02351 const Scope *parent = start; 02352 02353 // check if in same namespace 02354 while (parent) { 02355 // out of line class function belongs to class 02356 if (parent->type == Scope::eFunction && parent->functionOf) 02357 parent = parent->functionOf; 02358 else if (parent != type->enclosingScope) 02359 parent = parent->nestedIn; 02360 else 02361 break; 02362 } 02363 02364 if (type->enclosingScope == parent) 02365 return &(*type); 02366 } 02367 02368 // type has a namespace 02369 else { 02370 // FIXME check if namespace path matches supplied path 02371 return &(*type); 02372 } 02373 } 02374 } 02375 02376 return NULL; 02377 } 02378 02379 //--------------------------------------------------------------------------- 02380 02381 /** @todo This function only counts the number of arguments in the function call. 02382 It does not take into account function constantness. 02383 It does not take into account argument types. This can be difficult because of promotion and conversion operators and casts and because the argument can also be a function call. 02384 */ 02385 const Function* Scope::findFunction(const Token *tok) const 02386 { 02387 for (std::list<Function>::const_iterator i = functionList.begin(); i != functionList.end(); ++i) { 02388 if (i->tokenDef->str() == tok->str()) { 02389 const Function *func = &*i; 02390 if (tok->strAt(1) == "(" && tok->tokAt(2)) { 02391 // check if function has no arguments 02392 if (tok->strAt(2) == ")" && (func->argCount() == 0 || func->minArgCount() == 0)) 02393 return func; 02394 02395 // check the arguments 02396 unsigned int args = 0; 02397 const Token *arg = tok->tokAt(2); 02398 while (arg && arg->str() != ")") { 02399 /** @todo check argument type for match */ 02400 args++; 02401 arg = arg->nextArgument(); 02402 } 02403 02404 // check for argument count match or default arguments 02405 if (args == func->argCount() || 02406 (args < func->argCount() && args >= func->minArgCount())) 02407 return func; 02408 } 02409 } 02410 } 02411 02412 return 0; 02413 } 02414 02415 //--------------------------------------------------------------------------- 02416 02417 const Function* SymbolDatabase::findFunction(const Token *tok) const 02418 { 02419 // find the scope this function is in 02420 const Scope *currScope = tok->scope(); 02421 while (currScope && currScope->isExecutable()) { 02422 if (currScope->functionOf) 02423 currScope = currScope->functionOf; 02424 else 02425 currScope = currScope->nestedIn; 02426 } 02427 02428 // check for a qualified name and use it when given 02429 if (tok->strAt(-1) == "::") { 02430 // find start of qualified function name 02431 const Token *tok1 = tok; 02432 02433 while (Token::Match(tok1->tokAt(-2), "%type% ::")) 02434 tok1 = tok1->tokAt(-2); 02435 02436 // check for global scope 02437 if (tok1->strAt(-1) == "::") { 02438 currScope = &scopeList.front(); 02439 02440 currScope = currScope->findRecordInNestedList(tok1->str()); 02441 } 02442 02443 // find start of qualification 02444 else { 02445 while (currScope) { 02446 if (currScope->className == tok1->str()) 02447 break; 02448 else { 02449 const Scope *scope = currScope->findRecordInNestedList(tok1->str()); 02450 02451 if (scope) { 02452 currScope = scope; 02453 break; 02454 } else 02455 currScope = currScope->nestedIn; 02456 } 02457 } 02458 } 02459 02460 if (currScope) { 02461 while (currScope && !Token::Match(tok1, "%type% :: %any% (")) { 02462 currScope = currScope->findRecordInNestedList(tok1->strAt(2)); 02463 tok1 = tok1->tokAt(2); 02464 } 02465 02466 tok1 = tok1->tokAt(2); 02467 02468 if (currScope && tok1) 02469 return currScope->findFunction(tok1); 02470 } 02471 } 02472 02473 // check for member function 02474 else if (tok->strAt(-1) == ".") { 02475 if (Token::Match(tok->tokAt(-2), "%var% .")) { 02476 const Token *tok1 = tok->tokAt(-2); 02477 02478 if (tok1->varId()) { 02479 const Variable *var = getVariableFromVarId(tok1->varId()); 02480 if (var && var->typeScope()) 02481 return var->typeScope()->findFunction(tok); 02482 } 02483 } 02484 } 02485 02486 // check in enclosing scopes 02487 else { 02488 while (currScope) { 02489 const Function *func = currScope->findFunction(tok); 02490 if (func) 02491 return func; 02492 currScope = currScope->nestedIn; 02493 } 02494 } 02495 return 0; 02496 } 02497 02498 //--------------------------------------------------------------------------- 02499 02500 const Scope *SymbolDatabase::findScopeByName(const std::string& name) const 02501 { 02502 for (std::list<Scope>::const_iterator it = scopeList.begin(); it != scopeList.end(); ++it) { 02503 if (it->className == name) 02504 return &*it; 02505 } 02506 return 0; 02507 } 02508 02509 //--------------------------------------------------------------------------- 02510 02511 Scope *Scope::findInNestedList(const std::string & name) 02512 { 02513 std::list<Scope *>::iterator it; 02514 02515 for (it = nestedList.begin(); it != nestedList.end(); ++it) { 02516 if ((*it)->className == name) 02517 return (*it); 02518 } 02519 return 0; 02520 } 02521 02522 //--------------------------------------------------------------------------- 02523 02524 const Scope *Scope::findRecordInNestedList(const std::string & name) const 02525 { 02526 std::list<Scope *>::const_iterator it; 02527 02528 for (it = nestedList.begin(); it != nestedList.end(); ++it) { 02529 if ((*it)->className == name && (*it)->type != eFunction) 02530 return (*it); 02531 } 02532 return 0; 02533 } 02534 02535 //--------------------------------------------------------------------------- 02536 02537 const Type* Scope::findType(const std::string & name) const 02538 { 02539 std::list<Type*>::const_iterator it; 02540 02541 for (it = definedTypes.begin(); it != definedTypes.end(); ++it) { 02542 if ((*it)->name() == name) 02543 return (*it); 02544 } 02545 return 0; 02546 } 02547 02548 //--------------------------------------------------------------------------- 02549 02550 Scope *Scope::findInNestedListRecursive(const std::string & name) 02551 { 02552 std::list<Scope *>::iterator it; 02553 02554 for (it = nestedList.begin(); it != nestedList.end(); ++it) { 02555 if ((*it)->className == name) 02556 return (*it); 02557 } 02558 02559 for (it = nestedList.begin(); it != nestedList.end(); ++it) { 02560 Scope *child = (*it)->findInNestedListRecursive(name); 02561 if (child) 02562 return child; 02563 } 02564 return 0; 02565 } 02566 02567 //--------------------------------------------------------------------------- 02568 02569 const Function *Scope::getDestructor() const 02570 { 02571 std::list<Function>::const_iterator it; 02572 for (it = functionList.begin(); it != functionList.end(); ++it) { 02573 if (it->type == Function::eDestructor) 02574 return &(*it); 02575 } 02576 return 0; 02577 } 02578 02579 //--------------------------------------------------------------------------- 02580 02581 unsigned int Scope::getNestedNonFunctions() const 02582 { 02583 unsigned int nested = 0; 02584 std::list<Scope *>::const_iterator ni; 02585 for (ni = nestedList.begin(); ni != nestedList.end(); ++ni) { 02586 if ((*ni)->type != Scope::eFunction) 02587 nested++; 02588 } 02589 return nested; 02590 } 02591 02592 //--------------------------------------------------------------------------- 02593 02594 bool SymbolDatabase::isCPP() const 02595 { 02596 return _tokenizer->isCPP(); 02597 } 02598 02599 //--------------------------------------------------------------------------- 02600 02601 const Scope *SymbolDatabase::findScope(const Token *tok, const Scope *startScope) const 02602 { 02603 const Scope *scope = 0; 02604 // absolute path 02605 if (tok->str() == "::") { 02606 tok = tok->next(); 02607 scope = &scopeList.front(); 02608 } 02609 // relative path 02610 else if (tok->isName()) { 02611 scope = startScope; 02612 } 02613 02614 while (scope && tok && tok->isName()) { 02615 if (tok->strAt(1) == "::") { 02616 scope = scope->findRecordInNestedList(tok->str()); 02617 tok = tok->tokAt(2); 02618 } else 02619 return scope->findRecordInNestedList(tok->str()); 02620 } 02621 02622 02623 // not a valid path 02624 return 0; 02625 } 02626 02627 const Type* SymbolDatabase::findType(const Token *startTok, const Scope *startScope) const 02628 { 02629 // absolute path - directly start in global scope 02630 if (startTok->str() == "::") { 02631 startTok = startTok->next(); 02632 startScope = &scopeList.front(); 02633 } 02634 02635 const Token* tok = startTok; 02636 const Scope* scope = startScope; 02637 02638 while (scope && tok && tok->isName()) { 02639 if (tok->strAt(1) == "::") { 02640 scope = scope->findRecordInNestedList(tok->str()); 02641 if (scope) { 02642 tok = tok->tokAt(2); 02643 } else { 02644 startScope = startScope->nestedIn; 02645 if (!startScope) 02646 break; 02647 scope = startScope; 02648 tok = startTok; 02649 } 02650 } else 02651 return scope->findType(tok->str()); 02652 } 02653 02654 02655 // not a valid path 02656 return 0; 02657 }
1.7.6.1