* Preliminary * Fix member search, add tests
This commit is contained in:
parent
850ad0fed9
commit
557263acde
|
@ -1210,20 +1210,36 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
|
||||||
|
|
||||||
// Set Token::variable pointer for array member variable
|
// Set Token::variable pointer for array member variable
|
||||||
// Since it doesn't point at a fixed location it doesn't have varid
|
// Since it doesn't point at a fixed location it doesn't have varid
|
||||||
if (tok->variable() != nullptr &&
|
const bool isVar = tok->variable() && (tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER));
|
||||||
(tok->variable()->typeScope() || tok->variable()->isSmartPointer() || (tok->valueType() && tok->valueType()->type == ValueType::CONTAINER)) &&
|
const bool isArrayAccess = isVar && Token::simpleMatch(tok->astParent(), "[");
|
||||||
Token::Match(tok, "%name% [|.")) {
|
const bool isDirectAccess = isVar && !isArrayAccess && Token::simpleMatch(tok->astParent(), ".");
|
||||||
|
const bool isDerefAccess = isVar && !isDirectAccess && Token::simpleMatch(tok->astParent(), "*") && Token::simpleMatch(tok->astParent()->astParent(), ".");
|
||||||
Token *tok2 = tok->next();
|
if (isVar && (isArrayAccess || isDirectAccess || isDerefAccess)) {
|
||||||
// Locate "]"
|
Token* membertok{};
|
||||||
while (tok2 && tok2->str() == "[")
|
if (isArrayAccess) {
|
||||||
tok2 = tok2->link()->next();
|
membertok = const_cast<Token*>(tok->astParent());
|
||||||
|
while (Token::simpleMatch(membertok, "["))
|
||||||
Token *membertok = nullptr;
|
membertok = membertok->astParent();
|
||||||
if (Token::Match(tok2, ". %name%"))
|
if (membertok)
|
||||||
membertok = tok2->next();
|
membertok = membertok->astOperand2();
|
||||||
else if (Token::Match(tok2, ") . %name%") && tok->strAt(-1) == "(")
|
}
|
||||||
membertok = tok2->tokAt(2);
|
else if (isDirectAccess) {
|
||||||
|
membertok = const_cast<Token*>(tok->astParent()->astOperand2());
|
||||||
|
if (membertok == tok) {
|
||||||
|
Token* gptok = const_cast<Token*>(tok->astParent()->astParent());
|
||||||
|
if (Token::simpleMatch(gptok, ".")) // chained access
|
||||||
|
membertok = gptok->astOperand2();
|
||||||
|
else if (Token::simpleMatch(gptok, "[") && Token::simpleMatch(gptok->astParent(), "."))
|
||||||
|
membertok = gptok->astParent()->astOperand2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { // isDerefAccess
|
||||||
|
membertok = const_cast<Token*>(tok->astParent());
|
||||||
|
while (Token::simpleMatch(membertok, "*"))
|
||||||
|
membertok = membertok->astParent();
|
||||||
|
if (membertok)
|
||||||
|
membertok = membertok->astOperand2();
|
||||||
|
}
|
||||||
|
|
||||||
if (membertok) {
|
if (membertok) {
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
|
|
|
@ -1629,8 +1629,8 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void structmember19() { // #10826
|
void structmember19() {
|
||||||
checkStructMemberUsage("class C {};\n"
|
checkStructMemberUsage("class C {};\n" // #10826
|
||||||
"struct S {\n"
|
"struct S {\n"
|
||||||
" char* p;\n"
|
" char* p;\n"
|
||||||
" std::string str;\n"
|
" std::string str;\n"
|
||||||
|
@ -1653,6 +1653,54 @@ private:
|
||||||
"[test.cpp:4]: (style) struct member 'S::str' is never used.\n"
|
"[test.cpp:4]: (style) struct member 'S::str' is never used.\n"
|
||||||
"[test.cpp:5]: (style) struct member 'S::c' is never used.\n",
|
"[test.cpp:5]: (style) struct member 'S::c' is never used.\n",
|
||||||
errout.str());
|
errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S {\n"
|
||||||
|
" struct T {\n"
|
||||||
|
" int i;\n"
|
||||||
|
" } t[2];\n"
|
||||||
|
"};\n"
|
||||||
|
"S s[1];\n"
|
||||||
|
"int f() {\n"
|
||||||
|
" return s[0].t[1].i;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"struct T { S s; };\n"
|
||||||
|
"int f(const T** tp) {\n"
|
||||||
|
" return tp[0]->s.a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"int f(const S* sp) {\n"
|
||||||
|
" return (*sp).a; \n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"int f(const S** spp) {\n"
|
||||||
|
" return spp[0]->a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"int f(const S** spp) {\n"
|
||||||
|
" return spp[0][0].a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"int f(const S* sp) {\n"
|
||||||
|
" return sp[0].a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
checkStructMemberUsage("struct S { int a; };\n"
|
||||||
|
"int f(const S* sp) {\n"
|
||||||
|
" return sp->a;\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") {
|
void functionVariableUsage_(const char* file, int line, const char code[], const char filename[] = "test.cpp") {
|
||||||
|
|
Loading…
Reference in New Issue