diff --git a/lib/clangimport.cpp b/lib/clangimport.cpp index 8eed21e58..93c732f85 100644 --- a/lib/clangimport.cpp +++ b/lib/clangimport.cpp @@ -249,6 +249,14 @@ namespace clangimport { notFound(addr); } + void replaceVarDecl(const Variable *from, Variable *to) { + for (auto &it: mDeclMap) { + Decl &decl = it.second; + if (decl.var == from) + decl.var = to; + } + } + void ref(const std::string &addr, Token *tok) { auto it = mDeclMap.find(addr); if (it != mDeclMap.end()) @@ -632,6 +640,29 @@ Scope *clangimport::AstNode::createScope(TokenList *tokenList, Scope::ScopeType scope->type = scopeType; scope->classDef = def; scope->check = nestedIn->check; + if (Token::Match(def, "if|for|while (")) { + std::map replaceVar; + for (const Token *vartok = def->tokAt(2); vartok; vartok = vartok->next()) { + if (!vartok->variable()) + continue; + if (vartok->variable()->nameToken() == vartok) { + const Variable *from = vartok->variable(); + scope->varlist.emplace_back(*from, scope); + Variable *to = &scope->varlist.back(); + replaceVar[from] = to; + mData->replaceVarDecl(from, to); + } + if (replaceVar.find(vartok->variable()) != replaceVar.end()) + const_cast(vartok)->variable(replaceVar[vartok->variable()]); + } + std::list &varlist = const_cast(def->scope())->varlist; + for (std::list::iterator var = varlist.begin(); var != varlist.end();) { + if (replaceVar.find(&(*var)) != replaceVar.end()) + varlist.erase(var++); + else + var++; + } + } scope->bodyStart = addtoken(tokenList, "{"); tokenList->back()->scope(scope); mData->scopeAccessControl[scope] = scope->defaultAccess(); diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index ba0836bb1..5c7a29c5f 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1886,6 +1886,38 @@ Variable::Variable(const Token *name_, const std::string &clangType, const Token setFlag(fIsInit, true); } +Variable::Variable(const Variable &var, const Scope *scope) + : mNameToken(var.mNameToken) + , mTypeStartToken(var.mTypeStartToken) + , mTypeEndToken(var.mTypeEndToken) + , mIndex(var.mIndex) + , mAccess(var.mAccess) + , mFlags(var.mFlags) + , mType(var.mType) + , mScope(scope ? scope : var.mScope) + , mValueType(nullptr) + , mDimensions(var.mDimensions) +{ + if (var.mValueType) + mValueType = new ValueType(*var.mValueType); +} + +Variable::Variable(const Variable &var) + : mNameToken(var.mNameToken) + , mTypeStartToken(var.mTypeStartToken) + , mTypeEndToken(var.mTypeEndToken) + , mIndex(var.mIndex) + , mAccess(var.mAccess) + , mFlags(var.mFlags) + , mType(var.mType) + , mScope(var.mScope) + , mValueType(nullptr) + , mDimensions(var.mDimensions) +{ + if (var.mValueType) + mValueType = new ValueType(*var.mValueType); +} + Variable::~Variable() { delete mValueType; diff --git a/lib/symboldatabase.h b/lib/symboldatabase.h index b69011b60..376e2440b 100644 --- a/lib/symboldatabase.h +++ b/lib/symboldatabase.h @@ -240,6 +240,10 @@ public: const Token *typeEnd, nonneg int index_, AccessControl access_, const Type *type_, const Scope *scope_); + Variable(const Variable &var, const Scope *scope); + + Variable(const Variable &var); + ~Variable(); /** @@ -1236,6 +1240,21 @@ public: containerTypeToken(nullptr), originalTypeName(otn) {} + ValueType(const ValueType &vt) + : sign(vt.sign) + , type(vt.type) + , bits(vt.bits) + , pointer(vt.pointer) + , constness(vt.constness) + , reference(vt.reference) + , typeScope(vt.typeScope) + , smartPointerType(vt.smartPointerType) + , smartPointerTypeToken(vt.smartPointerTypeToken) + , container(vt.container) + , containerTypeToken(vt.containerTypeToken) + , originalTypeName(vt.originalTypeName) + {} + static ValueType parseDecl(const Token *type, const Settings *settings); static Type typeFromString(const std::string &typestr, bool longType); diff --git a/test/testclangimport.cpp b/test/testclangimport.cpp index 20febee46..0d3a970ce 100644 --- a/test/testclangimport.cpp +++ b/test/testclangimport.cpp @@ -119,6 +119,7 @@ private: TEST_CASE(symbolDatabaseVariableRRef); TEST_CASE(symbolDatabaseVariablePointerRef); TEST_CASE(symbolDatabaseNodeType1); + TEST_CASE(symbolDatabaseForVariable); TEST_CASE(valueFlow1); TEST_CASE(valueFlow2); @@ -1210,6 +1211,28 @@ private: ASSERT_EQUALS("signed long", tok->valueType()->str()); } + void symbolDatabaseForVariable() { + const char clang[] = "`-FunctionDecl 0x38f8bb0 <10100.c:2:1, line:4:1> line:2:6 f 'void (void)'\n" + " `-CompoundStmt 0x38f8d88 \n" + " `-ForStmt 0x38f8d50 \n" + " |-DeclStmt 0x38f8d28 \n" + " | `-VarDecl 0x38f8ca8 col:14 i 'int' cinit\n" + " | `-IntegerLiteral 0x38f8d08 'int' 0\n" + " |-<<>>\n" + " |-<<>>\n" + " |-<<>>\n" + " `-CompoundStmt 0x38f8d40 "; + + ASSERT_EQUALS("void f ( ) { for ( int i@1 = 0 ; ; ) { } }", parse(clang)); + + GET_SYMBOL_DB(clang); + + const Token *tok = Token::findsimplematch(tokenizer.tokens(), "i"); + ASSERT(!!tok); + ASSERT(!!tok->variable()); + ASSERT_EQUALS(Scope::ScopeType::eFor, tok->variable()->scope()->type); + } + void valueFlow1() { // struct S { int x; int buf[10]; } ; int sz = sizeof(struct S); const char clang[] = "|-RecordDecl 0x2fc5a88 <1.c:1:1, line:4:1> line:1:8 struct S definition\n"