From 39562227fda0cc7ae66fa767ccbdf99843108cba Mon Sep 17 00:00:00 2001 From: Phodal Huang Date: Wed, 14 Feb 2024 10:03:37 +0800 Subject: [PATCH] feat(chapi-ast-cpp): add support for importing C++ headers This commit adds support for importing C++ headers in the CPPBasicIdentListener class. The includes are extracted from the code using a regular expression and added to the CodeContainer as CodeImport objects. This allows for better analysis of C++ code that relies on external headers. --- .../chapi/ast/cast/CFullIdentListenerTest.kt | 2 +- .../kotlin/chapi/ast/cppast/CPPAnalyser.kt | 7 ++++++- .../chapi/ast/cppast/CPPBasicIdentListener.kt | 18 +++++++++++++++++- .../ast/cppast/CPPBasicIdentListenerTest.kt | 4 ++++ 4 files changed, 28 insertions(+), 3 deletions(-) diff --git a/chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt b/chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt index b28b0063..0d633064 100644 --- a/chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt +++ b/chapi-ast-c/src/test/kotlin/chapi/ast/cast/CFullIdentListenerTest.kt @@ -304,7 +304,7 @@ typedef struct { } @Test - fun readlWorld() { + fun shouldSuccessHandleDs() { val code = """ // https://stackoverflow.com/questions/12642830/can-i-define-a-function-inside-a-c-structure #include diff --git a/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPAnalyser.kt b/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPAnalyser.kt index ae759aff..eb5b1808 100644 --- a/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPAnalyser.kt +++ b/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPAnalyser.kt @@ -45,11 +45,16 @@ open class CPPAnalyser: Analyser { return output } + private val importRegex = Regex("""#include\s+(<[^>]+>|\"[^\"]+\")""") override fun analysis(code: String, filePath: String): CodeContainer { val processedCode = preProcessing(code) + val includesDirective = importRegex.findAll(code).map { + it.groupValues[1] + }.toMutableList() + val context = this.parse(processedCode).translationUnit() - val listener = CPPBasicIdentListener(fileName = filePath) + val listener = CPPBasicIdentListener(fileName = filePath, includesDirective) ParseTreeWalker().walk(listener, context) diff --git a/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPBasicIdentListener.kt b/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPBasicIdentListener.kt index ec186bcc..897208ee 100644 --- a/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPBasicIdentListener.kt +++ b/chapi-ast-cpp/src/main/kotlin/chapi/ast/cppast/CPPBasicIdentListener.kt @@ -4,7 +4,7 @@ import chapi.ast.antlr.CPP14Parser import chapi.ast.antlr.CPP14ParserBaseListener import chapi.domain.core.* -class CPPBasicIdentListener(fileName: String) : CPP14ParserBaseListener() { +class CPPBasicIdentListener(fileName: String, includes: MutableList) : CPP14ParserBaseListener() { private var codeContainer: CodeContainer = CodeContainer(FullName = fileName) /// for example, Friend function, global function (`main`), etc. private var defaultNode = CodeDataStruct() @@ -12,6 +12,22 @@ class CPPBasicIdentListener(fileName: String) : CPP14ParserBaseListener() { private var classes = mutableListOf() private var currentNode: CodeDataStruct? = null + init { + includes.forEach { + val value = it + .removeSurrounding("\"", "\"") + .removeSurrounding("<", ">") + + val imp = CodeImport( + Source = value, + AsName = value + ) + + codeContainer.Imports += imp + } + + } + override fun enterNamespaceDefinition(ctx: CPP14Parser.NamespaceDefinitionContext?) { ctx?.Identifier()?.let { codeContainer.PackageName = it.text diff --git a/chapi-ast-cpp/src/test/kotlin/chapi/ast/cppast/CPPBasicIdentListenerTest.kt b/chapi-ast-cpp/src/test/kotlin/chapi/ast/cppast/CPPBasicIdentListenerTest.kt index 009b88fd..532e2d3e 100644 --- a/chapi-ast-cpp/src/test/kotlin/chapi/ast/cppast/CPPBasicIdentListenerTest.kt +++ b/chapi-ast-cpp/src/test/kotlin/chapi/ast/cppast/CPPBasicIdentListenerTest.kt @@ -31,6 +31,10 @@ int main(){} """ val container = CPPAnalyser().analysis(code, "helloworld.cpp") assertEquals(container.DataStructures[0].Functions[0].ReturnType, "int") + + // imports + assertEquals(container.Imports.size, 1) + assertEquals(container.Imports[0].Source, "iostream") } @Test