diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 8ad49dedd37..a642bbd278b 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -103,14 +103,14 @@ static void skipEnumBody(T *&tok) /** * is tok the start brace { of a class, struct, union, or enum */ -static bool isClassStructUnionEnumStart(const Token * tok) +static const Token* isClassStructUnionEnumStart(const Token* tok) { if (!Token::Match(tok->previous(), "class|struct|union|enum|%name%|>|>> {")) - return false; + return nullptr; const Token * tok2 = tok->previous(); while (tok2 && !Token::Match(tok2, "class|struct|union|enum|{|}|)|;")) tok2 = tok2->previous(); - return Token::Match(tok2, "class|struct|union|enum") && !Token::simpleMatch(tok2->tokAt(-1), "->"); + return (Token::Match(tok2, "class|struct|union|enum") && !Token::simpleMatch(tok2->tokAt(-1), "->")) ? tok2 : nullptr; } //--------------------------------------------------------------------------- @@ -1028,6 +1028,13 @@ bool Tokenizer::isFunctionPointer(const Token* tok) { return Token::Match(tok, "%name% ) ("); } +static bool matchCurrentType(const std::string& typeStr, const std::map& types) +{ + return std::any_of(types.begin(), types.end(), [&](const std::pair& element) { + return typeStr == element.second; + }); +} + void Tokenizer::simplifyTypedef() { // Simplify global typedefs that are not redefined with the fast 1-pass simplification. @@ -1050,12 +1057,19 @@ void Tokenizer::simplifyTypedef() int indentlevel = 0; std::map typedefs; + std::map inType; for (Token* tok = list.front(); tok; tok = tok->next()) { if (!tok->isName()) { - if (tok->str()[0] == '{') + if (tok->str()[0] == '{') { ++indentlevel; - else if (tok->str()[0] == '}') + if (const Token* typeStart = isClassStructUnionEnumStart(tok)) { + inType.emplace(indentlevel, typeStart->strAt(1)); + } + } + else if (tok->str()[0] == '}') { + inType.erase(indentlevel); --indentlevel; + } continue; } @@ -1072,7 +1086,7 @@ void Tokenizer::simplifyTypedef() } auto it = typedefs.find(tok->str()); - if (it != typedefs.end() && it->second.canReplace(tok)) { + if (it != typedefs.end() && it->second.canReplace(tok) && !matchCurrentType(tok->str(), inType)) { std::set r; std::string originalname; while (it != typedefs.end() && r.insert(tok->str()).second) { diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 12ee24ee5e1..49934ab864c 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -230,6 +230,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedef157); TEST_CASE(simplifyTypedef158); TEST_CASE(simplifyTypedef159); + TEST_CASE(simplifyTypedef160); TEST_CASE(simplifyTypedefFunction1); TEST_CASE(simplifyTypedefFunction2); // ticket #1685 @@ -3812,6 +3813,28 @@ class TestSimplifyTypedef : public TestFixture { ASSERT_EQUALS(exp, tok(code)); } + void simplifyTypedef160() { + const char code[] = "struct S1 {};\n" + "typedef struct S1 S2;\n" + "namespace N {\n" + " struct B {\n" + " explicit B(int& i);\n" + " };\n" + " struct S2 : B {\n" + " explicit S2(int& i) : B(i) {}\n" + " };\n" + "}\n"; + const char exp[] = "struct S1 { } ; " + "namespace N { " + "struct B { " + "explicit B ( int & i ) ; } ; " + "struct S2 : B { " + "explicit S2 ( int & i ) : B ( i ) { } " + "} ; " + "}"; + ASSERT_EQUALS(exp, tok(code)); + } + void simplifyTypedefFunction1() { { const char code[] = "typedef void (*my_func)();\n"