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:
Rikard Falkeborn 2020-02-01 07:22:41 +01:00 committed by GitHub
parent 5eaf437c44
commit ff9c04dc28
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 51 additions and 0 deletions

View File

@ -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);

View File

@ -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);