fix using type alias with derived class (#3050)
This commit is contained in:
parent
b2ed372f75
commit
dd866f2898
137
lib/tokenize.cpp
137
lib/tokenize.cpp
|
@ -421,19 +421,41 @@ namespace {
|
||||||
|
|
||||||
static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
|
static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
|
||||||
{
|
{
|
||||||
Token *tok1;
|
|
||||||
std::string name;
|
std::string name;
|
||||||
bool isConst = false;
|
bool isConst = false;
|
||||||
|
Token *tok1 = tok->next();
|
||||||
|
|
||||||
if (tok->next()->str() == "const") {
|
// skip const if present
|
||||||
tok->deleteNext();
|
if (tok1->str() == "const") {
|
||||||
|
tok1->deleteThis();
|
||||||
isConst = true;
|
isConst = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok->strAt(2) == "{") { // unnamed
|
// skip "class|struct|union|enum"
|
||||||
tok1 = tok->linkAt(2);
|
tok1 = tok1->next();
|
||||||
|
|
||||||
if (tok1 && tok1->next()) {
|
const bool hasName = Token::Match(tok1, "%name%");
|
||||||
|
|
||||||
|
// skip name
|
||||||
|
if (hasName) {
|
||||||
|
name = tok1->str();
|
||||||
|
tok1 = tok1->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip base classes if present
|
||||||
|
if (tok1->str() == ":") {
|
||||||
|
tok1 = tok1->next();
|
||||||
|
while (tok1 && tok1->str() != "{")
|
||||||
|
tok1 = tok1->next();
|
||||||
|
if (!tok1)
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip to end
|
||||||
|
tok1 = tok1->link();
|
||||||
|
|
||||||
|
if (!hasName) { // unnamed
|
||||||
|
if (tok1->next()) {
|
||||||
// use typedef name if available
|
// use typedef name if available
|
||||||
if (Token::Match(tok1->next(), "%type%"))
|
if (Token::Match(tok1->next(), "%type%"))
|
||||||
name = tok1->next()->str();
|
name = tok1->next()->str();
|
||||||
|
@ -442,23 +464,6 @@ static Token *splitDefinitionFromTypedef(Token *tok, nonneg int *unnamedCount)
|
||||||
tok->next()->insertToken(name);
|
tok->next()->insertToken(name);
|
||||||
} else
|
} else
|
||||||
return nullptr;
|
return nullptr;
|
||||||
} else if (tok->strAt(3) == ":") {
|
|
||||||
tok1 = tok->tokAt(4);
|
|
||||||
while (tok1 && tok1->str() != "{")
|
|
||||||
tok1 = tok1->next();
|
|
||||||
if (!tok1)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
tok1 = tok1->link();
|
|
||||||
|
|
||||||
name = tok->strAt(2);
|
|
||||||
} else { // has a name
|
|
||||||
tok1 = tok->linkAt(3);
|
|
||||||
|
|
||||||
if (!tok1)
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
name = tok->strAt(2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tok1->insertToken(";");
|
tok1->insertToken(";");
|
||||||
|
@ -623,21 +628,11 @@ void Tokenizer::simplifyTypedef()
|
||||||
|
|
||||||
// pull struct, union, enum or class definition out of typedef
|
// pull struct, union, enum or class definition out of typedef
|
||||||
// use typedef name for unnamed struct, union, enum or class
|
// use typedef name for unnamed struct, union, enum or class
|
||||||
if (Token::Match(tok->next(), "const| struct|enum|union|class %type%| {")) {
|
if (Token::Match(tok->next(), "const| struct|enum|union|class %type%| {|:")) {
|
||||||
Token *tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
|
Token *tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
|
||||||
if (!tok1)
|
if (!tok1)
|
||||||
continue;
|
continue;
|
||||||
tok = tok1;
|
tok = tok1;
|
||||||
} else if (Token::Match(tok->next(), "const| struct|class %type% :")) {
|
|
||||||
Token *tok1 = tok;
|
|
||||||
while (tok1 && tok1->str() != ";" && tok1->str() != "{")
|
|
||||||
tok1 = tok1->next();
|
|
||||||
if (tok1 && tok1->str() == "{") {
|
|
||||||
tok1 = splitDefinitionFromTypedef(tok, &mUnnamedCount);
|
|
||||||
if (!tok1)
|
|
||||||
continue;
|
|
||||||
tok = tok1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @todo add support for union */
|
/** @todo add support for union */
|
||||||
|
@ -2003,25 +1998,31 @@ bool Tokenizer::simplifyUsing()
|
||||||
// Move struct defined in using out of using.
|
// Move struct defined in using out of using.
|
||||||
// using T = struct t { }; => struct t { }; using T = struct t;
|
// using T = struct t { }; => struct t { }; using T = struct t;
|
||||||
// fixme: this doesn't handle attributes
|
// fixme: this doesn't handle attributes
|
||||||
if (Token::Match(start, "struct|union|enum %name%| {")) {
|
if (Token::Match(start, "class|struct|union|enum %name%| {|:")) {
|
||||||
if (start->strAt(1) != "{") {
|
Token *structEnd = start->tokAt(1);
|
||||||
Token *structEnd = start->linkAt(2);
|
const bool hasName = Token::Match(structEnd, "%name%");
|
||||||
structEnd->insertToken(";", "");
|
|
||||||
TokenList::copyTokens(structEnd->next(), tok, start->next());
|
// skip over name if present
|
||||||
usingStart = structEnd->tokAt(2);
|
if (hasName)
|
||||||
nameToken = usingStart->next();
|
structEnd = structEnd->next();
|
||||||
if (usingStart->strAt(2) == "=")
|
|
||||||
start = usingStart->tokAt(3);
|
// skip over base class information
|
||||||
else
|
if (structEnd->str() == ":") {
|
||||||
start = usingStart->linkAt(2)->tokAt(3);
|
structEnd = structEnd->next(); // skip over ":"
|
||||||
usingEnd = findSemicolon(start);
|
while (structEnd && structEnd->str() != "{")
|
||||||
tok->deleteThis();
|
structEnd = structEnd->next();
|
||||||
tok->deleteThis();
|
if (!structEnd)
|
||||||
tok->deleteThis();
|
continue;
|
||||||
tok = usingStart;
|
}
|
||||||
} else {
|
|
||||||
Token *structEnd = start->linkAt(1);
|
// use link to go to end
|
||||||
structEnd->insertToken(";", "");
|
structEnd = structEnd->link();
|
||||||
|
|
||||||
|
// add ';' after end of struct
|
||||||
|
structEnd->insertToken(";", "");
|
||||||
|
|
||||||
|
// add name for anonymous struct
|
||||||
|
if (!hasName) {
|
||||||
std::string newName;
|
std::string newName;
|
||||||
if (structEnd->strAt(2) == ";")
|
if (structEnd->strAt(2) == ";")
|
||||||
newName = name;
|
newName = name;
|
||||||
|
@ -2030,19 +2031,23 @@ bool Tokenizer::simplifyUsing()
|
||||||
TokenList::copyTokens(structEnd->next(), tok, start);
|
TokenList::copyTokens(structEnd->next(), tok, start);
|
||||||
structEnd->tokAt(5)->insertToken(newName, "");
|
structEnd->tokAt(5)->insertToken(newName, "");
|
||||||
start->insertToken(newName, "");
|
start->insertToken(newName, "");
|
||||||
|
} else
|
||||||
|
TokenList::copyTokens(structEnd->next(), tok, start->next());
|
||||||
|
|
||||||
usingStart = structEnd->tokAt(2);
|
// add using after end of struct
|
||||||
nameToken = usingStart->next();
|
usingStart = structEnd->tokAt(2);
|
||||||
if (usingStart->strAt(2) == "=")
|
nameToken = usingStart->next();
|
||||||
start = usingStart->tokAt(3);
|
if (usingStart->strAt(2) == "=")
|
||||||
else
|
start = usingStart->tokAt(3);
|
||||||
start = usingStart->linkAt(2)->tokAt(3);
|
else
|
||||||
usingEnd = findSemicolon(start);
|
start = usingStart->linkAt(2)->tokAt(3);
|
||||||
tok->deleteThis();
|
usingEnd = findSemicolon(start);
|
||||||
tok->deleteThis();
|
|
||||||
tok->deleteThis();
|
// delete original using before struct
|
||||||
tok = usingStart;
|
tok->deleteThis();
|
||||||
}
|
tok->deleteThis();
|
||||||
|
tok->deleteThis();
|
||||||
|
tok = usingStart;
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove 'typename' and 'template'
|
// remove 'typename' and 'template'
|
||||||
|
@ -2131,7 +2136,7 @@ bool Tokenizer::simplifyUsing()
|
||||||
if (Token::Match(type, "%type%"))
|
if (Token::Match(type, "%type%"))
|
||||||
type = type->next();
|
type = type->next();
|
||||||
} else if (Token::Match(type, "%type%")) {
|
} else if (Token::Match(type, "%type%")) {
|
||||||
while (Token::Match(type, "const|struct|union|enum %type%") ||
|
while (Token::Match(type, "const|class|struct|union|enum %type%") ||
|
||||||
(type->next() && type->next()->isStandardType()))
|
(type->next() && type->next()->isStandardType()))
|
||||||
type = type->next();
|
type = type->next();
|
||||||
|
|
||||||
|
|
|
@ -176,6 +176,7 @@ private:
|
||||||
TEST_CASE(simplifyTypedef133); // ticket #9812 - using
|
TEST_CASE(simplifyTypedef133); // ticket #9812 - using
|
||||||
TEST_CASE(simplifyTypedef134);
|
TEST_CASE(simplifyTypedef134);
|
||||||
TEST_CASE(simplifyTypedef135); // ticket #10068
|
TEST_CASE(simplifyTypedef135); // ticket #10068
|
||||||
|
TEST_CASE(simplifyTypedef136);
|
||||||
|
|
||||||
TEST_CASE(simplifyTypedefFunction1);
|
TEST_CASE(simplifyTypedefFunction1);
|
||||||
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
TEST_CASE(simplifyTypedefFunction2); // ticket #1685
|
||||||
|
@ -2712,6 +2713,30 @@ private:
|
||||||
ASSERT_EQUALS(expected, tok(code));
|
ASSERT_EQUALS(expected, tok(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyTypedef136() {
|
||||||
|
const char code[] = "class C1 {};\n"
|
||||||
|
"typedef class S1 {} S1;\n"
|
||||||
|
"typedef class S2 : public C1 {} S2;\n"
|
||||||
|
"typedef class {} S3;\n"
|
||||||
|
"typedef class : public C1 {} S4;\n"
|
||||||
|
"S1 s1;\n"
|
||||||
|
"S2 s2;\n"
|
||||||
|
"S3 s3;\n"
|
||||||
|
"S4 s4;";
|
||||||
|
|
||||||
|
const char expected[] = "class C1 { } ; "
|
||||||
|
"class S1 { } ; "
|
||||||
|
"class S2 : public C1 { } ; "
|
||||||
|
"class S3 { } ; "
|
||||||
|
"class S4 : public C1 { } ; "
|
||||||
|
"class S1 s1 ; "
|
||||||
|
"class S2 s2 ; "
|
||||||
|
"class S3 s3 ; "
|
||||||
|
"class S4 s4 ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
void simplifyTypedefFunction1() {
|
void simplifyTypedefFunction1() {
|
||||||
{
|
{
|
||||||
const char code[] = "typedef void (*my_func)();\n"
|
const char code[] = "typedef void (*my_func)();\n"
|
||||||
|
|
|
@ -63,6 +63,7 @@ private:
|
||||||
TEST_CASE(simplifyUsing14);
|
TEST_CASE(simplifyUsing14);
|
||||||
TEST_CASE(simplifyUsing15);
|
TEST_CASE(simplifyUsing15);
|
||||||
TEST_CASE(simplifyUsing16);
|
TEST_CASE(simplifyUsing16);
|
||||||
|
TEST_CASE(simplifyUsing17);
|
||||||
|
|
||||||
TEST_CASE(simplifyUsing8970);
|
TEST_CASE(simplifyUsing8970);
|
||||||
TEST_CASE(simplifyUsing8971);
|
TEST_CASE(simplifyUsing8971);
|
||||||
|
@ -428,6 +429,30 @@ private:
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void simplifyUsing17() {
|
||||||
|
const char code[] = "class C1 {};\n"
|
||||||
|
"using S1 = class S1 {};\n"
|
||||||
|
"using S2 = class S2 : public C1 {};\n"
|
||||||
|
"using S3 = class {};\n"
|
||||||
|
"using S4 = class : public C1 {};\n"
|
||||||
|
"S1 s1;\n"
|
||||||
|
"S2 s2;\n"
|
||||||
|
"S3 s3;\n"
|
||||||
|
"S4 s4;";
|
||||||
|
|
||||||
|
const char expected[] = "class C1 { } ; "
|
||||||
|
"class S1 { } ; "
|
||||||
|
"class S2 : public C1 { } ; "
|
||||||
|
"class S3 { } ; "
|
||||||
|
"class S4 : public C1 { } ; "
|
||||||
|
"class S1 s1 ; "
|
||||||
|
"class S2 s2 ; "
|
||||||
|
"class S3 s3 ; "
|
||||||
|
"class S4 s4 ;";
|
||||||
|
|
||||||
|
ASSERT_EQUALS(expected, tok(code, false));
|
||||||
|
}
|
||||||
|
|
||||||
void simplifyUsing8970() {
|
void simplifyUsing8970() {
|
||||||
const char code[] = "using V = std::vector<int>;\n"
|
const char code[] = "using V = std::vector<int>;\n"
|
||||||
"struct A {\n"
|
"struct A {\n"
|
||||||
|
|
Loading…
Reference in New Issue