diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index a9e2d845c20..8edeaa4ac1f 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4209,7 +4209,7 @@ void VariableMap::addVariable(const std::string& varname, bool globalNamespace) it->second = ++mVarId; } -static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope) +static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap, bool executableScope, Standards::cstd_t cStandard) { const Token* const tok1 = tok; Token* tok2 = tok; @@ -4229,7 +4229,9 @@ static bool setVarIdParseDeclaration(Token*& tok, const VariableMap& variableMap } if (tok2->isCpp() && Token::Match(tok2, "namespace|public|private|protected")) return false; - if (tok2->isCpp() && Token::simpleMatch(tok2, "decltype (")) { + bool isC23 = tok2->isC() && cStandard >= Standards::C23; + if (((tok2->isCpp() || isC23) && Token::Match(tok2, "decltype|typeof (")) || + (tok2->isC() && Token::simpleMatch(tok2, "__typeof ("))) { typeCount = 1; tok2 = tok2->linkAt(1)->next(); continue; @@ -4762,7 +4764,7 @@ void Tokenizer::setVarIdPass1() } try { /* Ticket #8151 */ - decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable); + decl = setVarIdParseDeclaration(tok2, variableMap, scopeStack.top().isExecutable, mSettings.standards.c); } catch (const Token * errTok) { syntaxError(errTok); } @@ -4782,11 +4784,19 @@ void Tokenizer::setVarIdPass1() variableMap.map(true), mTemplateVarIdUsage); } - if (Token *declTypeTok = Token::findsimplematch(tok, "decltype (", tok2)) { - for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) { - if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str())) - declTok->varId(variableMap.map(false).find(declTok->str())->second); - } + } + + Token *declTypeTok = nullptr; + if (cpp || mSettings.standards.c >= Standards::C23) { + declTypeTok = Token::findmatch(tok, "decltype|typeof (", tok2); + } else { + declTypeTok = Token::findsimplematch(tok, "__typeof ("); + } + + if (declTypeTok) { + for (Token *declTok = declTypeTok->linkAt(1); declTok != declTypeTok; declTok = declTok->previous()) { + if (declTok->isName() && !Token::Match(declTok->previous(), "::|.") && variableMap.hasVariable(declTok->str())) + declTok->varId(variableMap.map(false).find(declTok->str())->second); } } diff --git a/test/testvarid.cpp b/test/testvarid.cpp index d509ece2f13..ab9bb5af489 100644 --- a/test/testvarid.cpp +++ b/test/testvarid.cpp @@ -240,6 +240,11 @@ class TestVarID : public TestFixture { TEST_CASE(decltype1); TEST_CASE(decltype2); + TEST_CASE(typeof1); + TEST_CASE(typeof2); + TEST_CASE(typeof3); + TEST_CASE(typeof4); + TEST_CASE(exprid1); TEST_CASE(exprid2); TEST_CASE(exprid3); @@ -4189,6 +4194,32 @@ class TestVarID : public TestFixture { ASSERT_EQUALS(expected, tokenize(code)); } + void typeof1() { + const char code[] = "int x; typeof(x) y;"; + const char expected[] = "1: int x@1 ; typeof ( x@1 ) y@2 ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void typeof2() { + const char code[] = "int x; typeof(x) *y;"; + const char expected[] = "1: int x@1 ; typeof ( x@1 ) * y@2 ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void typeof3() { + const char code[] = "int x; const typeof(x) *const y;"; + const char expected[] = "1: int x@1 ; const typeof ( x@1 ) * const y@2 ;\n"; + ASSERT_EQUALS(expected, tokenize(code)); + } + + void typeof4() { + const char code[] = "int x; __typeof(x) y;"; + const char expected[] = "1: int x@1 ; __typeof ( x@1 ) y@2 ;\n"; + TokenizeOptions options; + options.cpp = false; + ASSERT_EQUALS(expected, tokenize(code, options)); + } + void exprid1() { const std::string actual = tokenizeExpr( "struct A {\n"