Support trailing return types (C++11)
This commit is contained in:
parent
91e38f3eb9
commit
801fd8f96a
|
@ -348,6 +348,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
else if (scope->type == Scope::eClass || scope->type == Scope::eStruct) {
|
else if (scope->type == Scope::eClass || scope->type == Scope::eStruct) {
|
||||||
const Token *funcStart = nullptr;
|
const Token *funcStart = nullptr;
|
||||||
const Token *argStart = nullptr;
|
const Token *argStart = nullptr;
|
||||||
|
const Token *declEnd = nullptr;
|
||||||
|
|
||||||
// What section are we in..
|
// What section are we in..
|
||||||
if (tok->str() == "private:")
|
if (tok->str() == "private:")
|
||||||
|
@ -368,7 +369,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
|
|
||||||
// class function?
|
// class function?
|
||||||
else if (isFunction(tok, scope, &funcStart, &argStart)) {
|
else if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
|
||||||
if (tok->previous()->str() != "::") {
|
if (tok->previous()->str() != "::") {
|
||||||
Function function;
|
Function function;
|
||||||
|
|
||||||
|
@ -455,11 +456,15 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
|
|
||||||
// find the return type
|
// find the return type
|
||||||
if (!function.isConstructor() && !function.isDestructor()) {
|
if (!function.isConstructor() && !function.isDestructor()) {
|
||||||
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union|enum"))
|
if (argStart->link()->strAt(1) == ".") // Trailing return type
|
||||||
tok1 = tok1->next();
|
function.retDef = argStart->link()->tokAt(2);
|
||||||
|
else {
|
||||||
|
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union|enum"))
|
||||||
|
tok1 = tok1->next();
|
||||||
|
|
||||||
if (tok1)
|
if (tok1)
|
||||||
function.retDef = tok1;
|
function.retDef = tok1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token *end = function.argDef->link();
|
const Token *end = function.argDef->link();
|
||||||
|
@ -635,21 +640,12 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
} else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) {
|
} else if (scope->type == Scope::eNamespace || scope->type == Scope::eGlobal) {
|
||||||
const Token *funcStart = nullptr;
|
const Token *funcStart = nullptr;
|
||||||
const Token *argStart = nullptr;
|
const Token *argStart = nullptr;
|
||||||
|
const Token *declEnd = nullptr;
|
||||||
|
|
||||||
// function?
|
// function?
|
||||||
if (isFunction(tok, scope, &funcStart, &argStart)) {
|
if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
|
||||||
const Token* scopeBegin = argStart->link()->next();
|
|
||||||
if (scopeBegin->isName()) { // Jump behind 'const' or unknown Macro
|
|
||||||
scopeBegin = scopeBegin->next();
|
|
||||||
if (_tokenizer->isCPP() && scopeBegin->str() == "throw")
|
|
||||||
scopeBegin = scopeBegin->next();
|
|
||||||
|
|
||||||
if (scopeBegin->link() && scopeBegin->str() == "(") // Jump behind unknown macro of type THROW(...)
|
|
||||||
scopeBegin = scopeBegin->link()->next();
|
|
||||||
}
|
|
||||||
|
|
||||||
// has body?
|
// has body?
|
||||||
if (Token::Match(scopeBegin, "&|&&| {|:")) {
|
if (declEnd && declEnd->str() == "{") {
|
||||||
tok = funcStart;
|
tok = funcStart;
|
||||||
|
|
||||||
// class function
|
// class function
|
||||||
|
@ -717,7 +713,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
_tokenizer->syntaxError(tok);
|
_tokenizer->syntaxError(tok);
|
||||||
}
|
}
|
||||||
// function prototype?
|
// function prototype?
|
||||||
else if (scopeBegin->str() == ";") {
|
else if (declEnd && declEnd->str() == ";") {
|
||||||
bool newFunc = true; // Is this function already in the database?
|
bool newFunc = true; // Is this function already in the database?
|
||||||
for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
|
for (std::multimap<std::string, const Function *>::const_iterator i = scope->functionMap.find(tok->str()); i != scope->functionMap.end() && i->first == tok->str(); ++i) {
|
||||||
if (Function::argsMatch(scope, i->second->argDef->next(), argStart->next(), "", 0)) {
|
if (Function::argsMatch(scope, i->second->argDef->next(), argStart->next(), "", 0)) {
|
||||||
|
@ -766,7 +762,7 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = scopeBegin;
|
tok = declEnd;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1388,19 +1384,20 @@ SymbolDatabase::~SymbolDatabase()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart) const
|
bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const
|
||||||
{
|
{
|
||||||
if (tok->varId())
|
if (tok->varId())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
|
// function returning function pointer? '... ( ... %name% ( ... ))( ... ) {'
|
||||||
if (tok->str() == "(" &&
|
if (tok->str() == "(" && tok->strAt(1) != "*" &&
|
||||||
tok->link()->previous()->str() == ")") {
|
tok->link()->previous()->str() == ")") {
|
||||||
const Token* tok2 = tok->link()->next();
|
const Token* tok2 = tok->link()->next();
|
||||||
if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) {
|
if (tok2 && tok2->str() == "(" && Token::Match(tok2->link()->next(), "{|;|const|=")) {
|
||||||
const Token* argStartTok = tok->link()->previous()->link();
|
const Token* argStartTok = tok->link()->previous()->link();
|
||||||
*funcStart = argStartTok->previous();
|
*funcStart = argStartTok->previous();
|
||||||
*argStart = argStartTok;
|
*argStart = argStartTok;
|
||||||
|
*declEnd = Token::findmatch(tok2->link()->next(), "{|;");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1411,6 +1408,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
||||||
tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok
|
tok->strAt(-1) == "::" || tok->strAt(-1) == "~" || // or a scope qualifier in front of tok
|
||||||
outerScope->isClassOrStruct())) { // or a ctor/dtor
|
outerScope->isClassOrStruct())) { // or a ctor/dtor
|
||||||
const Token* tok1 = tok->previous();
|
const Token* tok1 = tok->previous();
|
||||||
|
const Token* tok2 = tok->next()->link()->next();
|
||||||
|
|
||||||
// skip over destructor "~"
|
// skip over destructor "~"
|
||||||
if (tok1->str() == "~")
|
if (tok1->str() == "~")
|
||||||
|
@ -1426,6 +1424,22 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
||||||
tok1 = tok1->tokAt(-1);
|
tok1 = tok1->tokAt(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// skip over const, noexcept, throw and override specifiers
|
||||||
|
while (Token::Match(tok2, "const|noexcept|throw|override")) {
|
||||||
|
tok2 = tok2->next();
|
||||||
|
if (tok2 && tok2->str() == "(")
|
||||||
|
tok2 = tok2->link()->next();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tok2 && tok2->str() == ".") {
|
||||||
|
for (tok2 = tok2->next(); tok2; tok2 = tok2->next()) {
|
||||||
|
if (Token::Match(tok2, ";|{|="))
|
||||||
|
break;
|
||||||
|
if (tok2->link() && Token::Match(tok2, "<|[|("))
|
||||||
|
tok2 = tok2->link();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// done if constructor or destructor
|
// done if constructor or destructor
|
||||||
if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
|
if (!Token::Match(tok1, "{|}|;|public:|protected:|private:") && tok1) {
|
||||||
// skip over pointers and references
|
// skip over pointers and references
|
||||||
|
@ -1468,21 +1482,16 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token* tok2 = tok->next()->link()->next();
|
|
||||||
if (tok2 &&
|
if (tok2 &&
|
||||||
(Token::Match(tok2, "const| ;|{|=") ||
|
(Token::Match(tok2, ";|{|=") ||
|
||||||
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
|
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% ;|{")) ||
|
||||||
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
|
(tok2->isUpperCaseName() && Token::Match(tok2, "%name% (") && tok2->next()->link()->strAt(1) == "{") ||
|
||||||
Token::Match(tok2, ": ::| %name% (|::|<|{") ||
|
Token::Match(tok2, ": ::| %name% (|::|<|{") ||
|
||||||
Token::Match(tok2, "const| &|&&| ;|{") ||
|
Token::Match(tok2, "&|&&| ;|{") ||
|
||||||
Token::Match(tok2, "const| override ;|{") ||
|
Token::Match(tok2, "= delete|default ;"))) {
|
||||||
Token::Match(tok2, "= delete|default ;") ||
|
|
||||||
Token::Match(tok2, "const| noexcept {|:|;|=") ||
|
|
||||||
(Token::Match(tok2, "const| noexcept|throw (") &&
|
|
||||||
tok2->str() == "const" ? (tok2->tokAt(2) && Token::Match(tok2->linkAt(2), ") const| {|:|;|=")) :
|
|
||||||
(tok2->next() && Token::Match(tok2->next()->link(), ") {|:|;|="))))) {
|
|
||||||
*funcStart = tok;
|
*funcStart = tok;
|
||||||
*argStart = tok->next();
|
*argStart = tok->next();
|
||||||
|
*declEnd = Token::findmatch(tok2, "{|;");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1495,6 +1504,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
||||||
(!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
|
(!tok->previous() || Token::Match(tok->previous(), "[;{}]"))) {
|
||||||
*funcStart = tok;
|
*funcStart = tok;
|
||||||
*argStart = tok->next();
|
*argStart = tok->next();
|
||||||
|
*declEnd = tok->linkAt(1)->next();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1506,6 +1516,7 @@ bool SymbolDatabase::isFunction(const Token *tok, const Scope* outerScope, const
|
||||||
Token::Match(tok->next()->link()->next()->link(), ") const| noexcept {|;|(")) {
|
Token::Match(tok->next()->link()->next()->link(), ") const| noexcept {|;|(")) {
|
||||||
*funcStart = tok;
|
*funcStart = tok;
|
||||||
*argStart = tok2->link();
|
*argStart = tok2->link();
|
||||||
|
*declEnd = Token::findmatch(tok2->next(), "{|;");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1880,7 +1891,9 @@ Function* SymbolDatabase::addGlobalFunctionDecl(Scope*& scope, const Token *tok,
|
||||||
tok1 = tok1->next();
|
tok1 = tok1->next();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tok1)
|
if (function.argDef->link()->strAt(1) == ".")
|
||||||
|
function.retDef = function.argDef->link()->tokAt(2);
|
||||||
|
else if (tok1)
|
||||||
function.retDef = tok1;
|
function.retDef = tok1;
|
||||||
|
|
||||||
scope->addFunction(function);
|
scope->addFunction(function);
|
||||||
|
@ -4444,7 +4457,7 @@ void SymbolDatabase::setValueTypeInTokenList(Token *tokens, bool cpp, char defau
|
||||||
// function
|
// function
|
||||||
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
|
else if (tok->previous() && tok->previous()->function() && tok->previous()->function()->retDef) {
|
||||||
ValueType valuetype;
|
ValueType valuetype;
|
||||||
if (Token::simpleMatch(parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, lib), "("))
|
if (parsedecl(tok->previous()->function()->retDef, &valuetype, defsign, lib))
|
||||||
::setValueType(tok, valuetype, cpp, defsign, lib);
|
::setValueType(tok, valuetype, cpp, defsign, lib);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1079,7 +1079,7 @@ private:
|
||||||
Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart);
|
Function *addGlobalFunctionDecl(Scope*& scope, const Token* tok, const Token *argStart, const Token* funcStart);
|
||||||
Function *addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart);
|
Function *addGlobalFunction(Scope*& scope, const Token*& tok, const Token *argStart, const Token* funcStart);
|
||||||
void addNewFunction(Scope **info, const Token **tok);
|
void addNewFunction(Scope **info, const Token **tok);
|
||||||
bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart) const;
|
bool isFunction(const Token *tok, const Scope* outerScope, const Token **funcStart, const Token **argStart, const Token** declEnd) const;
|
||||||
const Type *findTypeInNested(const Token *tok, const Scope *startScope) const;
|
const Type *findTypeInNested(const Token *tok, const Scope *startScope) const;
|
||||||
const Scope *findNamespace(const Token * tok, const Scope * scope) const;
|
const Scope *findNamespace(const Token * tok, const Scope * scope) const;
|
||||||
Function *findFunctionInScope(const Token *func, const Scope *ns);
|
Function *findFunctionInScope(const Token *func, const Scope *ns);
|
||||||
|
|
|
@ -79,6 +79,11 @@ const Token * Tokenizer::isFunctionHead(const Token *tok, const std::string &end
|
||||||
tok = tok->linkAt(1)->next();
|
tok = tok->linkAt(1)->next();
|
||||||
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
|
if (Token::Match(tok, "%name% (") && tok->isUpperCaseName())
|
||||||
tok = tok->linkAt(1)->next();
|
tok = tok->linkAt(1)->next();
|
||||||
|
if (tok && tok->str() == ".") { // trailing return type
|
||||||
|
for (tok = tok->next(); tok && !Token::Match(tok, "[;{]"); tok = tok->next())
|
||||||
|
if (tok->link() && Token::Match(tok, "<|[|("))
|
||||||
|
tok = tok->link();
|
||||||
|
}
|
||||||
if (Token::Match(tok, "= 0|default|delete ;"))
|
if (Token::Match(tok, "= 0|default|delete ;"))
|
||||||
tok = tok->tokAt(2);
|
tok = tok->tokAt(2);
|
||||||
return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
|
return (tok && endsWith.find(tok->str()) != std::string::npos) ? tok : nullptr;
|
||||||
|
|
|
@ -1421,7 +1421,7 @@ private:
|
||||||
|
|
||||||
void garbageCode164() {
|
void garbageCode164() {
|
||||||
//7234
|
//7234
|
||||||
ASSERT_THROW(checkCode("class d{k p;}(){d::d():B<()}", false), InternalError);
|
checkCode("class d{k p;}(){d::d():B<()}", false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void garbageCode165() {
|
void garbageCode165() {
|
||||||
|
|
|
@ -141,9 +141,12 @@ private:
|
||||||
TEST_CASE(getVariableFromVarIdBoundsCheck);
|
TEST_CASE(getVariableFromVarIdBoundsCheck);
|
||||||
|
|
||||||
TEST_CASE(hasRegularFunction);
|
TEST_CASE(hasRegularFunction);
|
||||||
|
TEST_CASE(hasRegularFunction_trailingReturnType);
|
||||||
TEST_CASE(hasInlineClassFunction);
|
TEST_CASE(hasInlineClassFunction);
|
||||||
|
TEST_CASE(hasInlineClassFunction_trailingReturnType);
|
||||||
TEST_CASE(hasMissingInlineClassFunction);
|
TEST_CASE(hasMissingInlineClassFunction);
|
||||||
TEST_CASE(hasClassFunction);
|
TEST_CASE(hasClassFunction);
|
||||||
|
TEST_CASE(hasClassFunction_trailingReturnType);
|
||||||
|
|
||||||
TEST_CASE(hasRegularFunctionReturningFunctionPointer);
|
TEST_CASE(hasRegularFunctionReturningFunctionPointer);
|
||||||
TEST_CASE(hasInlineClassFunctionReturningFunctionPointer);
|
TEST_CASE(hasInlineClassFunctionReturningFunctionPointer);
|
||||||
|
@ -848,7 +851,9 @@ private:
|
||||||
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next());
|
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next());
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf == 0);
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf == 0);
|
||||||
|
|
||||||
const Function *function = findFunctionByName("func", &db->scopeList.front());
|
const Function *function = findFunctionByName("func", &db->scopeList.front());
|
||||||
|
|
||||||
|
@ -860,6 +865,30 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void hasRegularFunction_trailingReturnType() {
|
||||||
|
GET_SYMBOL_DB("auto func() -> int { }")
|
||||||
|
|
||||||
|
// 2 scopes: Global and Function
|
||||||
|
ASSERT(db && db->scopeList.size() == 2);
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
const Scope *scope = findFunctionScopeByToken(db, tokenizer.tokens()->next());
|
||||||
|
|
||||||
|
ASSERT(scope && scope->className == "func");
|
||||||
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf == 0);
|
||||||
|
|
||||||
|
const Function *function = findFunctionByName("func", &db->scopeList.front());
|
||||||
|
|
||||||
|
ASSERT(function && function->token->str() == "func");
|
||||||
|
ASSERT(function && function->token == tokenizer.tokens()->next());
|
||||||
|
ASSERT(function && function->hasBody());
|
||||||
|
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn != scope);
|
||||||
|
ASSERT(function && function->retDef == tokenizer.tokens()->tokAt(5));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hasInlineClassFunction() {
|
void hasInlineClassFunction() {
|
||||||
GET_SYMBOL_DB("class Fred { void func() { } };\n")
|
GET_SYMBOL_DB("class Fred { void func() { } };\n")
|
||||||
|
|
||||||
|
@ -872,7 +901,9 @@ private:
|
||||||
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
||||||
|
|
||||||
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
||||||
|
|
||||||
|
@ -886,6 +917,35 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hasInlineClassFunction_trailingReturnType() {
|
||||||
|
GET_SYMBOL_DB("class Fred { auto func() -> int { } };")
|
||||||
|
|
||||||
|
// 3 scopes: Global, Class, and Function
|
||||||
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens(), "func");
|
||||||
|
|
||||||
|
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
||||||
|
|
||||||
|
ASSERT(scope && scope->className == "func");
|
||||||
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
||||||
|
|
||||||
|
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
||||||
|
|
||||||
|
ASSERT(function && function->token->str() == "func");
|
||||||
|
ASSERT(function && function->token == functionToken);
|
||||||
|
ASSERT(function && function->hasBody() && function->isInline());
|
||||||
|
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
|
||||||
|
ASSERT(function && function->retDef == functionToken->tokAt(4));
|
||||||
|
|
||||||
|
ASSERT(db && db->findScopeByName("Fred") && db->findScopeByName("Fred")->definedType->getFunction("func") == function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void hasMissingInlineClassFunction() {
|
void hasMissingInlineClassFunction() {
|
||||||
GET_SYMBOL_DB("class Fred { void func(); };\n")
|
GET_SYMBOL_DB("class Fred { void func(); };\n")
|
||||||
|
|
||||||
|
@ -919,7 +979,34 @@ private:
|
||||||
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
||||||
|
|
||||||
ASSERT(scope && scope->className == "func");
|
ASSERT(scope && scope->className == "func");
|
||||||
ASSERT(scope && scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
||||||
|
|
||||||
|
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
||||||
|
|
||||||
|
ASSERT(function && function->token->str() == "func");
|
||||||
|
ASSERT(function && function->token == functionToken);
|
||||||
|
ASSERT(function && function->hasBody() && !function->isInline());
|
||||||
|
ASSERT(function && function->functionScope == scope && scope->function == function && function->nestedIn == db->findScopeByName("Fred"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void hasClassFunction_trailingReturnType() {
|
||||||
|
GET_SYMBOL_DB("class Fred { auto func() -> int; }; auto Fred::func() -> int { }\n");
|
||||||
|
|
||||||
|
// 3 scopes: Global, Class, and Function
|
||||||
|
ASSERT(db && db->scopeList.size() == 3);
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
const Token * const functionToken = Token::findsimplematch(tokenizer.tokens()->linkAt(2), "func");
|
||||||
|
|
||||||
|
const Scope *scope = findFunctionScopeByToken(db, functionToken);
|
||||||
|
|
||||||
|
ASSERT(scope && scope->className == "func");
|
||||||
|
if (!scope)
|
||||||
|
return;
|
||||||
|
ASSERT(scope->functionOf && scope->functionOf == db->findScopeByName("Fred"));
|
||||||
|
|
||||||
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
const Function *function = findFunctionByName("func", &db->scopeList.back());
|
||||||
|
|
||||||
|
@ -3550,6 +3637,7 @@ private:
|
||||||
|
|
||||||
// function call..
|
// function call..
|
||||||
ASSERT_EQUALS("signed int", typeOf("int a(int); a(5);", "( 5"));
|
ASSERT_EQUALS("signed int", typeOf("int a(int); a(5);", "( 5"));
|
||||||
|
ASSERT_EQUALS("signed int", typeOf("auto a(int) -> int; a(5);", "( 5"));
|
||||||
ASSERT_EQUALS("unsigned long", typeOf("sizeof(x);", "("));
|
ASSERT_EQUALS("unsigned long", typeOf("sizeof(x);", "("));
|
||||||
|
|
||||||
// struct member..
|
// struct member..
|
||||||
|
|
Loading…
Reference in New Issue