| 2389 | |
| 2390 | |
| 2391 | bool TemplateSimplifier::simplifyNumericCalculations(Token *tok, bool isTemplate) |
| 2392 | { |
| 2393 | bool ret = false; |
| 2394 | // (1-2) |
| 2395 | while (tok->tokAt(3) && tok->isNumber() && tok->tokAt(2)->isNumber()) { // %any% %num% %any% %num% %any% |
| 2396 | const Token *before = tok->previous(); |
| 2397 | if (!before) |
| 2398 | break; |
| 2399 | const Token* op = tok->next(); |
| 2400 | const Token* after = tok->tokAt(3); |
| 2401 | const std::string &num1 = op->strAt(-1); |
| 2402 | const std::string &num2 = op->strAt(1); |
| 2403 | if (Token::Match(before, "* %num% /") && (num2 != "0") && num1 == MathLib::multiply(num2, MathLib::divide(num1, num2))) { |
| 2404 | // Division where result is a whole number |
| 2405 | } else if (!((op->str() == "*" && (isLowerThanMulDiv(before) || before->str() == "*") && isLowerEqualThanMulDiv(after)) || // associative |
| 2406 | (Token::Match(op, "[/%]") && isLowerThanMulDiv(before) && isLowerEqualThanMulDiv(after)) || // NOT associative |
| 2407 | (Token::Match(op, "[+-]") && isLowerThanMulDiv(before) && isLowerThanMulDiv(after)) || // Only partially (+) associative, but handled later |
| 2408 | (Token::Match(op, ">>|<<") && isLowerThanShift(before) && isLowerThanPlusMinus(after)) || // NOT associative |
| 2409 | (op->str() == "&" && isLowerThanShift(before) && isLowerThanShift(after)) || // associative |
| 2410 | (op->str() == "^" && isLowerThanAnd(before) && isLowerThanAnd(after)) || // associative |
| 2411 | (op->str() == "|" && isLowerThanXor(before) && isLowerThanXor(after)) || // associative |
| 2412 | (op->str() == "&&" && isLowerThanOr(before) && isLowerThanOr(after)) || |
| 2413 | (op->str() == "||" && isLowerThanLogicalAnd(before) && isLowerThanLogicalAnd(after)))) |
| 2414 | break; |
| 2415 | |
| 2416 | // Don't simplify "%num% / 0" |
| 2417 | if (Token::Match(op, "[/%] 0")) { |
| 2418 | if (isTemplate) |
| 2419 | throw InternalError(op, "Instantiation error: Divide by zero in template instantiation.", InternalError::INSTANTIATION); |
| 2420 | return ret; |
| 2421 | } |
| 2422 | |
| 2423 | // Integer operations |
| 2424 | if (Token::Match(op, ">>|<<|&|^|%or%")) { |
| 2425 | // Don't simplify if operand is negative, shifting with negative |
| 2426 | // operand is UB. Bitmasking with negative operand is implementation |
| 2427 | // defined behaviour. |
| 2428 | if (MathLib::isNegative(num1) || MathLib::isNegative(num2)) |
| 2429 | break; |
| 2430 | |
| 2431 | const MathLib::value v1(num1); |
| 2432 | const MathLib::value v2(num2); |
| 2433 | |
| 2434 | if (!v1.isInt() || !v2.isInt()) |
| 2435 | break; |
| 2436 | |
| 2437 | switch (op->str()[0]) { |
| 2438 | case '<': |
| 2439 | tok->str((v1 << v2).str()); |
| 2440 | break; |
| 2441 | case '>': |
| 2442 | tok->str((v1 >> v2).str()); |
| 2443 | break; |
| 2444 | case '&': |
| 2445 | tok->str((v1 & v2).str()); |
| 2446 | break; |
| 2447 | case '|': |
| 2448 | tok->str((v1 | v2).str()); |
nothing calls this directly
no test coverage detected