Tokenizer::simplifyEnum: Reverted refactorings/optimisations as there were regressions (#3949, #3950, #4025)

This commit is contained in:
Daniel Marjamäki 2012-08-10 14:06:24 +02:00
parent ca4ed5e0c3
commit 0254344df5
3 changed files with 119 additions and 194 deletions

View File

@ -6866,81 +6866,6 @@ bool Tokenizer::duplicateDefinition(Token ** tokPtr, const Token * name) const
return false; return false;
} }
class EnumValue {
public:
EnumValue() {
name = 0;
value = 0;
start = 0;
end = 0;
}
EnumValue(const EnumValue &ev) {
name = ev.name;
value = ev.value;
start = ev.start;
end = ev.end;
}
EnumValue(Token *name_, Token *value_, Token *start_, Token *end_) {
name = name_;
value = value_;
start = start_;
end = end_;
}
void simplify(const std::map<std::string, EnumValue> &enumValues) {
for (Token *tok = start; tok; tok = tok->next()) {
if (enumValues.find(tok->str()) != enumValues.end()) {
const EnumValue &other = enumValues.find(tok->str())->second;
if (other.value != NULL)
tok->str(other.value->str());
else {
bool islast = (tok == end);
Token *last = Tokenizer::copyTokens(tok, other.start, other.end);
if (last == tok->next()) // tok->deleteThis() invalidates a pointer that points at the next token
last = tok;
tok->deleteThis();
if (islast) {
end = last;
}
tok = last;
}
}
if (tok == end)
break;
}
// Simplify calculations..
while (Token::Match(start, "%num% %op% %num% %op%") &&
start->strAt(1) == start->strAt(3)) {
const std::string &op = start->strAt(1);
if (op.size() != 1U)
break;
const std::string &val1 = start->str();
const std::string &val2 = start->strAt(2);
const std::string result = MathLib::calculate(val1, val2, op[0]);
start->str(result);
start->deleteNext(2);
}
if (Token::Match(start, "%num% %op% %num% [,}]")) {
const std::string &op = start->strAt(1);
if (op.size() == 1U) {
const std::string &val1 = start->str();
const std::string &val2 = start->strAt(2);
const std::string result = MathLib::calculate(val1, val2, op[0]);
start->str(result);
start->deleteNext(2);
value = start;
start = end = 0;
}
}
}
Token *name;
Token *value;
Token *start;
Token *end;
};
void Tokenizer::simplifyEnum() void Tokenizer::simplifyEnum()
{ {
// Don't simplify enums in java files // Don't simplify enums in java files
@ -7043,7 +6968,6 @@ void Tokenizer::simplifyEnum()
// iterate over all enumerators between { and } // iterate over all enumerators between { and }
// Give each enumerator the const value specified or if not specified, 1 + the // Give each enumerator the const value specified or if not specified, 1 + the
// previous value or 0 if it is the first one. // previous value or 0 if it is the first one.
std::map<std::string,EnumValue> enumValues;
for (; tok1 && tok1 != end; tok1 = tok1->next()) { for (; tok1 && tok1 != end; tok1 = tok1->next()) {
Token * enumName = 0; Token * enumName = 0;
Token * enumValue = 0; Token * enumValue = 0;
@ -7070,7 +6994,7 @@ void Tokenizer::simplifyEnum()
// value is previous expression + 1 // value is previous expression + 1
tok1->insertToken("+"); tok1->insertToken("+");
tok1 = tok1->next(); tok1 = tok1->next();
tok1->insertToken("1"); tok1->insertToken(MathLib::toString<MathLib::bigint>(lastValue));
enumValue = 0; enumValue = 0;
enumValueStart = valueStart->next(); enumValueStart = valueStart->next();
enumValueEnd = tok1->next(); enumValueEnd = tok1->next();
@ -7094,10 +7018,19 @@ void Tokenizer::simplifyEnum()
enumValueStart = tok1; enumValueStart = tok1;
enumValueEnd = tok1; enumValueEnd = tok1;
int level = 0; int level = 0;
while (enumValueEnd->next() && (!Token::Match(enumValueEnd->next(), "[},]") || level)) { if (enumValueEnd->str() == "(" ||
if (Token::Match(enumValueEnd, "(|[")) enumValueEnd->str() == "[" ||
enumValueEnd->str() == "{")
++level;
while (enumValueEnd->next() &&
(!Token::Match(enumValueEnd->next(), "}|,") || level)) {
if (enumValueEnd->next()->str() == "(" ||
enumValueEnd->next()->str() == "[" ||
enumValueEnd->next()->str() == "{")
++level; ++level;
else if (Token::Match(enumValueEnd->next(), "]|)")) else if (enumValueEnd->next()->str() == ")" ||
enumValueEnd->next()->str() == "]" ||
enumValueEnd->next()->str() == "}")
--level; --level;
enumValueEnd = enumValueEnd->next(); enumValueEnd = enumValueEnd->next();
@ -7109,102 +7042,111 @@ void Tokenizer::simplifyEnum()
tok1 = enumValueEnd; tok1 = enumValueEnd;
} }
// add enumerator constant.. // find all uses of this enumerator and substitute it's value for it's name
if (enumName && (enumValue || (enumValueStart && enumValueEnd))) { if (enumName && (enumValue || (enumValueStart && enumValueEnd))) {
EnumValue ev(enumName, enumValue, enumValueStart, enumValueEnd); const std::string pattern = className.empty() ?
ev.simplify(enumValues); std::string("") :
enumValues[enumName->str()] = ev; std::string(className + " :: " + enumName->str());
lastEnumValueStart = ev.start; int level = 1;
lastEnumValueEnd = ev.end; bool inScope = true;
if (ev.start == NULL)
lastValue = MathLib::toLongNumber(ev.value->str());
tok1 = ev.end ? ev.end : ev.value;
}
}
// Substitute enum values bool exitThisScope = false;
{ int exitScope = 0;
const std::string pattern = className.empty() ? bool simplify = false;
std::string("") : bool hasClass = false;
std::string(className + " :: "); const Token *endScope = 0;
int level = 1; for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) {
bool inScope = true; if (tok2->str() == "}") {
--level;
if (level < 0)
inScope = false;
std::stack<std::set<std::string> > shadowId; // duplicate ids in inner scope if (exitThisScope) {
bool simplify = false; if (level < exitScope)
bool hasClass = false; exitThisScope = false;
EnumValue *ev = NULL; }
for (Token *tok2 = tok1->next(); tok2; tok2 = tok2->next()) { } else if (tok2->str() == "{") {
if (tok2->str() == "}") { // Is the same enum redefined?
--level; const Token *begin = end->link();
if (level < 0) if (tok2->fileIndex() == begin->fileIndex() &&
inScope = false; tok2->linenr() == begin->linenr() &&
Token::Match(begin->tokAt(-2), "enum %type% {") &&
if (!shadowId.empty()) Token::Match(tok2->tokAt(-2), "enum %type% {") &&
shadowId.pop(); begin->previous()->str() == tok2->previous()->str()) {
} else if (tok2->str() == "{") { // remove duplicate enum
// Is the same enum redefined? Token * startToken = tok2->tokAt(-3);
const Token *begin = end->link(); tok2 = tok2->link()->next();
if (tok2->fileIndex() == begin->fileIndex() && Token::eraseTokens(startToken, tok2);
tok2->linenr() == begin->linenr() && if (!tok2)
Token::Match(begin->tokAt(-2), "enum %type% {") && break;
Token::Match(tok2->tokAt(-2), "enum %type% {") && } else {
begin->previous()->str() == tok2->previous()->str()) { // Not a duplicate enum..
// remove duplicate enum ++level;
Token * startToken = tok2->tokAt(-3); }
tok2 = tok2->link()->next(); endScope = tok2->link();
Token::eraseTokens(startToken, tok2); } else if (!pattern.empty() && Token::Match(tok2, pattern.c_str())) {
if (!tok2) simplify = true;
break; hasClass = true;
} else { } else if (inScope && !exitThisScope && tok2->str() == enumName->str()) {
// Not a duplicate enum.. if (!duplicateDefinition(&tok2, enumName)) {
++level; if (tok2->strAt(-1) == "::" ||
Token::Match(tok2->next(), "::|[")) {
// Create a copy of the shadow ids for the inner scope // Don't replace this enum if:
if (!shadowId.empty()) // * it's preceded or followed by "::"
shadowId.push(shadowId.top()); // * it's followed by "["
} } else {
} else if (!pattern.empty() && Token::Match(tok2, pattern.c_str()) && enumValues.find(tok2->strAt(2)) != enumValues.end()) { simplify = true;
simplify = true; hasClass = false;
hasClass = true; }
ev = &(enumValues.find(tok2->strAt(2))->second); } else {
} else if (inScope && // enum is in scope // something with the same name.
(shadowId.empty() || shadowId.top().find(tok2->str()) == shadowId.top().end()) && // no shadow enum/var/etc of enum exitScope = level;
enumValues.find(tok2->str()) != enumValues.end()) { // tok2 is a enum id with a known value if (endScope)
ev = &(enumValues.find(tok2->str())->second); tok2 = endScope->previous();
if (!duplicateDefinition(&tok2, ev->name)) {
if (tok2->strAt(-1) == "::" ||
Token::Match(tok2->next(), "::|[")) {
// Don't replace this enum if:
// * it's preceded or followed by "::"
// * it's followed by "["
} else {
simplify = true;
hasClass = false;
ev = &(enumValues.find(tok2->str())->second);
} }
} else {
// something with the same name.
if (shadowId.empty())
shadowId.push(std::set<std::string>());
shadowId.top().insert(tok2->str());
}
}
if (simplify) {
if (ev->value)
tok2->str(ev->value->str());
else {
tok2 = tok2->previous();
tok2->deleteNext();
tok2 = copyTokens(tok2, ev->start, ev->end);
} }
if (hasClass) { if (simplify) {
tok2->deleteNext(2); // Simplify calculations..
} while (Token::Match(enumValueStart, "%num% %op% %num% %op%") &&
enumValueStart->strAt(1) == enumValueStart->strAt(3)) {
const std::string &op = enumValueStart->strAt(1);
if (op.size() != 1U)
break;
const std::string &val1 = enumValueStart->str();
const std::string &val2 = enumValueStart->strAt(2);
const std::string result = MathLib::calculate(val1, val2, op[0]);
enumValueStart->str(result);
enumValueStart->deleteNext(2);
}
if (Token::Match(enumValueStart, "%num% %op% %num% [,}]")) {
const std::string &op = enumValueStart->strAt(1);
if (op.size() == 1U) {
const std::string &val1 = enumValueStart->str();
const std::string &val2 = enumValueStart->strAt(2);
const std::string result = MathLib::calculate(val1, val2, op[0]);
enumValueStart->str(result);
enumValueStart->deleteNext(2);
enumValue = tok1 = enumValueStart;
enumValueStart = enumValueEnd = 0;
}
}
simplify = false;
if (enumValue)
tok2->str(enumValue->str());
else {
tok2 = tok2->previous();
tok2->deleteNext();
tok2 = copyTokens(tok2, enumValueStart, enumValueEnd);
}
if (hasClass) {
tok2->deleteNext(2);
}
simplify = false;
}
} }
} }
} }

