Fixed #5621 and slightly simplified symboldatabase code.
This commit is contained in:
parent
5fc89656c0
commit
345a80f4d5
|
@ -330,203 +330,202 @@ SymbolDatabase::SymbolDatabase(const Tokenizer *tokenizer, const Settings *setti
|
||||||
}
|
}
|
||||||
|
|
||||||
// class function?
|
// class function?
|
||||||
else if (tok->previous()->str() != "::" && isFunction(tok, scope, &funcStart, &argStart)) {
|
else if (isFunction(tok, scope, &funcStart, &argStart)) {
|
||||||
Function function;
|
if (tok->previous()->str() != "::") {
|
||||||
|
Function function;
|
||||||
|
|
||||||
// save the function definition argument start '('
|
// save the function definition argument start '('
|
||||||
function.argDef = argStart;
|
function.argDef = argStart;
|
||||||
|
|
||||||
// save the access type
|
// save the access type
|
||||||
function.access = access[scope];
|
function.access = access[scope];
|
||||||
|
|
||||||
// save the function name location
|
// save the function name location
|
||||||
function.tokenDef = funcStart;
|
function.tokenDef = funcStart;
|
||||||
|
|
||||||
// save the function parent scope
|
// save the function parent scope
|
||||||
function.nestedIn = scope;
|
function.nestedIn = scope;
|
||||||
|
|
||||||
// operator function
|
// operator function
|
||||||
if (function.tokenDef->str().find("operator") == 0) {
|
if (function.tokenDef->str().find("operator") == 0) {
|
||||||
function.isOperator = true;
|
function.isOperator = true;
|
||||||
|
|
||||||
// 'operator =' is special
|
// 'operator =' is special
|
||||||
if (function.tokenDef->str() == "operator=")
|
if (function.tokenDef->str() == "operator=")
|
||||||
function.type = Function::eOperatorEqual;
|
function.type = Function::eOperatorEqual;
|
||||||
}
|
}
|
||||||
|
|
||||||
// class constructor/destructor
|
// class constructor/destructor
|
||||||
else if (function.tokenDef->str() == scope->className) {
|
else if (function.tokenDef->str() == scope->className) {
|
||||||
// destructor
|
// destructor
|
||||||
if (function.tokenDef->previous()->str() == "~")
|
if (function.tokenDef->previous()->str() == "~")
|
||||||
function.type = Function::eDestructor;
|
function.type = Function::eDestructor;
|
||||||
|
|
||||||
// copy/move constructor?
|
// copy/move constructor?
|
||||||
else if (Token::Match(function.tokenDef, "%var% ( const| %var% &|&& &| %var%| )") ||
|
else if (Token::Match(function.tokenDef, "%var% ( const| %var% &|&& &| %var%| )") ||
|
||||||
Token::Match(function.tokenDef, "%var% ( const| %var% <")) {
|
Token::Match(function.tokenDef, "%var% ( const| %var% <")) {
|
||||||
const Token* typTok = function.tokenDef->tokAt(2);
|
const Token* typTok = function.tokenDef->tokAt(2);
|
||||||
if (typTok->str() == "const")
|
if (typTok->str() == "const")
|
||||||
typTok = typTok->next();
|
typTok = typTok->next();
|
||||||
if (typTok->strAt(1) == "<") { // TODO: Remove this branch (#4710)
|
if (typTok->strAt(1) == "<") { // TODO: Remove this branch (#4710)
|
||||||
if (Token::Match(typTok->linkAt(1), "> & %var%| )"))
|
if (Token::Match(typTok->linkAt(1), "> & %var%| )"))
|
||||||
function.type = Function::eCopyConstructor;
|
function.type = Function::eCopyConstructor;
|
||||||
else if (Token::Match(typTok->linkAt(1), "> &&|& & %var%| )"))
|
else if (Token::Match(typTok->linkAt(1), "> &&|& & %var%| )"))
|
||||||
|
function.type = Function::eMoveConstructor;
|
||||||
|
else
|
||||||
|
function.type = Function::eConstructor;
|
||||||
|
} else if (typTok->strAt(1) == "&&" || typTok->strAt(2) == "&")
|
||||||
function.type = Function::eMoveConstructor;
|
function.type = Function::eMoveConstructor;
|
||||||
else
|
else
|
||||||
function.type = Function::eConstructor;
|
function.type = Function::eCopyConstructor;
|
||||||
} else if (typTok->strAt(1) == "&&" || typTok->strAt(2) == "&")
|
|
||||||
function.type = Function::eMoveConstructor;
|
if (typTok->str() != function.tokenDef->str())
|
||||||
|
function.type = Function::eConstructor; // Overwrite, if types are not identical
|
||||||
|
}
|
||||||
|
// regular constructor
|
||||||
else
|
else
|
||||||
function.type = Function::eCopyConstructor;
|
function.type = Function::eConstructor;
|
||||||
|
|
||||||
if (typTok->str() != function.tokenDef->str())
|
if (function.tokenDef->previous()->str() == "explicit")
|
||||||
function.type = Function::eConstructor; // Overwrite, if types are not identical
|
function.isExplicit = true;
|
||||||
}
|
}
|
||||||
// regular constructor
|
|
||||||
|
// function returning function pointer
|
||||||
|
else if (tok->str() == "(") {
|
||||||
|
function.retFuncPtr = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token *tok1 = tok;
|
||||||
|
|
||||||
|
// look for end of previous statement
|
||||||
|
while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
|
||||||
|
// virtual function
|
||||||
|
if (tok1->previous()->str() == "virtual") {
|
||||||
|
function.isVirtual = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// static function
|
||||||
|
else if (tok1->previous()->str() == "static") {
|
||||||
|
function.isStatic = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// friend function
|
||||||
|
else if (tok1->previous()->str() == "friend") {
|
||||||
|
function.isFriend = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
tok1 = tok1->previous();
|
||||||
|
}
|
||||||
|
|
||||||
|
// find the return type
|
||||||
|
if (!function.isConstructor() && !function.isDestructor()) {
|
||||||
|
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union"))
|
||||||
|
tok1 = tok1->next();
|
||||||
|
|
||||||
|
if (tok1)
|
||||||
|
function.retDef = tok1;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Token *end;
|
||||||
|
|
||||||
|
if (!function.retFuncPtr)
|
||||||
|
end = function.argDef->link();
|
||||||
else
|
else
|
||||||
function.type = Function::eConstructor;
|
end = tok->link()->next()->link();
|
||||||
|
|
||||||
if (function.tokenDef->previous()->str() == "explicit")
|
|
||||||
function.isExplicit = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// function returning function pointer
|
|
||||||
else if (tok->str() == "(") {
|
|
||||||
function.retFuncPtr = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token *tok1 = tok;
|
|
||||||
|
|
||||||
// look for end of previous statement
|
|
||||||
while (tok1->previous() && !Token::Match(tok1->previous(), ";|}|{|public:|protected:|private:")) {
|
|
||||||
// virtual function
|
|
||||||
if (tok1->previous()->str() == "virtual") {
|
|
||||||
function.isVirtual = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// static function
|
|
||||||
else if (tok1->previous()->str() == "static") {
|
|
||||||
function.isStatic = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// friend function
|
|
||||||
else if (tok1->previous()->str() == "friend") {
|
|
||||||
function.isFriend = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
tok1 = tok1->previous();
|
|
||||||
}
|
|
||||||
|
|
||||||
// find the return type
|
|
||||||
if (!function.isConstructor() && !function.isDestructor()) {
|
|
||||||
while (tok1 && Token::Match(tok1->next(), "virtual|static|friend|const|struct|union"))
|
|
||||||
tok1 = tok1->next();
|
|
||||||
|
|
||||||
if (tok1)
|
|
||||||
function.retDef = tok1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Token *end;
|
|
||||||
|
|
||||||
if (!function.retFuncPtr)
|
|
||||||
end = function.argDef->link();
|
|
||||||
else
|
|
||||||
end = tok->link()->next()->link();
|
|
||||||
|
|
||||||
// const function
|
|
||||||
if (end->next()->str() == "const")
|
|
||||||
function.isConst = true;
|
|
||||||
|
|
||||||
// count the number of constructors
|
|
||||||
if (function.isConstructor())
|
|
||||||
scope->numConstructors++;
|
|
||||||
if (function.type == Function::eCopyConstructor ||
|
|
||||||
function.type == Function::eMoveConstructor)
|
|
||||||
scope->numCopyOrMoveConstructors++;
|
|
||||||
|
|
||||||
// assume implementation is inline (definition and implementation same)
|
|
||||||
function.token = function.tokenDef;
|
|
||||||
function.arg = function.argDef;
|
|
||||||
|
|
||||||
// out of line function
|
|
||||||
if (Token::Match(end, ") const| ;")) {
|
|
||||||
// find the function implementation later
|
|
||||||
tok = end->next();
|
|
||||||
if (tok->str() != ";")
|
|
||||||
tok = tok->next();
|
|
||||||
|
|
||||||
scope->functionList.push_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
// default or delete
|
|
||||||
else if (Token::Match(end, ") = default|delete ;")) {
|
|
||||||
if (end->strAt(2) == "default")
|
|
||||||
function.isDefault = true;
|
|
||||||
else
|
|
||||||
function.isDelete = true;
|
|
||||||
|
|
||||||
tok = end->tokAt(3);
|
|
||||||
|
|
||||||
scope->functionList.push_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
// pure virtual function
|
|
||||||
else if (Token::Match(end, ") const| = %any% ;")) {
|
|
||||||
function.isPure = true;
|
|
||||||
|
|
||||||
|
// const function
|
||||||
if (end->next()->str() == "const")
|
if (end->next()->str() == "const")
|
||||||
tok = end->tokAt(4);
|
function.isConst = true;
|
||||||
else
|
|
||||||
|
// count the number of constructors
|
||||||
|
if (function.isConstructor())
|
||||||
|
scope->numConstructors++;
|
||||||
|
if (function.type == Function::eCopyConstructor ||
|
||||||
|
function.type == Function::eMoveConstructor)
|
||||||
|
scope->numCopyOrMoveConstructors++;
|
||||||
|
|
||||||
|
// assume implementation is inline (definition and implementation same)
|
||||||
|
function.token = function.tokenDef;
|
||||||
|
function.arg = function.argDef;
|
||||||
|
|
||||||
|
// out of line function
|
||||||
|
if (Token::simpleMatch(end, ") ;")) {
|
||||||
|
// find the function implementation later
|
||||||
|
tok = end->next();
|
||||||
|
|
||||||
|
scope->functionList.push_back(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
// default or delete
|
||||||
|
else if (Token::Match(end, ") = default|delete ;")) {
|
||||||
|
if (end->strAt(2) == "default")
|
||||||
|
function.isDefault = true;
|
||||||
|
else
|
||||||
|
function.isDelete = true;
|
||||||
|
|
||||||
tok = end->tokAt(3);
|
tok = end->tokAt(3);
|
||||||
|
|
||||||
scope->functionList.push_back(function);
|
scope->functionList.push_back(function);
|
||||||
}
|
|
||||||
|
|
||||||
// unknown macro (#5197)
|
|
||||||
else if (Token::Match(end, ") %any% ;")) {
|
|
||||||
tok = end->tokAt(3);
|
|
||||||
|
|
||||||
scope->functionList.push_back(function);
|
|
||||||
}
|
|
||||||
|
|
||||||
// inline function
|
|
||||||
else {
|
|
||||||
function.isInline = true;
|
|
||||||
function.hasBody = true;
|
|
||||||
|
|
||||||
// find start of function '{'
|
|
||||||
while (end && end->str() != "{")
|
|
||||||
end = end->next();
|
|
||||||
if (!end)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
scope->functionList.push_back(function);
|
|
||||||
|
|
||||||
Function* funcptr = &scope->functionList.back();
|
|
||||||
const Token *tok2 = funcStart;
|
|
||||||
|
|
||||||
addNewFunction(&scope, &tok2);
|
|
||||||
if (scope) {
|
|
||||||
scope->functionOf = function.nestedIn;
|
|
||||||
scope->function = funcptr;
|
|
||||||
scope->function->functionScope = scope;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tok = tok2;
|
// pure virtual function
|
||||||
|
else if (Token::Match(end, ") const| = %any% ;")) {
|
||||||
|
function.isPure = true;
|
||||||
|
|
||||||
|
if (end->next()->str() == "const")
|
||||||
|
tok = end->tokAt(4);
|
||||||
|
else
|
||||||
|
tok = end->tokAt(3);
|
||||||
|
|
||||||
|
scope->functionList.push_back(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 'const' or unknown macro (#5197)
|
||||||
|
else if (Token::Match(end, ") %any% ;")) {
|
||||||
|
tok = end->tokAt(2);
|
||||||
|
scope->functionList.push_back(function);
|
||||||
|
}
|
||||||
|
|
||||||
|
// inline function
|
||||||
|
else {
|
||||||
|
function.isInline = true;
|
||||||
|
function.hasBody = true;
|
||||||
|
|
||||||
|
// find start of function '{'
|
||||||
|
while (end && end->str() != "{")
|
||||||
|
end = end->next();
|
||||||
|
if (!end)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
scope->functionList.push_back(function);
|
||||||
|
|
||||||
|
Function* funcptr = &scope->functionList.back();
|
||||||
|
const Token *tok2 = funcStart;
|
||||||
|
|
||||||
|
addNewFunction(&scope, &tok2);
|
||||||
|
if (scope) {
|
||||||
|
scope->functionOf = function.nestedIn;
|
||||||
|
scope->function = funcptr;
|
||||||
|
scope->function->functionScope = scope;
|
||||||
|
}
|
||||||
|
|
||||||
|
tok = tok2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// nested class or friend function?
|
// nested class or friend function?
|
||||||
else if (tok->previous()->str() == "::" && isFunction(tok, scope, &funcStart, &argStart)) {
|
|
||||||
/** @todo check entire qualification for match */
|
|
||||||
Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2));
|
|
||||||
|
|
||||||
if (nested)
|
|
||||||
addClassFunction(&scope, &tok, argStart);
|
|
||||||
else {
|
else {
|
||||||
/** @todo handle friend functions */
|
/** @todo check entire qualification for match */
|
||||||
|
Scope * nested = scope->findInNestedListRecursive(tok->strAt(-2));
|
||||||
|
|
||||||
|
if (nested)
|
||||||
|
addClassFunction(&scope, &tok, argStart);
|
||||||
|
else {
|
||||||
|
/** @todo handle friend functions */
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -140,6 +140,7 @@ private:
|
||||||
TEST_CASE(testConstructors);
|
TEST_CASE(testConstructors);
|
||||||
TEST_CASE(functionDeclarationTemplate);
|
TEST_CASE(functionDeclarationTemplate);
|
||||||
TEST_CASE(functionDeclarations);
|
TEST_CASE(functionDeclarations);
|
||||||
|
TEST_CASE(memberFunctionOfUnknownClassMacro);
|
||||||
|
|
||||||
TEST_CASE(classWithFriend);
|
TEST_CASE(classWithFriend);
|
||||||
|
|
||||||
|
@ -955,6 +956,22 @@ private:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void memberFunctionOfUnknownClassMacro() {
|
||||||
|
GET_SYMBOL_DB("class ScVbaFormatCondition { OUString getServiceImplName() SAL_OVERRIDE; };\n"
|
||||||
|
"void ScVbaValidation::getFormula1() {\n"
|
||||||
|
" sal_uInt16 nFlags = 0;\n"
|
||||||
|
" if (pDocSh && !getCellRangesForAddress(nFlags)) ;\n"
|
||||||
|
"}");
|
||||||
|
|
||||||
|
ASSERT(db && errout.str() == "");
|
||||||
|
|
||||||
|
if (db) {
|
||||||
|
const Scope *scope = db->findScopeByName("getFormula1");
|
||||||
|
ASSERT(scope != nullptr);
|
||||||
|
ASSERT(scope && scope->nestedIn == &db->scopeList.front());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void classWithFriend() {
|
void classWithFriend() {
|
||||||
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };")
|
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };")
|
||||||
// 3 scopes: Global, 3 classes
|
// 3 scopes: Global, 3 classes
|
||||||
|
|
Loading…
Reference in New Issue