Clang import: Better handling of methods that are defined after declaration

This commit is contained in:
Daniel Marjamäki 2020-04-06 17:18:40 +02:00
parent 8fd0839fea
commit 66ee3a0afc
2 changed files with 74 additions and 16 deletions

View File

@ -214,6 +214,10 @@ namespace clangimport {
return ret;
}
bool hasDecl(const std::string &addr) const {
return mDeclMap.find(addr) != mDeclMap.end();
}
// "}" tokens that are not end-of-scope
std::set<Token *> mNotScope;
private:
@ -678,6 +682,10 @@ Token *clangimport::AstNode::createTokens(TokenList *tokenList)
return nullptr;
}
if (nodeType == CXXMethodDecl) {
for (int i = 0; i+1 < mExtTokens.size(); ++i) {
if (mExtTokens[i] == "prev" && !mData->hasDecl(mExtTokens[i+1]))
return nullptr;
}
createTokensFunctionDecl(tokenList);
return nullptr;
}
@ -1053,19 +1061,38 @@ Token * clangimport::AstNode::createTokensCall(TokenList *tokenList)
void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
{
const bool prev = (std::find(mExtTokens.begin(), mExtTokens.end(), "prev") != mExtTokens.end());
const bool hasBody = mFile == 0 && !children.empty() && children.back()->nodeType == CompoundStmt;
SymbolDatabase *symbolDatabase = mData->mSymbolDatabase;
addTypeTokens(tokenList, '\'' + getType() + '\'');
Token *nameToken = addtoken(tokenList, getSpelling() + getTemplateParameters());
Scope *nestedIn = const_cast<Scope *>(nameToken->scope());
symbolDatabase->scopeList.push_back(Scope(nullptr, nullptr, nestedIn));
Scope &scope = symbolDatabase->scopeList.back();
nestedIn->functionList.push_back(Function(nameToken));
scope.function = &nestedIn->functionList.back();
scope.type = Scope::ScopeType::eFunction;
scope.className = nameToken->str();
mData->funcDecl(mExtTokens.front(), nameToken, scope.function);
if (!prev) {
nestedIn->functionList.push_back(Function(nameToken));
mData->funcDecl(mExtTokens.front(), nameToken, &nestedIn->functionList.back());
} else {
const std::string addr = *(std::find(mExtTokens.begin(), mExtTokens.end(), "prev") + 1);
mData->ref(addr, nameToken);
}
Function * const function = const_cast<Function*>(nameToken->function());
Scope *scope = nullptr;
if (hasBody) {
symbolDatabase->scopeList.push_back(Scope(nullptr, nullptr, nestedIn));
scope = &symbolDatabase->scopeList.back();
scope->function = function;
scope->type = Scope::ScopeType::eFunction;
scope->className = nameToken->str();
nestedIn->nestedList.push_back(scope);
function->hasBody(true);
}
Token *par1 = addtoken(tokenList, "(");
// Function arguments
function->argumentList.clear();
for (int i = 0; i < children.size(); ++i) {
AstNodePtr child = children[i];
if (child->nodeType != ParmVarDecl)
@ -1077,24 +1104,25 @@ void clangimport::AstNode::createTokensFunctionDecl(TokenList *tokenList)
Token *vartok = nullptr;
if (!spelling.empty())
vartok = child->addtoken(tokenList, spelling);
scope.function->argumentList.push_back(Variable(vartok, child->getType(), nullptr, i, AccessControl::Argument, nullptr, &scope));
function->argumentList.push_back(Variable(vartok, child->getType(), nullptr, i, AccessControl::Argument, nullptr, scope));
if (vartok) {
const std::string addr = child->mExtTokens[0];
mData->varDecl(addr, vartok, &scope.function->argumentList.back());
mData->varDecl(addr, vartok, &function->argumentList.back());
}
}
Token *par2 = addtoken(tokenList, ")");
par1->link(par2);
par2->link(par1);
// Function body
if (mFile == 0 && !children.empty() && children.back()->nodeType == CompoundStmt) {
symbolDatabase->functionScopes.push_back(&scope);
if (hasBody) {
symbolDatabase->functionScopes.push_back(scope);
Token *bodyStart = addtoken(tokenList, "{");
bodyStart->scope(&scope);
bodyStart->scope(scope);
children.back()->createTokens(tokenList);
Token *bodyEnd = addtoken(tokenList, "}");
scope.bodyStart = bodyStart;
scope.bodyEnd = bodyEnd;
scope->bodyStart = bodyStart;
scope->bodyEnd = bodyEnd;
bodyStart->link(bodyEnd);
bodyEnd->link(bodyStart);
} else {

View File

@ -50,7 +50,9 @@ private:
TEST_CASE(cxxForRangeStmt1);
TEST_CASE(cxxForRangeStmt2);
TEST_CASE(cxxMemberCall);
TEST_CASE(cxxMethodDecl);
TEST_CASE(cxxMethodDecl1);
TEST_CASE(cxxMethodDecl2);
TEST_CASE(cxxMethodDecl3);
TEST_CASE(cxxNewExpr);
TEST_CASE(cxxNullPtrLiteralExpr);
TEST_CASE(cxxOperatorCallExpr);
@ -435,7 +437,7 @@ private:
ASSERT_EQUALS("void bar ( ) { C<int> c@1 ( C<int> ( ) ) ; c@1 . foo ( ) ; }", parse(clang));
}
void cxxMethodDecl() {
void cxxMethodDecl1() {
const char clang[] = "|-CXXMethodDecl 0x55c786f5ad60 <line:56:5, col:179> col:10 analyzeFile '_Bool (const std::string &, const std::string &, const std::string &, unsigned long long, std::list<ErrorLogger::ErrorMessage> *)'\n"
"| |-ParmVarDecl 0x55c786f5a4c8 <col:22, col:41> col:41 buildDir 'const std::string &'\n"
"| |-ParmVarDecl 0x55c786f5a580 <col:51, col:70> col:70 sourcefile 'const std::string &'\n"
@ -446,6 +448,34 @@ private:
ASSERT_EQUALS("_Bool analyzeFile ( const std::string & buildDir@1 , const std::string & sourcefile@2 , const std::string & cfg@3 , unsigned long long checksum@4 , std::list<ErrorLogger::ErrorMessage> * errors@5 ) { }", parse(clang));
}
void cxxMethodDecl2() { // "unexpanded" template method
const char clang[] = "`-CXXMethodDecl 0x220ecb0 parent 0x21e4c28 prev 0x21e5338 <line:11:1, line:18:1> line:14:1 find 'const typename char_traits<_CharT>::char_type *(const char_traits::char_type *, int, const char_traits::char_type &)'\n"
" `-CompoundStmt 0x220ede0 <line:15:1, line:18:1>\n"
" `-ReturnStmt 0x220edd0 <line:17:5, col:12>\n"
" `-IntegerLiteral 0x220edb0 <col:12> 'int' 0";
ASSERT_EQUALS("", parse(clang));
}
void cxxMethodDecl3() {
const char clang[] = "|-CXXRecordDecl 0x21cca40 <2.cpp:2:1, line:4:1> line:2:7 class Fred definition\n"
"| |-DefinitionData pass_in_registers empty aggregate standard_layout trivially_copyable pod trivial literal has_constexpr_non_copy_move_ctor can_const_default_init\n"
"| | |-DefaultConstructor exists trivial constexpr needs_implicit defaulted_is_constexpr\n"
"| | |-CopyConstructor simple trivial has_const_param needs_implicit implicit_has_const_param\n"
"| | |-MoveConstructor exists simple trivial needs_implicit\n"
"| | |-CopyAssignment trivial has_const_param needs_implicit implicit_has_const_param\n"
"| | |-MoveAssignment exists simple trivial needs_implicit\n"
"| | `-Destructor simple irrelevant trivial needs_implicit\n"
"| |-CXXRecordDecl 0x21ccb58 <col:1, col:7> col:7 implicit class Fred\n"
"| `-CXXMethodDecl 0x21ccc68 <line:3:1, col:10> col:6 foo 'void ()'\n"
"`-CXXMethodDecl 0x21ccd60 parent 0x21cca40 prev 0x21ccc68 <line:6:1, col:19> col:12 foo 'void ()'\n"
" `-CompoundStmt 0x21cce50 <col:18, col:19>";
ASSERT_EQUALS("class Fred\n"
"{ void foo ( ) ; }\n"
"\n"
"\n"
"void foo ( ) { }", parse(clang));
}
void cxxNewExpr() {
const char clang[] = "|-VarDecl 0x3a97680 <1.cpp:2:1, col:14> col:6 i 'int *' cinit\n"
"| `-CXXNewExpr 0x3a97d18 <col:10, col:14> 'int *' Function 0x3a97778 'operator new' 'void *(unsigned long)'\n"