Show struct member in unsignedLessThanZeroError warning
Before: [/tmp/test.c:8]: (style) Checking if unsigned variable '.' is less than zero. [/tmp/test.c:12]: (style) Checking if unsigned variable '.' is less than zero. After: [/tmp/test.c:8]: (style) Checking if unsigned variable 'd.n' is less than zero. [/tmp/test.c:12]: (style) Checking if unsigned variable 'd.n' is less than zero.
This commit is contained in:
parent
652043fa22
commit
0154d39bf6
|
@ -2157,13 +2157,13 @@ void CheckOther::checkSignOfUnsignedVariable()
|
||||||
if (vt && vt->pointer)
|
if (vt && vt->pointer)
|
||||||
pointerLessThanZeroError(tok, inconclusive);
|
pointerLessThanZeroError(tok, inconclusive);
|
||||||
if (vt && vt->sign == ValueType::UNSIGNED)
|
if (vt && vt->sign == ValueType::UNSIGNED)
|
||||||
unsignedLessThanZeroError(tok, tok->astOperand1()->str(), inconclusive);
|
unsignedLessThanZeroError(tok, tok->astOperand1()->expressionString(), inconclusive);
|
||||||
} else if (Token::Match(tok->previous(), "0 >|>=") && tok->previous() == tok->astOperand1()) {
|
} else if (Token::Match(tok->previous(), "0 >|>=") && tok->previous() == tok->astOperand1()) {
|
||||||
const ValueType* vt = tok->astOperand2()->valueType();
|
const ValueType* vt = tok->astOperand2()->valueType();
|
||||||
if (vt && vt->pointer)
|
if (vt && vt->pointer)
|
||||||
pointerLessThanZeroError(tok, inconclusive);
|
pointerLessThanZeroError(tok, inconclusive);
|
||||||
if (vt && vt->sign == ValueType::UNSIGNED)
|
if (vt && vt->sign == ValueType::UNSIGNED)
|
||||||
unsignedLessThanZeroError(tok, tok->astOperand2()->str(), inconclusive);
|
unsignedLessThanZeroError(tok, tok->astOperand2()->expressionString(), inconclusive);
|
||||||
} else if (Token::simpleMatch(tok, ">= 0") && tok->next() == tok->astOperand2()) {
|
} else if (Token::simpleMatch(tok, ">= 0") && tok->next() == tok->astOperand2()) {
|
||||||
const ValueType* vt = tok->astOperand1()->valueType();
|
const ValueType* vt = tok->astOperand1()->valueType();
|
||||||
if (vt && vt->pointer)
|
if (vt && vt->pointer)
|
||||||
|
|
|
@ -1146,6 +1146,51 @@ bool Token::isUnaryPreOp() const
|
||||||
return false; // <- guess
|
return false; // <- guess
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const Token* goToLeftParenthesis(const Token* start, const Token* end)
|
||||||
|
{
|
||||||
|
// move start to lpar in such expression: '(*it).x'
|
||||||
|
int par = 0;
|
||||||
|
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
||||||
|
if (tok->str() == "(")
|
||||||
|
++par;
|
||||||
|
else if (tok->str() == ")") {
|
||||||
|
if (par == 0)
|
||||||
|
start = tok->link();
|
||||||
|
else
|
||||||
|
--par;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return start;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const Token* goToRightParenthesis(const Token* start, const Token* end)
|
||||||
|
{
|
||||||
|
// move end to rpar in such expression: '2>(x+1)'
|
||||||
|
int par = 0;
|
||||||
|
for (const Token *tok = end; tok && tok != start; tok = tok->previous()) {
|
||||||
|
if (tok->str() == ")")
|
||||||
|
++par;
|
||||||
|
else if (tok->str() == "(") {
|
||||||
|
if (par == 0)
|
||||||
|
end = tok->link();
|
||||||
|
else
|
||||||
|
--par;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string stringFromTokenRange(const Token* start, const Token* end)
|
||||||
|
{
|
||||||
|
std::string ret;
|
||||||
|
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
||||||
|
ret += tok->str();
|
||||||
|
if (Token::Match(tok, "%name%|%num% %name%|%num%"))
|
||||||
|
ret += " ";
|
||||||
|
}
|
||||||
|
return ret + end->str();
|
||||||
|
}
|
||||||
|
|
||||||
std::string Token::expressionString() const
|
std::string Token::expressionString() const
|
||||||
{
|
{
|
||||||
const Token * const top = this;
|
const Token * const top = this;
|
||||||
|
@ -1163,39 +1208,10 @@ std::string Token::expressionString() const
|
||||||
end = end->astOperand2() ? end->astOperand2() : end->astOperand1();
|
end = end->astOperand2() ? end->astOperand2() : end->astOperand1();
|
||||||
}
|
}
|
||||||
|
|
||||||
// move start to lpar in such expression: '(*it).x'
|
start = goToLeftParenthesis(start, end);
|
||||||
int par = 0;
|
end = goToRightParenthesis(start, end);
|
||||||
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
|
||||||
if (tok->str() == "(")
|
|
||||||
++par;
|
|
||||||
else if (tok->str() == ")") {
|
|
||||||
if (par == 0)
|
|
||||||
start = tok->link();
|
|
||||||
else
|
|
||||||
--par;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// move end to rpar in such expression: '2>(x+1)'
|
return stringFromTokenRange(start, end);
|
||||||
par = 0;
|
|
||||||
for (const Token *tok = end; tok && tok != start; tok = tok->previous()) {
|
|
||||||
if (tok->str() == ")")
|
|
||||||
++par;
|
|
||||||
else if (tok->str() == "(") {
|
|
||||||
if (par == 0)
|
|
||||||
end = tok->link();
|
|
||||||
else
|
|
||||||
--par;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string ret;
|
|
||||||
for (const Token *tok = start; tok && tok != end; tok = tok->next()) {
|
|
||||||
ret += tok->str();
|
|
||||||
if (Token::Match(tok, "%name%|%num% %name%|%num%"))
|
|
||||||
ret += " ";
|
|
||||||
}
|
|
||||||
return ret + end->str();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void astStringXml(const Token *tok, std::size_t indent, std::ostream &out)
|
static void astStringXml(const Token *tok, std::size_t indent, std::ostream &out)
|
||||||
|
|
|
@ -170,6 +170,8 @@ private:
|
||||||
TEST_CASE(testEvaluationOrderSequencePointsFunctionCall);
|
TEST_CASE(testEvaluationOrderSequencePointsFunctionCall);
|
||||||
TEST_CASE(testEvaluationOrderSequencePointsComma);
|
TEST_CASE(testEvaluationOrderSequencePointsComma);
|
||||||
TEST_CASE(testEvaluationOrderSizeof);
|
TEST_CASE(testEvaluationOrderSizeof);
|
||||||
|
|
||||||
|
TEST_CASE(testUnsignedLessThanZero);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char *filename = nullptr, bool experimental = false, bool inconclusive = true, bool runSimpleChecks=true, Settings* settings = 0) {
|
void check(const char code[], const char *filename = nullptr, bool experimental = false, bool inconclusive = true, bool runSimpleChecks=true, Settings* settings = 0) {
|
||||||
|
@ -6053,6 +6055,27 @@ private:
|
||||||
"}", "test.c");
|
"}", "test.c");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void testUnsignedLessThanZero() {
|
||||||
|
check("struct d {\n"
|
||||||
|
" unsigned n;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(void) {\n"
|
||||||
|
" struct d d;\n"
|
||||||
|
" d.n = 3;\n"
|
||||||
|
"\n"
|
||||||
|
" if (d.n < 0) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"\n"
|
||||||
|
" if (0 > d.n) {\n"
|
||||||
|
" return;\n"
|
||||||
|
" }\n"
|
||||||
|
"}", "test.c");
|
||||||
|
ASSERT_EQUALS("[test.c:8]: (style) Checking if unsigned variable 'd.n' is less than zero.\n"
|
||||||
|
"[test.c:12]: (style) Checking if unsigned variable 'd.n' is less than zero.\n",
|
||||||
|
errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
Loading…
Reference in New Issue