Fixed #3593 (New Check: Check for assignment within conditional expression)
This commit is contained in:
parent
21b1987b55
commit
72802554c9
|
@ -1698,3 +1698,46 @@ void CheckCondition::duplicateConditionalAssignError(const Token *condTok, const
|
||||||
reportError(
|
reportError(
|
||||||
errors, Severity::style, "duplicateConditionalAssign", msg, CWE398, Certainty::normal);
|
errors, Severity::style, "duplicateConditionalAssign", msg, CWE398, Certainty::normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void CheckCondition::checkAssignmentInCondition()
|
||||||
|
{
|
||||||
|
if (!mSettings->severity.isEnabled(Severity::style))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase *symbolDatabase = mTokenizer->getSymbolDatabase();
|
||||||
|
for (const Scope * scope : symbolDatabase->functionScopes) {
|
||||||
|
for (const Token* tok = scope->bodyStart; tok != scope->bodyEnd; tok = tok->next()) {
|
||||||
|
if (tok->str() != "=")
|
||||||
|
continue;
|
||||||
|
if (!tok->astParent())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// Is this assignment of container/iterator?
|
||||||
|
if (!tok->valueType())
|
||||||
|
continue;
|
||||||
|
if (tok->valueType()->type != ValueType::Type::CONTAINER && tok->valueType()->type != ValueType::Type::ITERATOR)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// warn if this is a conditional expression..
|
||||||
|
if (Token::Match(tok->astParent()->previous(), "if|while ("))
|
||||||
|
assignmentInCondition(tok);
|
||||||
|
else if (Token::Match(tok->astParent(), "%oror%|&&"))
|
||||||
|
assignmentInCondition(tok);
|
||||||
|
else if (Token::simpleMatch(tok->astParent(), "?") && tok == tok->astParent()->astOperand1())
|
||||||
|
assignmentInCondition(tok);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckCondition::assignmentInCondition(const Token *eq)
|
||||||
|
{
|
||||||
|
reportError(
|
||||||
|
eq,
|
||||||
|
Severity::style,
|
||||||
|
"assignmentInCondition",
|
||||||
|
"Assignment in condition should probably be comparison.",
|
||||||
|
CWE571,
|
||||||
|
Certainty::normal);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ public:
|
||||||
checkCondition.checkBadBitmaskCheck();
|
checkCondition.checkBadBitmaskCheck();
|
||||||
checkCondition.comparison();
|
checkCondition.comparison();
|
||||||
checkCondition.checkModuloAlwaysTrueFalse();
|
checkCondition.checkModuloAlwaysTrueFalse();
|
||||||
|
checkCondition.checkAssignmentInCondition();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** mismatching assignment / comparison */
|
/** mismatching assignment / comparison */
|
||||||
|
@ -122,6 +123,9 @@ public:
|
||||||
|
|
||||||
void checkDuplicateConditionalAssign();
|
void checkDuplicateConditionalAssign();
|
||||||
|
|
||||||
|
/** @brief Assignment in condition */
|
||||||
|
void checkAssignmentInCondition();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// The conditions that have been diagnosed
|
// The conditions that have been diagnosed
|
||||||
std::set<const Token*> mCondDiags;
|
std::set<const Token*> mCondDiags;
|
||||||
|
@ -161,6 +165,8 @@ private:
|
||||||
|
|
||||||
void duplicateConditionalAssignError(const Token *condTok, const Token* assignTok);
|
void duplicateConditionalAssignError(const Token *condTok, const Token* assignTok);
|
||||||
|
|
||||||
|
void assignmentInCondition(const Token *eq);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const OVERRIDE {
|
||||||
CheckCondition c(nullptr, settings, errorLogger);
|
CheckCondition c(nullptr, settings, errorLogger);
|
||||||
|
|
||||||
|
@ -183,6 +189,7 @@ private:
|
||||||
c.invalidTestForOverflow(nullptr, nullptr, "false");
|
c.invalidTestForOverflow(nullptr, nullptr, "false");
|
||||||
c.pointerAdditionResultNotNullError(nullptr, nullptr);
|
c.pointerAdditionResultNotNullError(nullptr, nullptr);
|
||||||
c.duplicateConditionalAssignError(nullptr, nullptr);
|
c.duplicateConditionalAssignError(nullptr, nullptr);
|
||||||
|
c.assignmentInCondition(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
@ -203,7 +210,8 @@ private:
|
||||||
"- Mutual exclusion over || always evaluating to true\n"
|
"- Mutual exclusion over || always evaluating to true\n"
|
||||||
"- Comparisons of modulo results that are always true/false.\n"
|
"- Comparisons of modulo results that are always true/false.\n"
|
||||||
"- Known variable values => condition is always true/false\n"
|
"- Known variable values => condition is always true/false\n"
|
||||||
"- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n";
|
"- Invalid test for overflow. Some mainstream compilers remove such overflow tests when optimising code.\n"
|
||||||
|
"- Assignment of container/iterator in condition should probably be comparison.\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -120,6 +120,8 @@ private:
|
||||||
TEST_CASE(alwaysTrueFalseInLogicalOperators);
|
TEST_CASE(alwaysTrueFalseInLogicalOperators);
|
||||||
TEST_CASE(pointerAdditionResultNotNull);
|
TEST_CASE(pointerAdditionResultNotNull);
|
||||||
TEST_CASE(duplicateConditionalAssign);
|
TEST_CASE(duplicateConditionalAssign);
|
||||||
|
|
||||||
|
TEST_CASE(checkAssignmentInCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
|
void check(const char code[], const char* filename = "test.cpp", bool inconclusive = false) {
|
||||||
|
@ -4153,6 +4155,13 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void checkAssignmentInCondition() {
|
||||||
|
check("void f(std::string s) {\n"
|
||||||
|
" if (s=\"123\"){}\n"
|
||||||
|
"}");
|
||||||
|
ASSERT_EQUALS("[test.cpp:2]: (style) Assignment in condition should probably be comparison.\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestCondition)
|
REGISTER_TEST(TestCondition)
|
||||||
|
|
Loading…
Reference in New Issue