Fixed #1343 (simplifyTypedef doesn't support deeply nested classes)
This commit is contained in:
parent
4ec94116f5
commit
f2eac901c0
111
lib/tokenize.cpp
111
lib/tokenize.cpp
|
@ -366,29 +366,65 @@ void Tokenizer::createTokens(std::istream &code)
|
|||
}
|
||||
}
|
||||
|
||||
// check if this statement is a typedef definition
|
||||
static bool duplicateTypedef(const Token * tok)
|
||||
{
|
||||
// check for a typedef end of definition
|
||||
if (tok && tok->next() && Token::Match(tok->next(), ";|,|["))
|
||||
{
|
||||
// scan backwards for the end of the previous statement
|
||||
while (tok && tok->previous() && !Token::Match(tok->previous(), ";|{"))
|
||||
{
|
||||
if (tok->str() == "typedef")
|
||||
return true;
|
||||
|
||||
tok = tok->previous();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
struct SpaceInfo
|
||||
{
|
||||
bool isNamespace;
|
||||
std::string className;
|
||||
const Token * classEnd;
|
||||
};
|
||||
|
||||
void Tokenizer::simplifyTypedef()
|
||||
{
|
||||
std::vector<SpaceInfo> spaceInfo;
|
||||
bool isNamespace = false;
|
||||
std::string className;
|
||||
int classLevel = 0;
|
||||
bool hasClass = false;
|
||||
for (Token *tok = _tokens; tok; tok = tok->next())
|
||||
{
|
||||
if (Token::Match(tok, "class|struct|namespace %any%"))
|
||||
{
|
||||
isNamespace = (tok->str() == "namespace");
|
||||
hasClass = true;
|
||||
className = tok->next()->str();
|
||||
classLevel = 0;
|
||||
continue;
|
||||
}
|
||||
else if (tok->str() == "}")
|
||||
else if (hasClass && tok->str() == ";")
|
||||
{
|
||||
--classLevel;
|
||||
if (classLevel < 0)
|
||||
className = "";
|
||||
hasClass = false;
|
||||
continue;
|
||||
}
|
||||
else if (hasClass && tok->str() == "{")
|
||||
{
|
||||
SpaceInfo info;
|
||||
info.isNamespace = isNamespace;
|
||||
info.className = className;
|
||||
info.classEnd = tok->link();
|
||||
spaceInfo.push_back(info);
|
||||
|
||||
hasClass = false;
|
||||
continue;
|
||||
}
|
||||
else if (tok->str() == "{")
|
||||
else if (!spaceInfo.empty() && tok->str() == "}" && spaceInfo.back().classEnd == tok)
|
||||
{
|
||||
++classLevel;
|
||||
spaceInfo.pop_back();
|
||||
continue;
|
||||
}
|
||||
else if (tok->str() != "typedef")
|
||||
|
@ -594,43 +630,75 @@ void Tokenizer::simplifyTypedef()
|
|||
|
||||
while (!done)
|
||||
{
|
||||
const std::string pattern(className.empty() ? "" : (className + " :: " + typeName).c_str());
|
||||
int level = 0;
|
||||
std::string pattern;
|
||||
int scope = 0;
|
||||
bool inScope = true;
|
||||
|
||||
bool exitThisScope = false;
|
||||
int exitScope = 0;
|
||||
bool simplifyType = false;
|
||||
unsigned int classLevel = spaceInfo.size();
|
||||
|
||||
for (unsigned int i = classLevel; i < spaceInfo.size(); i++)
|
||||
pattern += (spaceInfo[i].className + " :: ");
|
||||
|
||||
pattern += typeName;
|
||||
|
||||
for (Token *tok2 = tok; tok2; tok2 = tok2->next())
|
||||
{
|
||||
if (tok2->str() == "}")
|
||||
{
|
||||
--level;
|
||||
if (level < 0)
|
||||
if (classLevel > 0 && tok2 == spaceInfo[classLevel - 1].classEnd)
|
||||
{
|
||||
--classLevel;
|
||||
pattern.clear();
|
||||
|
||||
for (unsigned int i = classLevel; i < spaceInfo.size(); i++)
|
||||
pattern += (spaceInfo[i].className + " :: ");
|
||||
|
||||
pattern += typeName;
|
||||
}
|
||||
else
|
||||
{
|
||||
scope--;
|
||||
if (scope < 0)
|
||||
inScope = false;
|
||||
|
||||
if (exitThisScope)
|
||||
{
|
||||
if (level < exitScope)
|
||||
exitThisScope = false;
|
||||
if (scope < exitScope)
|
||||
exitScope = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (tok2->str() == "{")
|
||||
++level;
|
||||
else if (!pattern.empty() && Token::Match(tok2, pattern.c_str()))
|
||||
scope++;
|
||||
else if (Token::Match(tok2, pattern.c_str()))
|
||||
{
|
||||
if (pattern != typeName) // has a "something ::"
|
||||
{
|
||||
for (unsigned int i = classLevel; i < spaceInfo.size(); i++)
|
||||
{
|
||||
tok2->deleteNext();
|
||||
tok2->deleteNext();
|
||||
}
|
||||
simplifyType = true;
|
||||
}
|
||||
else if (inScope && !exitThisScope && tok2->str() == typeName)
|
||||
else if (inScope && !exitThisScope)
|
||||
{
|
||||
if (Token::simpleMatch(tok2->previous(), "::"))
|
||||
{
|
||||
// Don't replace this typename if it's preceded by "::"
|
||||
// Don't replace this typename if it's preceded by "::" unless it's a namespace
|
||||
if (!spaceInfo.empty() && (tok2->tokAt(-2)->str() == spaceInfo[0].className) && spaceInfo[0].isNamespace)
|
||||
{
|
||||
tok2 = tok2->tokAt(-3);
|
||||
tok2->deleteNext();
|
||||
tok2->deleteNext();
|
||||
tok2 = tok2->next();
|
||||
simplifyType = true;
|
||||
}
|
||||
else if (Token::Match(tok2->tokAt(-2), "!!typedef") &&
|
||||
Token::Match(tok2->tokAt(-3), "!!typedef"))
|
||||
}
|
||||
else if (!duplicateTypedef(tok2))
|
||||
{
|
||||
// Check for enum and typedef with same name.
|
||||
if (!hasTemplate && tok2->tokAt(-1)->str() != typeStart->str())
|
||||
|
@ -642,7 +710,8 @@ void Tokenizer::simplifyTypedef()
|
|||
{
|
||||
// Typedef with the same name.
|
||||
exitThisScope = true;
|
||||
exitScope = level;
|
||||
exitScope = scope;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -168,6 +168,8 @@ private:
|
|||
TEST_CASE(simplifyTypedef29);
|
||||
TEST_CASE(simplifyTypedef30);
|
||||
TEST_CASE(simplifyTypedef31);
|
||||
TEST_CASE(simplifyTypedef32);
|
||||
TEST_CASE(simplifyTypedef33);
|
||||
TEST_CASE(reverseArraySyntax)
|
||||
TEST_CASE(simplify_numeric_condition)
|
||||
|
||||
|
@ -3072,6 +3074,88 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void simplifyTypedef32()
|
||||
{
|
||||
const char code[] = "typedef char CHAR;\n"
|
||||
"typedef CHAR * LPSTR;\n"
|
||||
"typedef const CHAR * LPCSTR;\n"
|
||||
"CHAR c;\n"
|
||||
"LPSTR cp;\n"
|
||||
"LPCSTR ccp;";
|
||||
|
||||
const char expected[] =
|
||||
"; "
|
||||
"; "
|
||||
"; "
|
||||
"char c ; "
|
||||
"char * cp ; "
|
||||
"const char * ccp ;";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void simplifyTypedef33()
|
||||
{
|
||||
const char code[] = "class A {\n"
|
||||
"public:\n"
|
||||
" typedef char CHAR_A;\n"
|
||||
" CHAR_A funA();\n"
|
||||
" class B {\n"
|
||||
" public:\n"
|
||||
" typedef short SHRT_B;\n"
|
||||
" SHRT_B funB();\n"
|
||||
" class C {\n"
|
||||
" public:\n"
|
||||
" typedef int INT_C;\n"
|
||||
" INT_C funC();\n"
|
||||
" struct D {\n"
|
||||
" typedef long LONG_D;\n"
|
||||
" LONG_D funD();\n"
|
||||
" LONG_D d;\n"
|
||||
" };\n"
|
||||
" INT_C c;\n"
|
||||
" };\n"
|
||||
" SHRT_B b;\n"
|
||||
" };\n"
|
||||
" CHAR_A a;\n"
|
||||
"};\n"
|
||||
"A::CHAR_A A::funA() { return a; }\n"
|
||||
"A::B::SHRT_B A::B::funB() { return b; }\n"
|
||||
"A::B::C::INT_C A::B::C::funC() { return c; }"
|
||||
"A::B::C::D::LONG_D A::B::C::D::funD() { return d; }";
|
||||
|
||||
const char expected[] =
|
||||
"class A { "
|
||||
"public: "
|
||||
"; "
|
||||
"char funA ( ) ; "
|
||||
"class B { "
|
||||
"public: "
|
||||
"; "
|
||||
"short funB ( ) ; "
|
||||
"class C { "
|
||||
"public: "
|
||||
"; "
|
||||
"int funC ( ) ; "
|
||||
"struct D { "
|
||||
"; "
|
||||
"long funD ( ) ; "
|
||||
"long d ; "
|
||||
"} ; "
|
||||
"int c ; "
|
||||
"} ; "
|
||||
"short b ; "
|
||||
"} ; "
|
||||
"char a ; "
|
||||
"} ; "
|
||||
"char A :: funA ( ) { return a ; } "
|
||||
"short A :: B :: funB ( ) { return b ; } "
|
||||
"int A :: B :: C :: funC ( ) { return c ; } "
|
||||
"long A :: B :: C :: D :: funD ( ) { return d ; }";
|
||||
|
||||
ASSERT_EQUALS(expected, tok(code, false));
|
||||
}
|
||||
|
||||
void reverseArraySyntax()
|
||||
{
|
||||
ASSERT_EQUALS("a [ 13 ]", tok("13[a]"));
|
||||
|
|
Loading…
Reference in New Issue