SymbolDatabase: Better handling of smart pointers

This commit is contained in:
Daniel Marjamäki 2019-07-07 21:52:49 +02:00
parent 8a63a5d824
commit a0b22410cf
3 changed files with 44 additions and 6 deletions

View File

@ -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 += " *";

View File

@ -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);

View File

@ -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<foo> 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());