Cppcheck
symboldatabase.h
Go to the documentation of this file.
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