From 5bd85b03652419ef2209d3e56aa8df18cbe1603f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BCkki=20D=C3=A1niel?= Date: Sun, 22 Oct 2023 11:02:45 +0200 Subject: [PATCH 1/3] Destructor usage is now properly registered. Supported places of usage: - In delete expressions (for heap-allocated variables). - At the end of the parent scope (for stack-allocated local variables). - At the end of the destructor of enclosing record types (for member variables). --- plugins/cpp/parser/src/clangastvisitor.h | 84 +++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 0321f66ef..9253d88a6 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -435,15 +435,12 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor cppRecord->entityHash = astNode->entityHash; cppRecord->name = rd_->getNameAsString(); cppRecord->qualifiedName = rd_->getQualifiedNameAsString(); - if (const clang::CXXRecordDecl* crd - = llvm::dyn_cast(rd_)) + + if (clang::CXXRecordDecl* crd = llvm::dyn_cast(rd_)) { cppRecord->isAbstract = crd->isAbstract(); cppRecord->isPOD = crd->isPOD(); - } - if (clang::CXXRecordDecl* crd = llvm::dyn_cast(rd_)) - { //--- CppInheritance ---// for (auto it = crd->bases_begin(); it != crd->bases_end(); ++it) @@ -514,6 +511,28 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor friendship->theFriend = util::fnvHash(getUSR(friendDecl)); } } + + // --- Destructor --- // + + void* ref = crd; + model::FileLoc location = getFileLoc(crd->getEndLoc(), crd->getEndLoc()); + if (clang::CXXDestructorDecl* dd = crd->getDestructor()) + { + ref = dd; + if (crd->hasUserDeclaredDestructor()) + { + clang::Stmt* body = dd->getBody(); + location = body + ? getFileLoc(body->getEndLoc(), body->getEndLoc()) + : getFileLoc(dd->getEndLoc(), dd->getEndLoc()); + } + } + + for (auto it = crd->field_begin(); it != crd->field_end(); ++it) + { + clang::FieldDecl* fd = *it; + addDestructorUsage(fd->getType(), location, ref); + } } return true; @@ -921,6 +940,32 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor return true; } + bool VisitStmt(clang::Stmt* s_) + { + if (clang::DeclStmt* ds = llvm::dyn_cast(s_)) + { + // FIXME: Using the parent map is expensive. + // My original idea was to simply use the second top-most statement from + // _contextStatementStack as scopeSt, but the stack is always empty + // for some reason, except in VisitDeclRefExpr... (why?) + auto parents = _astContext.getParentMapContext() + .getParents(*s_); + const clang::Stmt* scopeSt = parents[0].get(); + + for (auto it = ds->decl_begin(); it != ds->decl_end(); ++it) + { + if (clang::VarDecl* vd = llvm::dyn_cast(*it)) + { + model::FileLoc loc = + getFileLoc(scopeSt->getEndLoc(), scopeSt->getEndLoc()); + addDestructorUsage(vd->getType(), loc, vd); + } + } + } + + return true; + } + bool VisitNamespaceDecl(clang::NamespaceDecl* nd_) { //--- CppAstNode ---// @@ -1036,6 +1081,8 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor if (insertToCache(de_, astNode)) _astNodes.push_back(astNode); + addDestructorUsage(de_->getDestroyedType(), astNode->location, de_); + return true; } @@ -1089,9 +1136,6 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor { astNode = std::make_shared(); - model::FileLoc location = - getFileLoc(vd->getLocation(), vd->getLocation()); - if (!_contextStatementStack.empty()) { clang::Stmt* context = _contextStatementStack.top(); @@ -1205,6 +1249,30 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor private: using Base = clang::RecursiveASTVisitor; + void addDestructorUsage( + clang::QualType type_, + const model::FileLoc& location_, + const void* clangPtr_) + { + if (clang::CXXRecordDecl* rd = type_->getAsCXXRecordDecl()) + { + if (clang::CXXDestructorDecl* dd = rd->getDestructor()) + { + model::CppAstNodePtr astNode = std::make_shared(); + + astNode->astValue = getSignature(dd); + astNode->location = location_; + astNode->entityHash = util::fnvHash(getUSR(dd)); + astNode->symbolType = model::CppAstNode::SymbolType::Function; + astNode->astType = model::CppAstNode::AstType::Usage; + astNode->id = model::createIdentifier(*astNode); + + if (insertToCache(clangPtr_, astNode)) + _astNodes.push_back(astNode); + } + } + } + /** * This function inserts a model::CppAstNodeId to a cache in a thread-safe * way. The cache is static so the parsers in each thread can use the same. From be5f66d63767c282af90fc9f62cbd501cea98624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BCkki=20D=C3=A1niel?= Date: Wed, 1 Nov 2023 10:17:20 +0100 Subject: [PATCH 2/3] Fixed the parent statement retrieval issue. A new _statements stack now stores all parent statements of the currently visited statement. --- plugins/cpp/parser/src/clangastvisitor.h | 39 +++++++++++++----------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 9253d88a6..8dd3e4393 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -335,6 +335,14 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor return b; } + bool TraverseStmt(clang::Stmt* s_) + { + _statements.push(s_); + bool b = Base::TraverseStmt(s_); + _statements.pop(); + return b; + } + bool VisitTypedefTypeLoc(clang::TypedefTypeLoc tl_) { const clang::TypedefType* type = tl_.getTypePtr(); @@ -940,26 +948,21 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor return true; } - bool VisitStmt(clang::Stmt* s_) + bool VisitDeclStmt(clang::DeclStmt* ds_) { - if (clang::DeclStmt* ds = llvm::dyn_cast(s_)) + assert(_statements.top() == ds_ && + "ds_ was expected to be the top-level statement."); + _statements.pop(); + clang::Stmt* scopeSt = _statements.top(); + _statements.push(ds_); + + for (auto it = ds_->decl_begin(); it != ds_->decl_end(); ++it) { - // FIXME: Using the parent map is expensive. - // My original idea was to simply use the second top-most statement from - // _contextStatementStack as scopeSt, but the stack is always empty - // for some reason, except in VisitDeclRefExpr... (why?) - auto parents = _astContext.getParentMapContext() - .getParents(*s_); - const clang::Stmt* scopeSt = parents[0].get(); - - for (auto it = ds->decl_begin(); it != ds->decl_end(); ++it) + if (clang::VarDecl* vd = llvm::dyn_cast(*it)) { - if (clang::VarDecl* vd = llvm::dyn_cast(*it)) - { - model::FileLoc loc = - getFileLoc(scopeSt->getEndLoc(), scopeSt->getEndLoc()); - addDestructorUsage(vd->getType(), loc, vd); - } + model::FileLoc loc = + getFileLoc(scopeSt->getEndLoc(), scopeSt->getEndLoc()); + addDestructorUsage(vd->getType(), loc, vd); } } @@ -1576,6 +1579,8 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor std::unordered_map _locToAstType; std::unordered_map _locToAstValue; + // This stack contains the parent chain of the current Stmt. + std::stack _statements; // This stack has the same role as _locTo* maps. In case of // clang::DeclRefExpr objects we need to determine the contect of the given // expression. In this stack we store the deepest statement node in AST which From 2d56647ffe4d950ebc1b2a25175b37b78843eb22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?B=C3=BCkki=20D=C3=A1niel?= Date: Sat, 11 Nov 2023 10:40:15 +0100 Subject: [PATCH 3/3] Minor data type corrections (review issues). --- plugins/cpp/parser/src/clangastvisitor.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/plugins/cpp/parser/src/clangastvisitor.h b/plugins/cpp/parser/src/clangastvisitor.h index 8dd3e4393..6977fde62 100644 --- a/plugins/cpp/parser/src/clangastvisitor.h +++ b/plugins/cpp/parser/src/clangastvisitor.h @@ -444,7 +444,8 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor cppRecord->name = rd_->getNameAsString(); cppRecord->qualifiedName = rd_->getQualifiedNameAsString(); - if (clang::CXXRecordDecl* crd = llvm::dyn_cast(rd_)) + if (const clang::CXXRecordDecl* crd + = llvm::dyn_cast(rd_)) { cppRecord->isAbstract = crd->isAbstract(); cppRecord->isPOD = crd->isPOD(); @@ -522,7 +523,7 @@ class ClangASTVisitor : public clang::RecursiveASTVisitor // --- Destructor --- // - void* ref = crd; + const clang::NamedDecl* ref = crd; model::FileLoc location = getFileLoc(crd->getEndLoc(), crd->getEndLoc()); if (clang::CXXDestructorDecl* dd = crd->getDestructor()) {