Fix scope for function returning rvalue reference, insert std:: in return statement (#5119)
* Fix scope for function returning rvalue reference * Insert std:: in return statement * Fix failing test
This commit is contained in:
parent
4dbbae62a7
commit
901b775471
|
@ -2174,7 +2174,7 @@ void CheckOther::checkMisusedScopedObject()
|
|||
}
|
||||
if (tok->isAssignmentOp() && Token::simpleMatch(tok->astOperand1(), "(") && tok->astOperand1()->astOperand1()) {
|
||||
if (const Function* ftok = tok->astOperand1()->astOperand1()->function()) {
|
||||
if (ftok->retType && Token::Match(ftok->retType->classDef, "class|struct|union") && !Function::returnsReference(ftok))
|
||||
if (ftok->retType && Token::Match(ftok->retType->classDef, "class|struct|union") && !Function::returnsReference(ftok, /*unknown*/ false, /*includeRValueRef*/ true))
|
||||
misusedScopeObjectError(tok->next(), ftok->retType->name(), /*isAssignment*/ true);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1833,7 +1833,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
|||
|
||||
// regular function?
|
||||
else if (Token::Match(tok, "%name% (") && !isReservedName(tok->str()) && tok->previous() &&
|
||||
(Token::Match(tok->previous(), "%name%|>|&|*|::|~") || // Either a return type or scope qualifier in front of tok
|
||||
(Token::Match(tok->previous(), "%name%|>|&|&&|*|::|~") || // Either a return type or scope qualifier in front of tok
|
||||
outerScope->isClassOrStructOrUnion())) { // or a ctor/dtor
|
||||
const Token* tok1 = tok->previous();
|
||||
const Token* tok2 = tok->next()->link()->next();
|
||||
|
@ -1874,7 +1874,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
|||
// done if constructor or destructor
|
||||
if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
|
||||
// skip over pointers and references
|
||||
while (Token::Match(tok1, "%type%|*|&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == "const"))
|
||||
while (Token::Match(tok1, "%type%|*|&|&&") && !endsWith(tok1->str(), ':') && (!isReservedName(tok1->str()) || tok1->str() == "const"))
|
||||
tok1 = tok1->previous();
|
||||
|
||||
// skip over decltype
|
||||
|
@ -3046,10 +3046,10 @@ bool Function::returnsConst(const Function* function, bool unknown)
|
|||
});
|
||||
}
|
||||
|
||||
bool Function::returnsReference(const Function* function, bool unknown)
|
||||
bool Function::returnsReference(const Function* function, bool unknown, bool includeRValueRef)
|
||||
{
|
||||
return checkReturns(function, unknown, false, [](UNUSED const Token* defStart, const Token* defEnd) {
|
||||
return Token::simpleMatch(defEnd->previous(), "&");
|
||||
return checkReturns(function, unknown, false, [includeRValueRef](UNUSED const Token* defStart, const Token* defEnd) {
|
||||
return includeRValueRef ? Token::Match(defEnd->previous(), "&|&&") : Token::simpleMatch(defEnd->previous(), "&");
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -936,7 +936,7 @@ public:
|
|||
static bool returnsConst(const Function* function, bool unknown = false);
|
||||
|
||||
static bool returnsPointer(const Function* function, bool unknown = false);
|
||||
static bool returnsReference(const Function* function, bool unknown = false);
|
||||
static bool returnsReference(const Function* function, bool unknown = false, bool includeRValueRef = false);
|
||||
static bool returnsStandardType(const Function* function, bool unknown = false);
|
||||
|
||||
static bool returnsVoid(const Function* function, bool unknown = false);
|
||||
|
|
|
@ -9439,7 +9439,7 @@ void Tokenizer::simplifyNamespaceStd()
|
|||
const Token *start = tok;
|
||||
while (Token::Match(start->previous(), "%type%|*|&"))
|
||||
start = start->previous();
|
||||
if (start != tok && start->isName() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
|
||||
if (start != tok && start->isName() && !start->isKeyword() && (!start->previous() || Token::Match(start->previous(), "[;{}]")))
|
||||
userFunctions.insert(tok->str());
|
||||
}
|
||||
if (userFunctions.find(tok->str()) == userFunctions.end() && mSettings->library.matchArguments(tok, "std::" + tok->str()))
|
||||
|
|
|
@ -390,6 +390,7 @@ private:
|
|||
|
||||
TEST_CASE(isFunction1); // UNKNOWN_MACRO(a,b) { .. }
|
||||
TEST_CASE(isFunction2);
|
||||
TEST_CASE(isFunction3);
|
||||
|
||||
TEST_CASE(findFunction1);
|
||||
TEST_CASE(findFunction2); // mismatch: parameter passed by address => reference argument
|
||||
|
@ -5839,6 +5840,18 @@ private:
|
|||
ASSERT(db->findScopeByName("PTRRELOC") == nullptr);
|
||||
}
|
||||
|
||||
void isFunction3() {
|
||||
GET_SYMBOL_DB("std::vector<int>&& f(std::vector<int>& v) {\n"
|
||||
" v.push_back(1);\n"
|
||||
" return std::move(v);\n"
|
||||
"}");
|
||||
ASSERT(db != nullptr);
|
||||
ASSERT_EQUALS(2, db->scopeList.size());
|
||||
const Token* ret = Token::findsimplematch(tokenizer.tokens(), "return");
|
||||
ASSERT(ret != nullptr);
|
||||
ASSERT(ret->scope() && ret->scope()->type == Scope::eFunction);
|
||||
}
|
||||
|
||||
|
||||
void findFunction1() {
|
||||
GET_SYMBOL_DB("int foo(int x);\n" /* 1 */
|
||||
|
|
|
@ -4711,6 +4711,17 @@ private:
|
|||
"void f() { string str = to_string(1); }\n";
|
||||
expected = "void f ( ) { std :: string str ; str = std :: to_string ( 1 ) ; }";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
|
||||
code = "using namespace std;\n"
|
||||
"vector<int>&& f(vector<int>& v) {\n"
|
||||
" v.push_back(1);\n"
|
||||
" return move(v);\n"
|
||||
"}\n";
|
||||
expected = "std :: vector < int > && f ( std :: vector < int > & v ) {\n"
|
||||
"v . push_back ( 1 ) ;\n"
|
||||
"return std :: move ( v ) ;\n"
|
||||
"}";
|
||||
ASSERT_EQUALS(expected, tokenizeAndStringify(code));
|
||||
}
|
||||
|
||||
void microsoftMemory() {
|
||||
|
|
Loading…
Reference in New Issue