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)
|
||||
pointerLessThanZeroError(tok, inconclusive);
|
||||
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()) {
|
||||
const ValueType* vt = tok->astOperand2()->valueType();
|
||||
if (vt && vt->pointer)
|
||||
pointerLessThanZeroError(tok, inconclusive);
|
||||
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()) {
|
||||
const ValueType* vt = tok->astOperand1()->valueType();
|
||||
if (vt && vt->pointer)
|
||||
|
|
|
@ -1146,6 +1146,51 @@ bool Token::isUnaryPreOp() const
|
|||
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
|
||||
{
|
||||
const Token * const top = this;
|
||||
|
@ -1163,39 +1208,10 @@ std::string Token::expressionString() const
|
|||
end = end->astOperand2() ? end->astOperand2() : end->astOperand1();
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
start = goToLeftParenthesis(start, end);
|
||||
end = goToRightParenthesis(start, end);
|
||||
|
||||
// move end to rpar in such expression: '2>(x+1)'
|
||||
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();
|
||||
return stringFromTokenRange(start, end);
|
||||
}
|
||||
|
||||
static void astStringXml(const Token *tok, std::size_t indent, std::ostream &out)
|
||||
|
|
|
@ -170,6 +170,8 @@ private:
|
|||
TEST_CASE(testEvaluationOrderSequencePointsFunctionCall);
|
||||
TEST_CASE(testEvaluationOrderSequencePointsComma);
|
||||
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) {
|
||||
|
@ -6053,6 +6055,27 @@ private:
|
|||
"}", "test.c");
|
||||
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)
|
||||
|
|
Loading…
Reference in New Issue