From 6ac804d2093db6eb31b3586e0692230147e73560 Mon Sep 17 00:00:00 2001 From: chrchr-github <78114321+chrchr-github@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:02:41 +0100 Subject: [PATCH] Fix #12178 extern "C++" scope generates valueflow (#5654) --- lib/tokenize.cpp | 7 +++--- test/testsimplifytemplate.cpp | 3 ++- test/testtokenize.cpp | 43 +++++++++++++++++++++++++++++++++-- 3 files changed, 47 insertions(+), 6 deletions(-) diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 9a44f6cd7..75fa0ebea 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -3592,17 +3592,18 @@ void Tokenizer::simplifyExternC() // Add attributes to all tokens within `extern "C"` inlines and blocks, and remove the `extern "C"` tokens. for (Token *tok = list.front(); tok; tok = tok->next()) { - if (Token::simpleMatch(tok, "extern \"C\"")) { + if (Token::Match(tok, "extern \"C\"|\"C++\"")) { Token *tok2 = tok->next(); + const bool isExtC = tok->next()->str().size() == 3; if (tok->strAt(2) == "{") { tok2 = tok2->next(); // skip { while ((tok2 = tok2->next()) && tok2 != tok->linkAt(2)) - tok2->isExternC(true); + tok2->isExternC(isExtC); tok->linkAt(2)->deleteThis(); // } tok->deleteNext(2); // "C" { } else { while ((tok2 = tok2->next()) && !Token::Match(tok2, "[;{]")) - tok2->isExternC(true); + tok2->isExternC(isExtC); tok->deleteNext(); // "C" } tok->deleteThis(); // extern diff --git a/test/testsimplifytemplate.cpp b/test/testsimplifytemplate.cpp index aa4db7d84..03d62dbe7 100644 --- a/test/testsimplifytemplate.cpp +++ b/test/testsimplifytemplate.cpp @@ -4163,7 +4163,8 @@ private: void template163() { // #9685 syntax error const char code[] = "extern \"C++\" template < typename T > T * test ( ) { return nullptr ; }"; - ASSERT_EQUALS(code, tok(code)); + const char expected[] = "template < typename T > T * test ( ) { return nullptr ; }"; + ASSERT_EQUALS(expected, tok(code)); } void template164() { // #9394 diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 791e56c3b..245db59df 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -1548,8 +1548,47 @@ private: void simplifyExternC() { - ASSERT_EQUALS("int foo ( ) ;", tokenizeAndStringify("extern \"C\" int foo();")); - ASSERT_EQUALS("int foo ( ) ;", tokenizeAndStringify("extern \"C\" { int foo(); }")); + const char expected[] = "int foo ( ) ;"; + { + const char code[] = "extern \"C\" int foo();"; + // tokenize.. + Tokenizer tokenizer(&settings0, this); + std::istringstream istr(code); + ASSERT(tokenizer.tokenize(istr, "test.cpp")); + // Expected result.. + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + ASSERT(tokenizer.tokens()->next()->isExternC()); + } + { + const char code[] = "extern \"C\" { int foo(); }"; + // tokenize.. + Tokenizer tokenizer(&settings0, this); + std::istringstream istr(code); + ASSERT(tokenizer.tokenize(istr, "test.cpp")); + // Expected result.. + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + ASSERT(tokenizer.tokens()->next()->isExternC()); + } + { + const char code[] = "extern \"C++\" int foo();"; + // tokenize.. + Tokenizer tokenizer(&settings0, this); + std::istringstream istr(code); + ASSERT(tokenizer.tokenize(istr, "test.cpp")); + // Expected result.. + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + ASSERT(!tokenizer.tokens()->next()->isExternC()); + } + { + const char code[] = "extern \"C++\" { int foo(); }"; + // tokenize.. + Tokenizer tokenizer(&settings0, this); + std::istringstream istr(code); + ASSERT(tokenizer.tokenize(istr, "test.cpp")); + // Expected result.. + ASSERT_EQUALS(expected, tokenizer.tokens()->stringifyList(nullptr, false)); + ASSERT(!tokenizer.tokens()->next()->isExternC()); + } } void simplifyFunctionParameters() {