From 9e6e14af34dfd7cbd86673a6157a1e50737a2980 Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Sat, 21 Dec 2024 18:16:20 +0100 Subject: [PATCH] Calculating multi language in component and translation result --- .../de/fraunhofer/aisec/cpg/ScopeManager.kt | 3 +- .../fraunhofer/aisec/cpg/TranslationResult.kt | 8 +++ .../aisec/cpg/frontends/UnknownLanguage.kt | 12 +++++ .../fraunhofer/aisec/cpg/graph/Component.kt | 18 +++---- .../fraunhofer/aisec/cpg/graph/TypeBuilder.kt | 4 +- .../aisec/cpg/graph/types/FunctionType.kt | 2 +- .../aisec/cpg/graph/types/IncompleteType.kt | 2 +- .../aisec/cpg/passes/inference/Inference.kt | 2 +- .../aisec/cpg/frontends/LanguageTest.kt | 50 +++++++++++++++++++ .../aisec/cpg/frontends/cxx/CPPLanguage.kt | 2 +- .../cpg/frontends/cxx/CXXLanguageFrontend.kt | 2 +- 11 files changed, 87 insertions(+), 18 deletions(-) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt index c14dd1b970..4c691cb6b8 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt @@ -532,7 +532,8 @@ class ScopeManager : ScopeProvider { helper?.type is FunctionPointerType && it is FunctionDeclaration -> { val fptrType = helper.type as FunctionPointerType // TODO(oxisto): Support multiple return values - val returnType = it.returnTypes.firstOrNull() ?: IncompleteType() + val returnType = + it.returnTypes.firstOrNull() ?: IncompleteType(ref.language) returnType == fptrType.returnType && it.matchesSignature(fptrType.parameters) != IncompatibleSignature diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationResult.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationResult.kt index 7b4b3ddfb6..5372e73840 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationResult.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationResult.kt @@ -25,7 +25,9 @@ */ package de.fraunhofer.aisec.cpg +import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend +import de.fraunhofer.aisec.cpg.frontends.multiLanguage import de.fraunhofer.aisec.cpg.graph.Component import de.fraunhofer.aisec.cpg.graph.Name import de.fraunhofer.aisec.cpg.graph.Node @@ -173,6 +175,12 @@ class TranslationResult( override val config: TranslationConfiguration get() = finalCtx.config + override var language: Language<*> + get() { + return multiLanguage() + } + set(_) {} + companion object { const val SOURCE_LOCATIONS_TO_FRONTEND = "sourceLocationsToFrontend" const val APPLICATION_LOCAL_NAME = "application" diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/UnknownLanguage.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/UnknownLanguage.kt index 1ae341412d..a829941665 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/UnknownLanguage.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/UnknownLanguage.kt @@ -25,6 +25,7 @@ */ package de.fraunhofer.aisec.cpg.frontends +import de.fraunhofer.aisec.cpg.graph.Node import de.fraunhofer.aisec.cpg.graph.types.Type import kotlin.reflect.KClass @@ -56,3 +57,14 @@ class MultipleLanguages(val languages: Set>) : Language() { override val builtInTypes: Map = mapOf() override val compoundAssignmentOperators: Set = setOf() } + +fun Node.multiLanguage(): Language<*> { + val languages = astChildren.map { it.language }.toSet() + return if (languages.size == 1) { + languages.singleOrNull() ?: UnknownLanguage + } else if (languages.size > 1) { + MultipleLanguages(languages = languages) + } else { + UnknownLanguage + } +} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Component.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Component.kt index b2c0bdcf6e..1fbdabecca 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Component.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Component.kt @@ -26,8 +26,8 @@ package de.fraunhofer.aisec.cpg.graph import de.fraunhofer.aisec.cpg.PopulatedByPass -import de.fraunhofer.aisec.cpg.frontends.MultipleLanguages -import de.fraunhofer.aisec.cpg.frontends.UnknownLanguage +import de.fraunhofer.aisec.cpg.frontends.Language +import de.fraunhofer.aisec.cpg.frontends.multiLanguage import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration import de.fraunhofer.aisec.cpg.graph.edges.ast.astEdgesOf import de.fraunhofer.aisec.cpg.graph.edges.unwrapping @@ -56,14 +56,6 @@ open class Component : Node() { @Synchronized fun addTranslationUnit(tu: TranslationUnitDeclaration) { translationUnits.add(tu) - - // Check, if this component is of a particular single language or multi-language - val languages = translationUnitEdges.map { it.end.language }.toSet() - if (languages.size == 1) { - this.language = languages.singleOrNull() ?: UnknownLanguage - } else if (languages.size > 1) { - this.language = MultipleLanguages(languages = languages) - } } /** @@ -75,4 +67,10 @@ open class Component : Node() { /** All outgoing interactions such as sending data to the network or some kind of IPC. */ val outgoingInteractions: MutableList = mutableListOf() + + override var language: Language<*> + get() { + return multiLanguage() + } + set(_) {} } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/TypeBuilder.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/TypeBuilder.kt index 10f318283f..ce43d403a2 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/TypeBuilder.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/TypeBuilder.kt @@ -45,8 +45,8 @@ fun LanguageProvider.autoType(): Type { return AutoType(this.language) } -fun MetadataProvider?.incompleteType(): Type { - return IncompleteType() +fun LanguageProvider.incompleteType(): Type { + return IncompleteType(this.language) } /** Returns a [PointerType] that describes an array reference to the current type. */ diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt index 55550fc462..54839f6645 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt @@ -42,7 +42,7 @@ constructor( typeName: String = "", var parameters: List = listOf(), var returnTypes: List = listOf(), - language: Language<*>? = null + language: Language<*> ) : Type(typeName, language) { override fun reference(pointer: PointerType.PointerOrigin?): Type { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IncompleteType.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IncompleteType.kt index 6806271eef..51ac03215a 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IncompleteType.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/IncompleteType.kt @@ -37,7 +37,7 @@ import de.fraunhofer.aisec.cpg.graph.types.PointerType.PointerOrigin * unknown size apart from void. Therefore, this Type is not called VoidType */ class IncompleteType : Type { - @JvmOverloads constructor(language: Language<*>? = null) : super("void", language) + constructor(language: Language<*>) : super("void", language) /** @return PointerType to a IncompleteType, e.g. void* */ override fun reference(pointer: PointerOrigin?): Type { diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt index 2073b108af..97f3b8b547 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt @@ -65,7 +65,7 @@ class Inference internal constructor(val start: Node, override val ctx: Translat ContextProvider, RawNodeTypeProvider { - override val language: Language<*>? + override val language: Language<*> get() = start.language override val isInferred: Boolean diff --git a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt index 4a98cfe482..b12cd44d36 100644 --- a/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt +++ b/cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTest.kt @@ -25,7 +25,15 @@ */ package de.fraunhofer.aisec.cpg.frontends +import de.fraunhofer.aisec.cpg.ScopeManager +import de.fraunhofer.aisec.cpg.TranslationConfiguration +import de.fraunhofer.aisec.cpg.TranslationContext +import de.fraunhofer.aisec.cpg.TranslationManager +import de.fraunhofer.aisec.cpg.TranslationResult +import de.fraunhofer.aisec.cpg.TypeManager +import de.fraunhofer.aisec.cpg.graph.Component import de.fraunhofer.aisec.cpg.graph.newRecordDeclaration +import de.fraunhofer.aisec.cpg.graph.newTranslationUnitDeclaration import de.fraunhofer.aisec.cpg.graph.objectType import de.fraunhofer.aisec.cpg.graph.pointer import de.fraunhofer.aisec.cpg.tryCast @@ -63,4 +71,46 @@ class LanguageTest { assertIs(matches) } } + + @Test + fun testMultiLanguage() { + val otherLanguage = object : TestLanguage() {} + val testLanguage = TestLanguage() + + val result = + TranslationResult( + translationManager = TranslationManager.builder().build(), + finalCtx = + TranslationContext( + config = TranslationConfiguration.builder().build(), + scopeManager = ScopeManager(), + typeManager = TypeManager(), + ), + ) + + val comp1 = + with(TestLanguageFrontend("::", language = otherLanguage)) { + val tu = newTranslationUnitDeclaration("tu-language-other") + val comp = Component() + comp.addTranslationUnit(tu) + comp + } + result.components += comp1 + + val comp2 = + with(TestLanguageFrontend("::", language = testLanguage)) { + val tu = newTranslationUnitDeclaration("tu-language-test") + val comp = Component() + comp.addTranslationUnit(tu) + comp + } + result.components += comp2 + + val language = result.language + assertIs(language) + assertEquals(setOf(otherLanguage, testLanguage), language.languages) + + assertEquals(otherLanguage, result.components.getOrNull(0)?.language) + assertEquals(testLanguage, result.components.getOrNull(1)?.language) + } } diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CPPLanguage.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CPPLanguage.kt index c5fc9815fd..c1188494d5 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CPPLanguage.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CPPLanguage.kt @@ -130,7 +130,7 @@ open class CPPLanguage : IntegerType("unsigned long long int", 64, this, NumericType.Modifier.UNSIGNED), // Boolean type - "bool" to BooleanType("bool"), + "bool" to BooleanType("bool", language = this), // Character types "signed char" to IntegerType("signed char", 8, this, NumericType.Modifier.SIGNED), diff --git a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt index 28b5ee5ed8..0768841c2a 100644 --- a/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt +++ b/cpg-language-cxx/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontend.kt @@ -572,7 +572,7 @@ open class CXXLanguageFrontend(language: Language, ctx: Tra } // void type specifier.type == IASTSimpleDeclSpecifier.t_void -> { - IncompleteType() + incompleteType() } // __typeof__ type specifier.type == IASTSimpleDeclSpecifier.t_typeof -> {