|
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 #ifndef SymbolDatabaseH 00021 #define SymbolDatabaseH 00022 //--------------------------------------------------------------------------- 00023 00024 #include <string> 00025 #include <list> 00026 #include <vector> 00027 #include <set> 00028 00029 #include "config.h" 00030 #include "token.h" 00031 #include "mathlib.h" 00032 00033 class Tokenizer; 00034 class Settings; 00035 class ErrorLogger; 00036 00037 class Scope; 00038 class SymbolDatabase; 00039 00040 /** 00041 * @brief Access control enumerations. 00042 */ 00043 enum AccessControl { Public, Protected, Private, Global, Namespace, Argument, Local, Throw }; 00044 00045 /** 00046 * @brief Array dimension information. 00047 */ 00048 struct Dimension { 00049 Dimension() : start(NULL), end(NULL), num(0), known(true) { } 00050 00051 const Token *start; // size start token 00052 const Token *end; // size end token 00053 MathLib::bigint num; // (assumed) dimension length when size is a number, 0 if not known 00054 bool known; // Known size 00055 }; 00056 00057 /** @brief Information about a class type. */ 00058 class CPPCHECKLIB Type { 00059 public: 00060 const Token* classDef; // Points to "class" token 00061 const Scope* classScope; 00062 const Scope* enclosingScope; 00063 enum NeedInitialization { 00064 Unknown, True, False 00065 } needInitialization; 00066 00067 struct BaseInfo { 00068 std::string name; 00069 const Type* type; 00070 const Token* nameTok; 00071 AccessControl access; // public/protected/private 00072 bool isVirtual; 00073 }; 00074 00075 struct FriendInfo { 00076 const Token* nameStart; 00077 const Token* nameEnd; 00078 std::string name; 00079 const Type* type; 00080 }; 00081 00082 std::vector<BaseInfo> derivedFrom; 00083 std::list<FriendInfo> friendList; 00084 00085 Type(const Token* classDef_ = 0, const Scope* classScope_ = 0, const Scope* enclosingScope_ = 0) : 00086 classDef(classDef_), 00087 classScope(classScope_), 00088 enclosingScope(enclosingScope_), 00089 needInitialization(Unknown) { 00090 } 00091 00092 const std::string& name() const { 00093 static const std::string empty; 00094 return classDef->next()->isName() ? classDef->strAt(1) : empty; 00095 } 00096 00097 const Token *initBaseInfo(const Token *tok, const Token *tok1); 00098 00099 const Function* getFunction(const std::string& funcName) const; 00100 }; 00101 00102 /** @brief Information about a member variable. */ 00103 class CPPCHECKLIB Variable { 00104 /** @brief flags mask used to access specific bit. */ 00105 enum { 00106 fIsMutable = (1 << 0), /** @brief mutable variable */ 00107 fIsStatic = (1 << 1), /** @brief static variable */ 00108 fIsConst = (1 << 2), /** @brief const variable */ 00109 fIsExtern = (1 << 3), /** @brief extern variable */ 00110 fIsClass = (1 << 4), /** @brief user defined type */ 00111 fIsArray = (1 << 5), /** @brief array variable */ 00112 fIsPointer = (1 << 6), /** @brief pointer variable */ 00113 fIsReference = (1 << 7), /** @brief reference variable */ 00114 fHasDefault = (1 << 8) /** @brief function argument with default value */ 00115 }; 00116 00117 /** 00118 * Get specified flag state. 00119 * @param flag_ flag to get state of 00120 * @return true if flag set or false in flag not set 00121 */ 00122 bool getFlag(int flag_) const { 00123 return bool((_flags & flag_) != 0); 00124 } 00125 00126 /** 00127 * Set specified flag state. 00128 * @param flag_ flag to set state 00129 * @param state_ new state of flag 00130 */ 00131 void setFlag(int flag_, bool state_) { 00132 _flags = state_ ? _flags | flag_ : _flags & ~flag_; 00133 } 00134 00135 /** 00136 * @brief parse and save array dimension information 00137 * @param dimensions array dimensions vector 00138 * @param tok the first '[' token of array declaration 00139 * @return true if array, false if not 00140 */ 00141 static bool arrayDimensions(std::vector<Dimension> &dimensions, const Token *tok); 00142 00143 public: 00144 Variable(const Token *name_, const Token *start_, const Token *end_, 00145 std::size_t index_, AccessControl access_, const Type *type_, 00146 const Scope *scope_) 00147 : _name(name_), 00148 _start(start_), 00149 _end(end_), 00150 _index(index_), 00151 _access(access_), 00152 _flags(0), 00153 _type(type_), 00154 _scope(scope_) { 00155 evaluate(); 00156 } 00157 00158 /** 00159 * Get name token. 00160 * @return name token 00161 */ 00162 const Token *nameToken() const { 00163 return _name; 00164 } 00165 00166 /** 00167 * Get type start token. 00168 * @return type start token 00169 */ 00170 const Token *typeStartToken() const { 00171 return _start; 00172 } 00173 00174 /** 00175 * Get type end token. 00176 * @return type end token 00177 */ 00178 const Token *typeEndToken() const { 00179 return _end; 00180 } 00181 00182 /** 00183 * Get name string. 00184 * @return name string 00185 */ 00186 const std::string &name() const { 00187 static const std::string noname; 00188 00189 // name may not exist for function arguments 00190 if (_name) 00191 return _name->str(); 00192 00193 return noname; 00194 } 00195 00196 /** 00197 * Get variable ID. 00198 * @return variable ID 00199 */ 00200 unsigned int varId() const { 00201 // name may not exist for function arguments 00202 if (_name) 00203 return _name->varId(); 00204 00205 return 0; 00206 } 00207 00208 /** 00209 * Get index of variable in declared order. 00210 * @return variable index 00211 */ 00212 std::size_t index() const { 00213 return _index; 00214 } 00215 00216 /** 00217 * Is variable public. 00218 * @return true if public, false if not 00219 */ 00220 bool isPublic() const { 00221 return _access == Public; 00222 } 00223 00224 /** 00225 * Is variable protected. 00226 * @return true if protected, false if not 00227 */ 00228 bool isProtected() const { 00229 return _access == Protected; 00230 } 00231 00232 /** 00233 * Is variable private. 00234 * @return true if private, false if not 00235 */ 00236 bool isPrivate() const { 00237 return _access == Private; 00238 } 00239 00240 /** 00241 * Is variable global. 00242 * @return true if global, false if not 00243 */ 00244 bool isGlobal() const { 00245 return _access == Global; 00246 } 00247 00248 /** 00249 * Is variable in a namespace. 00250 * @return true if in a namespace, false if not 00251 */ 00252 bool isNamespace() const { 00253 return _access == Namespace; 00254 } 00255 00256 /** 00257 * Is variable a function argument. 00258 * @return true if a function argument, false if not 00259 */ 00260 bool isArgument() const { 00261 return _access == Argument; 00262 } 00263 00264 /** 00265 * Is variable local. 00266 * @return true if local, false if not 00267 */ 00268 bool isLocal() const { 00269 return (_access == Local) && !isExtern(); 00270 } 00271 00272 /** 00273 * Is variable mutable. 00274 * @return true if mutable, false if not 00275 */ 00276 bool isMutable() const { 00277 return getFlag(fIsMutable); 00278 } 00279 00280 /** 00281 * Is variable static. 00282 * @return true if static, false if not 00283 */ 00284 bool isStatic() const { 00285 return getFlag(fIsStatic); 00286 } 00287 00288 /** 00289 * Is variable extern. 00290 * @return true if extern, false if not 00291 */ 00292 bool isExtern() const { 00293 return getFlag(fIsExtern); 00294 } 00295 00296 /** 00297 * Is variable const. 00298 * @return true if const, false if not 00299 */ 00300 bool isConst() const { 00301 return getFlag(fIsConst); 00302 } 00303 00304 /** 00305 * Is variable a throw type. 00306 * @return true if throw type, false if not 00307 */ 00308 bool isThrow() const { 00309 return _access == Throw; 00310 } 00311 00312 /** 00313 * Is variable a user defined (or unknown) type. 00314 * @return true if user defined type, false if not 00315 */ 00316 bool isClass() const { 00317 return getFlag(fIsClass); 00318 } 00319 00320 /** 00321 * Is variable an array. 00322 * @return true if array, false if not 00323 */ 00324 bool isArray() const { 00325 return getFlag(fIsArray); 00326 } 00327 00328 /** 00329 * Is pointer variable. 00330 * @return true if pointer, false otherwise 00331 */ 00332 bool isPointer() const { 00333 return getFlag(fIsPointer); 00334 } 00335 00336 /** 00337 * Is reference variable. 00338 * @return true if reference, false otherwise 00339 */ 00340 bool isReference() const { 00341 return getFlag(fIsReference); 00342 } 00343 00344 /** 00345 * Does variable have a default value. 00346 * @return true if has a default falue, false if not 00347 */ 00348 bool hasDefault() const { 00349 return getFlag(fHasDefault); 00350 } 00351 00352 /** 00353 * Get Type pointer of known type. 00354 * @return pointer to type if known, NULL if not known 00355 */ 00356 const Type *type() const { 00357 return _type; 00358 } 00359 00360 /** 00361 * Get Scope pointer of known type. 00362 * @return pointer to type scope if known, NULL if not known 00363 */ 00364 const Scope *typeScope() const { 00365 return _type ? _type->classScope : 0; 00366 } 00367 00368 /** 00369 * Get Scope pointer of enclosing scope. 00370 * @return pointer to enclosing scope 00371 */ 00372 const Scope *scope() const { 00373 return _scope; 00374 } 00375 00376 /** 00377 * Get array dimensions. 00378 * @return array dimensions vector 00379 */ 00380 const std::vector<Dimension> &dimensions() const { 00381 return _dimensions; 00382 } 00383 00384 /** 00385 * Get array dimension length. 00386 * @return length of dimension 00387 */ 00388 MathLib::bigint dimension(std::size_t index_) const { 00389 return _dimensions[index_].num; 00390 } 00391 00392 private: 00393 /** @brief variable name token */ 00394 const Token *_name; 00395 00396 /** @brief variable type start token */ 00397 const Token *_start; 00398 00399 /** @brief variable type end token */ 00400 const Token *_end; 00401 00402 /** @brief order declared */ 00403 std::size_t _index; 00404 00405 /** @brief what section is this variable declared in? */ 00406 AccessControl _access; // public/protected/private 00407 00408 /** @brief flags */ 00409 int _flags; 00410 00411 /** @brief pointer to user defined type info (for known types) */ 00412 const Type *_type; 00413 00414 /** @brief pointer to scope this variable is in */ 00415 const Scope *_scope; 00416 00417 /** @brief array dimensions */ 00418 std::vector<Dimension> _dimensions; 00419 00420 /** @brief fill in information, depending on Tokens given at instantiation */ 00421 void evaluate(); 00422 }; 00423 00424 class CPPCHECKLIB Function { 00425 public: 00426 enum Type { eConstructor, eCopyConstructor, eOperatorEqual, eDestructor, eFunction }; 00427 00428 Function() 00429 : tokenDef(NULL), 00430 argDef(NULL), 00431 token(NULL), 00432 arg(NULL), 00433 functionScope(NULL), 00434 nestedIn(NULL), 00435 initArgCount(0), 00436 type(eFunction), 00437 access(Public), 00438 hasBody(false), 00439 isInline(false), 00440 isConst(false), 00441 isVirtual(false), 00442 isPure(false), 00443 isStatic(false), 00444 isFriend(false), 00445 isExplicit(false), 00446 isDefault(false), 00447 isDelete(false), 00448 isOperator(false), 00449 retFuncPtr(false) { 00450 } 00451 00452 const std::string &name() const { 00453 return tokenDef->str(); 00454 } 00455 00456 std::size_t argCount() const { 00457 return argumentList.size(); 00458 } 00459 std::size_t minArgCount() const { 00460 return argumentList.size() - initArgCount; 00461 } 00462 const Variable* getArgumentVar(unsigned int num) const; 00463 unsigned int initializedArgCount() const { 00464 return initArgCount; 00465 } 00466 void addArguments(const SymbolDatabase *symbolDatabase, const Scope *scope); 00467 /** @brief check if this function is virtual in the base classes */ 00468 bool isImplicitlyVirtual(bool defaultVal = false) const; 00469 00470 const Token *tokenDef; // function name token in class definition 00471 const Token *argDef; // function argument start '(' in class definition 00472 const Token *token; // function name token in implementation 00473 const Token *arg; // function argument start '(' 00474 const Scope *functionScope; // scope of function body 00475 const Scope* nestedIn; // Scope the function is declared in 00476 std::list<Variable> argumentList; // argument list 00477 unsigned int initArgCount; // number of args with default values 00478 Type type; // constructor, destructor, ... 00479 AccessControl access; // public/protected/private 00480 bool hasBody; // has implementation 00481 bool isInline; // implementation in class definition 00482 bool isConst; // is const 00483 bool isVirtual; // is virtual 00484 bool isPure; // is pure virtual 00485 bool isStatic; // is static 00486 bool isFriend; // is friend 00487 bool isExplicit; // is explicit 00488 bool isDefault; // is default 00489 bool isDelete; // is delete 00490 bool isOperator; // is operator 00491 bool retFuncPtr; // returns function pointer 00492 00493 static bool argsMatch(const Scope *info, const Token *first, const Token *second, const std::string &path, unsigned int depth); 00494 00495 private: 00496 bool isImplicitlyVirtual_rec(const ::Type* type, bool& safe) const; 00497 }; 00498 00499 class CPPCHECKLIB Scope { 00500 // let tests access private function for testing 00501 friend class TestSymbolDatabase; 00502 00503 public: 00504 struct UsingInfo { 00505 const Token *start; 00506 const Scope *scope; 00507 }; 00508 00509 enum ScopeType { eGlobal, eClass, eStruct, eUnion, eNamespace, eFunction, eIf, eElse, eElseIf, eFor, eWhile, eDo, eSwitch, eUnconditional, eTry, eCatch }; 00510 00511 Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_); 00512 Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *nestedIn_, ScopeType type_, const Token *start_); 00513 00514 const SymbolDatabase *check; 00515 std::string className; 00516 const Token *classDef; // class/struct/union/namespace token 00517 const Token *classStart; // '{' token 00518 const Token *classEnd; // '}' token 00519 std::list<Function> functionList; 00520 std::list<Variable> varlist; 00521 const Scope *nestedIn; 00522 std::list<Scope *> nestedList; 00523 unsigned int numConstructors; 00524 unsigned int numCopyConstructors; 00525 std::list<UsingInfo> usingList; 00526 ScopeType type; 00527 Type* definedType; 00528 std::list<Type*> definedTypes; 00529 00530 // function specific fields 00531 const Scope *functionOf; // scope this function belongs to 00532 Function *function; // function info for this function 00533 00534 bool isClassOrStruct() const { 00535 return (type == eClass || type == eStruct); 00536 } 00537 00538 bool isExecutable() const { 00539 return type != eClass && type != eStruct && type != eUnion && type != eGlobal && type != eNamespace; 00540 } 00541 00542 bool isLocal() const { 00543 return (type == eIf || type == eElse || type == eElseIf || 00544 type == eFor || type == eWhile || type == eDo || 00545 type == eSwitch || type == eUnconditional || 00546 type == eTry || type == eCatch); 00547 } 00548 00549 /** 00550 * @brief find a function 00551 * @param tok token of function call 00552 * @return pointer to function if found or NULL if not found 00553 */ 00554 const Function *findFunction(const Token *tok) const; 00555 00556 /** 00557 * @brief find if name is in nested list 00558 * @param name name of nested scope 00559 */ 00560 Scope *findInNestedList(const std::string & name); 00561 00562 const Scope *findRecordInNestedList(const std::string & name) const; 00563 Scope *findRecordInNestedList(const std::string & name) { 00564 return const_cast<Scope *>(static_cast<const Scope *>(this)->findRecordInNestedList(name)); 00565 } 00566 00567 const Type* findType(const std::string& name) const; 00568 Type* findType(const std::string& name) { 00569 return const_cast<Type*>(static_cast<const Scope *>(this)->findType(name)); 00570 } 00571 00572 /** 00573 * @brief find if name is in nested list 00574 * @param name name of nested scope 00575 */ 00576 Scope *findInNestedListRecursive(const std::string & name); 00577 00578 void addVariable(const Token *token_, const Token *start_, 00579 const Token *end_, AccessControl access_, const Type *type_, 00580 const Scope *scope_) { 00581 varlist.push_back(Variable(token_, start_, end_, varlist.size(), 00582 access_, 00583 type_, scope_)); 00584 } 00585 00586 /** @brief initialize varlist */ 00587 void getVariableList(); 00588 00589 const Function *getDestructor() const; 00590 00591 /** 00592 * @brief get the number of nested scopes that are not functions 00593 * 00594 * This returns the number of user defined types (class, struct, union) 00595 * that are defined in this user defined type or namespace. 00596 */ 00597 unsigned int getNestedNonFunctions() const; 00598 00599 bool hasDefaultConstructor() const; 00600 00601 AccessControl defaultAccess() const; 00602 00603 /** 00604 * @brief check if statement is variable declaration and add it if it is 00605 * @param tok pointer to start of statement 00606 * @param varaccess access control of statement 00607 * @return pointer to last token 00608 */ 00609 const Token *checkVariable(const Token *tok, AccessControl varaccess); 00610 00611 /** 00612 * @brief get variable from name 00613 * @param varname name of variable 00614 * @return pointer to variable 00615 */ 00616 const Variable *getVariable(const std::string &varname) const; 00617 00618 private: 00619 /** 00620 * @brief helper function for getVariableList() 00621 * @param tok pointer to token to check 00622 * @param vartok populated with pointer to the variable token, if found 00623 * @param typetok populated with pointer to the type token, if found 00624 * @return true if tok points to a variable declaration, false otherwise 00625 */ 00626 bool isVariableDeclaration(const Token* tok, const Token*& vartok, const Token*& typetok) const; 00627 }; 00628 00629 class CPPCHECKLIB SymbolDatabase { 00630 public: 00631 SymbolDatabase(const Tokenizer *tokenizer, const Settings *settings, ErrorLogger *errorLogger); 00632 00633 /** @brief Information about all namespaces/classes/structrues */ 00634 std::list<Scope> scopeList; 00635 00636 /** @brief Fast access to function scopes */ 00637 std::vector<const Scope *> functionScopes; 00638 00639 /** @brief Fast access to class and struct scopes */ 00640 std::vector<const Scope *> classAndStructScopes; 00641 00642 /** @brief Fast access to types */ 00643 std::list<Type> typeList; 00644 00645 /** 00646 * @brief find a variable type if it's a user defined type 00647 * @param start scope to start looking in 00648 * @param type token containing variable type 00649 * @return pointer to type if found or NULL if not found 00650 */ 00651 const Type *findVariableType(const Scope *start, const Token *type) const; 00652 00653 /** 00654 * @brief find a function 00655 * @param tok token of function call 00656 * @return pointer to function if found or NULL if not found 00657 */ 00658 const Function *findFunction(const Token *tok) const; 00659 00660 const Scope *findScopeByName(const std::string& name) const; 00661 00662 const Type* findType(const Token *tok, const Scope *startScope) const; 00663 Type* findType(const Token *tok, Scope *startScope) const { 00664 return const_cast<Type*>(this->findType(tok, static_cast<const Scope *>(startScope))); 00665 } 00666 00667 const Scope *findScope(const Token *tok, const Scope *startScope) const; 00668 Scope *findScope(const Token *tok, Scope *startScope) const { 00669 return const_cast<Scope *>(this->findScope(tok, static_cast<const Scope *>(startScope))); 00670 } 00671 00672 bool isClassOrStruct(const std::string &type) const { 00673 for (std::list<Type>::const_iterator i = typeList.begin(); i != typeList.end(); ++i) 00674 if (i->name() == type) 00675 return true; 00676 return false; 00677 } 00678 00679 const Variable *getVariableFromVarId(std::size_t varId) const { 00680 return _variableList[varId]; 00681 } 00682 00683 std::size_t getVariableListSize() const { 00684 return _variableList.size(); 00685 } 00686 00687 /** 00688 * @brief output a debug message 00689 */ 00690 void debugMessage(const Token *tok, const std::string &msg) const; 00691 00692 void printOut(const char * title = NULL) const; 00693 void printVariable(const Variable *var, const char *indent) const; 00694 00695 bool isCPP() const; 00696 00697 private: 00698 00699 // Needed by Borland C++: 00700 friend class Scope; 00701 00702 void addClassFunction(Scope **info, const Token **tok, const Token *argStart); 00703 Function *addGlobalFunctionDecl(Scope*& scope, const Token *argStart, const Token* funcStart); 00704 Function *addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart); 00705 void addNewFunction(Scope **info, const Token **tok); 00706 static bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart); 00707 00708 const Tokenizer *_tokenizer; 00709 const Settings *_settings; 00710 ErrorLogger *_errorLogger; 00711 00712 /** variable symbol table */ 00713 std::vector<const Variable *> _variableList; 00714 }; 00715 00716 #endif
1.7.6.1