Tokenizer: Set variable() pointer for array members

This commit is contained in:
Daniel Marjamäki 2013-07-20 17:46:39 +02:00
parent 59f448da8a
commit 37716fb8bb
3 changed files with 96 additions and 5 deletions

View File

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

View File

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

View File

@ -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"