diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index fa922659d..859869b78 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -4811,6 +4811,9 @@ bool Tokenizer::simplifyTokenList1(const char FileName[]) // convert C++17 style nested namespaces to old style namespaces simplifyNestedNamespace(); + // convert c++20 coroutines + simplifyCoroutines(); + // simplify namespace aliases simplifyNamespaceAliases(); @@ -12340,6 +12343,29 @@ void Tokenizer::simplifyNestedNamespace() } } +void Tokenizer::simplifyCoroutines() +{ + if (!isCPP() || mSettings->standards.cpp < Standards::CPP20) + return; + for (Token *tok = list.front(); tok; tok = tok->next()) { + if (!tok->isName() || !Token::Match(tok, "co_return|co_yield|co_await")) + continue; + Token *end = tok->next(); + while (end && end->str() != ";") { + if (Token::Match(end, "[({[]")) + end = end->link(); + else if (Token::Match(end, "[)]}]")) + break; + end = end->next(); + } + if (Token::simpleMatch(end, ";")) { + tok->insertToken("("); + end->previous()->insertToken(")"); + Token::createMutualLinks(tok->next(), end->previous()); + } + } +} + static bool sameTokens(const Token *first, const Token *last, const Token *other) { while (other && first->str() == other->str()) { diff --git a/lib/tokenize.h b/lib/tokenize.h index 35be9b7da..af92bfc82 100644 --- a/lib/tokenize.h +++ b/lib/tokenize.h @@ -785,6 +785,13 @@ private: */ void simplifyNestedNamespace(); + /** + * Simplify coroutines - just put parentheses around arguments for + * co_* keywords so they can be handled like function calls in data + * flow. + */ + void simplifyCoroutines(); + /** * Prepare ternary operators with parentheses so that the AST can be created * */ diff --git a/test/testtokenize.cpp b/test/testtokenize.cpp index 21aa39ba9..ee8612a26 100644 --- a/test/testtokenize.cpp +++ b/test/testtokenize.cpp @@ -416,6 +416,8 @@ private: TEST_CASE(removeExtraTemplateKeywords); TEST_CASE(removeAlignas); + + TEST_CASE(simplifyCoroutines); } std::string tokenizeAndStringify(const char code[], bool expand = true, Settings::PlatformType platform = Settings::Native, const char* filename = "test.cpp", bool cpp11 = true) { @@ -6507,6 +6509,23 @@ private: const char expected[] = "unsigned char c [ sizeof ( float ) ] ;"; ASSERT_EQUALS(expected, tokenizeAndStringify(code)); } + + void simplifyCoroutines() { + Settings settings; + settings.standards.cpp = Standards::CPP20; + + const char code1[] = "generator f() { co_yield start++; }"; + const char expected1[] = "generator < int > f ( ) { co_yield ( start ++ ) ; }"; + ASSERT_EQUALS(expected1, tokenizeAndStringify(code1, settings)); + + const char code2[] = "task<> f() { co_await foo(); }"; + const char expected2[] = "task < > f ( ) { co_await ( foo ( ) ) ; }"; + ASSERT_EQUALS(expected2, tokenizeAndStringify(code2, settings)); + + const char code3[] = "generator f() { co_return 7; }"; + const char expected3[] = "generator < int > f ( ) { co_return ( 7 ) ; }"; + ASSERT_EQUALS(expected3, tokenizeAndStringify(code3, settings)); + } }; REGISTER_TEST(TestTokenizer)