diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index ea3367b0b..a74cb3f1f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -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); + } + } } } } diff --git a/test/testsizeof.cpp b/test/testsizeof.cpp index 61b82ee31..8e3b36406 100644 --- a/test/testsizeof.cpp +++ b/test/testsizeof.cpp @@ -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()); } }; diff --git a/test/testsymboldatabase.cpp b/test/testsymboldatabase.cpp index a8ea3ab3a..047cda4ea 100644 --- a/test/testsymboldatabase.cpp +++ b/test/testsymboldatabase.cpp @@ -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"