Tokenizer: Remove simplification of math functions from simplifyTokenList2

This commit is contained in:
Daniel Marjamäki 2022-06-08 09:58:11 +02:00
parent e7b5a776bd
commit 86a8d88729
5 changed files with 4 additions and 278 deletions

View File

@ -887,19 +887,11 @@ unsigned int CppCheck::checkFile(const std::string& filename, const std::string
if (!mSettings.buildDir.empty()) if (!mSettings.buildDir.empty())
checkUnusedFunctions.parseTokens(tokenizer, filename.c_str(), &mSettings); checkUnusedFunctions.parseTokens(tokenizer, filename.c_str(), &mSettings);
// simplify more if required, skip rest of iteration if failed // handling of "simple" rules has been removed.
if (mSimplify && hasRule("simple")) { if (mSimplify && hasRule("simple")) {
std::cout << "Handling of \"simple\" rules is deprecated and will be removed in Cppcheck 2.5." << std::endl; // FIXME Remove this function
tokenizer.simplifyTokenList2();
// if further simplification fails then skip rest of iteration throw InternalError(nullptr, "Handling of \"simple\" rules has been removed in Cppcheck. Use --addon instead.");
Timer timer3("Tokenizer::simplifyTokenList2", mSettings.showtime, &s_timerResults);
result = tokenizer.simplifyTokenList2();
timer3.stop();
if (!result)
continue;
if (!Settings::terminated())
executeRules("simple", tokenizer);
} }
} catch (const simplecpp::Output &o) { } catch (const simplecpp::Output &o) {

View File

@ -5275,9 +5275,6 @@ bool Tokenizer::simplifyTokenList2()
tok->clearValueFlow(); tok->clearValueFlow();
} }
// Convert e.g. atol("0") into 0
simplifyMathFunctions();
// f(x=g()) => x=g(); f(x) // f(x=g()) => x=g(); f(x)
simplifyAssignmentInFunctionCall(); simplifyAssignmentInFunctionCall();
@ -5388,8 +5385,6 @@ bool Tokenizer::simplifyTokenList2()
simplifyEmptyNamespaces(); simplifyEmptyNamespaces();
simplifyMathFunctions();
validate(); validate();
Token::assignProgressValues(list.front()); Token::assignProgressValues(list.front());
@ -9681,16 +9676,6 @@ static bool isNumberOneOf(const std::string &s, const MathLib::bigint& intConsta
return false; return false;
} }
// ------------------------------------------------------------------------
// Helper function to check whether number is zero (0 or 0.0 or 0E+0) or not?
// @param s the string to check
// @return true in case s is zero and false otherwise.
// ------------------------------------------------------------------------
bool Tokenizer::isZeroNumber(const std::string &s)
{
return isNumberOneOf(s, 0L, "0.0");
}
// ------------------------------------------------------------------------ // ------------------------------------------------------------------------
// Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not? // Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
// @param s the string to check // @param s the string to check
@ -9715,187 +9700,6 @@ bool Tokenizer::isTwoNumber(const std::string &s)
return isNumberOneOf(s, 2L, "2.0"); return isNumberOneOf(s, 2L, "2.0");
} }
// ------------------------------------------------------
// Simplify math functions.
// It simplifies the following functions: atol(), fmin(),
// fminl(), fminf(), fmax(), fmaxl(), fmaxf(), pow(),
// powf(), powl(), cbrt(), cbrtl(), cbtrf(), sqrt(),
// sqrtf(), sqrtl(), exp(), expf(), expl(), exp2(),
// exp2f(), exp2l(), log2(), log2f(), log2l(), log1p(),
// log1pf(), log1pl(), log10(), log10l(), log10f(),
// log(), logf(), logl(), logb(), logbf(), logbl(), acosh()
// acoshf(), acoshl(), acos(), acosf(), acosl(), cosh()
// coshf(), coshf(), cos(), cosf(), cosl(), erfc(),
// erfcf(), erfcl(), ilogb(), ilogbf(), ilogbf(), erf(),
// erfl(), erff(), asin(), asinf(), asinf(), asinh(),
// asinhf(), asinhl(), tan(), tanf(), tanl(), tanh(),
// tanhf(), tanhl(), atan(), atanf(), atanl(), atanh(),
// atanhf(), atanhl(), expm1(), expm1l(), expm1f(), sin(),
// sinf(), sinl(), sinh(), sinhf(), sinhl()
// in the tokenlist.
//
// Reference:
// - http://www.cplusplus.com/reference/cmath/
// ------------------------------------------------------
void Tokenizer::simplifyMathFunctions()
{
for (Token *tok = list.front(); tok; tok = tok->next()) {
if (tok->isName() && !tok->varId() && tok->strAt(1) == "(") { // precondition for function
bool simplifcationMade = false;
if (Token::Match(tok, "atol ( %str% )")) { //@todo Add support for atoll()
if (Token::simpleMatch(tok->tokAt(-2), "std ::")) {
tok = tok->tokAt(-2);// set token index two steps back
tok->deleteNext(2); // delete "std ::"
}
const std::string& strNumber = tok->tokAt(2)->strValue(); // get number
const bool isNotAnInteger = (!MathLib::isInt(strNumber));// check: is not an integer
if (strNumber.empty() || isNotAnInteger) {
// Ignore strings which we can't convert
continue;
}
// Convert string into a number and insert into token list
tok->str(MathLib::toString(MathLib::toLongNumber(strNumber)));
// remove ( %num% )
tok->deleteNext(3);
simplifcationMade = true;
} else if (Token::Match(tok, "sqrt|sqrtf|sqrtl|cbrt|cbrtf|cbrtl ( %num% )")) {
// Simplify: sqrt(0) = 0 and cbrt(0) == 0
// sqrt(1) = 1 and cbrt(1) == 1
// get number string
const std::string& parameter(tok->strAt(2));
// is parameter 0 ?
if (isZeroNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("0"); // insert result into token list
simplifcationMade = true;
} else if (isOneNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list
simplifcationMade = true;
}
} else if (Token::Match(tok, "exp|expf|expl|exp2|exp2f|exp2l|cos|cosf|cosl|cosh|coshf|coshl|erfc|erfcf|erfcl ( %num% )")) {
// Simplify: exp[f|l](0) = 1 and exp2[f|l](0) = 1
// cosh[f|l](0) = 1 and cos[f|l](0) = 1
// erfc[f|l](0) = 1
// get number string
const std::string& parameter(tok->strAt(2));
// is parameter 0 ?
if (isZeroNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("1"); // insert result into token list
simplifcationMade = true;
}
} else if (Token::Match(tok, "log1p|log1pf|log1pl|sin|sinf|sinl|sinh|sinhf|sinhl|erf|erff|erfl|asin|asinf|asinl|asinh|asinhf|asinhl|tan|tanf|tanl|tanh|tanhf|tanhl|atan|atanf|atanl|atanh|atanhf|atanhl|expm1|expm1f|expm1l ( %num% )")) {
// Simplify: log1p[f|l](0) = 0 and sin[f|l](0) = 0
// sinh[f|l](0) = 0 and erf[f|l](0) = 0
// asin[f|l](0) = 0 and sinh[f|l](0) = 0
// tan[f|l](0) = 0 and tanh[f|l](0) = 0
// atan[f|l](0) = 0 and atanh[f|l](0)= 0
// expm1[f|l](0) = 0
// get number string
const std::string& parameter(tok->strAt(2));
// is parameter 0 ?
if (isZeroNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("0"); // insert result into token list
simplifcationMade = true;
}
} else if (Token::Match(tok, "log2|log2f|log2l|log|logf|logl|log10|log10f|log10l|logb|logbf|logbl|acosh|acoshf|acoshl|acos|acosf|acosl|ilogb|ilogbf|ilogbl ( %num% )")) {
// Simplify: log2[f|l](1) = 0 , log10[f|l](1) = 0
// log[f|l](1) = 0 , logb10[f|l](1) = 0
// acosh[f|l](1) = 0 , acos[f|l](1) = 0
// ilogb[f|l](1) = 0
// get number string
const std::string& parameter(tok->strAt(2));
// is parameter 1 ?
if (isOneNumber(parameter)) {
tok->deleteNext(3); // delete tokens
tok->str("0"); // insert result into token list
simplifcationMade = true;
}
} else if (Token::Match(tok, "fmin|fminl|fminf ( %num% , %num% )")) {
// @todo if one of the parameters is NaN the other is returned
// e.g. printf ("fmin (NaN, -1.0) = %f\n", fmin(NaN,-1.0));
// e.g. printf ("fmin (-1.0, NaN) = %f\n", fmin(-1.0,NaN));
const std::string& strLeftNumber(tok->strAt(2));
const std::string& strRightNumber(tok->strAt(4));
const bool isLessEqual = MathLib::isLessEqual(strLeftNumber, strRightNumber);
// case: left <= right ==> insert left
if (isLessEqual) {
tok->str(strLeftNumber); // insert e.g. -1.0
tok->deleteNext(5); // delete e.g. fmin ( -1.0, 1.0 )
simplifcationMade = true;
} else { // case left > right ==> insert right
tok->str(strRightNumber); // insert e.g. 0.0
tok->deleteNext(5); // delete e.g. fmin ( 1.0, 0.0 )
simplifcationMade = true;
}
} else if (Token::Match(tok, "fmax|fmaxl|fmaxf ( %num% , %num% )")) {
// @todo if one of the parameters is NaN the other is returned
// e.g. printf ("fmax (NaN, -1.0) = %f\n", fmax(NaN,-1.0));
// e.g. printf ("fmax (-1.0, NaN) = %f\n", fmax(-1.0,NaN));
const std::string& strLeftNumber(tok->strAt(2));
const std::string& strRightNumber(tok->strAt(4));
const bool isLessEqual = MathLib::isLessEqual(strLeftNumber, strRightNumber);
// case: left <= right ==> insert right
if (isLessEqual) {
tok->str(strRightNumber);// insert e.g. 1.0
tok->deleteNext(5); // delete e.g. fmax ( -1.0, 1.0 )
simplifcationMade = true;
} else { // case left > right ==> insert left
tok->str(strLeftNumber); // insert e.g. 1.0
tok->deleteNext(5); // delete e.g. fmax ( 1.0, 0.0 )
simplifcationMade = true;
}
} else if (Token::Match(tok, "pow|powf|powl (")) {
if (Token::Match(tok->tokAt(2), "%num% , %num% )")) {
// In case of pow ( 0 , anyNumber > 0): It can be simplified to 0
// In case of pow ( 0 , 0 ): It simplified to 1
// In case of pow ( 1 , anyNumber ): It simplified to 1
const std::string& leftNumber(tok->strAt(2)); // get the left parameter
const std::string& rightNumber(tok->strAt(4)); // get the right parameter
const bool isLeftNumberZero = isZeroNumber(leftNumber);
const bool isLeftNumberOne = isOneNumber(leftNumber);
const bool isRightNumberZero = isZeroNumber(rightNumber);
if (isLeftNumberZero && !isRightNumberZero && MathLib::isPositive(rightNumber)) { // case: 0^(y) = 0 and y > 0
tok->deleteNext(5); // delete tokens
tok->str("0"); // insert simplified result
simplifcationMade = true;
} else if (isLeftNumberZero && isRightNumberZero) { // case: 0^0 = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
simplifcationMade = true;
} else if (isLeftNumberOne) { // case 1^(y) = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
simplifcationMade = true;
}
}
if (Token::Match(tok->tokAt(2), "%any% , %num% )")) {
// In case of pow( x , 1 ): It can be simplified to x.
const std::string& leftParameter(tok->strAt(2)); // get the left parameter
const std::string& rightNumber(tok->strAt(4)); // get right number
if (isOneNumber(rightNumber)) { // case: x^(1) = x
tok->str(leftParameter); // insert simplified result
tok->deleteNext(5); // delete tokens
simplifcationMade = true;
} else if (isZeroNumber(rightNumber)) { // case: x^(0) = 1
tok->deleteNext(5); // delete tokens
tok->str("1"); // insert simplified result
simplifcationMade = true;
}
}
}
// Jump back to begin of statement if a simplification was performed
if (simplifcationMade) {
while (tok->previous() && tok->str() != ";") {
tok = tok->previous();
}
}
}
}
}
void Tokenizer::simplifyComma() void Tokenizer::simplifyComma()
{ {
bool inReturn = false; bool inReturn = false;

View File

@ -547,11 +547,6 @@ public:
void findComplicatedSyntaxErrorsInTemplates(); void findComplicatedSyntaxErrorsInTemplates();
/**
* Simplify e.g. 'atol("0")' into '0'
*/
void simplifyMathFunctions();
/** /**
* Simplify e.g. 'sin(0)' into '0' * Simplify e.g. 'sin(0)' into '0'
*/ */
@ -897,13 +892,6 @@ public:
return list.front(); return list.front();
} }
/**
* Helper function to check whether number is zero (0 or 0.0 or 0E+0) or not?
* @param s the string to check
* @return true in case is is zero and false otherwise.
*/
static bool isZeroNumber(const std::string &s);
/** /**
* Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not? * Helper function to check whether number is one (1 or 0.1E+1 or 1E+0) or not?
* @param s the string to check * @param s the string to check

View File

@ -60,36 +60,6 @@ private:
TEST_CASE(test1); // array access. replace "*(p+1)" => "p[1]" TEST_CASE(test1); // array access. replace "*(p+1)" => "p[1]"
TEST_CASE(simplifyMathFunctions_sqrt);
TEST_CASE(simplifyMathFunctions_cbrt);
TEST_CASE(simplifyMathFunctions_exp);
TEST_CASE(simplifyMathFunctions_exp2);
TEST_CASE(simplifyMathFunctions_logb);
TEST_CASE(simplifyMathFunctions_log1p);
TEST_CASE(simplifyMathFunctions_ilogb);
TEST_CASE(simplifyMathFunctions_log10);
TEST_CASE(simplifyMathFunctions_log);
TEST_CASE(simplifyMathFunctions_log2);
TEST_CASE(simplifyMathFunctions_pow);
TEST_CASE(simplifyMathFunctions_fmin);
TEST_CASE(simplifyMathFunctions_fmax);
TEST_CASE(simplifyMathFunctions_acosh);
TEST_CASE(simplifyMathFunctions_acos);
TEST_CASE(simplifyMathFunctions_cosh);
TEST_CASE(simplifyMathFunctions_cos);
TEST_CASE(simplifyMathFunctions_erfc);
TEST_CASE(simplifyMathFunctions_erf);
TEST_CASE(simplifyMathFunctions_sin);
TEST_CASE(simplifyMathFunctions_sinh);
TEST_CASE(simplifyMathFunctions_asin);
TEST_CASE(simplifyMathFunctions_asinh);
TEST_CASE(simplifyMathFunctions_tan);
TEST_CASE(simplifyMathFunctions_tanh);
TEST_CASE(simplifyMathFunctions_atan);
TEST_CASE(simplifyMathFunctions_atanh);
TEST_CASE(simplifyMathFunctions_expm1);
TEST_CASE(simplifyMathExpressions); //ticket #1620
// foo(p = new char[10]); => p = new char[10]; foo(p); // foo(p = new char[10]); => p = new char[10]; foo(p);
TEST_CASE(simplifyAssignmentInFunctionCall); TEST_CASE(simplifyAssignmentInFunctionCall);
@ -188,8 +158,6 @@ private:
TEST_CASE(strcat1); TEST_CASE(strcat1);
TEST_CASE(strcat2); TEST_CASE(strcat2);
TEST_CASE(simplifyAtol);
TEST_CASE(simplifyOperator1); TEST_CASE(simplifyOperator1);
TEST_CASE(simplifyOperator2); TEST_CASE(simplifyOperator2);
@ -4117,13 +4085,6 @@ private:
ASSERT_EQUALS(expect, tok(code)); ASSERT_EQUALS(expect, tok(code));
} }
void simplifyAtol() {
ASSERT_EQUALS("a = std :: atol ( x ) ;", tok("a = std::atol(x);"));
ASSERT_EQUALS("a = atol ( \"text\" ) ;", tok("a = atol(\"text\");"));
ASSERT_EQUALS("a = 0 ;", tok("a = std::atol(\"0\");"));
ASSERT_EQUALS("a = 10 ;", tok("a = atol(\"0xa\");"));
}
void simplifyOperator1() { void simplifyOperator1() {
// #3237 - error merging namespaces with operators // #3237 - error merging namespaces with operators
const char code[] = "class c {\n" const char code[] = "class c {\n"

View File

@ -145,7 +145,6 @@ private:
TEST_CASE(simplifyExternC); TEST_CASE(simplifyExternC);
TEST_CASE(simplifyKeyword); // #5842 - remove C99 static keyword between [] TEST_CASE(simplifyKeyword); // #5842 - remove C99 static keyword between []
TEST_CASE(isZeroNumber);
TEST_CASE(isOneNumber); TEST_CASE(isOneNumber);
TEST_CASE(isTwoNumber); TEST_CASE(isTwoNumber);
@ -5628,24 +5627,6 @@ private:
ASSERT_EQUALS(expected2, tokenizeAndStringifyWindows(code2, true, Settings::Win32A)); ASSERT_EQUALS(expected2, tokenizeAndStringifyWindows(code2, true, Settings::Win32A));
} }
void isZeroNumber() const {
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0.0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0L"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("+0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0"));
ASSERT_EQUALS(true, Tokenizer::isZeroNumber("-0E+0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("1.0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("+1.0"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("-1"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber(""));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("garbage"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("E2"));
ASSERT_EQUALS(false, Tokenizer::isZeroNumber("2e"));
}
void isOneNumber() const { void isOneNumber() const {
ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0")); ASSERT_EQUALS(true, Tokenizer::isOneNumber("1.0"));
ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1.0")); ASSERT_EQUALS(true, Tokenizer::isOneNumber("+1.0"));