Fix issue 9710 and 9767: Use AST to get function from argument
This commit is contained in:
parent
c21b5b1aa4
commit
1676ad5f45
|
@ -1226,34 +1226,78 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// goto start of function call and get argn
|
const Token* argtok = tok;
|
||||||
argn = 0;
|
while(!Token::Match(argtok->astParent(), ",|(|{") || (argtok->astParent() && argtok->astParent()->isCast())) {
|
||||||
while (tok && !Token::simpleMatch(tok, ";") && !isScopeBracket(tok)) {
|
argtok = argtok->astParent();
|
||||||
if (tok->str() == ",")
|
|
||||||
++argn;
|
|
||||||
else if (Token::Match(tok, ")|}"))
|
|
||||||
tok = tok->link();
|
|
||||||
else if (Token::Match(tok->previous(), "%name% (|{"))
|
|
||||||
break;
|
|
||||||
else if (Token::Match(tok->previous(), "> (|{") && tok->previous()->link())
|
|
||||||
break;
|
|
||||||
tok = tok->previous();
|
|
||||||
}
|
}
|
||||||
|
if (!argtok)
|
||||||
|
return nullptr;
|
||||||
|
if (Token::simpleMatch(argtok, ","))
|
||||||
|
argtok = argtok->astOperand1();
|
||||||
|
if (Token::simpleMatch(argtok, "(") && argtok->astOperand2())
|
||||||
|
argtok = argtok->astOperand2();
|
||||||
|
tok = argtok;
|
||||||
|
while(Token::Match(tok->astParent(), ",|(|{")) {
|
||||||
|
tok = tok->astParent();
|
||||||
|
if (Token::Match(tok, "(|{"))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
std::vector<const Token*> args = getArguments(tok);
|
||||||
|
auto it = std::find(args.begin(), args.end(), argtok);
|
||||||
|
if (it != args.end())
|
||||||
|
argn = std::distance(args.begin(), it);
|
||||||
|
if (argn == -1)
|
||||||
|
return nullptr;
|
||||||
if (!Token::Match(tok, "{|("))
|
if (!Token::Match(tok, "{|("))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
tok = tok->previous();
|
tok = tok->astOperand1();
|
||||||
|
while(Token::simpleMatch(tok, "."))
|
||||||
|
tok = tok->astOperand2();
|
||||||
|
while(Token::simpleMatch(tok, "::")) {
|
||||||
|
tok = tok->astOperand2();
|
||||||
|
if(Token::simpleMatch(tok, "<") && tok->link())
|
||||||
|
tok = tok->astOperand1();
|
||||||
|
}
|
||||||
if (tok && tok->link() && tok->str() == ">")
|
if (tok && tok->link() && tok->str() == ">")
|
||||||
tok = tok->link()->previous();
|
tok = tok->link()->previous();
|
||||||
if (!Token::Match(tok, "%name% [({<]"))
|
if (!Token::Match(tok, "%name%|(|{"))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return tok;
|
return tok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Variable* getArgumentVar(const Token* tok, int argnr)
|
||||||
|
{
|
||||||
|
if (!tok)
|
||||||
|
return nullptr;
|
||||||
|
if (tok->function())
|
||||||
|
return tok->function()->getArgumentVar(argnr);
|
||||||
|
if (Token::Match(tok->previous(), "%type% (|{") || tok->variable()) {
|
||||||
|
const Type* type = Token::typeOf(tok);
|
||||||
|
if (!type)
|
||||||
|
return nullptr;
|
||||||
|
const Scope* typeScope = type->classScope;
|
||||||
|
const int argCount = numberOfArguments(tok);
|
||||||
|
for (const Function &function : typeScope->functionList) {
|
||||||
|
if (function.isConstructor())
|
||||||
|
continue;
|
||||||
|
if (function.argCount() < argCount)
|
||||||
|
continue;
|
||||||
|
if (!Token::simpleMatch(function.token, "operator()"))
|
||||||
|
continue;
|
||||||
|
return function.getArgumentVar(argnr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive)
|
bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Settings *settings, bool *inconclusive)
|
||||||
{
|
{
|
||||||
if (!tok)
|
if (!tok)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if(Token::simpleMatch(tok, ","))
|
||||||
|
return false;
|
||||||
|
|
||||||
const Token * const tok1 = tok;
|
const Token * const tok1 = tok;
|
||||||
|
|
||||||
// address of variable
|
// address of variable
|
||||||
|
@ -1288,7 +1332,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!tok->function()) {
|
if (!tok->function() && !tok->variable() && Token::Match(tok, "%name%")) {
|
||||||
// Check if direction (in, out, inout) is specified in the library configuration and use that
|
// Check if direction (in, out, inout) is specified in the library configuration and use that
|
||||||
if (!addressOf && settings) {
|
if (!addressOf && settings) {
|
||||||
const Library::ArgumentChecks::Direction argDirection = settings->library.getArgDirection(tok, 1 + argnr);
|
const Library::ArgumentChecks::Direction argDirection = settings->library.getArgDirection(tok, 1 + argnr);
|
||||||
|
@ -1318,7 +1362,12 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Variable *arg = tok->function()->getArgumentVar(argnr);
|
const Variable *arg = getArgumentVar(tok, argnr);
|
||||||
|
if (!arg) {
|
||||||
|
if (inconclusive)
|
||||||
|
*inconclusive = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (addressOf || (indirect > 0 && arg && arg->isPointer())) {
|
if (addressOf || (indirect > 0 && arg && arg->isPointer())) {
|
||||||
if (!(arg && arg->isConst()))
|
if (!(arg && arg->isConst()))
|
||||||
|
|
|
@ -2054,6 +2054,8 @@ void Token::type(const ::Type *t)
|
||||||
|
|
||||||
const ::Type *Token::typeOf(const Token *tok)
|
const ::Type *Token::typeOf(const Token *tok)
|
||||||
{
|
{
|
||||||
|
if (!tok)
|
||||||
|
return nullptr;
|
||||||
if (Token::simpleMatch(tok, "return")) {
|
if (Token::simpleMatch(tok, "return")) {
|
||||||
const Scope *scope = tok->scope();
|
const Scope *scope = tok->scope();
|
||||||
if (!scope)
|
if (!scope)
|
||||||
|
@ -2074,6 +2076,8 @@ const ::Type *Token::typeOf(const Token *tok)
|
||||||
if (!function)
|
if (!function)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return function->retType;
|
return function->retType;
|
||||||
|
} else if (Token::Match(tok->previous(), "%type% (|{")) {
|
||||||
|
return typeOf(tok->previous());
|
||||||
} else if (Token::simpleMatch(tok, "=")) {
|
} else if (Token::simpleMatch(tok, "=")) {
|
||||||
return Token::typeOf(tok->astOperand1());
|
return Token::typeOf(tok->astOperand1());
|
||||||
} else if (Token::simpleMatch(tok, ".")) {
|
} else if (Token::simpleMatch(tok, ".")) {
|
||||||
|
|
|
@ -1983,6 +1983,63 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
// #9710
|
||||||
|
check("class a {\n"
|
||||||
|
" void operator()(int& i) const {\n"
|
||||||
|
" i++;\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(int& i) {\n"
|
||||||
|
" a()(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("class a {\n"
|
||||||
|
" void operator()(int& i) const {\n"
|
||||||
|
" i++;\n"
|
||||||
|
" }\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(int& i) {\n"
|
||||||
|
" a x;\n"
|
||||||
|
" x(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("class a {\n"
|
||||||
|
" void operator()(const int& i) const;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(int& i) {\n"
|
||||||
|
" a x;\n"
|
||||||
|
" x(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
check("class a {\n"
|
||||||
|
" void foo(const int& i) const;\n"
|
||||||
|
" void operator()(int& i) const;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(int& i) {\n"
|
||||||
|
" a()(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
|
check("class a {\n"
|
||||||
|
" void operator()(const int& i) const;\n"
|
||||||
|
"};\n"
|
||||||
|
"void f(int& i) {\n"
|
||||||
|
" a()(i);\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("[test.cpp:4]: (style) Parameter 'i' can be declared with const\n", errout.str());
|
||||||
|
|
||||||
|
// #9767
|
||||||
|
check("void fct1(MyClass& object) {\n"
|
||||||
|
" fct2([&](void){}, object);\n"
|
||||||
|
"}\n"
|
||||||
|
"bool fct2(std::function<void()> lambdaExpression, MyClass& object) {\n"
|
||||||
|
" object.modify();\n"
|
||||||
|
"}\n");
|
||||||
|
ASSERT_EQUALS("", errout.str());
|
||||||
|
|
||||||
check("void e();\n"
|
check("void e();\n"
|
||||||
"void g(void);\n"
|
"void g(void);\n"
|
||||||
"void h(void);\n"
|
"void h(void);\n"
|
||||||
|
|
Loading…
Reference in New Issue