Skip to content

Commit 37716fb

Browse files
committed
Tokenizer: Set variable() pointer for array members
1 parent 59f448d commit 37716fb

3 files changed

Lines changed: 96 additions & 5 deletions

File tree

lib/tokenize.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9375,6 +9375,31 @@ void Tokenizer::createSymbolDatabase()
93759375
for (Token* tok = list.front(); tok != list.back(); tok = tok->next()) {
93769376
if (tok->varId())
93779377
tok->variable(_symbolDatabase->getVariableFromVarId(tok->varId()));
9378+
9379+
// Set Token::variable pointer for array member variable
9380+
// Since it doesn't point at a fixed location it doesn't have varid
9381+
if (tok->variable() != NULL &&
9382+
tok->variable()->typeScope() &&
9383+
Token::Match(tok, "%var% [")) {
9384+
9385+
// Locate "]"
9386+
Token *tok2 = tok->next();
9387+
while (tok2 && tok2->str() == "[")
9388+
tok2 = tok2->link()->next();
9389+
9390+
Token *membertok = NULL;
9391+
if (Token::Match(tok2, ". %var%"))
9392+
membertok = tok2->next();
9393+
else if (Token::Match(tok2, ") . %var%") && tok->strAt(-1) == "(")
9394+
membertok = tok2->tokAt(2);
9395+
9396+
if (membertok) {
9397+
const Variable *var = tok->variable();
9398+
const Variable *membervar = var->typeScope()->getVariable(membertok->str());
9399+
if (membervar)
9400+
membertok->variable(membervar);
9401+
}
9402+
}
93789403
}
93799404
}
93809405
}

test/testsizeof.cpp

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -598,14 +598,17 @@ class TestSizeof : public TestFixture {
598598
" void *data;\n"
599599
"};\n"
600600
"char f(struct FOO* foo) {\n"
601-
" char x = *(foo[1].data + 1);\n"
602-
" return x;\n"
603-
"}\n"
601+
" *(foo[1].data + 1) = 0;\n"
602+
"}\n");
603+
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());
604+
605+
check("struct FOO {\n"
606+
" void *data;\n"
607+
"};\n"
604608
"void f2(struct FOO* foo) {\n"
605609
" (foo[0]).data++;\n"
606610
"}");
607-
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"
608-
"[test.cpp:9]: (portability) 'foo[0].data' is of type 'void *'. When using void pointers in calculations, the behaviour is undefined.\n", "", errout.str());
611+
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());
609612
}
610613

611614
};

test/testsymboldatabase.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,9 @@ class TestSymbolDatabase: public TestFixture {
120120
TEST_CASE(isVariableDeclarationPointerConst);
121121
TEST_CASE(isVariableDeclarationRValueRef);
122122

123+
TEST_CASE(arrayMemberVar1);
124+
TEST_CASE(arrayMemberVar2);
125+
TEST_CASE(arrayMemberVar3);
123126
TEST_CASE(staticMemberVar);
124127

125128
TEST_CASE(hasRegularFunction);
@@ -545,6 +548,66 @@ class TestSymbolDatabase: public TestFixture {
545548
ASSERT(var.tokens()->tokAt(2)->scope() != 0);
546549
}
547550

551+
void arrayMemberVar1() {
552+
const char code[] = "struct Foo {\n"
553+
" int x;\n"
554+
"};\n"
555+
"void f() {\n"
556+
" struct Foo foo[10];\n"
557+
" foo[1].x = 123;\n" // <- x should get a variable() pointer
558+
"}";
559+
560+
Settings settings;
561+
Tokenizer tokenizer(&settings, this);
562+
std::istringstream istr(code);
563+
tokenizer.tokenize(istr, "test.cpp");
564+
565+
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
566+
tok = tok ? tok->next() : NULL;
567+
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
568+
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
569+
}
570+
571+
void arrayMemberVar2() {
572+
const char code[] = "struct Foo {\n"
573+
" int x;\n"
574+
"};\n"
575+
"void f() {\n"
576+
" struct Foo foo[10][10];\n"
577+
" foo[1][2].x = 123;\n" // <- x should get a variable() pointer
578+
"}";
579+
580+
Settings settings;
581+
Tokenizer tokenizer(&settings, this);
582+
std::istringstream istr(code);
583+
tokenizer.tokenize(istr, "test.cpp");
584+
585+
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
586+
tok = tok ? tok->next() : NULL;
587+
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
588+
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
589+
}
590+
591+
void arrayMemberVar3() {
592+
const char code[] = "struct Foo {\n"
593+
" int x;\n"
594+
"};\n"
595+
"void f() {\n"
596+
" struct Foo foo[10];\n"
597+
" (foo[1]).x = 123;\n" // <- x should get a variable() pointer
598+
"}";
599+
600+
Settings settings;
601+
Tokenizer tokenizer(&settings, this);
602+
std::istringstream istr(code);
603+
tokenizer.tokenize(istr, "test.cpp");
604+
605+
const Token *tok = Token::findmatch(tokenizer.tokens(), ". x");
606+
tok = tok ? tok->next() : NULL;
607+
ASSERT(tok && tok->variable() && Token::Match(tok->variable()->typeStartToken(), "int x ;"));
608+
ASSERT(tok && tok->varId() == 0U); // It's possible to set a varId
609+
}
610+
548611
void staticMemberVar() {
549612
GET_SYMBOL_DB("class Foo {\n"
550613
" static const double d;\n"

0 commit comments

Comments
 (0)