diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 21779f61f..8fc56faf0 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1712,6 +1712,20 @@ void Variable::setValueType(const ValueType &valueType) setFlag(fIsConst, mValueType->constness & (1U << mValueType->pointer)); } +const Type *Variable::smartPointerType() const +{ + if (!isSmartPointer()) + return nullptr; + + // TODO: Cache result + const Token *ptrType = typeStartToken(); + while (Token::Match(ptrType, "%name%|::")) + ptrType = ptrType->next(); + if (Token::Match(ptrType, "< %name% >")) + return ptrType->next()->type(); + return nullptr; +} + Function::Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef) : tokenDef(tokDef), argDef(tokArgDef), @@ -4441,6 +4455,8 @@ const Function* SymbolDatabase::findFunction(const Token *tok) const const Token *tok1 = tok->tokAt(-2); if (Token::Match(tok1, "%var% .")) { const Variable *var = getVariableFromVarId(tok1->varId()); + if (var && var->smartPointerType() && tok1->next()->originalName() == "->") + return var->smartPointerType()->classScope->findFunction(tok, var->valueType()->constness == 1); if (var && var->typeScope()) return var->typeScope()->findFunction(tok, var->valueType()->constness == 1); } else if (Token::simpleMatch(tok->previous()->astOperand1(), "(")) { @@ -4858,6 +4874,7 @@ void SymbolDatabase::setValueType(Token *tok, const Variable &var) if (var.valueType()) { valuetype.container = var.valueType()->container; } + valuetype.smartPointerType = var.smartPointerType(); if (parsedecl(var.typeStartToken(), &valuetype, mDefaultSignedness, mSettings)) { if (tok->str() == "." && tok->astOperand1()) { const ValueType * const vt = tok->astOperand1()->valueType(); @@ -5192,8 +5209,10 @@ static const Token * parsedecl(const Token *type, ValueType * const valuetype, V while (Token::Match(type->previous(), "%name%")) type = type->previous(); valuetype->sign = ValueType::Sign::UNKNOWN_SIGN; - if (!valuetype->typeScope) + if (!valuetype->typeScope && !valuetype->smartPointerType) valuetype->type = ValueType::Type::UNKNOWN_TYPE; + else if (valuetype->smartPointerType) + valuetype->type = ValueType::Type::NONSTD; else if (valuetype->typeScope->type == Scope::eEnum) { const Token * enum_type = valuetype->typeScope->enumType; if (enum_type) { @@ -5798,6 +5817,8 @@ std::string ValueType::str() const ret += " container(" + container->startPattern + ')'; } else if (type == ValueType::Type::ITERATOR && container) { ret += " iterator(" + container->startPattern + ')'; + } else if (smartPointerType) { + ret += " smart-pointer<" + smartPointerType->name() + ">"; } for (unsigned int p = 0; p < pointer; p++) { ret += " *"; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index 1765e3ec1..aea127ec1 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -560,6 +560,8 @@ public: return getFlag(fIsSmartPointer); } + const Type *smartPointerType() const; + /** * Checks if the variable is of any of the STL types passed as arguments ('std::') * E.g.: @@ -1116,15 +1118,16 @@ public: unsigned int pointer; ///< 0=>not pointer, 1=>*, 2=>**, 3=>***, etc unsigned int constness; ///< bit 0=data, bit 1=*, bit 2=** const Scope *typeScope; ///< if the type definition is seen this point out the type scope + const ::Type *smartPointerType; ///< Smart pointer type const Library::Container *container; ///< If the type is a container defined in a cfg file, this is the used container const Token *containerTypeToken; ///< The container type token. the template argument token that defines the container element type. std::string originalTypeName; ///< original type name as written in the source code. eg. this might be "uint8_t" when type is CHAR. - ValueType() : sign(UNKNOWN_SIGN), type(UNKNOWN_TYPE), bits(0), pointer(0U), constness(0U), typeScope(nullptr), container(nullptr), containerTypeToken(nullptr) {} - ValueType(const ValueType &vt) : sign(vt.sign), type(vt.type), bits(vt.bits), pointer(vt.pointer), constness(vt.constness), typeScope(vt.typeScope), container(vt.container), containerTypeToken(vt.containerTypeToken), originalTypeName(vt.originalTypeName) {} - ValueType(enum Sign s, enum Type t, unsigned int p) : sign(s), type(t), bits(0), pointer(p), constness(0U), typeScope(nullptr), container(nullptr), containerTypeToken(nullptr) {} - ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), bits(0), pointer(p), constness(c), typeScope(nullptr), container(nullptr), containerTypeToken(nullptr) {} - ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c, const std::string &otn) : sign(s), type(t), bits(0), pointer(p), constness(c), typeScope(nullptr), container(nullptr), containerTypeToken(nullptr), originalTypeName(otn) {} + ValueType() : sign(UNKNOWN_SIGN), type(UNKNOWN_TYPE), bits(0), pointer(0U), constness(0U), typeScope(nullptr), smartPointerType(nullptr), container(nullptr), containerTypeToken(nullptr) {} + ValueType(const ValueType &vt) : sign(vt.sign), type(vt.type), bits(vt.bits), pointer(vt.pointer), constness(vt.constness), typeScope(vt.typeScope), smartPointerType(vt.smartPointerType), container(vt.container), containerTypeToken(vt.containerTypeToken), originalTypeName(vt.originalTypeName) {} + ValueType(enum Sign s, enum Type t, unsigned int p) : sign(s), type(t), bits(0), pointer(p), constness(0U), typeScope(nullptr), smartPointerType(nullptr), container(nullptr), containerTypeToken(nullptr) {} + ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c) : sign(s), type(t), bits(0), pointer(p), constness(c), typeScope(nullptr), smartPointerType(nullptr), container(nullptr), containerTypeToken(nullptr) {} + ValueType(enum Sign s, enum Type t, unsigned int p, unsigned int c, const std::string &otn) : sign(s), type(t), bits(0), pointer(p), constness(c), typeScope(nullptr), smartPointerType(nullptr), container(nullptr), containerTypeToken(nullptr), originalTypeName(otn) {} ValueType &operator=(const ValueType &other) = delete; static ValueType parseDecl(const Token *type, const Settings *settings); diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index 44c587547..cae783edd 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -340,6 +340,7 @@ private: TEST_CASE(findFunction21); TEST_CASE(findFunction22); TEST_CASE(findFunction23); + TEST_CASE(findFunction24); // smart pointer TEST_CASE(noexceptFunction1); TEST_CASE(noexceptFunction2); @@ -5484,6 +5485,19 @@ private: ASSERT_EQUALS(true, f && f->isConst()); } + void findFunction24() { // smart pointers + GET_SYMBOL_DB("struct foo {\n" + " void dostuff();\n" + "}\n" + "\n" + "void f(std::shared_ptr p) {\n" + " p->dostuff();\n" + "}"); + ASSERT(db != nullptr); + const Token *tok1 = Token::findsimplematch(tokenizer.tokens(), ". dostuff ( ) ;")->next(); + ASSERT(tok1->function()); + } + #define FUNC(x) const Function *x = findFunctionByName(#x, &db->scopeList.front()); \ ASSERT_EQUALS(true, x != nullptr); \ if (x) ASSERT_EQUALS(true, x->isNoExcept());