Fixed #3852: Support simplification of C++11 "enum class", fixed existing simplifications
This commit is contained in:
parent
6b16b519a2
commit
e05fb847df
|
@ -7359,7 +7359,8 @@ void Tokenizer::simplifyEnum()
|
||||||
Token *typeTokenEnd = nullptr;
|
Token *typeTokenEnd = nullptr;
|
||||||
|
|
||||||
// check for C++0x enum class
|
// check for C++0x enum class
|
||||||
if (Token::Match(tok->next(), "class|struct"))
|
bool enumClass = Token::Match(tok->next(), "class|struct");
|
||||||
|
if (enumClass)
|
||||||
tok->deleteNext();
|
tok->deleteNext();
|
||||||
|
|
||||||
// check for name
|
// check for name
|
||||||
|
@ -7521,15 +7522,17 @@ void Tokenizer::simplifyEnum()
|
||||||
if (_settings->terminated())
|
if (_settings->terminated())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
const std::string pattern = className.empty() ?
|
std::string pattern;
|
||||||
std::string("") :
|
if (!className.empty())
|
||||||
std::string(className + " :: ");
|
pattern += className + " :: ";
|
||||||
|
if (enumClass)
|
||||||
|
pattern += enumType->str() + " :: ";
|
||||||
|
|
||||||
int level = 0;
|
int level = 0;
|
||||||
bool inScope = true;
|
bool inScope = !enumClass; // enum class objects are always in a different scope
|
||||||
|
|
||||||
std::stack<std::set<std::string> > shadowId; // duplicate ids in inner scope
|
std::stack<std::set<std::string> > shadowId; // duplicate ids in inner scope
|
||||||
bool simplify = false;
|
bool simplify = false;
|
||||||
bool hasClass = false;
|
|
||||||
EnumValue *ev = nullptr;
|
EnumValue *ev = nullptr;
|
||||||
|
|
||||||
if (!tok1)
|
if (!tok1)
|
||||||
|
@ -7631,10 +7634,14 @@ void Tokenizer::simplifyEnum()
|
||||||
// skip ( .. )
|
// skip ( .. )
|
||||||
tok2 = tok2->next()->link();
|
tok2 = tok2->next()->link();
|
||||||
}
|
}
|
||||||
} else if (!pattern.empty() && Token::Match(tok2, pattern.c_str()) && enumValues.find(tok2->strAt(2)) != enumValues.end()) {
|
} else if (!pattern.empty() && Token::Match(tok2, pattern.c_str())) {
|
||||||
simplify = true;
|
const Token* tok3 = tok2;
|
||||||
hasClass = true;
|
while (tok3->strAt(1) == "::")
|
||||||
ev = &(enumValues.find(tok2->strAt(2))->second);
|
tok3 = tok3->tokAt(2);
|
||||||
|
if (enumValues.find(tok3->str()) != enumValues.end()) {
|
||||||
|
simplify = true;
|
||||||
|
ev = &(enumValues.find(tok3->str())->second);
|
||||||
|
}
|
||||||
} else if (inScope && // enum is in scope
|
} else if (inScope && // enum is in scope
|
||||||
(shadowId.empty() || shadowId.top().find(tok2->str()) == shadowId.top().end()) && // no shadow enum/var/etc of enum
|
(shadowId.empty() || shadowId.top().find(tok2->str()) == shadowId.top().end()) && // no shadow enum/var/etc of enum
|
||||||
enumValues.find(tok2->str()) != enumValues.end()) { // tok2 is a enum id with a known value
|
enumValues.find(tok2->str()) != enumValues.end()) { // tok2 is a enum id with a known value
|
||||||
|
@ -7647,7 +7654,6 @@ void Tokenizer::simplifyEnum()
|
||||||
// * it's followed by "["
|
// * it's followed by "["
|
||||||
} else {
|
} else {
|
||||||
simplify = true;
|
simplify = true;
|
||||||
hasClass = false;
|
|
||||||
ev = &(enumValues.find(tok2->str())->second);
|
ev = &(enumValues.find(tok2->str())->second);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -7661,11 +7667,13 @@ void Tokenizer::simplifyEnum()
|
||||||
if (simplify) {
|
if (simplify) {
|
||||||
if (ev->value) {
|
if (ev->value) {
|
||||||
tok2->str(ev->value->str());
|
tok2->str(ev->value->str());
|
||||||
if (hasClass)
|
while (tok2->strAt(1) == "::")
|
||||||
tok2->deleteNext(2);
|
tok2->deleteNext(2);
|
||||||
} else {
|
} else {
|
||||||
|
while (tok2->strAt(1) == "::")
|
||||||
|
tok2->deleteNext(2);
|
||||||
tok2 = tok2->previous();
|
tok2 = tok2->previous();
|
||||||
tok2->deleteNext(hasClass ? 3 : 1);
|
tok2->deleteNext();
|
||||||
bool hasOp = false;
|
bool hasOp = false;
|
||||||
int indentlevel = 0;
|
int indentlevel = 0;
|
||||||
for (const Token *enumtok = ev->start; enumtok != ev->end; enumtok = enumtok->next()) {
|
for (const Token *enumtok = ev->start; enumtok != ev->end; enumtok = enumtok->next()) {
|
||||||
|
|
|
@ -6841,11 +6841,18 @@ private:
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "enum class Enum1 { a };\n"
|
const char code[] = "enum class Enum1 { a };\n"
|
||||||
"Enum1 e1 = a;";
|
"Enum1 e1 = Enum1::a;";
|
||||||
const char expected[] = "int e1 ; e1 = 0 ;";
|
const char expected[] = "int e1 ; e1 = 0 ;";
|
||||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const char code[] = "enum class Enum1 { a };\n"
|
||||||
|
"Enum1 e1 = a;";
|
||||||
|
const char expected[] = "int e1 ; e1 = a ;";
|
||||||
|
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "enum Enum1 : char { a };\n"
|
const char code[] = "enum Enum1 : char { a };\n"
|
||||||
"Enum1 e1 = a;";
|
"Enum1 e1 = a;";
|
||||||
|
@ -6855,21 +6862,21 @@ private:
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "enum class Enum1 : unsigned char { a };\n"
|
const char code[] = "enum class Enum1 : unsigned char { a };\n"
|
||||||
"Enum1 e1 = a;";
|
"Enum1 e1 = Enum1::a;";
|
||||||
const char expected[] = "unsigned char e1 ; e1 = 0 ;";
|
const char expected[] = "unsigned char e1 ; e1 = 0 ;";
|
||||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "enum class Enum1 : unsigned int { a };\n"
|
const char code[] = "enum class Enum1 : unsigned int { a };\n"
|
||||||
"Enum1 e1 = a;";
|
"Enum1 e1 = Enum1::a;";
|
||||||
const char expected[] = "unsigned int e1 ; e1 = 0 ;";
|
const char expected[] = "unsigned int e1 ; e1 = 0 ;";
|
||||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
const char code[] = "enum class Enum1 : unsigned long long int { a };\n"
|
const char code[] = "enum class Enum1 : unsigned long long int { a };\n"
|
||||||
"Enum1 e1 = a;";
|
"Enum1 e1 = Enum1::a;";
|
||||||
const char expected[] = "unsigned long long e1 ; e1 = 0 ;";
|
const char expected[] = "unsigned long long e1 ; e1 = 0 ;";
|
||||||
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
ASSERT_EQUALS(expected, checkSimplifyEnum(code));
|
||||||
}
|
}
|
||||||
|
@ -6989,23 +6996,25 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void enum30() { // #3852 - false positive
|
void enum30() { // #3852 - false positive
|
||||||
|
const char code [] = "class TestIf\n"
|
||||||
const char code[] = "class TestIf\n"
|
"{\n"
|
||||||
"{\n"
|
"public:\n"
|
||||||
"public:\n"
|
" enum class Foo\n"
|
||||||
" enum class Foo\n"
|
" {\n"
|
||||||
" {\n"
|
" one = 0,\n"
|
||||||
" one = 0,\n"
|
" two = 1\n"
|
||||||
" two = 1\n"
|
" };\n"
|
||||||
" };\n"
|
" enum class Bar\n"
|
||||||
" enum class Bar\n"
|
" {\n"
|
||||||
" {\n"
|
" one = 0,\n"
|
||||||
" one = 0,\n"
|
" two = 1\n"
|
||||||
" two = 1\n"
|
" };\n"
|
||||||
" };\n"
|
"};\n"
|
||||||
"};\n";
|
"int main() {"
|
||||||
checkSimplifyEnum(code);
|
" return TestIf::Bar::two;\n"
|
||||||
TODO_ASSERT_EQUALS("","[test.cpp:12] -> [test.cpp:7]: (style) Variable 'two' hides enumerator with same name\n", errout.str());
|
"}";
|
||||||
|
ASSERT_EQUALS("class TestIf { public: } ; int main ( ) { return 1 ; }", checkSimplifyEnum(code));
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void enum31() { // #3934 - calculation in first item
|
void enum31() { // #3934 - calculation in first item
|
||||||
|
|
Loading…
Reference in New Issue