Fixed #7875 (New check: function declaration and definition argument names don't match)
This commit is contained in:
parent
8ba9ce4924
commit
139071d88b
|
@ -2775,3 +2775,124 @@ void CheckOther::accessMovedError(const Token *tok, const std::string &varname,
|
||||||
reportError(tok, Severity::warning, errorId, errmsg, CWE672, inconclusive);
|
reportError(tok, Severity::warning, errorId, errmsg, CWE672, inconclusive);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void CheckOther::checkFuncArgNamesDifferent()
|
||||||
|
{
|
||||||
|
const bool style = _settings->isEnabled("style");
|
||||||
|
const bool inconclusive = _settings->inconclusive;
|
||||||
|
const bool warning = _settings->isEnabled("warning");
|
||||||
|
|
||||||
|
if (!(warning || (style && inconclusive)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const SymbolDatabase *symbolDatabase = _tokenizer->getSymbolDatabase();
|
||||||
|
// check every function
|
||||||
|
for (std::size_t i = 0, end = symbolDatabase->functionScopes.size(); i < end; ++i) {
|
||||||
|
const Function * function = symbolDatabase->functionScopes[i]->function;
|
||||||
|
// only check functions with arguments
|
||||||
|
if (!function || function->argCount() == 0)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// only check functions with seperate declarations and definitions
|
||||||
|
if (function->argDef == function->arg)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
// get the function argument name tokens
|
||||||
|
std::vector<const Token *> declarations(function->argCount());
|
||||||
|
std::vector<const Token *> definitions(function->argCount());
|
||||||
|
const Token * decl = function->argDef->next();
|
||||||
|
for (std::size_t j = 0; j < function->argCount(); ++j) {
|
||||||
|
declarations[j] = nullptr;
|
||||||
|
definitions[j] = nullptr;
|
||||||
|
// get the definition
|
||||||
|
const Variable * variable = function->getArgumentVar(j);
|
||||||
|
if (variable) {
|
||||||
|
definitions[j] = variable->nameToken();
|
||||||
|
}
|
||||||
|
// get the declaration (search for first token with varId)
|
||||||
|
bool skip = false;
|
||||||
|
while (decl && !Token::Match(decl, ",|)|;")) {
|
||||||
|
// skip everything after the assignment because
|
||||||
|
// it could also have a varId or be the first
|
||||||
|
// token with a varId if there is no name token
|
||||||
|
if (decl->str() == "=")
|
||||||
|
skip = true;
|
||||||
|
// skip over template
|
||||||
|
else if (decl->link())
|
||||||
|
decl = decl->link();
|
||||||
|
else if (!skip && decl->varId()) {
|
||||||
|
declarations[j] = decl;
|
||||||
|
}
|
||||||
|
decl = decl->next();
|
||||||
|
}
|
||||||
|
if (decl)
|
||||||
|
decl = decl->next();
|
||||||
|
}
|
||||||
|
// check for different argument order
|
||||||
|
if (warning) {
|
||||||
|
bool order_different = false;
|
||||||
|
for (std::size_t j = 0; j < function->argCount(); ++j) {
|
||||||
|
if (!declarations[j] || !definitions[j] || declarations[j]->str() == definitions[j]->str())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (std::size_t k = 0; k < function->argCount(); ++k) {
|
||||||
|
if (j != k && definitions[k] && declarations[j]->str() == definitions[k]->str()) {
|
||||||
|
order_different = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (order_different) {
|
||||||
|
funcArgOrderDifferent(function->name(), function->argDef->next(), function->arg->next(), declarations, definitions);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check for different argument names
|
||||||
|
if (style && inconclusive) {
|
||||||
|
for (std::size_t j = 0; j < function->argCount(); ++j) {
|
||||||
|
if (declarations[j] && definitions[j] && declarations[j]->str() != definitions[j]->str())
|
||||||
|
funcArgNamesDifferent(function->name(), j, declarations[j], definitions[j]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::funcArgNamesDifferent(const std::string & name, size_t index,
|
||||||
|
const Token* declaration, const Token* definition)
|
||||||
|
{
|
||||||
|
std::list<const Token *> tokens;
|
||||||
|
tokens.push_back(declaration);
|
||||||
|
tokens.push_back(definition);
|
||||||
|
reportError(tokens, Severity::style, "funcArgNamesDifferent",
|
||||||
|
"Function '" + name + "' argument " + MathLib::toString(index + 1) + " names different: declaration '" +
|
||||||
|
(declaration ? declaration->str() : std::string("A")) + "' definition '" +
|
||||||
|
(definition ? definition->str() : std::string("B")) + "'.", CWE(0U), true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CheckOther::funcArgOrderDifferent(const std::string & name,
|
||||||
|
const Token* declaration, const Token* definition,
|
||||||
|
const std::vector<const Token *> & declarations,
|
||||||
|
const std::vector<const Token *> & definitions)
|
||||||
|
{
|
||||||
|
std::list<const Token *> tokens;
|
||||||
|
tokens.push_back(declarations.size() ? declarations[0] ? declarations[0] : declaration : nullptr);
|
||||||
|
tokens.push_back(definitions.size() ? definitions[0] ? definitions[0] : definition : nullptr);
|
||||||
|
std::string msg = "Function '" + name + "' argument order different: declaration '";
|
||||||
|
for (std::size_t i = 0; i < declarations.size(); ++i) {
|
||||||
|
if (i != 0)
|
||||||
|
msg += ", ";
|
||||||
|
if (declarations[i])
|
||||||
|
msg += declarations[i]->str();
|
||||||
|
}
|
||||||
|
msg += "' definition '";
|
||||||
|
for (std::size_t i = 0; i < definitions.size(); ++i) {
|
||||||
|
if (i != 0)
|
||||||
|
msg += ", ";
|
||||||
|
if (definitions[i])
|
||||||
|
msg += definitions[i]->str();
|
||||||
|
}
|
||||||
|
msg += "'";
|
||||||
|
reportError(tokens, Severity::warning, "funcArgOrderDifferent", msg, CWE(0U), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -72,6 +72,7 @@ public:
|
||||||
checkOther.checkInterlockedDecrement();
|
checkOther.checkInterlockedDecrement();
|
||||||
checkOther.checkUnusedLabel();
|
checkOther.checkUnusedLabel();
|
||||||
checkOther.checkEvaluationOrder();
|
checkOther.checkEvaluationOrder();
|
||||||
|
checkOther.checkFuncArgNamesDifferent();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Run checks against the simplified token list */
|
/** @brief Run checks against the simplified token list */
|
||||||
|
@ -207,6 +208,9 @@ public:
|
||||||
/** @brief %Check for access of moved or forwarded variable */
|
/** @brief %Check for access of moved or forwarded variable */
|
||||||
void checkAccessOfMovedVariable();
|
void checkAccessOfMovedVariable();
|
||||||
|
|
||||||
|
/** @brief %Check if function declaration and definition argument names different */
|
||||||
|
void checkFuncArgNamesDifferent();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Error messages..
|
// Error messages..
|
||||||
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &strFunctionName, const std::string &varName, const bool result);
|
void checkComparisonFunctionIsAlwaysTrueOrFalseError(const Token* tok, const std::string &strFunctionName, const std::string &varName, const bool result);
|
||||||
|
@ -258,6 +262,8 @@ private:
|
||||||
void unknownEvaluationOrder(const Token* tok);
|
void unknownEvaluationOrder(const Token* tok);
|
||||||
static bool isMovedParameterAllowedForInconclusiveFunction(const Token * tok);
|
static bool isMovedParameterAllowedForInconclusiveFunction(const Token * tok);
|
||||||
void accessMovedError(const Token *tok, const std::string &varname, ValueFlow::Value::MoveKind moveKind, bool inconclusive);
|
void accessMovedError(const Token *tok, const std::string &varname, ValueFlow::Value::MoveKind moveKind, bool inconclusive);
|
||||||
|
void funcArgNamesDifferent(const std::string & name, size_t index, const Token* declaration, const Token* definition);
|
||||||
|
void funcArgOrderDifferent(const std::string & name, const Token * declaration, const Token * definition, const std::vector<const Token*> & declarations, const std::vector<const Token*> & definitions);
|
||||||
|
|
||||||
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
void getErrorMessages(ErrorLogger *errorLogger, const Settings *settings) const {
|
||||||
CheckOther c(nullptr, settings, errorLogger);
|
CheckOther c(nullptr, settings, errorLogger);
|
||||||
|
@ -317,6 +323,10 @@ private:
|
||||||
c.unknownEvaluationOrder(nullptr);
|
c.unknownEvaluationOrder(nullptr);
|
||||||
c.accessMovedError(nullptr, "v", ValueFlow::Value::MovedVariable, false);
|
c.accessMovedError(nullptr, "v", ValueFlow::Value::MovedVariable, false);
|
||||||
c.accessMovedError(nullptr, "v", ValueFlow::Value::ForwardedVariable, false);
|
c.accessMovedError(nullptr, "v", ValueFlow::Value::ForwardedVariable, false);
|
||||||
|
c.funcArgNamesDifferent("function", 1, nullptr, nullptr);
|
||||||
|
|
||||||
|
std::vector<const Token *> nullvec;
|
||||||
|
c.funcArgOrderDifferent("function", nullptr, nullptr, nullvec, nullvec);
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::string myName() {
|
static std::string myName() {
|
||||||
|
@ -375,7 +385,9 @@ private:
|
||||||
"- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
|
"- prefer erfc, expm1 or log1p to avoid loss of precision.\n"
|
||||||
"- identical code in both branches of if/else or ternary operator.\n"
|
"- identical code in both branches of if/else or ternary operator.\n"
|
||||||
"- redundant pointer operation on pointer like &*some_ptr.\n"
|
"- redundant pointer operation on pointer like &*some_ptr.\n"
|
||||||
"- find unused 'goto' labels.\n";
|
"- find unused 'goto' labels.\n"
|
||||||
|
"- function declaration and definition argument names different.\n"
|
||||||
|
"- function declaration and definition argument order different.\n";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
/// @}
|
/// @}
|
||||||
|
|
|
@ -192,6 +192,9 @@ private:
|
||||||
TEST_CASE(partiallyMoved);
|
TEST_CASE(partiallyMoved);
|
||||||
TEST_CASE(moveAndLambda);
|
TEST_CASE(moveAndLambda);
|
||||||
TEST_CASE(forwardAndUsed);
|
TEST_CASE(forwardAndUsed);
|
||||||
|
|
||||||
|
TEST_CASE(funcArgNamesDifferent);
|
||||||
|
TEST_CASE(funcArgOrderDifferent);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -6349,6 +6352,57 @@ private:
|
||||||
"}");
|
"}");
|
||||||
ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable t.\n", errout.str());
|
ASSERT_EQUALS("[test.cpp:4]: (warning) Access of forwarded variable t.\n", errout.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void funcArgNamesDifferent() {
|
||||||
|
check("void func1(int a, int b, int c); \n"
|
||||||
|
"void func1(int a, int b, int c) { }\n"
|
||||||
|
"void func2(int a, int b, int c);\n"
|
||||||
|
"void func2(int A, int B, int C) { }\n"
|
||||||
|
"class Fred {\n"
|
||||||
|
" void func1(int a, int b, int c); \n"
|
||||||
|
" void func2(int a, int b, int c);\n"
|
||||||
|
" void func3(int a = 0, int b = 0, int c = 0);\n"
|
||||||
|
" void func4(int a = 0, int b = 0, int c = 0);\n"
|
||||||
|
"};\n"
|
||||||
|
"void Fred::func1(int a, int b, int c) { }\n"
|
||||||
|
"void Fred::func2(int A, int B, int C) { }\n"
|
||||||
|
"void Fred::func3(int a, int b, int c) { }\n"
|
||||||
|
"void Fred::func4(int A, int B, int C) { }\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (style, inconclusive) Function 'func2' argument 1 names different: declaration 'a' definition 'A'.\n"
|
||||||
|
"[test.cpp:3] -> [test.cpp:4]: (style, inconclusive) Function 'func2' argument 2 names different: declaration 'b' definition 'B'.\n"
|
||||||
|
"[test.cpp:3] -> [test.cpp:4]: (style, inconclusive) Function 'func2' argument 3 names different: declaration 'c' definition 'C'.\n"
|
||||||
|
"[test.cpp:7] -> [test.cpp:12]: (style, inconclusive) Function 'func2' argument 1 names different: declaration 'a' definition 'A'.\n"
|
||||||
|
"[test.cpp:7] -> [test.cpp:12]: (style, inconclusive) Function 'func2' argument 2 names different: declaration 'b' definition 'B'.\n"
|
||||||
|
"[test.cpp:7] -> [test.cpp:12]: (style, inconclusive) Function 'func2' argument 3 names different: declaration 'c' definition 'C'.\n"
|
||||||
|
"[test.cpp:9] -> [test.cpp:14]: (style, inconclusive) Function 'func4' argument 1 names different: declaration 'a' definition 'A'.\n"
|
||||||
|
"[test.cpp:9] -> [test.cpp:14]: (style, inconclusive) Function 'func4' argument 2 names different: declaration 'b' definition 'B'.\n"
|
||||||
|
"[test.cpp:9] -> [test.cpp:14]: (style, inconclusive) Function 'func4' argument 3 names different: declaration 'c' definition 'C'.\n", errout.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void funcArgOrderDifferent() {
|
||||||
|
check("void func1(int a, int b, int c);\n"
|
||||||
|
"void func1(int a, int b, int c) { }\n"
|
||||||
|
"void func2(int a, int b, int c);\n"
|
||||||
|
"void func2(int c, int b, int a) { }\n"
|
||||||
|
"void func3(int, int b, int c);\n"
|
||||||
|
"void func3(int c, int b, int a) { }\n"
|
||||||
|
"class Fred {\n"
|
||||||
|
" void func1(int a, int b, int c);\n"
|
||||||
|
" void func2(int a, int b, int c);\n"
|
||||||
|
" void func3(int a = 0, int b = 0, int c = 0);\n"
|
||||||
|
" void func4(int, int b = 0, int c = 0);\n"
|
||||||
|
"};\n"
|
||||||
|
"void Fred::func1(int a, int b, int c) { }\n"
|
||||||
|
"void Fred::func2(int c, int b, int a) { }\n"
|
||||||
|
"void Fred::func3(int c, int b, int a) { }\n"
|
||||||
|
"void Fred::func4(int c, int b, int a) { }\n",
|
||||||
|
nullptr, false, false);
|
||||||
|
ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (warning) Function 'func2' argument order different: declaration 'a, b, c' definition 'c, b, a'\n"
|
||||||
|
"[test.cpp:5] -> [test.cpp:6]: (warning) Function 'func3' argument order different: declaration ', b, c' definition 'c, b, a'\n"
|
||||||
|
"[test.cpp:9] -> [test.cpp:14]: (warning) Function 'func2' argument order different: declaration 'a, b, c' definition 'c, b, a'\n"
|
||||||
|
"[test.cpp:10] -> [test.cpp:15]: (warning) Function 'func3' argument order different: declaration 'a, b, c' definition 'c, b, a'\n"
|
||||||
|
"[test.cpp:11] -> [test.cpp:16]: (warning) Function 'func4' argument order different: declaration ', b, c' definition 'c, b, a'\n", errout.str());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
REGISTER_TEST(TestOther)
|
REGISTER_TEST(TestOther)
|
||||||
|
|
Loading…
Reference in New Issue