Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 12 additions & 8 deletions lib/symboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -737,15 +737,21 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
} else {
tok = tok->link();
}
} else if (Token::Match(tok, "%name% (")) {
if (Token::simpleMatch(tok->linkAt(1), ") ;")) {
} else if (Token::Match(tok, "extern %type%")) {
const Token * ftok = tok->next();
while (Token::Match(ftok, "%name%|*|&"))
ftok = ftok->next();
if (!ftok || ftok->str() != "(")
continue;
ftok = ftok->previous();
if (Token::simpleMatch(ftok->linkAt(1), ") ;")) {
const Token *funcStart = nullptr;
const Token *argStart = nullptr;
const Token *declEnd = nullptr;
if (isFunction(tok, scope, &funcStart, &argStart, &declEnd)) {
if (isFunction(ftok, scope, &funcStart, &argStart, &declEnd)) {
if (declEnd && declEnd->str() == ";") {
bool newFunc = true; // Is this function already in the database?
auto range = scope->functionMap.equal_range(tok->str());
auto range = scope->functionMap.equal_range(ftok->str());
for (std::multimap<std::string, const Function*>::const_iterator it = range.first; it != range.second; ++it) {
if (it->second->argsMatch(scope, it->second->argDef, argStart, emptyString, 0)) {
newFunc = false;
Expand All @@ -754,13 +760,12 @@ void SymbolDatabase::createSymbolDatabaseFindAllScopes()
}
// save function prototype in database
if (newFunc) {
Function function(tok, scope, funcStart, argStart);
Function function(ftok, scope, funcStart, argStart);
if (function.isExtern()) {
scope->addFunction(std::move(function));
tok = declEnd;
}
}
continue;
}
}
}
Expand Down Expand Up @@ -5930,8 +5935,7 @@ const Function* SymbolDatabase::findFunction(const Token* const tok) const
const Scope *currScope = tok->scope();
while (currScope && currScope->isExecutable()) {
if (const Function* f = currScope->findFunction(tok)) {
if (f->isExtern())
return f;
return f;
}
if (currScope->functionOf)
currScope = currScope->functionOf;
Expand Down
17 changes: 16 additions & 1 deletion test/testsymboldatabase.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -270,7 +270,8 @@ class TestSymbolDatabase : public TestFixture {
TEST_CASE(memberFunctionOfUnknownClassMacro2);
TEST_CASE(memberFunctionOfUnknownClassMacro3);
TEST_CASE(functionLinkage);
TEST_CASE(externalFunctionsInsideAFunction); // #12420
TEST_CASE(externalFunctionsInsideAFunction); // #12420
TEST_CASE(namespacedFunctionInsideExternBlock); // #12420

TEST_CASE(classWithFriend);

Expand Down Expand Up @@ -2378,6 +2379,20 @@ class TestSymbolDatabase : public TestFixture {
ASSERT(call && call->function() == f->function());
}

void namespacedFunctionInsideExternBlock() {
// Should not crash
GET_SYMBOL_DB("namespace N {\n"
" void f();\n"
"}\n"
"extern \"C\" {\n"
" void f() {\n"
" N::f();\n"
" }\n"
"}\n");

ASSERT(db && errout.str().empty());
}

void classWithFriend() {
GET_SYMBOL_DB("class Foo {}; class Bar1 { friend class Foo; }; class Bar2 { friend Foo; };");
// 3 scopes: Global, 3 classes
Expand Down