Merge pull request #2696 from pfultz2/getTokenArgumentFunction-ast

Fix issue 9710 and 9767: Use AST to get function from argument
This commit is contained in:
Daniel Marjamäki 2020-06-26 09:50:18 +02:00 committed by GitHub
commit cb8396aaf8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 20 deletions

View File

@ -1226,34 +1226,78 @@ const Token * getTokenArgumentFunction(const Token * tok, int& argn)
return nullptr;
}
// goto start of function call and get argn
argn = 0;
while (tok && !Token::simpleMatch(tok, ";") && !isScopeBracket(tok)) {
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();
const Token* argtok = tok;
while(argtok && argtok->astParent() && (!Token::Match(argtok->astParent(), ",|(|{") || argtok->astParent()->isCast())) {
argtok = argtok->astParent();
}
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, "{|("))
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() == ">")
tok = tok->link()->previous();
if (!Token::Match(tok, "%name% [({<]"))
if (!Token::Match(tok, "%name%|(|{"))
return nullptr;
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)
{
if (!tok)
return false;
if(Token::simpleMatch(tok, ","))
return false;
const Token * const tok1 = tok;
// address of variable
@ -1288,7 +1332,7 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
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
if (!addressOf && settings) {
const Library::ArgumentChecks::Direction argDirection = settings->library.getArgDirection(tok, 1 + argnr);
@ -1318,17 +1362,22 @@ bool isVariableChangedByFunctionCall(const Token *tok, int indirect, const Setti
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 (!(arg && arg->isConst()))
if (addressOf || (indirect > 0 && arg->isPointer())) {
if (!arg->isConst())
return true;
// If const is applied to the pointer, then the value can still be modified
if (arg && Token::simpleMatch(arg->typeEndToken(), "* const"))
if (Token::simpleMatch(arg->typeEndToken(), "* const"))
return true;
}
return arg && !arg->isConst() && arg->isReference();
return !arg->isConst() && arg->isReference();
}
bool isVariableChanged(const Token *tok, int indirect, const Settings *settings, bool cpp, int depth)

View File

@ -2054,6 +2054,8 @@ void Token::type(const ::Type *t)
const ::Type *Token::typeOf(const Token *tok)
{
if (!tok)
return nullptr;
if (Token::simpleMatch(tok, "return")) {
const Scope *scope = tok->scope();
if (!scope)
@ -2074,6 +2076,8 @@ const ::Type *Token::typeOf(const Token *tok)
if (!function)
return nullptr;
return function->retType;
} else if (Token::Match(tok->previous(), "%type% (|{")) {
return typeOf(tok->previous());
} else if (Token::simpleMatch(tok, "=")) {
return Token::typeOf(tok->astOperand1());
} else if (Token::simpleMatch(tok, ".")) {

View File

@ -1983,6 +1983,63 @@ private:
"}\n");
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"
"void g(void);\n"
"void h(void);\n"