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:
parent
cb915085ea
commit
01a22159b8
|
@ -312,11 +312,11 @@ bool astIsRangeBasedForDecl(const Token* tok)
|
||||||
return Token::simpleMatch(tok->astParent(), ":") && Token::simpleMatch(tok->astParent()->astParent(), "(");
|
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)
|
if (!expr)
|
||||||
return "";
|
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) {
|
if (decl.first && decl.second) {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) {
|
for (const Token *type = decl.first; Token::Match(type,"%name%|::") && type != decl.second; type = type->next()) {
|
||||||
|
|
|
@ -167,7 +167,7 @@ bool astIsRangeBasedForDecl(const Token* tok);
|
||||||
* static const int int
|
* static const int int
|
||||||
* std::vector<T> std::vector
|
* 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 */
|
/** 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);
|
const Token * astIsVariableComparison(const Token *tok, const std::string &comp, const std::string &rhs, const Token **vartok=nullptr);
|
||||||
|
|
|
@ -978,7 +978,7 @@ std::string Library::getFunctionName(const Token *ftok, bool &error) const
|
||||||
return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
|
return getFunctionName(ftok->astOperand1(),error) + "::" + getFunctionName(ftok->astOperand2(),error);
|
||||||
}
|
}
|
||||||
if (ftok->str() == "." && ftok->astOperand1()) {
|
if (ftok->str() == "." && ftok->astOperand1()) {
|
||||||
const std::string type = astCanonicalType(ftok->astOperand1());
|
const std::string type = astCanonicalType(ftok->astOperand1(), ftok->originalName() == "->");
|
||||||
if (type.empty()) {
|
if (type.empty()) {
|
||||||
error = true;
|
error = true;
|
||||||
return "";
|
return "";
|
||||||
|
|
|
@ -1303,12 +1303,12 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
|
||||||
(Token::Match(tok->next()->link(), ") . %name% !!(") ||
|
(Token::Match(tok->next()->link(), ") . %name% !!(") ||
|
||||||
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
|
(Token::Match(tok->next()->link(), ") [") && Token::Match(tok->next()->link()->next()->link(), "] . %name% !!(")))) {
|
||||||
const Type *type = tok->function()->retType;
|
const Type *type = tok->function()->retType;
|
||||||
if (type) {
|
|
||||||
Token* membertok;
|
Token* membertok;
|
||||||
if (tok->next()->link()->next()->str() == ".")
|
if (tok->next()->link()->next()->str() == ".")
|
||||||
membertok = tok->next()->link()->next()->next();
|
membertok = tok->next()->link()->next()->next();
|
||||||
else
|
else
|
||||||
membertok = tok->next()->link()->next()->link()->next()->next();
|
membertok = tok->next()->link()->next()->link()->next()->next();
|
||||||
|
if (type) {
|
||||||
const Variable *membervar = membertok->variable();
|
const Variable *membervar = membertok->variable();
|
||||||
if (!membervar) {
|
if (!membervar) {
|
||||||
if (type->classScope) {
|
if (type->classScope) {
|
||||||
|
@ -1316,6 +1316,15 @@ void SymbolDatabase::createSymbolDatabaseSetVariablePointers()
|
||||||
setMemberVar(membervar, membertok, tok->function()->retDef);
|
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() == "(" &&
|
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);
|
const Library::ArgumentChecks::IteratorInfo* info = mSettings.library.getArgIteratorInfo(tok->previous(), 1);
|
||||||
if (info && info->it) {
|
if (info && info->it) {
|
||||||
const Token* contTok = args[0];
|
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();
|
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) {
|
if (contTok && contTok->variable() && contTok->variable()->valueType() && contTok->variable()->valueType()->container) {
|
||||||
ValueType vt;
|
ValueType vt;
|
||||||
vt.type = ValueType::Type::ITERATOR;
|
vt.type = ValueType::Type::ITERATOR;
|
||||||
|
@ -7199,7 +7214,7 @@ void SymbolDatabase::setValueTypeInTokenList(bool reportDebugWarnings, Token *to
|
||||||
if (tok->str() == "auto" && !tok->valueType()) {
|
if (tok->str() == "auto" && !tok->valueType()) {
|
||||||
if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
|
if (Token::Match(tok->next(), "%name% ; %name% = [") && isLambdaCaptureList(tok->tokAt(5)))
|
||||||
continue;
|
continue;
|
||||||
if (Token::Match(tok->next(), "%name% { [") && isLambdaCaptureList(tok->tokAt(3)))
|
if (Token::Match(tok->next(), "%name% {|= [") && isLambdaCaptureList(tok->tokAt(3)))
|
||||||
continue;
|
continue;
|
||||||
debugMessage(tok, "autoNoType", "auto token with no type.");
|
debugMessage(tok, "autoNoType", "auto token with no type.");
|
||||||
}
|
}
|
||||||
|
|
|
@ -2257,6 +2257,16 @@ std::pair<const Token*, const Token*> Token::typeDecl(const Token* tok, bool poi
|
||||||
const Variable *var = tok->variable();
|
const Variable *var = tok->variable();
|
||||||
if (!var->typeStartToken() || !var->typeEndToken())
|
if (!var->typeStartToken() || !var->typeEndToken())
|
||||||
return {};
|
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;
|
std::pair<const Token*, const Token*> result;
|
||||||
if (Token::simpleMatch(var->typeStartToken(), "auto")) {
|
if (Token::simpleMatch(var->typeStartToken(), "auto")) {
|
||||||
const Token * tok2 = var->declEndToken();
|
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) };
|
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)
|
if (result.first)
|
||||||
return result;
|
return result;
|
||||||
return {var->typeStartToken(), var->typeEndToken()->next()};
|
return {var->typeStartToken(), var->typeEndToken()->next()};
|
||||||
|
|
|
@ -2003,6 +2003,18 @@ private:
|
||||||
"}\n");
|
"}\n");
|
||||||
ASSERT_EQUALS("", errout.str());
|
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;
|
settings = settings_old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8241,6 +8241,57 @@ private:
|
||||||
const Type* smpType = tok->valueType()->smartPointerType;
|
const Type* smpType = tok->valueType()->smartPointerType;
|
||||||
ASSERT(smpType && smpType == tok->scope()->functionOf->definedType);
|
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() {
|
void valueTypeThis() {
|
||||||
|
|
Loading…
Reference in New Issue