Improve isSameExpression for literals (#2514)
Improve isSameExpression() for literals with same value but different representation, for example the following different ways of representing 9 as double: 9.0, 0.9e1 and 0x1.2p3. With this change, cppcheck can (for example) correctly detect that the else if statements are always false in the following example: void f(double x) { if (x < 9.0) {} else if (x < 0x1.2p3) {} else if (x < 0.9e1) {} }
This commit is contained in:
parent
5eaf437c44
commit
ff9c04dc28
|
@ -547,6 +547,26 @@ bool isDifferentKnownValues(const Token * const tok1, const Token * const tok2)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool isSameConstantValue(bool macro, const Token * const tok1, const Token * const tok2)
|
||||||
|
{
|
||||||
|
if (tok1 == nullptr || tok2 == nullptr)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!tok1->isNumber() || !tok2->isNumber())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (macro && (tok1->isExpandedMacro() || tok2->isExpandedMacro() || tok1->isTemplateArg() || tok2->isTemplateArg()))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
const ValueType * v1 = tok1->valueType();
|
||||||
|
const ValueType * v2 = tok2->valueType();
|
||||||
|
|
||||||
|
if (!v1 || !v2 || v1->sign != v2->sign || v1->type != v2->type || v1->pointer != v2->pointer)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return isEqualKnownValue(tok1, tok2);
|
||||||
|
}
|
||||||
|
|
||||||
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors)
|
bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2, const Library& library, bool pure, bool followVar, ErrorPath* errors)
|
||||||
{
|
{
|
||||||
if (tok1 == nullptr && tok2 == nullptr)
|
if (tok1 == nullptr && tok2 == nullptr)
|
||||||
|
@ -568,6 +588,9 @@ bool isSameExpression(bool cpp, bool macro, const Token *tok1, const Token *tok2
|
||||||
}
|
}
|
||||||
if (tok1->str() != tok2->str() && isDifferentKnownValues(tok1, tok2))
|
if (tok1->str() != tok2->str() && isDifferentKnownValues(tok1, tok2))
|
||||||
return false;
|
return false;
|
||||||
|
if (isSameConstantValue(macro, tok1, tok2))
|
||||||
|
return true;
|
||||||
|
|
||||||
// Follow variable
|
// Follow variable
|
||||||
if (followVar && tok1->str() != tok2->str() && (Token::Match(tok1, "%var%") || Token::Match(tok2, "%var%"))) {
|
if (followVar && tok1->str() != tok2->str() && (Token::Match(tok1, "%var%") || Token::Match(tok2, "%var%"))) {
|
||||||
const Token * varTok1 = followVariableExpression(tok1, cpp, tok2);
|
const Token * varTok1 = followVariableExpression(tok1, cpp, tok2);
|
||||||
|
|
|
@ -36,6 +36,7 @@ private:
|
||||||
TEST_CASE(findLambdaEndToken);
|
TEST_CASE(findLambdaEndToken);
|
||||||
TEST_CASE(findLambdaStartToken);
|
TEST_CASE(findLambdaStartToken);
|
||||||
TEST_CASE(isReturnScope);
|
TEST_CASE(isReturnScope);
|
||||||
|
TEST_CASE(isSameExpression);
|
||||||
TEST_CASE(isVariableChanged);
|
TEST_CASE(isVariableChanged);
|
||||||
TEST_CASE(isVariableChangedByFunctionCall);
|
TEST_CASE(isVariableChangedByFunctionCall);
|
||||||
TEST_CASE(nextAfterAstRightmostLeaf);
|
TEST_CASE(nextAfterAstRightmostLeaf);
|
||||||
|
@ -135,6 +136,33 @@ private:
|
||||||
ASSERT_EQUALS(true, isReturnScope("void positiveTokenOffset() { return; }", 7));
|
ASSERT_EQUALS(true, isReturnScope("void positiveTokenOffset() { return; }", 7));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool isSameExpression(const char code[], const char tokStr1[], const char tokStr2[]) {
|
||||||
|
Settings settings;
|
||||||
|
Library library;
|
||||||
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
std::istringstream istr(code);
|
||||||
|
tokenizer.tokenize(istr, "test.cpp");
|
||||||
|
const Token * const tok1 = Token::findsimplematch(tokenizer.tokens(), tokStr1);
|
||||||
|
const Token * const tok2 = Token::findsimplematch(tok1->next(), tokStr2);
|
||||||
|
return ::isSameExpression(false, false, tok1, tok2, library, false, false, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void isSameExpression() {
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("x = 1 + 1;", "1", "1"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("x = 1 + 1u;", "1", "1u"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("x = 1.0 + 1.0;", "1.0", "1.0"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("x = 1.0f + 1.0;", "1.0f", "1.0"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("x = 1L + 1;", "1L", "1"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("x = 0.0f + 0x0p+0f;", "0.0f", "0x0p+0f"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("x < x;", "x", "x"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("x < y;", "x", "y"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("(x + 1) < (x + 1);", "+", "+"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("(x + 1) < (x + 1L);", "+", "+"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("(1 + x) < (x + 1);", "+", "+"));
|
||||||
|
ASSERT_EQUALS(false, isSameExpression("(1.0l + x) < (1.0 + x);", "+", "+"));
|
||||||
|
ASSERT_EQUALS(true, isSameExpression("(0.0 + x) < (x + 0x0p+0);", "+", "+"));
|
||||||
|
}
|
||||||
|
|
||||||
bool isVariableChanged(const char code[], const char startPattern[], const char endPattern[]) {
|
bool isVariableChanged(const char code[], const char startPattern[], const char endPattern[]) {
|
||||||
Settings settings;
|
Settings settings;
|
||||||
Tokenizer tokenizer(&settings, this);
|
Tokenizer tokenizer(&settings, this);
|
||||||
|
|
Loading…
Reference in New Issue