From e27db371d7f0d019c0bf4200ee44414c6fff063b Mon Sep 17 00:00:00 2001 From: Christian Banse Date: Thu, 23 Nov 2023 21:14:05 +0100 Subject: [PATCH] More cleanup of old typedef remnants --- .../de/fraunhofer/aisec/cpg/ScopeManager.kt | 21 +- .../de/fraunhofer/aisec/cpg/TypeManager.kt | 2 +- .../aisec/cpg/frontends/LanguageFrontend.kt | 4 - .../de/fraunhofer/aisec/cpg/graph/Node.kt | 7 - .../graph/declarations/FunctionDeclaration.kt | 4 + .../cpg/enhancements/types/TypedefTest.kt | 249 +++++++++++------- .../frontends/cxx/CXXLanguageFrontendTest.kt | 31 +-- .../src/test/resources/typedefs/typedefs.cpp | 2 +- 8 files changed, 171 insertions(+), 149 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 2dfa9203a8..497e876e85 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 @@ -94,12 +94,6 @@ class ScopeManager : ScopeProvider { */ private val aliases = mutableMapOf>() - /** - * The language frontend tied to the scope manager. Can be used to implement language specific - * scope resolution or lookup. - */ - var lang: LanguageFrontend<*, *>? = null - /** True, if the scope manager is currently in a [BlockScope]. */ val isInBlock: Boolean get() = this.firstScopeOrNull { it is BlockScope } != null @@ -568,10 +562,7 @@ class ScopeManager : ScopeProvider { } } - /** - * Only used by the [de.fraunhofer.aisec.cpg.graph.TypeManager], adds typedefs to the current - * [ValueDeclarationScope]. - */ + /** Only used by the [TypeManager], adds typedefs to the current [ValueDeclarationScope]. */ fun addTypedef(typedef: TypedefDeclaration) { val scope = this.firstScopeIsInstanceOrNull() if (scope == null) { @@ -580,12 +571,6 @@ class ScopeManager : ScopeProvider { } scope.addTypedef(typedef) - - if (scope.astNode == null) { - lang?.currentTU?.addTypedef(typedef) - } else { - scope.astNode?.addTypedef(typedef) - } } private fun getCurrentTypedefs(searchScope: Scope?): Collection { @@ -878,14 +863,14 @@ class ScopeManager : ScopeProvider { list += Alias(from, to) } - fun typeDefFor(finalToCheck: Type): Type? { + fun typedefFor(alias: Type): Type? { var current = currentScope // We need to build a path from the current scope to the top most one. This ensures us that // a local definition overwrites / shadows one that was there on a higher scope. while (current != null) { if (current is ValueDeclarationScope) { - val decl = current.typedefs[finalToCheck] + val decl = current.typedefs[alias] if (decl != null) { return decl.type } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TypeManager.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TypeManager.kt index 56c431b4b2..276b50bc72 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TypeManager.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TypeManager.kt @@ -252,7 +252,7 @@ class TypeManager { fun resolvePossibleTypedef(alias: Type, scopeManager: ScopeManager): Type { val finalToCheck = alias.root - val applicable = scopeManager.typeDefFor(finalToCheck) + val applicable = scopeManager.typedefFor(finalToCheck) return applicable ?: alias } } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt index 6ecb61fcf7..75965712a3 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageFrontend.kt @@ -66,10 +66,6 @@ abstract class LanguageFrontend( val typeManager: TypeManager = ctx.typeManager val config: TranslationConfiguration = ctx.config - init { - this.scopeManager.lang = this - } - var currentTU: TranslationUnitDeclaration? = null @Throws(TranslationException::class) diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt index 4466ada290..129f9e0392 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt @@ -34,7 +34,6 @@ import de.fraunhofer.aisec.cpg.frontends.Language import de.fraunhofer.aisec.cpg.graph.declarations.MethodDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration -import de.fraunhofer.aisec.cpg.graph.declarations.TypedefDeclaration import de.fraunhofer.aisec.cpg.graph.edge.* import de.fraunhofer.aisec.cpg.graph.edge.Properties import de.fraunhofer.aisec.cpg.graph.scopes.GlobalScope @@ -203,8 +202,6 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider /** Virtual property for accessing the parents of the Program Dependence Graph (PDG). */ var prevPDG: MutableSet by PropertyEdgeSetDelegate(Node::prevPDGEdges, false) - var typedefs: MutableSet = HashSet() - /** * If a node is marked as being inferred, it means that it was created artificially and does not * necessarily have a real counterpart in the scanned source code. However, the nodes @@ -333,10 +330,6 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider } } - fun addTypedef(typedef: TypedefDeclaration) { - typedefs.add(typedef) - } - fun addAnnotations(annotations: Collection) { this.annotations.addAll(annotations) } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/declarations/FunctionDeclaration.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/declarations/FunctionDeclaration.kt index bf69a20c09..61359c40ef 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/declarations/FunctionDeclaration.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/declarations/FunctionDeclaration.kt @@ -284,6 +284,10 @@ val Statement.cyclomaticComplexity: Int // add one for the do statement (and include the children) i += (stmt.statement?.cyclomaticComplexity ?: 0) + 1 } + is WhileStatement -> { + // add one for the while statement (and include the children) + i += (stmt.statement?.cyclomaticComplexity ?: 0) + 1 + } is GotoStatement -> { // add one i++ diff --git a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/types/TypedefTest.kt b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/types/TypedefTest.kt index 6416d95136..e98a7c0eee 100644 --- a/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/types/TypedefTest.kt +++ b/cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/types/TypedefTest.kt @@ -26,14 +26,17 @@ package de.fraunhofer.aisec.cpg.enhancements.types import de.fraunhofer.aisec.cpg.BaseTest -import de.fraunhofer.aisec.cpg.TestUtils.analyze +import de.fraunhofer.aisec.cpg.TestUtils.analyzeAndGetFirstTU import de.fraunhofer.aisec.cpg.TestUtils.findByUniqueName -import de.fraunhofer.aisec.cpg.TestUtils.findByUniquePredicate +import de.fraunhofer.aisec.cpg.assertLocalName import de.fraunhofer.aisec.cpg.frontends.cxx.CPPLanguage +import de.fraunhofer.aisec.cpg.graph.* import de.fraunhofer.aisec.cpg.graph.declarations.ValueDeclaration -import de.fraunhofer.aisec.cpg.graph.records +import de.fraunhofer.aisec.cpg.graph.objectType import de.fraunhofer.aisec.cpg.graph.types.FunctionPointerType +import de.fraunhofer.aisec.cpg.graph.types.IntegerType import de.fraunhofer.aisec.cpg.graph.types.NumericType +import de.fraunhofer.aisec.cpg.graph.types.ObjectType import de.fraunhofer.aisec.cpg.graph.variables import java.nio.file.Path import kotlin.test.* @@ -44,141 +47,185 @@ internal class TypedefTest : BaseTest() { @Test @Throws(Exception::class) fun testSingle() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - - // normal type - val l1 = findByUniqueName(variables, "l1") - val l2 = findByUniqueName(variables, "l2") - assertEquals(l1.type, l2.type) - - // pointer - val longptr1 = findByUniqueName(variables, "longptr1") - val longptr2 = findByUniqueName(variables, "longptr2") - assertEquals(longptr1.type, longptr2.type) - - // array - val arr1 = findByUniqueName(variables, "arr1") - val arr2 = findByUniqueName(variables, "arr2") - assertEquals(arr1.type, arr2.type) - - // function pointer - val uintfp1 = findByUniqueName(variables, "uintfp1") - val uintfp2 = findByUniqueName(variables, "uintfp2") - - val fpType = uintfp1.type as? FunctionPointerType - assertNotNull(fpType) - - val returnType = fpType.returnType as? NumericType - assertNotNull(returnType) - assertEquals(NumericType.Modifier.UNSIGNED, returnType.modifier) - assertEquals(uintfp1.type, uintfp2.type) - - val typedefs = result.finalCtx.scopeManager.currentTypedefs - val def = - typedefs.stream().filter { it.alias.name.localName == "test" }.findAny().orElse(null) - assertNotNull(def) + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + with(tu) { + // normal type + val l1 = tu.variables["l1"] + val l2 = tu.variables["l2"] + assertEquals(l1?.type, l2?.type) + + // pointer + val longptr1 = tu.variables["longptr1"] + val longptr2 = tu.variables["longptr2"] + assertEquals(longptr1?.type, longptr2?.type) + + // array + val arr1 = tu.variables["arr1"] + val arr2 = tu.variables["arr2"] + assertEquals(arr1?.type, arr2?.type) + + // function pointer + val uintfp1 = tu.variables["uintfp1"] + val uintfp2 = tu.variables["uintfp2"] + + val fpType = uintfp1?.type as? FunctionPointerType + assertNotNull(fpType) + + val returnType = fpType.returnType as? NumericType + assertNotNull(returnType) + assertEquals(NumericType.Modifier.UNSIGNED, returnType.modifier) + assertEquals(uintfp1.type, uintfp2?.type) + + val type = tu.ctx?.scopeManager?.typedefFor(objectType("test")) + assertIs(type) + assertLocalName("uint8_t", type) + } } @Test @Throws(Exception::class) fun testWithModifier() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } // pointer - val l1ptr = findByUniqueName(variables, "l1ptr") - val l2ptr = findByUniqueName(variables, "l2ptr") - val l3ptr = findByUniqueName(variables, "l3ptr") - val l4ptr = findByUniqueName(variables, "l4ptr") - assertEquals(l1ptr.type, l2ptr.type) - assertEquals(l1ptr.type, l3ptr.type) - assertEquals(l1ptr.type, l4ptr.type) + val l1ptr = tu.variables["l1ptr"] + val l2ptr = tu.variables["l2ptr"] + val l3ptr = tu.variables["l3ptr"] + val l4ptr = tu.variables["l4ptr"] + assertEquals(l1ptr?.type, l2ptr?.type) + assertEquals(l1ptr?.type, l3ptr?.type) + assertEquals(l1ptr?.type, l4ptr?.type) } @Test @Throws(Exception::class) fun testChained() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - val l1 = findByUniqueName(variables, "l1") - val l3 = findByUniqueName(variables, "l3") - val l4 = findByUniqueName(variables, "l4") - assertEquals(l1.type, l3.type) - assertEquals(l1.type, l4.type) + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + + val l1 = tu.variables["l1"] + val l3 = tu.variables["l3"] + val l4 = tu.variables["l4"] + assertEquals(l1?.type, l3?.type) + assertEquals(l1?.type, l4?.type) } @Test @Throws(Exception::class) fun testMultiple() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - - // simple type - val i1 = findByUniqueName(variables, "i1") - val i2 = findByUniqueName(variables, "i2") - assertEquals(i1.type, i2.type) - - // array - val a1 = findByUniqueName(variables, "a1") - val a2 = findByUniqueName(variables, "a2") - assertEquals(a1.type, a2.type) - - // pointer - val intPtr1 = findByUniqueName(variables, "intPtr1") - val intPtr2 = findByUniqueName(variables, "intPtr2") - assertEquals(intPtr1.type, intPtr2.type) - - // function pointer - val fPtr1 = findByUniqueName(variables, "intFptr1") - val fPtr2 = findByUniqueName(variables, "intFptr2") - assertEquals(fPtr1.type, fPtr2.type) - - // template, not to be confused with multiple typedef - val template = - findByUniquePredicate(result.translationUnits.firstOrNull()?.typedefs ?: listOf()) { - it.type.typeName == "template_class_A" + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() } - assertEquals(template.alias.typeName, "type_B") + with(tu) { + // simple type + val i1 = tu.variables["i1"] + val i2 = tu.variables["i2"] + assertEquals(i1?.type, i2?.type) + + // array + val a1 = tu.variables["a1"] + val a2 = tu.variables["a2"] + assertEquals(a1?.type, a2?.type) + + // pointer + val intPtr1 = tu.variables["intPtr1"] + val intPtr2 = tu.variables["intPtr2"] + assertEquals(intPtr1?.type, intPtr2?.type) + + // function pointer + val fPtr1 = tu.variables["intFptr1"] + val fPtr2 = tu.variables["intFptr2"] + assertEquals(fPtr1?.type, fPtr2?.type) + + val type = tu.ctx?.scopeManager?.typedefFor(objectType("type_B")) + assertLocalName("template_class_A", type) + assertIs(type) + assertEquals(listOf(primitiveType("int"), primitiveType("int")), type.generics) + } } @Test @Throws(Exception::class) fun testStructs() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - val ps1 = findByUniqueName(variables, "ps1") - val ps2 = findByUniqueName(variables, "ps2") - assertEquals(ps1.type, ps2.type) + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + + val ps1 = tu.variables["ps1"] + val ps2 = tu.variables["ps2"] + assertEquals(ps1?.type, ps2?.type) } @Test @Throws(Exception::class) fun testArbitraryTypedefLocation() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - val ullong1 = findByUniqueName(variables, "someUllong1") - val ullong2 = findByUniqueName(variables, "someUllong2") - assertEquals(ullong1.type, ullong2.type) + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + + val ullong1 = tu.variables["someUllong1"] + val ullong2 = tu.variables["someUllong2"] + assertEquals(ullong1?.type, ullong2?.type) } @Test @Throws(Exception::class) fun testMemberTypeDef() { - val result = analyze("cpp", topLevel, true) { it.registerLanguage() } - val variables = result.variables - val records = result.records - val addConst = findByUniqueName(records, "add_const") + val tu = + analyzeAndGetFirstTU( + listOf(topLevel.resolve("typedefs.cpp").toFile()), + topLevel, + true + ) { + it.registerLanguage() + } + + val addConst = tu.records["add_const"] val typeMember1: ValueDeclaration = findByUniqueName(addConst.fields, "typeMember1") val typeMember2: ValueDeclaration = findByUniqueName(addConst.fields, "typeMember2") assertEquals(typeMember1.type, typeMember2.type) - val typeMemberOutside = findByUniqueName(variables, "typeMemberOutside") - assertNotEquals(typeMemberOutside.type, typeMember2.type) + val typeMemberOutside = tu.variables["typeMemberOutside"] + assertNotEquals(typeMemberOutside?.type, typeMember2.type) - val cptr1 = findByUniqueName(variables, "cptr1") - val cptr2 = findByUniqueName(variables, "cptr2") - assertEquals(cptr1.type, cptr2.type) - assertNotEquals(typeMemberOutside.type, cptr2.type) + val cptr1 = tu.variables["cptr1"] + val cptr2 = tu.variables["cptr2"] + assertEquals(cptr1?.type, cptr2?.type) + assertNotEquals(typeMemberOutside?.type, cptr2?.type) } } 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 ca7769e965..693673a7c2 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 @@ -1452,28 +1452,25 @@ internal class CXXLanguageFrontendTest : BaseTest() { @Throws(Exception::class) fun testTypedef() { val file = File("src/test/resources/c/typedef_in_header/main.c") - val result = - analyze(listOf(file), file.parentFile.toPath(), true) { + val tu = + analyzeAndGetFirstTU(listOf(file), file.parentFile.toPath(), true) { it.registerLanguage() } + with(tu) { + val typedefs = tu.ctx?.scopeManager?.typedefFor(objectType("MyStruct")) + assertLocalName("__myStruct", typedefs) - val typedefs = result.finalCtx.scopeManager.currentTypedefs - assertNotNull(typedefs) - assertTrue(typedefs.isNotEmpty()) - - val tu = result.translationUnits.firstOrNull() - assertNotNull(tu) - - val main = tu.byNameOrNull("main") - assertNotNull(main) + val main = tu.byNameOrNull("main") + assertNotNull(main) - val call = main.bodyOrNull() - assertNotNull(call) - assertTrue(call.invokes.isNotEmpty()) + val call = main.bodyOrNull() + assertNotNull(call) + assertTrue(call.invokes.isNotEmpty()) - val func = call.invokes.firstOrNull() - assertNotNull(func) - assertFalse(func.isInferred) + val func = call.invokes.firstOrNull() + assertNotNull(func) + assertFalse(func.isInferred) + } } @Test diff --git a/cpg-language-cxx/src/test/resources/typedefs/typedefs.cpp b/cpg-language-cxx/src/test/resources/typedefs/typedefs.cpp index ce7f569b78..f118811c43 100644 --- a/cpg-language-cxx/src/test/resources/typedefs/typedefs.cpp +++ b/cpg-language-cxx/src/test/resources/typedefs/typedefs.cpp @@ -75,7 +75,7 @@ typedef long type; type typeMemberOutside; // sample typedef with tabs -typedef uint8 test; +typedef uint8_t test; struct add_const { typedef const int type;