diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt index 11d47fdb84..71c3ecd172 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/DeclarationHandler.kt @@ -73,6 +73,7 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : is CPPASTUsingDeclaration -> handleUsingDeclaration(node) is CPPASTAliasDeclaration -> handleAliasDeclaration(node) is CPPASTNamespaceAlias -> handleNamespaceAlias(node) + is CPPASTLinkageSpecification -> handleLinkageSpecification(node) else -> { return handleNotSupported(node, node.javaClass.name) } @@ -668,6 +669,23 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : return enum } + /** + * Translates a C++ (linkage + * specification)[https://en.cppreference.com/w/cpp/language/language_linkage]. Actually, we do + * not care about the linkage specification per-se, but we need to parse the declaration(s) it + * contains. + */ + private fun handleLinkageSpecification(ctx: CPPASTLinkageSpecification): Declaration { + var sequence = DeclarationSequence() + + // Just forward its declaration(s) to our handler + for (decl in ctx.declarations) { + handle(decl)?.let { sequence += it } + } + + return simplifySequence(sequence) + } + /** * @param sequence * @return First Element of DeclarationSequence if the Sequence consist of only one element, @@ -707,9 +725,6 @@ class DeclarationHandler(lang: CXXLanguageFrontend) : val problematicIncludes = HashMap>() for (declaration in translationUnit.declarations) { - if (declaration is CPPASTLinkageSpecification) { - continue // do not care about these for now - } val decl = handle(declaration) ?: continue (decl as? ProblemDeclaration)?.location?.let { val problems = diff --git a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt index c02a689d28..ec9ec9fb93 100644 --- a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt +++ b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt @@ -1721,4 +1721,17 @@ internal class CXXLanguageFrontendTest : BaseTest() { assertTrue(printf.prevEOG.isNotEmpty()) assertTrue(printf.invokes.isNotEmpty()) } + + @Test + fun testExternC() { + val file = File("src/test/resources/cxx/extern_c.cpp") + val result = + analyze(listOf(file), file.parentFile.toPath(), true) { + it.registerLanguage() + } + assertNotNull(result) + + val test = result.functions["test"] + assertNotNull(test) + } } diff --git a/cpg-language-cxx/src/test/resources/cxx/extern_c.cpp b/cpg-language-cxx/src/test/resources/cxx/extern_c.cpp new file mode 100644 index 0000000000..3413845dea --- /dev/null +++ b/cpg-language-cxx/src/test/resources/cxx/extern_c.cpp @@ -0,0 +1,3 @@ +extern "C" { +void test(); +}