Parse lambdas as functions (#1955)
* Parse lambdas as functions * Fix issue with missing paren * Fix error when parsing non-existent args * Remove unused function variable
This commit is contained in:
parent
2a17e624d9
commit
e0ced1c415
|
@ -666,9 +666,9 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
|
|||
tok = tok->linkAt(1);
|
||||
} else if (const Token *lambdaEndToken = findLambdaEndToken(tok)) {
|
||||
const Token *lambdaStartToken = lambdaEndToken->link();
|
||||
scopeList.emplace_back(this, tok, scope, Scope::eLambda, lambdaStartToken);
|
||||
scope->nestedList.push_back(&scopeList.back());
|
||||
scope = &scopeList.back();
|
||||
const Token * argStart = lambdaStartToken->astParent();
|
||||
const Token * funcStart = Token::simpleMatch(argStart, "[") ? argStart : argStart->astParent();
|
||||
addGlobalFunction(scope, tok, argStart, funcStart);
|
||||
tok = lambdaStartToken;
|
||||
} else if (tok->str() == "{") {
|
||||
if (isExecutableScope(tok)) {
|
||||
|
@ -1732,6 +1732,10 @@ Function::Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *s
|
|||
type = Function::eOperatorEqual;
|
||||
}
|
||||
|
||||
else if (tokenDef->str() == "[") {
|
||||
type = Function::eLambda;
|
||||
}
|
||||
|
||||
// class constructor/destructor
|
||||
else if (tokenDef->str() == scope->className) {
|
||||
// destructor
|
||||
|
@ -1778,7 +1782,7 @@ Function::Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *s
|
|||
}
|
||||
|
||||
// find the return type
|
||||
if (!isConstructor() && !isDestructor()) {
|
||||
if (!isConstructor() && !isDestructor() && !isLambda()) {
|
||||
// @todo auto type deduction should be checked
|
||||
// @todo attributes and exception specification can also precede trailing return type
|
||||
if (Token::Match(argDef->link()->next(), "const|volatile| &|&&| .")) { // Trailing return type
|
||||
|
@ -2054,13 +2058,16 @@ const Token * Function::constructorMemberInitialization() const
|
|||
Function* SymbolDatabase::addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart)
|
||||
{
|
||||
Function* function = nullptr;
|
||||
for (std::multimap<std::string, const Function *>::iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
|
||||
const Function *f = i->second;
|
||||
if (f->hasBody())
|
||||
continue;
|
||||
if (Function::argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
|
||||
function = const_cast<Function *>(i->second);
|
||||
break;
|
||||
// Lambda functions are always unique
|
||||
if (tok->str() != "[") {
|
||||
for (std::multimap<std::string, const Function *>::iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
|
||||
const Function *f = i->second;
|
||||
if (f->hasBody())
|
||||
continue;
|
||||
if (Function::argsMatch(scope, f->argDef, argStart, emptyString, 0)) {
|
||||
function = const_cast<Function *>(i->second);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3038,6 +3045,8 @@ void Function::addArguments(const SymbolDatabase *symbolDatabase, const Scope *s
|
|||
{
|
||||
// check for non-empty argument list "( ... )"
|
||||
const Token * start = arg ? arg : argDef;
|
||||
if (!Token::simpleMatch(start, "("))
|
||||
return;
|
||||
if (!(start && start->link() != start->next() && !Token::simpleMatch(start, "( void )")))
|
||||
return;
|
||||
|
||||
|
@ -3296,6 +3305,8 @@ Scope::Scope(const SymbolDatabase *check_, const Token *classDef_, const Scope *
|
|||
enumClass = true;
|
||||
nameTok = nameTok->next();
|
||||
}
|
||||
} else if (classDef->str() == "[") {
|
||||
type = Scope::eLambda;
|
||||
} else {
|
||||
type = Scope::eFunction;
|
||||
}
|
||||
|
|
|
@ -705,7 +705,7 @@ class CPPCHECKLIB Function {
|
|||
}
|
||||
|
||||
public:
|
||||
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction };
|
||||
enum Type { eConstructor, eCopyConstructor, eMoveConstructor, eOperatorEqual, eDestructor, eFunction, eLambda };
|
||||
|
||||
Function(const Tokenizer *mTokenizer, const Token *tok, const Scope *scope, const Token *tokDef, const Token *tokArgDef);
|
||||
|
||||
|
@ -731,6 +731,10 @@ public:
|
|||
/** @brief get function in base class that is overridden */
|
||||
const Function *getOverriddenFunction(bool *foundAllBaseClasses = nullptr) const;
|
||||
|
||||
bool isLambda() const {
|
||||
return type==eLambda;
|
||||
}
|
||||
|
||||
bool isConstructor() const {
|
||||
return type==eConstructor ||
|
||||
type==eCopyConstructor ||
|
||||
|
|
|
@ -955,6 +955,17 @@ const Token *Token::findmatch(const Token * const startTok, const char pattern[]
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void Token::function(const Function *f) {
|
||||
mImpl->mFunction = f;
|
||||
if (f) {
|
||||
if (f->isLambda())
|
||||
tokType(eLambda);
|
||||
else
|
||||
tokType(eFunction);
|
||||
} else if (mTokType == eFunction)
|
||||
tokType(eName);
|
||||
}
|
||||
|
||||
void Token::insertToken(const std::string &tokenStr, const std::string &originalNameStr, bool prepend)
|
||||
{
|
||||
Token *newToken;
|
||||
|
|
11
lib/token.h
11
lib/token.h
|
@ -146,6 +146,7 @@ public:
|
|||
eNumber, eString, eChar, eBoolean, eLiteral, eEnumerator, // Literals: Number, String, Character, Boolean, User defined literal (C++11), Enumerator
|
||||
eArithmeticalOp, eComparisonOp, eAssignmentOp, eLogicalOp, eBitOp, eIncDecOp, eExtendedOp, // Operators: Arithmetical, Comparison, Assignment, Logical, Bitwise, ++/--, Extended
|
||||
eBracket, // {, }, <, >: < and > only if link() is set. Otherwise they are comparison operators.
|
||||
eLambda, // A function without a name
|
||||
eOther,
|
||||
eNone
|
||||
};
|
||||
|
@ -765,19 +766,13 @@ public:
|
|||
* Associate this token with given function
|
||||
* @param f Function to be associated
|
||||
*/
|
||||
void function(const Function *f) {
|
||||
mImpl->mFunction = f;
|
||||
if (f)
|
||||
tokType(eFunction);
|
||||
else if (mTokType == eFunction)
|
||||
tokType(eName);
|
||||
}
|
||||
void function(const Function *f);
|
||||
|
||||
/**
|
||||
* @return a pointer to the Function associated with this token.
|
||||
*/
|
||||
const Function *function() const {
|
||||
return mTokType == eFunction ? mImpl->mFunction : nullptr;
|
||||
return mTokType == eFunction || mTokType == eLambda ? mImpl->mFunction : nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1438,14 +1438,13 @@ private:
|
|||
"}\n");
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:3] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning.\n", errout.str());
|
||||
|
||||
// TODO: Variable is not set correctly for this case
|
||||
check("auto f(int b) {\n"
|
||||
" return [=](int a){\n"
|
||||
" a += b;\n"
|
||||
" return [&](){ return a; };\n"
|
||||
" };\n"
|
||||
"}\n");
|
||||
TODO_ASSERT_EQUALS("[test.cpp:3] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning.\n", "", errout.str());
|
||||
ASSERT_EQUALS("[test.cpp:4] -> [test.cpp:2] -> [test.cpp:4]: (error) Returning lambda that captures local variable 'a' that will be invalid when returning.\n", errout.str());
|
||||
|
||||
check("auto g(int& a) {\n"
|
||||
" return [&](){ return a; };\n"
|
||||
|
|
Loading…
Reference in New Issue