View File

@ -727,6 +727,13 @@ public:
return list.front(); return list.front();
} }
private:
/** Disable copy constructor, no implementation */
Tokenizer(const Tokenizer &);
/** Disable assignment operator, no implementation */
Tokenizer &operator=(const Tokenizer &);
/** /**
* Copy tokens. * Copy tokens.
* @param dest destination token where copied tokens will be inserted after * @param dest destination token where copied tokens will be inserted after
@ -737,13 +744,6 @@ public:
*/ */
static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true); static Token *copyTokens(Token *dest, const Token *first, const Token *last, bool one_line = true);
private:
/** Disable copy constructor, no implementation */
Tokenizer(const Tokenizer &);
/** Disable assignment operator, no implementation */
Tokenizer &operator=(const Tokenizer &);
/** settings */ /** settings */
const Settings * _settings; const Settings * _settings;

View File

@ -351,9 +351,6 @@ private:
TEST_CASE(enum28); TEST_CASE(enum28);
TEST_CASE(enum29); // ticket #3747 (bitwise or value) TEST_CASE(enum29); // ticket #3747 (bitwise or value)
TEST_CASE(enum30); // ticket #3852 (false positive) TEST_CASE(enum30); // ticket #3852 (false positive)
TEST_CASE(enum31); // ticket #3934 (calculation in first item)
TEST_CASE(enum32); // ticket #3998 (access violation)
TEST_CASE(enum33); // ticket #4015 (segmentation fault)
// remove "std::" on some standard functions // remove "std::" on some standard functions
TEST_CASE(removestd); TEST_CASE(removestd);
@ -6773,7 +6770,7 @@ private:
"1 + sizeof ( int ) + " "1 + sizeof ( int ) + "
"1 + sizeof ( int ) + 100 + " "1 + sizeof ( int ) + 100 + "
"1 + sizeof ( int ) + 100 + 1 + " "1 + sizeof ( int ) + 100 + 1 + "
"1 + sizeof ( int ) + 100 + 1 + 1 + " "1 + sizeof ( int ) + 100 + 2 + "
"90 + " "90 + "
"91 ;"; "91 ;";
@ -7099,20 +7096,6 @@ private:
TODO_ASSERT_EQUALS("","[test.cpp:12] -> [test.cpp:7]: (style) Variable 'two' hides enumerator with same name\n", errout.str()); TODO_ASSERT_EQUALS("","[test.cpp:12] -> [test.cpp:7]: (style) Variable 'two' hides enumerator with same name\n", errout.str());
} }
void enum31() { // #3934 - calculation in first item
const char code[] = "enum { x=2*32, y }; i = y;";
ASSERT_EQUALS("i = 65 ;", checkSimplifyEnum(code));
}
void enum32() { // #3998 - wrong enum simplification => access violation
const char code[] = "enum { x=(32), y=x, z }; { a, z }";
ASSERT_EQUALS("{ a , ( 32 ) + 1 }", checkSimplifyEnum(code));
}
void enum33() { // #4015 - segmentation fault
const char code[] = "enum { A=SOME_VALUE, B=A };";
ASSERT_EQUALS(";", checkSimplifyEnum(code));
}
void removestd() { void removestd() {
ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);")); ASSERT_EQUALS("; strcpy ( a , b ) ;", tok("; std::strcpy(a,b);"));