Skip to content

Commit 01a2215

Browse files
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
1 parent cb91508 commit 01a2215

7 files changed

Lines changed: 99 additions & 21 deletions

File tree

lib/astutils.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -312,11 +312,11 @@ bool astIsRangeBasedForDecl(const Token* tok)
312312
return Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "(");
313313
}
314314

315-
std::string astCanonicalType(const Token *expr)
315+
std::string astCanonicalType(const Token *expr, bool pointedToType)
316316
{
317317
if (!expr)
318318
return "";
319-
std::pair<const Token*, const Token*> decl = Token::typeDecl(expr, /*pointedToType*/ true);
319+
std::pair<const Token*, const Token*> decl = Token::typeDecl(expr, pointedToType);
320320
if (decl.first && decl.second) {
321321
std::string ret;
322322
for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) {

lib/astutils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ bool astIsRangeBasedForDecl(const Token* tok);
167167
* static const int int
168168
* std::vector<T> std::vector
169169
*/
170-
std::string astCanonicalType(const Token *expr);
170+
std::string astCanonicalType(const Token *expr, bool pointedToType);
171171

172172
/** Is given syntax tree a variable comparison against value */
173173
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);

lib/library.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -978,7 +978,7 @@ std::string Library::getFunctionName(const Token *ftok, bool &error) const
978978
return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
979979
}
980980
if (ftok->str() == "." && ftok->astOperand1()) {
981-
const std::string type = astCanonicalType(ftok->astOperand1());
981+
const std::string type = astCanonicalType(ftok->astOperand1(), ftok->originalName() == "->");
982982
if (type.empty()) {
983983
error = true;
984984
return "";

lib/symboldatabase.cpp

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1303,19 +1303,28 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
13031303
(Token::Match(tok->next()->link(), ") . %name% !!(") ||
13041304
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
13051305
const Type *type = tok->function()->retType;
1306+
Token* membertok;
1307+
if (tok->next()->link()->next()->str() == ".")
1308+
membertok = tok->next()->link()->next()->next();
1309+
else
1310+
membertok = tok->next()->link()->next()->link()->next()->next();
13061311
if (type) {
1307-
Token *membertok;
1308-
if (tok->next()->link()->next()->str() == ".")
1309-
membertok = tok->next()->link()->next()->next();
1310-
else
1311-
membertok = tok->next()->link()->next()->link()->next()->next();
13121312
const Variable *membervar = membertok->variable();
13131313
if (!membervar) {
13141314
if (type->classScope) {
13151315
membervar = type->classScope->getVariable(membertok->str());
13161316
setMemberVar(membervar, membertok, tok->function()->retDef);
13171317
}
13181318
}
1319+
} else if (mSettings.library.detectSmartPointer(tok->function()->retDef)) {
1320+
if (const Token* templateArg = Token::findsimplematch(tok->function()->retDef, "<")) {
1321+
if (const Type* spType = findTypeInNested(templateArg->next(), tok->scope())) {
1322+
if (spType->classScope) {
1323+
const Variable* membervar = spType->classScope->getVariable(membertok->str());
1324+
setMemberVar(membervar, membertok, tok->function()->retDef);
1325+
}
1326+
}
1327+
}
13191328
}
13201329
}
13211330
else if (Token::simpleMatch(tok->astParent(), ".") && tok->next()->str() == "(" &&
@@ -7083,8 +7092,14 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
70837092
const Library::ArgumentChecks::IteratorInfo* info = mSettings.library.getArgIteratorInfo(tok->previous(), 1);
70847093
if (info && info->it) {
70857094
const Token* contTok = args[0];
7086-
if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1())
7095+
if (Token::simpleMatch(args[0]->astOperand1(), ".") && args[0]->astOperand1()->astOperand1()) // .begin()
70877096
contTok = args[0]->astOperand1()->astOperand1();
7097+
else if (Token::simpleMatch(args[0], "(") && args[0]->astOperand2()) // std::begin()
7098+
contTok = args[0]->astOperand2();
7099+
while (Token::simpleMatch(contTok, "[")) // move to container token
7100+
contTok = contTok->astOperand1();
7101+
if (Token::simpleMatch(contTok, "."))
7102+
contTok = contTok->astOperand2();
70887103
if (contTok && contTok->variable() && contTok->variable()->valueType() && contTok->variable()->valueType()->container) {
70897104
ValueType vt;
70907105
vt.type = ValueType::Type::ITERATOR;
@@ -7199,7 +7214,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
71997214
if (tok->str() == "auto" && !tok->valueType()) {
72007215
if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
72017216
continue;
7202-
if (Token::Match(tok->next(), "%name% { [") && isLambdaCaptureList(tok->tokAt(3)))
7217+
if (Token::Match(tok->next(), "%name% {|= [") && isLambdaCaptureList(tok->tokAt(3)))
72037218
continue;
72047219
debugMessage(tok, "autoNoType", "auto token with no type.");
72057220
}

lib/token.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2257,6 +2257,16 @@ std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool poi
22572257
const Variable *var = tok->variable();
22582258
if (!var->typeStartToken() || !var->typeEndToken())
22592259
return {};
2260+
if (pointedToType && astIsSmartPointer(var->nameToken())) {
2261+
const ValueType* vt = var->valueType();
2262+
if (vt && vt->smartPointerTypeToken)
2263+
return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
2264+
}
2265+
if (pointedToType && astIsIterator(var->nameToken())) {
2266+
const ValueType* vt = var->valueType();
2267+
if (vt && vt->containerTypeToken)
2268+
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2269+
}
22602270
std::pair<const Token*, const Token*> result;
22612271
if (Token::simpleMatch(var->typeStartToken(), "auto")) {
22622272
const Token * tok2 = var->declEndToken();
@@ -2306,16 +2316,6 @@ std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool poi
23062316
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
23072317
}
23082318
}
2309-
if (pointedToType && astIsSmartPointer(var->nameToken())) {
2310-
const ValueType* vt = var->valueType();
2311-
if (vt && vt->smartPointerTypeToken)
2312-
return { vt->smartPointerTypeToken, vt->smartPointerTypeToken->linkAt(-1) };
2313-
}
2314-
if (pointedToType && astIsIterator(var->nameToken())) {
2315-
const ValueType* vt = var->valueType();
2316-
if (vt && vt->containerTypeToken)
2317-
return { vt->containerTypeToken, vt->containerTypeToken->linkAt(-1) };
2318-
}
23192319
if (result.first)
23202320
return result;
23212321
return {var->typeStartToken(), var->typeEndToken()->next()};

test/testfunctions.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,18 @@ class TestFunctions : public TestFixture {
20032003
"}\n");
20042004
ASSERT_EQUALS("", errout.str());
20052005

2006+
check("struct T;\n"
2007+
"std::shared_ptr<T> get();\n"
2008+
"void f(int i) {\n"
2009+
" auto p = get();\n"
2010+
" p->h(i);\n"
2011+
" p.reset(nullptr);\n"
2012+
"}\n");
2013+
TODO_ASSERT_EQUALS("[test.cpp:5]: (information) --check-library: There is no matching configuration for function T::h()\n",
2014+
"[test.cpp:5]: (information) --check-library: There is no matching configuration for function T::h()\n"
2015+
"[test.cpp:6]: (information) --check-library: There is no matching configuration for function std::shared_ptr::reset()\n",
2016+
errout.str());
2017+
20062018
settings = settings_old;
20072019
}
20082020

test/testsymboldatabase.cpp

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8241,6 +8241,57 @@ class TestSymbolDatabase : public TestFixture {
82418241
const Type* smpType = tok->valueType()->smartPointerType;
82428242
ASSERT(smpType && smpType == tok->scope()->functionOf->definedType);
82438243
}
8244+
{
8245+
GET_SYMBOL_DB("struct S { int i; };\n"
8246+
"void f(const std::vector<S>& v) {\n"
8247+
" auto it = std::find_if(std::begin(v), std::end(v), [](const S& s) { return s.i != 0; });\n"
8248+
"}\n");
8249+
ASSERT_EQUALS("", errout.str());
8250+
8251+
const Token* tok = tokenizer.tokens();
8252+
tok = Token::findsimplematch(tok, "auto");
8253+
ASSERT(tok && tok->valueType());
8254+
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
8255+
}
8256+
{
8257+
GET_SYMBOL_DB("struct S { std::vector<int> v; };\n"
8258+
"struct T { S s; };\n"
8259+
"void f(T* t) {\n"
8260+
" auto it = std::find(t->s.v.begin(), t->s.v.end(), 0);\n"
8261+
"}\n");
8262+
ASSERT_EQUALS("", errout.str());
8263+
8264+
const Token* tok = tokenizer.tokens();
8265+
tok = Token::findsimplematch(tok, "auto");
8266+
ASSERT(tok && tok->valueType());
8267+
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
8268+
}
8269+
{
8270+
GET_SYMBOL_DB("struct S { std::vector<int> v[1][1]; };\n"
8271+
"struct T { S s[1]; };\n"
8272+
"void f(T * t) {\n"
8273+
" auto it = std::find(t->s[0].v[0][0].begin(), t->s[0].v[0][0].end(), 0);\n"
8274+
"}\n");
8275+
ASSERT_EQUALS("", errout.str());
8276+
8277+
const Token* tok = tokenizer.tokens();
8278+
tok = Token::findsimplematch(tok, "auto");
8279+
ASSERT(tok && tok->valueType());
8280+
ASSERT_EQUALS("iterator(std :: vector <)", tok->valueType()->str());
8281+
}
8282+
{
8283+
GET_SYMBOL_DB("struct T { std::set<std::string> s; };\n"
8284+
"struct U { std::shared_ptr<T> get(); };\n"
8285+
"void f(U* u) {\n"
8286+
" for (const auto& str : u->get()->s) {}\n"
8287+
"}\n");
8288+
ASSERT_EQUALS("", errout.str());
8289+
8290+
const Token* tok = tokenizer.tokens();
8291+
tok = Token::findsimplematch(tok, "auto");
8292+
ASSERT(tok && tok->valueType());
8293+
ASSERT_EQUALS("container(std :: string|wstring|u16string|u32string)", tok->valueType()->str());
8294+
}
82448295
}
82458296

82468297
void valueTypeThis() {

0 commit comments

Comments
 (0)