diff --git a/lib/token.cpp b/lib/token.cpp index eac69decee7..48ba4981e79 100644 --- a/lib/token.cpp +++ b/lib/token.cpp @@ -1281,7 +1281,7 @@ std::string Token::stringify(const stringifyOptions& options) const ret += "long "; } } - if (options.macro && isExpandedMacro()) + if (options.macro && hasMacroName()) ret += '$'; if (isName() && mStr.find(' ') != std::string::npos) { for (const char i : mStr) { @@ -1697,7 +1697,7 @@ static void indent(std::string &str, const nonneg int indent1, const nonneg int void Token::astStringVerboseRecursive(std::string& ret, const nonneg int indent1, const nonneg int indent2) const { - if (isExpandedMacro()) + if (hasMacroName()) ret += '$'; ret += mStr; if (mImpl->mValueType) diff --git a/lib/token.h b/lib/token.h index 3df24a86cb6..3741a74ac14 100644 --- a/lib/token.h +++ b/lib/token.h @@ -499,7 +499,18 @@ class CPPCHECKLIB Token { void isStandardType(const bool b) { setFlag(fIsStandardType, b); } + /** + * Is this token macro code at this location? Tokens copied from a + * typedef are excluded, see hasMacroName(). + */ bool isExpandedMacro() const { + return mImpl->mMacroName && !isSimplifiedTypedef(); + } + /** + * Did the token text originate from a macro? Also true for tokens copied + * from a typedef. Intended for dump output and copying tokens. + */ + bool hasMacroName() const { return !!mImpl->mMacroName; } bool isCast() const { diff --git a/lib/tokenize.cpp b/lib/tokenize.cpp index 436a6655284..8fa51ef935c 100644 --- a/lib/tokenize.cpp +++ b/lib/tokenize.cpp @@ -1034,6 +1034,8 @@ namespace { to = to->next(); to->isSimplifiedTypedef(true); to->isExternC(from->isExternC()); + if (from->hasMacroName()) + to->setMacroName(from->getMacroName()); } return to; } @@ -6382,7 +6384,7 @@ void Tokenizer::dump(std::ostream &out) const outs += " isCast=\"true\""; if (tok->isExternC()) outs += " externLang=\"C\""; - if (tok->isExpandedMacro()) + if (tok->hasMacroName()) outs += " macroName=\"" + tok->getMacroName() + "\""; if (tok->isTemplateArg()) { outs += " isTemplateArg=\"true\""; diff --git a/lib/tokenlist.cpp b/lib/tokenlist.cpp index 26b24d649c8..a7304ad0252 100644 --- a/lib/tokenlist.cpp +++ b/lib/tokenlist.cpp @@ -267,6 +267,8 @@ Token *TokenList::copyTokens(Token *dest, const Token *first, const Token *last, tok2->flags(tok->flags()); tok2->varId(tok->varId()); tok2->setTokenDebug(tok->getTokenDebug()); + if (tok->hasMacroName()) + tok2->setMacroName(tok->getMacroName()); // Check for links and fix them up if (Token::Match(tok2, "(|[|{")) diff --git a/test/testother.cpp b/test/testother.cpp index a194c297a8b..68725574f6f 100644 --- a/test/testother.cpp +++ b/test/testother.cpp @@ -7508,6 +7508,16 @@ class TestOther : public TestFixture { " {}\n" "}\n"); ASSERT_EQUALS("", errout_str()); + + // typedef of macro, same typedef in both branches + checkP("#define INT int\n" + "typedef INT T;\n" + "void g(T);\n" + "void f(bool c) {\n" + " if (c) { T x = 1; g(x); }\n" + " else { T x = 1; g(x); }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:6:3] -> [test.cpp:5:3]: (style, inconclusive) Found duplicate branches for 'if' and 'else'. [duplicateBranch]\n", errout_str()); } void duplicateBranch2() { @@ -7634,6 +7644,14 @@ class TestOther : public TestFixture { } void duplicateExpression1() { + // typedef of macro is not macro code at the point of use + checkP("#define INT int\n" + "typedef INT T;\n" + "void foo(int a) {\n" + " if ((T)a == (T)a) { }\n" + "}\n"); + ASSERT_EQUALS("[test.cpp:4:14]: (style) Same expression on both sides of '=='. [duplicateExpression]\n", errout_str()); + check("void foo(int a) {\n" " if (a == a) { }\n" "}\n"); diff --git a/test/testsimplifytypedef.cpp b/test/testsimplifytypedef.cpp index 8ea0766c977..ef6c9a3a6f9 100644 --- a/test/testsimplifytypedef.cpp +++ b/test/testsimplifytypedef.cpp @@ -254,6 +254,7 @@ class TestSimplifyTypedef : public TestFixture { TEST_CASE(simplifyTypedefShadow); // #4445 - shadow variable TEST_CASE(simplifyTypedefMacro); + TEST_CASE(simplifyTypedefMacroName); TEST_CASE(simplifyTypedefOriginalName1); TEST_CASE(simplifyTypedefOriginalName2); @@ -4547,6 +4548,16 @@ class TestSimplifyTypedef : public TestFixture { simplifyTypedefP(code)); } + void simplifyTypedefMacroName() { + const char code[] = "#define A int\n" + "typedef void (*F)(A x);\n" + "void f(F g);\n"; + SimpleTokenizer2 tokenizer(settings0, *this, code, "test.c"); + tokenizer.createLinks(); + tokenizer.simplifyTypedef(); + ASSERT_EQUALS("void f ( void ( * g ) ( $int x ) ) ;", tokenizer.tokens()->stringifyList(false, true, false, false, false)); + } + void simplifyTypedefOriginalName1() { const char code[] = "typedef unsigned char uint8_t;\n" "typedef float (*rFunctionPointer_fp)(uint8_t, uint8_t);\n" diff --git a/test/testsimplifyusing.cpp b/test/testsimplifyusing.cpp index 239407f5c2f..82a123c6ac8 100644 --- a/test/testsimplifyusing.cpp +++ b/test/testsimplifyusing.cpp @@ -102,6 +102,7 @@ class TestSimplifyUsing : public TestFixture { TEST_CASE(simplifyUsing10720); TEST_CASE(simplifyUsing13873); // function declaration TEST_CASE(simplifyUsing14877); + TEST_CASE(simplifyUsingMacroName); TEST_CASE(scopeInfo1); TEST_CASE(scopeInfo2); @@ -1725,6 +1726,16 @@ class TestSimplifyUsing : public TestFixture { ASSERT_EQUALS(expected, tok(code)); } + void simplifyUsingMacroName() { + const char code[] = "#define A int\n" + "using F = void (*)(A x);\n" + "void f(F g);\n"; + const Settings settings = settingsBuilder(settings0).cpp(Standards::CPPLatest).build(); + SimpleTokenizer2 tokenizer(settings, *this, code, "test.cpp"); + ASSERT(tokenizer.simplifyTokens1("")); + ASSERT_EQUALS("void f ( void ( * g ) ( $int ) ) ;", tokenizer.tokens()->stringifyList(false, true, false, false, false)); + } + void scopeInfo1() { const char code[] = "struct A {\n" " enum class Mode { UNKNOWN, ENABLED, NONE, };\n"