Fix handling of namespace scope with several bodystarts (#3438)
Follow up to 0093452bed
.
Give the proper end to getVariableList, since it might not be bodyEnd.
Before that, getVariableList would add the same variables in several
unrelated scopes, and all kind of false positive would follow.
For instance, with the case I added in the unit-tests, I had:
```
../code.cpp:15:18: warning: The struct 'is_A' defines member variable with name 'foo' also defined in its parent struct 'is_A_impl'. [duplInheritedMember]
static const int foo = 8;
^
../code.cpp:15:18: note: Parent variable 'is_A_impl::foo'
static const int foo = 8;
^
../code.cpp:15:18: note: Derived variable 'is_A::foo'
static const int foo = 8;
^
../code.cpp:15:18: style: struct member 'has_A::foo' is never used. [unusedStructMember]
static const int foo = 8;
^
../code.cpp:15:18: style: struct member 'is_A::foo' is never used. [unusedStructMember]
static const int foo = 8;
^
```
This commit is contained in:
parent
2b7523e466
commit
b3b3b6b2a1
|
@ -4194,19 +4194,19 @@ void Scope::getVariableList(const Settings* settings)
|
|||
{
|
||||
if (!bodyStartList.empty()) {
|
||||
for (const Token *bs: bodyStartList)
|
||||
getVariableList(settings, bs->next());
|
||||
getVariableList(settings, bs->next(), bs->link());
|
||||
}
|
||||
|
||||
// global scope
|
||||
else if (type == Scope::eGlobal)
|
||||
getVariableList(settings, check->mTokenizer->tokens());
|
||||
getVariableList(settings, check->mTokenizer->tokens(), nullptr);
|
||||
|
||||
// forward declaration
|
||||
else
|
||||
return;
|
||||
}
|
||||
|
||||
void Scope::getVariableList(const Settings* settings, const Token* start)
|
||||
void Scope::getVariableList(const Settings* settings, const Token* start, const Token* end)
|
||||
{
|
||||
// Variable declared in condition: if (auto x = bar())
|
||||
if (Token::Match(classDef, "if|while ( %type%") && Token::simpleMatch(classDef->next()->astOperand2(), "=")) {
|
||||
|
@ -4214,7 +4214,7 @@ void Scope::getVariableList(const Settings* settings, const Token* start)
|
|||
}
|
||||
|
||||
AccessControl varaccess = defaultAccess();
|
||||
for (const Token *tok = start; tok && tok != bodyEnd; tok = tok->next()) {
|
||||
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
||||
// syntax error?
|
||||
if (tok->next() == nullptr)
|
||||
break;
|
||||
|
|
|
@ -1204,7 +1204,7 @@ private:
|
|||
void findFunctionInBase(const std::string & name, nonneg int args, std::vector<const Function *> & matches) const;
|
||||
|
||||
/** @brief initialize varlist */
|
||||
void getVariableList(const Settings* settings, const Token *start);
|
||||
void getVariableList(const Settings* settings, const Token *start, const Token *end);
|
||||
};
|
||||
|
||||
enum class Reference {
|
||||
|
|
|
@ -355,6 +355,7 @@ private:
|
|||
|
||||
TEST_CASE(createSymbolDatabaseFindAllScopes1);
|
||||
TEST_CASE(createSymbolDatabaseFindAllScopes2);
|
||||
TEST_CASE(createSymbolDatabaseFindAllScopes3);
|
||||
|
||||
TEST_CASE(enum1);
|
||||
TEST_CASE(enum2);
|
||||
|
@ -4811,6 +4812,33 @@ private:
|
|||
ASSERT(var2->variable());
|
||||
}
|
||||
|
||||
void createSymbolDatabaseFindAllScopes3() {
|
||||
GET_SYMBOL_DB("namespace ns {\n"
|
||||
"\n"
|
||||
"namespace ns_details {\n"
|
||||
"template <typename T, typename = void> struct has_A : std::false_type {};\n"
|
||||
"template <typename T> struct has_A<T, typename make_void<typename T::A>::type> : std::true_type {};\n"
|
||||
"template <typename T, bool> struct is_A_impl : public std::is_trivially_copyable<T> {};\n"
|
||||
"template <typename T> struct is_A_impl<T, true> : public std::is_same<typename T::A, std::true_type> {};\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"template <typename T> struct is_A : ns_details::is_A_impl<T, ns_details::has_A<T>::value> {};\n"
|
||||
"template <class T, class U> struct is_A<std::pair<T, U>> : std::integral_constant<bool, is_A<T>::value && is_A<U>::value> {};\n"
|
||||
"}\n"
|
||||
"\n"
|
||||
"extern \"C\" {\n"
|
||||
"static const int foo = 8;\n"
|
||||
"}\n");
|
||||
ASSERT(db);
|
||||
ASSERT_EQUALS(6, db->scopeList.size());
|
||||
ASSERT_EQUALS(1, db->scopeList.front().varlist.size());
|
||||
auto list = db->scopeList;
|
||||
list.pop_front();
|
||||
for (const auto &scope : list) {
|
||||
ASSERT_EQUALS(0, scope.varlist.size());
|
||||
}
|
||||
}
|
||||
|
||||
void enum1() {
|
||||
GET_SYMBOL_DB("enum BOOL { FALSE, TRUE }; enum BOOL b;");
|
||||
|
||||
|
|
Loading…
Reference in New Issue