Tokenizer: Set variable() pointer for array members
This commit is contained in:
parent
59f448da8a
commit
37716fb8bb
|
@ -9375,6 +9375,31 @@ void Tokenizer::createSymbolDatabase()
|
|||
for (Token* tok = list.front(); tok != list.back(); tok = tok->next()) {
|
||||
if (tok->varId())
|
||||
tok->variable(_symbolDatabase->getVariableFromVarId(tok->varId()));
|
||||
|
||||
// Set Token::variable pointer for array member variable
|
||||
// Since it doesn't point at a fixed location it doesn't have varid
|
||||
if (tok->variable() != NULL &&
|
||||
tok->variable()->typeScope() &&
|
||||
Token::Match(tok, "%var% [")) {
|
||||
|
||||
// Locate "]"
|
||||
Token *tok2 = tok->next();
|
||||
while (tok2 && tok2->str() == "[")
|
||||
tok2 = tok2->link()->next();
|
||||
|
||||
Token *membertok = NULL;
|
||||
if (Token::Match(tok2, ". %var%"))
|
||||
membertok = tok2->next();
|
||||
else if (Token::Match(tok2, ") . %var%") && tok->strAt(-1) == "(")
|
||||
membertok = tok2->tokAt(2);
|
||||
|
||||
if (membertok) {
|
||||
const Variable *var = tok->variable();
|
||||
const Variable *membervar = var->typeScope()->getVariable(membertok->str());
|
||||
if (membervar)
|
||||
membertok->variable(membervar);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -598,14 +598,17 @@ private:
|
|||
" void *data;\n"
|
||||
"};\n"
|
||||
"char f(struct FOO* foo) {\n"
|
||||
" char x = *(foo[1].data + 1);\n"
|
||||
" return x;\n"
|
||||
"}\n"
|
||||
" *(foo[1].data + 1) = 0;\n"
|
||||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:5]: (portability) 'foo[1].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
|
||||
check("struct FOO {\n"
|
||||
" void *data;\n"
|
||||
"};\n"
|
||||
"void f2(struct FOO* foo) {\n"
|
||||
" (foo[0]).data++;\n"
|
||||
"}");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:5]: (portability) 'foo[1].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n"
|
||||
"[test.cpp:9]: (portability) 'foo[0].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", "", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:5]: (portability) '(foo[0]).data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", errout.str());
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -120,6 +120,9 @@ private:
|
|||
TEST_CASE(isVariableDeclarationPointerConst);
|
||||
TEST_CASE(isVariableDeclarationRValueRef);
|
||||
|
||||
TEST_CASE(arrayMemberVar1);
|
||||
TEST_CASE(arrayMemberVar2);
|
||||
TEST_CASE(arrayMemberVar3);
|
||||
TEST_CASE(staticMemberVar);
|
||||
|
||||
TEST_CASE(hasRegularFunction);
|
||||
|
@ -545,6 +548,66 @@ private:
|
|||
ASSERT(var.tokens()->tokAt(2)->scope() != 0);
|
||||
}
|
||||
|
||||
void arrayMemberVar1() {
|
||||
const char code[] = "struct Foo {\n"
|
||||
" int x;\n"
|
||||
"};\n"
|
||||
"void f() {\n"
|
||||
" struct Foo foo[10];\n"
|
||||
" foo[1].x = 123;\n" // <- x should get a variable() pointer
|
||||
"}";
|
||||
|
||||
Settings settings;
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
|
||||
tok = tok ? tok->next() : NULL;
|
||||
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
|
||||
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
|
||||
}
|
||||
|
||||
void arrayMemberVar2() {
|
||||
const char code[] = "struct Foo {\n"
|
||||
" int x;\n"
|
||||
"};\n"
|
||||
"void f() {\n"
|
||||
" struct Foo foo[10][10];\n"
|
||||
" foo[1][2].x = 123;\n" // <- x should get a variable() pointer
|
||||
"}";
|
||||
|
||||
Settings settings;
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
|
||||
tok = tok ? tok->next() : NULL;
|
||||
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
|
||||
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
|
||||
}
|
||||
|
||||
void arrayMemberVar3() {
|
||||
const char code[] = "struct Foo {\n"
|
||||
" int x;\n"
|
||||
"};\n"
|
||||
"void f() {\n"
|
||||
" struct Foo foo[10];\n"
|
||||
" (foo[1]).x = 123;\n" // <- x should get a variable() pointer
|
||||
"}";
|
||||
|
||||
Settings settings;
|
||||
Tokenizer tokenizer(&settings, this);
|
||||
std::istringstream istr(code);
|
||||
tokenizer.tokenize(istr, "test.cpp");
|
||||
|
||||
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
|
||||
tok = tok ? tok->next() : NULL;
|
||||
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
|
||||
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
|
||||
}
|
||||
|
||||
void staticMemberVar() {
|
||||
GET_SYMBOL_DB("class Foo {\n"
|
||||
" static const double d;\n"
|
||||
|
|
Loading…
Reference in New Issue