Skip to content

Commit

Permalink
logic: Add indexing of non-trivial destructor calls
Browse files Browse the repository at this point in the history
  • Loading branch information
petermost committed May 13, 2024
1 parent 8494b8d commit 0beeaa0
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 15 deletions.
20 changes: 9 additions & 11 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
---
Language: Cpp

AccessModifierOffset: -4
AlignAfterOpenBracket: AlwaysBreak
AlignConsecutiveAssignments: false
Expand Down Expand Up @@ -27,7 +30,7 @@ BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeComma
BreakInheritanceList: BeforeComma
BreakStringLiterals: true
ColumnLimit: 100
ColumnLimit: 0
CompactNamespaces: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
Expand All @@ -37,7 +40,7 @@ DerivePointerAlignment: false
FixNamespaceComments: true
IncludeBlocks: Preserve
IndentCaseLabels: false
IndentPPDirectives: AfterHash
IndentPPDirectives: BeforeHash
IndentWidth: 4
IndentWrappedFunctionNames: true
KeepEmptyLinesAtTheStartOfBlocks: false
Expand All @@ -51,7 +54,7 @@ PenaltyBreakString: 100
PenaltyBreakTemplateDeclaration: 0
PenaltyExcessCharacter: 10
PenaltyReturnTypeOnItsOwnLine: 1000
PointerAlignment: Left
PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
Expand All @@ -62,7 +65,7 @@ SpaceBeforeCpp11BracedList: true
SpaceBeforeCtorInitializerColon: false
SpaceBeforeInheritanceColon: false
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 4
Expand All @@ -71,12 +74,7 @@ SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: c++17
Standard: Latest
TabWidth: 4
UseTab: Always
---
Language: Cpp
---
Language: Java
#BasedOnStyle: Google
#BreakAfterJavaFieldAnnotations: true
...
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ if (BUILD_CXX_LANGUAGE_PACKAGE)

# Clang:

find_package(Clang REQUIRED)
find_package(Clang 17 REQUIRED)
message(STATUS "Found LLVM ${LLVM_VERSION}")

if (isVcpkgBuild)
Expand Down
4 changes: 3 additions & 1 deletion project/Sourcetrail-Linux-System.srctrlprj
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
<header_search_path>${JAVA_HOME}/include/linux</header_search_path>
</header_search_paths>
<indexed_header_paths>
<indexed_header_path>/usr/include/x86_64-linux-gnu/qt6</indexed_header_path>
<indexed_header_path>/usr/lib/jvm/java-21-openjdk-amd64/include</indexed_header_path>
<indexed_header_path>/usr/lib/llvm-17/include</indexed_header_path>
<indexed_header_path>..</indexed_header_path>
<indexed_header_path>../../build/system-ninja-debug</indexed_header_path>
<indexed_header_path>${JAVA_HOME}/include</indexed_header_path>
</indexed_header_paths>
<name>C/C++ from Compilation Database</name>
<pch_flags>
Expand Down
73 changes: 73 additions & 0 deletions src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.cpp
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#include "CxxAstVisitorComponentIndexer.h"

#include <clang/AST/ASTContext.h>
#include <clang/Analysis/CFG.h>
#include <clang/Basic/SourceLocation.h>
#include <clang/Basic/SourceManager.h>
#include <clang/Lex/Preprocessor.h>
Expand All @@ -16,6 +17,9 @@
#include "ParserClient.h"
#include "utilityClang.h"

using namespace std;
using namespace clang;

CxxAstVisitorComponentIndexer::CxxAstVisitorComponentIndexer(
CxxAstVisitor* astVisitor, clang::ASTContext* astContext, std::shared_ptr<ParserClient> client)
: CxxAstVisitorComponent(astVisitor), m_astContext(astContext), m_client(client)
Expand Down Expand Up @@ -425,6 +429,75 @@ void CxxAstVisitorComponentIndexer::visitFunctionDecl(clang::FunctionDecl* d)
getParseLocation(d->getLocation()));
}
}
findNonTrivialDestructorCalls(d);
}
}

