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()) {
|
for (Token* tok = list.front(); tok != list.back(); tok = tok->next()) {
|
||||||
if (tok->varId())
|
if (tok->varId())
|
||||||
tok->variable(_symbolDatabase->getVariableFromVarId(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"
|
" void *data;\n"
|
||||||
"};\n"
|
"};\n"
|
||||||
"char f(struct FOO* foo) {\n"
|
"char f(struct FOO* foo) {\n"
|
||||||
" char x = *(foo[1].data + 1);\n"
|
" *(foo[1].data + 1) = 0;\n"
|
||||||
" return x;\n"
|
"}\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"
|
"void f2(struct FOO* foo) {\n"
|
||||||
" (foo[0]).data++;\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"
|
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());
|
||||||
"[test.cpp:9]: (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(isVariableDeclarationPointerConst);
|
||||||
TEST_CASE(isVariableDeclarationRValueRef);
|
TEST_CASE(isVariableDeclarationRValueRef);
|
||||||
|
|
||||||
|
TEST_CASE(arrayMemberVar1);
|
||||||
|
TEST_CASE(arrayMemberVar2);
|
||||||
|
TEST_CASE(arrayMemberVar3);
|
||||||
TEST_CASE(staticMemberVar);
|
TEST_CASE(staticMemberVar);
|
||||||
|
|
||||||
TEST_CASE(hasRegularFunction);
|
TEST_CASE(hasRegularFunction);
|
||||||
|
@ -545,6 +548,66 @@ private:
|
||||||
ASSERT(var.tokens()->tokAt(2)->scope() != 0);
|
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() {
|
void staticMemberVar() {
|
||||||
GET_SYMBOL_DB("class Foo {\n"
|
GET_SYMBOL_DB("class Foo {\n"
|
||||||
" static const double d;\n"
|
" static const double d;\n"
|
||||||
|
|
Loading…
Reference in New Issue