Fix autoNoType with std::begin() / function returning smart ptr (#4919)

* Fix autoNoType with std::begin()

* Suppress warning for const lambda

* Fix autoNoType with function returning smart ptr

* Handle more complex expression

* Fix scope with auto and smart ptr

* Handle smart pointers and iterators first
This commit is contained in:
chrchr-github 2023-04-01 09:38:40 +02:00 committed by GitHub
parent cb915085ea
commit 01a22159b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 99 additions and 21 deletions

View File

@ -312,11 +312,11 @@ bool astIsRangeBasedForDecl(const Token* tok)
return Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "(");
}
std::string astCanonicalType(const Token *expr)
std::string astCanonicalType(const Token *expr, bool pointedToType)
{
if (!expr)
return "";
std::pair<const Token*, const Token*> decl = Token::typeDecl(expr, /*pointedToType*/ true);
std::pair<const Token*, const Token*> decl = Token::typeDecl(expr, pointedToType);
if (decl.first && decl.second) {
std::string ret;
for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) {

View File

@ -167,7 +167,7 @@ bool astIsRangeBasedForDecl(const Token* tok);
* static const int int
* std::vector<T> std::vector
*/
std::string astCanonicalType(const Token *expr);
std::string astCanonicalType(const Token *expr, bool pointedToType);
/** Is given syntax tree a variable comparison against value */
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);

View File

@ -978,7 +978,7 @@ std::string Library::getFunctionName(const Token *ftok, bool &error) const
return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
}
if (ftok->str() == "." && ftok->astOperand1()) {
const std::string type = astCanonicalType(ftok->astOperand1());
const std::string type = astCanonicalType(ftok->astOperand1(), ftok->originalName() == "->");
if (type.empty()) {
error = true;
return "";

View File

@ -1303,12 +1303,12 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
(Token::Match(tok->next()->link(), ") . %name% !!(") ||
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
const Type *type = tok->function()->retType;
if (type) {
Token *membertok;
Token* membertok;
if (tok->next()->link()->next()->str() == ".")
membertok = tok->next()->link()->next()->next();
else
membertok = tok->next()->link()->next()->link()->next()->next();
if (type) {
const Variable *membervar = membertok->variable();
if (!membervar) {
if (type->classScope) {
@ -1316,6 +1316,15 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
setMemberVar(membervar, membertok, tok->function()->retDef);
}
}
} else if (mSettings.library.detectSmartPointer(tok->function()->retDef)) {
if (const Token* templateArg = Token::findsimplematch(tok->function()->retDef, "<")) {
if (const Type* spType = findTypeInNested(templateArg->next(), tok->scope())) {
if (spType->classScope) {
const Variable* membervar = spType->classScope->getVariable(membertok->str());
setMemberVar(membervar, membertok, tok->function()->retDef);
}
}
}
}
}
else if (Token::simpleMatch(tok->astParent(), ".") && tok->next()->str() == "(" &&
@ -7083,8 +7092,14 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
const Library::ArgumentChecks::IteratorInfo* info = mSettings.library.getArgIteratorInfo(tok->previous(), 1);
if (info && info->it) {
const Token* contTok = args[0];
if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1())
if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1()) // .begin()
contTok = args[0]->astOperand1()->astOperand1();
else if (Token::simpleMatch(args[0], "(") && args[0]->astOperand2()) // std::begin()
contTok = args[0]->astOperand2();
while (Token::simpleMatch(contTok, "[")) // move to container token
contTok = contTok->astOperand1();
if (Token::simpleMatch(contTok, "."))
contTok = contTok->astOperand2();
if (contTok && contTok->variable() && contTok->variable()->valueType() && contTok->variable()->valueType()->container) {
ValueType vt;
vt.type = ValueType::Type::ITERATOR;
@ -7199,7 +7214,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
if (tok->str() == "auto" && !tok->valueType()) {
if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
continue;
if (Token::Match(tok->next(), "%name% { [") && isLambdaCaptureList(tok->tokAt(3)))
if (Token::Match(tok->next(), "%name% {|= [") && isLambdaCaptureList(tok->tokAt(3)))
continue;
debugMessage(tok, "autoNoType", "auto token with no type.");
}

View File

@ -2257,6 +2257,16 @@ std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool poi
const Variable *var = tok->variable();
if (!var->typeStartToken() || !var->typeEndToken())
return {};
if (pointedToType && astIsSmartPointer(var->nameToken())) {
const ValueType* vt = var->valueType();
if (vt && vt->smartPointerTypeToken)
return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
}
if (pointedToType && astIsIterator(var->nameToken())) {
const ValueType* vt = var->valueType();
if (vt && vt->containerTypeToken)
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
}
std::pair<const Token*, const Token*> result;
if (Token::simpleMatch(var->typeStartToken(), "auto")) {
const Token * tok2 = var->declEndToken();
@ -2306,16 +2316,6 @@ std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool poi
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
}
}
if (pointedToType && astIsSmartPointer(var->nameToken())) {
const ValueType* vt = var->valueType();
if (vt && vt->smartPointerTypeToken)
return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
}
if (pointedToType && astIsIterator(var->nameToken())) {
const ValueType* vt = var->valueType();
if (vt && vt->containerTypeToken)
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
}
if (result.first)
return result;
return {var->typeStartToken(), var->typeEndToken()->next()};

View File

@ -2003,6 +2003,18 @@ private:
"}\n");
ASSERT_EQUALS("", errout.str());
check("struct T;\n"
"std::shared_ptr<T> get();\n"
"void f(int i) {\n"
" auto p = get();\n"
" p->h(i);\n"
" p.reset(nullptr);\n"
"}\n");
TODO_ASSERT_EQUALS("[test.cpp:5]: (information) --check-library: There is no matching configuration for function T::h()\n",
"[test.cpp:5]: (information) --check-library: There is no matching configuration for function T::h()\n"
"[test.cpp:6]: (information) --check-library: There is no matching configuration for function std::shared_ptr::reset()\n",
errout.str());
settings = settings_old;
}

View File

@ -8241,6 +8241,57 @@ private:
const Type* smpType = tok->valueType()->smartPointerType;
ASSERT(smpType && smpType == tok->scope()->functionOf->definedType);
}
{
GET_SYMBOL_DB("struct S { int i; };\n"
"void f(const std::vector<S>& v) {\n"
" auto it = std::find_if(std::begin(v), std::end(v), [](const S& s) { return s.i != 0; });\n"
"}\n");
ASSERT_EQUALS("", errout.str());
const Token* tok = tokenizer.tokens();
tok = Token::findsimplematch(tok, "auto");
ASSERT(tok && tok->valueType());
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
}
{
GET_SYMBOL_DB("struct S { std::vector<int> v; };\n"
"struct T { S s; };\n"
"void f(T* t) {\n"
" auto it = std::find(t->s.v.begin(), t->s.v.end(), 0);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
const Token* tok = tokenizer.tokens();
tok = Token::findsimplematch(tok, "auto");
ASSERT(tok && tok->valueType());
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
}
{
GET_SYMBOL_DB("struct S { std::vector<int> v[1][1]; };\n"
"struct T { S s[1]; };\n"
"void f(T * t) {\n"
" auto it = std::find(t->s[0].v[0][0].begin(), t->s[0].v[0][0].end(), 0);\n"
"}\n");
ASSERT_EQUALS("", errout.str());
const Token* tok = tokenizer.tokens();
tok = Token::findsimplematch(tok, "auto");
ASSERT(tok && tok->valueType());
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
}
{
GET_SYMBOL_DB("struct T { std::set<std::string> s; };\n"
"struct U { std::shared_ptr<T> get(); };\n"
"void f(U* u) {\n"
" for (const auto& str : u->get()->s) {}\n"
"}\n");
ASSERT_EQUALS("", errout.str());
const Token* tok = tokenizer.tokens();
tok = Token::findsimplematch(tok, "auto");
ASSERT(tok && tok->valueType());
ASSERT_EQUALS("container(std :: string|wstring|u16string|u32string)", tok->valueType()->str());
}
}
void valueTypeThis() {