Fixed #3964 (False positive: Expressions in array declarations are not simplified 'char mac[17+1];')

This commit is contained in:
Daniel Marjamäki 2012-08-20 18:10:32 +02:00
parent a243983242
commit 9ffc7f4c2d
4 changed files with 89 additions and 63 deletions

View File

@ -705,6 +705,74 @@ static bool isLowerEqualThanMulDiv(const Token* lower)
return isLowerThanMulDiv(lower) || Token::Match(lower, "[*/%]");
}
bool TemplateSimplifier::simplifyNumericCalculations(Token *tok)
{
bool ret = false;
// (1-2)
while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any%
const Token* op = tok->tokAt(2);
const Token* after = tok->tokAt(4);
if (Token::Match(tok, "* %num% /") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) {
// Division where result is a whole number
} else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative
(Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative
(Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later
(Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative
(op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative
(op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative
(op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative
break;
tok = tok->next();
// Don't simplify "%num% / 0"
if (Token::Match(op, "[/%] 0"))
continue;
// Integer operations
if (Token::Match(op, ">>|<<|&|^|%or%")) {
const char cop = op->str()[0];
const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str()));
const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2)));
std::string result;
if (cop == '&' || cop == '|' || cop == '^')
result = MathLib::calculate(tok->str(), tok->strAt(2), cop);
else if (cop == '<') {
if (tok->previous()->str() != "<<") // Ensure that its not a shift operator as used for streams
result = MathLib::toString<MathLib::bigint>(leftInt << rightInt);
} else
result = MathLib::toString<MathLib::bigint>(leftInt >> rightInt);
if (!result.empty()) {
ret = true;
tok->str(result);
tok->deleteNext(2);
continue;
}
}
else if (Token::Match(tok->previous(), "- %num% - %num%"))
tok->str(MathLib::add(tok->str(), tok->strAt(2)));
else if (Token::Match(tok->previous(), "- %num% + %num%"))
tok->str(MathLib::subtract(tok->str(), tok->strAt(2)));
else {
try {
tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0]));
} catch (InternalError &e) {
e.token = tok;
throw;
}
}
tok->deleteNext(2);
ret = true;
}
return ret;
}
// TODO: This is not the correct class for simplifyCalculations(), so it
// should be moved away.
bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
@ -882,67 +950,7 @@ bool TemplateSimplifier::simplifyCalculations(Token *_tokens)
}
else {
// (1-2)
while (tok->tokAt(4) && tok->next()->isNumber() && tok->tokAt(3)->isNumber()) { // %any% %num% %any% %num% %any%
const Token* op = tok->tokAt(2);
const Token* after = tok->tokAt(4);
if (Token::Match(tok, "* %num% /") && tok->next()->str() == MathLib::multiply(tok->strAt(3), MathLib::divide(tok->next()->str(), tok->strAt(3)))) {
// Division where result is a whole number
} else if (!((op->str() == "*" && (isLowerThanMulDiv(tok) || tok->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative
(Token::Match(op, "[/%]") && isLowerThanMulDiv(tok) && isLowerEqualThanMulDiv(after)) || // NOT associative
(Token::Match(op, "[+-]") && isLowerThanMulDiv(tok) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later
(Token::Match(op, ">>|<<") && isLowerThanShift(tok) && isLowerThanPlusMinus(after)) || // NOT associative
(op->str() == "&" && isLowerThanShift(tok) && isLowerThanShift(after)) || // associative
(op->str() == "^" && isLowerThanAnd(tok) && isLowerThanAnd(after)) || // associative
(op->str() == "|" && isLowerThanXor(tok) && isLowerThanXor(after)))) // associative
break;
tok = tok->next();
// Don't simplify "%num% / 0"
if (Token::Match(op, "[/%] 0"))
continue;
// Integer operations
if (Token::Match(op, ">>|<<|&|^|%or%")) {
const char cop = op->str()[0];
const MathLib::bigint leftInt(MathLib::toLongNumber(tok->str()));
const MathLib::bigint rightInt(MathLib::toLongNumber(tok->strAt(2)));
std::string result;
if (cop == '&' || cop == '|' || cop == '^')
result = MathLib::calculate(tok->str(), tok->strAt(2), cop);
else if (cop == '<') {
if (tok->previous()->str() != "<<") // Ensure that its not a shift operator as used for streams
result = MathLib::toString<MathLib::bigint>(leftInt << rightInt);
} else
result = MathLib::toString<MathLib::bigint>(leftInt >> rightInt);
if (!result.empty()) {
ret = true;
tok->str(result);
tok->deleteNext(2);
continue;
}
}
else if (Token::Match(tok->previous(), "- %num% - %num%"))
tok->str(MathLib::add(tok->str(), tok->strAt(2)));
else if (Token::Match(tok->previous(), "- %num% + %num%"))
tok->str(MathLib::subtract(tok->str(), tok->strAt(2)));
else {
try {
tok->str(MathLib::calculate(tok->str(), tok->strAt(2), op->str()[0]));
} catch (InternalError &e) {
e.token = tok;
throw;
}
}
tok->deleteNext(2);
ret = true;
}
ret |= simplifyNumericCalculations(tok);
}
}
return ret;

View File

@ -151,6 +151,15 @@ public:
/**
* Simplify constant calculations such as "1+2" => "3"
* @param tok start token
* @return true if modifications to token-list are done.
* false if no modifications are done.
*/
static bool simplifyNumericCalculations(Token *tok);
/**
* Simplify constant calculations such as "1+2" => "3".
* This also perform simple cleanup of parantheses etc.
* @param _tokens start token
* @return true if modifications to token-list are done.
* false if no modifications are done.

View File

@ -1624,6 +1624,12 @@ bool Tokenizer::tokenize(std::istream &code,
// combine "- %num%"
concatenateNegativeNumber();
// simplify simple calculations
for (Token *tok = list.front() ? list.front()->next() : NULL; tok; tok = tok->next()) {
if (tok->isNumber())
TemplateSimplifier::simplifyNumericCalculations(tok->previous());
}
// remove extern "C" and extern "C" {}
if (isCPP())
simplifyExternC();

View File

@ -4513,7 +4513,7 @@ private:
std::istringstream istr(code);
tokenizer.tokenize(istr, "test.cpp");
ASSERT_EQUALS("void f ( ) { double a ; a = 4.2 ; float b ; b = 4.2f ; double c ; c = 4.2e+10 ; double d ; d = 4.2e-10 ; int e ; e = 4 + 2 ; }", tokenizer.tokens()->stringifyList(0, false));
ASSERT_EQUALS("void f ( ) { double a ; a = 4.2 ; float b ; b = 4.2f ; double c ; c = 4.2e+10 ; double d ; d = 4.2e-10 ; int e ; e = 6 ; }", tokenizer.tokens()->stringifyList(0, false));
}
void tokenize_strings() {
@ -4719,7 +4719,7 @@ private:
void vardecl_template_1() {
// ticket #1046
const char code1[] = "b<(1<<24),10,24> u, v;";
const char res1[] = "b < ( 1 << 24 ) , 10 , 24 > u ; b < ( 1 << 24 ) , 10 , 24 > v ;";
const char res1[] = "b < ( 16777216 ) , 10 , 24 > u ; b < ( 16777216 ) , 10 , 24 > v ;";
ASSERT_EQUALS(res1, tokenizeAndStringify(code1));
// ticket #3571 (segmentation fault)
tokenizeAndStringify("template <int i = (3>4) > class X4 {};");
@ -6468,6 +6468,9 @@ private:
// ticket #3723 - Simplify condition (0 && a < 123)
ASSERT_EQUALS("( 0 )",
tokenizeAndStringify("( 0 && a < 123 )", true));
// ticket #3964 - simplify numeric calculations in tokenization
ASSERT_EQUALS("char a [ 10 ] ;", tokenizeAndStringify("char a[9+1];"));
}
void simplifyCompoundAssignment() {