void CxxAstVisitorComponentIndexer::findNonTrivialDestructorCalls(const FunctionDecl *functionDecl)
{
auto recordCall = [this](const FunctionDecl *functionDecl, const CXXDestructorDecl *destructorDecl)
{
Id referencedSymbolId = getOrCreateSymbolId(destructorDecl);
Id contextSymbolId = getOrCreateSymbolId(getAstVisitor()->getComponent<CxxAstVisitorComponentContext>()->getContext());
// functionDecl->getLocation: The function name
// functionDecl->getBeginLoc: Begin of function
// functionDecl->getEndLoc: End of function
// functionDecl->getSourceRange: The complete function
// functionDecl->getDefaultLoc: No location but 'call' edge
// destructorDecl->getSourceRange: The destructor itself

ParseLocation parseLocation = getParseLocation(functionDecl->getEndLoc());
m_client->recordReference(REFERENCE_CALL, referencedSymbolId, contextSymbolId, parseLocation);
};

// Adapted from:
// "How to get information about call to destructors in Clang LibTooling?"
// https://stackoverflow.com/questions/59610156/how-to-get-information-about-call-to-destructors-in-clang-libtooling

if (functionDecl->isThisDeclarationADefinition())
{
CFG::BuildOptions buildOptions;
buildOptions.AddImplicitDtors = true;
buildOptions.AddTemporaryDtors = true;

if (unique_ptr<CFG> cfg = CFG::buildCFG(functionDecl, functionDecl->getBody(), m_astContext, buildOptions))
{
for (CFGBlock *block : cfg->const_nodes())
{
for (auto ref : block->refs())
{
// It should not be necessary to special-case 'CFGBaseDtor'. But as of Clang/LLVM 17.0.2,
// 'CFGImplicitDtor::getDestructorDecl' is simply missing the implementation of
// that case. See CFG.cpp(5320):
// case CFGElement::BaseDtor:
// // Not yet supported.
// return nullptr;
if (optional<CFGBaseDtor> baseDtor = ref->getAs<CFGBaseDtor>())
{
const CXXBaseSpecifier *baseSpec = baseDtor->getBaseSpecifier();
if (const RecordType *recordType = dyn_cast<RecordType>(baseSpec->getType().getDesugaredType(*m_astContext).getTypePtr()))
{
if (const CXXRecordDecl *recordDecl = dyn_cast<CXXRecordDecl>(recordType->getDecl()))
{
if (const CXXDestructorDecl *dtorDecl = recordDecl->getDestructor())
{
recordCall(functionDecl, dtorDecl);
}
}
}
}
// If it were not for the above unimplemented functionality, we would only need
// this block.
else if (optional<CFGImplicitDtor> implicitDtor = ref->getAs<CFGImplicitDtor>())
{
if (const CXXDestructorDecl *dtorDecl = implicitDtor->getDestructorDecl(*m_astContext))
{
recordCall(functionDecl, dtorDecl);
}
}
}
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/lib_cxx/data/parser/cxx/CxxAstVisitorComponentIndexer.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,8 @@ class CxxAstVisitorComponentIndexer: public CxxAstVisitorComponent
const ParseLocation& location,
SymbolKind symbolKind);

void findNonTrivialDestructorCalls(const clang::FunctionDecl *d);

ParseLocation getSignatureLocation(clang::FunctionDecl* d);
ParseLocation getParseLocationOfTagDeclBody(clang::TagDecl* decl) const;
ParseLocation getParseLocationOfFunctionBody(const clang::FunctionDecl* decl) const;
Expand Down
25 changes: 23 additions & 2 deletions src/test/CxxParserTestSuite.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ using namespace std;
using namespace std::string_literals;
using namespace utility;

// To see the AST: 'clang <input_file> -Xclang -ast-dump -fsyntax-only [-fno-color-diagnostics]'

namespace
{
Expand Down Expand Up @@ -181,7 +182,6 @@ TEST_CASE("cxx parser finds overloaded operator declaration")
TEST_CASE("cxx parser finds explicit bool conversion operator")
{
// AST: https://godbolt.org/z/rKhTnKjf8
// To see the AST: 'clang <input_file> -Xclang -ast-dump -fsyntax-only [-fno-color-diagnostics]'

std::shared_ptr<TestStorage> client = parseCode(
R"(class B
Expand All @@ -200,7 +200,6 @@ TEST_CASE("cxx parser finds explicit bool conversion operator")

// Find usage:
INFO(encodeToUtf8(join(client->calls, L"\n"s)));
REQUIRE(client->calls.size() == 2);
REQUIRE(containsElement(client->calls, L"void f() -> bool B::operator bool() const <9:8 9:8>"s));
}

Expand Down Expand Up @@ -2045,6 +2044,28 @@ TEST_CASE("cxx parser finds explicit constructor call")
client->calls, L"int main() -> void App::App() <8:2 8:4>"));
}

TEST_CASE("cxx parser finds call of explicitly defined non-trivial destructor")
{
std::shared_ptr<TestStorage> client = parseCode(
R"(class App
{
public:
~App() {};
};
int main()
{
{
App app;
}
})");

REQUIRE(client->errors.empty());

// Find usage:
INFO(encodeToUtf8(join(client->calls, L"\n"s)));
REQUIRE(containsElement(client->calls, L"int main() -> void App::~App() <11:3 11:3>"s));
}

TEST_CASE("cxx parser finds call of explicitly defined destructor at delete keyword")
{
std::shared_ptr<TestStorage> client = parseCode(
Expand Down

0 comments on commit 0beeaa0

Please sign in to comment.