diff --git a/lib/checkclass.cpp b/lib/checkclass.cpp index 4cb706de0..a4100745d 100644 --- a/lib/checkclass.cpp +++ b/lib/checkclass.cpp @@ -2173,6 +2173,9 @@ bool CheckClass::isMemberVar(const Scope *scope, const Token *tok) const } } while (again); + if (tok->isKeyword() || tok->isStandardType()) + return false; + for (const Variable& var : scope->varlist) { if (var.name() == tok->str()) { if (Token::Match(tok, "%name% ::")) diff --git a/lib/symboldatabase.cpp b/lib/symboldatabase.cpp index 4b59bf97f..0ad64db3e 100644 --- a/lib/symboldatabase.cpp +++ b/lib/symboldatabase.cpp @@ -1208,6 +1208,8 @@ void SymbolDatabase::fixVarId(VarIdMap & varIds, const Token * vartok, Token * m membertok->varId(memberId->second); } +static bool isContainerYieldElement(Library::Container::Yield yield); + void SymbolDatabase::createSymbolDatabaseSetVariablePointers() { VarIdMap varIds; @@ -1222,6 +1224,8 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() // Set variable pointers for (const Token* tok = mTokenizer->list.front(); tok != mTokenizer->list.back(); tok = tok->next()) { + if (!tok->isName() || tok->isKeyword() || tok->isStandardType()) + continue; if (tok->varId()) const_cast(tok)->variable(getVariableFromVarId(tok->varId())); @@ -1310,6 +1314,16 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers() } } } + else if (Token::simpleMatch(tok->astParent(), ".") && tok->next()->str() == "(" && + astIsContainer(tok->astParent()->astOperand1()) && Token::Match(tok->next()->link(), ") . %name% !!(")) { + const ValueType* vt = tok->astParent()->astOperand1()->valueType(); + const Library::Container* cont = vt->container; + auto it = cont->functions.find(tok->str()); + if (it != cont->functions.end() && isContainerYieldElement(it->second.yield) && vt->containerTypeToken && vt->containerTypeToken->scope()) { + Token* memberTok = tok->next()->link()->tokAt(2); + setMemberVar(vt->containerTypeToken->scope()->getVariable(memberTok->str()), memberTok, vt->containerTypeToken); + } + } } } @@ -6052,7 +6066,7 @@ static void setAutoTokenProperties(Token * const autoTok) autoTok->isStandardType(true); } -static bool isContainerYieldElement(Library::Container::Yield yield) +bool isContainerYieldElement(Library::Container::Yield yield) { return yield == Library::Container::Yield::ITEM || yield == Library::Container::Yield::AT_INDEX || yield == Library::Container::Yield::BUFFER || yield == Library::Container::Yield::BUFFER_NT; diff --git a/test/testvarid.cpp b/test/testvarid.cpp index 587166ac1..72040163e 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -32,9 +32,15 @@ struct InternalError; class TestVarID : public TestFixture { public: - TestVarID() : TestFixture("TestVarID") {} + TestVarID() : TestFixture("TestVarID") { + settings.platform(Settings::Unix64); + settings.standards.c = Standards::C89; + settings.standards.cpp = Standards::CPPLatest; + settings.checkUnusedTemplates = true; + } private: + Settings settings; void run() override { TEST_CASE(varid1); TEST_CASE(varid2); @@ -137,6 +143,7 @@ private: TEST_CASE(varid_in_class22); // #10872 TEST_CASE(varid_in_class23); // #11293 TEST_CASE(varid_in_class24); + TEST_CASE(varid_in_class25); TEST_CASE(varid_namespace_1); // #7272 TEST_CASE(varid_namespace_2); // #7000 TEST_CASE(varid_namespace_3); // #8627 @@ -235,12 +242,6 @@ private: std::string tokenize_(const char* file, int line, const char code[], const char filename[] = "test.cpp") { errout.str(""); - Settings settings; - settings.platform(Settings::Unix64); - settings.standards.c = Standards::C89; - settings.standards.cpp = Standards::CPPLatest; - settings.checkUnusedTemplates = true; - Tokenizer tokenizer(&settings, this); std::istringstream istr(code); ASSERT_LOC((tokenizer.tokenize)(istr, filename), file, line); @@ -255,12 +256,6 @@ private: std::string tokenizeExpr_(const char* file, int line, const char code[], const char filename[] = "test.cpp") { errout.str(""); - Settings settings; - settings.platform(Settings::Unix64); - settings.standards.c = Standards::C89; - settings.standards.cpp = Standards::CPPLatest; - settings.checkUnusedTemplates = true; - Tokenizer tokenizer(&settings, this); std::istringstream istr(code); ASSERT_LOC((tokenizer.tokenize)(istr, filename), file, line); @@ -275,12 +270,6 @@ private: std::string compareVaridsForVariable_(const char* file, int line, const char code[], const char varname[], const char filename[] = "test.cpp") { errout.str(""); - Settings settings; - settings.platform(Settings::Unix64); - settings.standards.c = Standards::C89; - settings.standards.cpp = Standards::CPP11; - settings.checkUnusedTemplates = true; - Tokenizer tokenizer(&settings, this); std::istringstream istr(code); ASSERT_LOC((tokenizer.tokenize)(istr, filename), file, line); @@ -2015,6 +2004,27 @@ private: ASSERT_EQUALS(expected, tokenize(code, "test.cpp")); } + void varid_in_class25() { // #11497 + const char *code{}, *expected{}; + Settings oldSettings = settings; + LOAD_LIB_2(settings.library, "std.cfg"); + + code = "struct F {\n" + " int i;\n" + " void f(const std::vector&v) {\n" + " if (v.front().i) {}\n" + " }\n" + "};\n"; + expected = "1: struct F {\n" + "2: int i@1 ;\n" + "3: void f ( const std :: vector < F > & v@2 ) {\n" + "4: if ( v@2 . front ( ) . i@3 ) { }\n" + "5: }\n" + "6: } ;\n"; + ASSERT_EQUALS(expected, tokenize(code, "test.cpp")); + settings = oldSettings; + } + void varid_namespace_1() { // #7272 const char code[] = "namespace Blah {\n" " struct foo { int x;};\n"