Skip to content

Commit 94d1f3d

Browse files
committed
Make the translation context available everywhere
1 parent 40ed9f1 commit 94d1f3d

File tree

14 files changed

+69
-68
lines changed

14 files changed

+69
-68
lines changed

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/ScopeManager.kt

+2-3
Original file line numberDiff line numberDiff line change
@@ -881,9 +881,8 @@ class ScopeManager : ScopeProvider {
881881
): TranslationUnitDeclaration? {
882882
// TODO(oxisto): This workaround is needed because it seems that not all types have a proper
883883
// context :(. In this case we need to fall back to the global scope's astNode, which can
884-
// be
885-
// error-prone in a multi-language scenario.
886-
return if (source.ctx == null) {
884+
// be error-prone in a multi-language scenario.
885+
return if (!source.isInitialized) {
887886
globalScope?.astNode as? TranslationUnitDeclaration
888887
} else {
889888
source.language.translationUnitForInference<TypeToInfer>(source)

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/TranslationResult.kt

+1-4
Original file line numberDiff line numberDiff line change
@@ -93,10 +93,7 @@ class TranslationResult(
9393
val isCancelled: Boolean
9494
get() = translationManager.isCancelled()
9595

96-
override var ctx: TranslationContext? = null
97-
get() {
98-
return finalCtx
99-
}
96+
override var ctx: TranslationContext = finalCtx
10097

10198
/**
10299
* Checks if only a single software component has been analyzed and returns its translation

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/Language.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -340,7 +340,7 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
340340
null,
341341
source,
342342
false,
343-
source.ctx!!,
343+
source.ctx,
344344
null,
345345
needsExactMatch = true,
346346
)
@@ -416,7 +416,7 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
416416
* @param source the source that was responsible for the inference
417417
*/
418418
fun <TypeToInfer : Node> translationUnitForInference(source: Node): TranslationUnitDeclaration {
419-
val tu = source.ctx?.currentComponent?.translationUnits?.firstOrNull()
419+
val tu = source.ctx.currentComponent?.translationUnits?.firstOrNull()
420420
if (tu == null) {
421421
throw TranslationException(
422422
"No translation unit found that should be used for inference"

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Component.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ open class Component : Node() {
7373
@DoNotPersist
7474
val topLevel: File?
7575
get() {
76-
return ctx?.config?.topLevels?.get(this.name.localName)
76+
return ctx.config.topLevels[this.name.localName]
7777
}
7878

7979
/**

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/Node.kt

+13-3
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,18 @@ abstract class Node :
7676
* to managers such as the [TypeManager] instance which is responsible for this particular node.
7777
* All managers are bundled in [TranslationContext]. It is set in [Node.applyMetadata] when a
7878
* [ContextProvider] is provided.
79+
*
80+
* Note: We EXPECT that this property is set before any other property is accessed and therefore
81+
* this is a lateinit variable. In the past this was a nullable variable, and we had many null
82+
* checks in the code, which then threw exceptions somewhere late in the analysis. Now, the
83+
* program will abort sooner if the context is not set correctly.
84+
*
85+
* In the future, we might re-structure our node system and make this a constructor parameter.
7986
*/
80-
@get:JsonIgnore @Transient override var ctx: TranslationContext? = null
87+
@get:JsonIgnore @Transient override lateinit var ctx: TranslationContext
88+
89+
val isInitialized: Boolean
90+
get() = this::ctx.isInitialized
8191

8292
/** This property holds the full name using our new [Name] class. */
8393
@Convert(NameConverter::class) override var name: Name = Name(EMPTY_NAME)
@@ -376,8 +386,8 @@ abstract class Node :
376386
*/
377387
inline fun <reified T : Node> T.applyWithScope(block: T.() -> Unit): T {
378388
return this.apply {
379-
ctx?.scopeManager?.enterScope(this)
389+
ctx.scopeManager.enterScope(this)
380390
block()
381-
ctx?.scopeManager?.leaveScope(this)
391+
ctx.scopeManager.leaveScope(this)
382392
}
383393
}

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/NodeBuilder.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ private fun <AstNode> Node.setCodeAndLocation(
378378
provider: CodeAndLocationProvider<AstNode>,
379379
rawNode: AstNode,
380380
) {
381-
if (this.ctx?.config?.codeInNodes == true) {
381+
if (this.ctx.config.codeInNodes == true) {
382382
// only set code, if it's not already set or empty
383383
val code = provider.codeOf(rawNode)
384384
if (code != null) {

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/types/FunctionType.kt

+1-3
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
package de.fraunhofer.aisec.cpg.graph.types
2727

2828
import de.fraunhofer.aisec.cpg.frontends.Language
29-
import de.fraunhofer.aisec.cpg.frontends.TranslationException
3029
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
3130
import de.fraunhofer.aisec.cpg.graph.unknownType
3231

@@ -73,8 +72,7 @@ constructor(
7372
func.language,
7473
)
7574

76-
val c = func.ctx ?: throw TranslationException("context not available")
77-
return c.typeManager.registerType(type)
75+
return func.ctx.typeManager.registerType(type)
7876
}
7977
}
8078
}

cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/DFGFunctionSummaries.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ class DFGFunctionSummaries {
117117
val language = functionDecl.language
118118
val languageName = language.javaClass.name
119119
val methodName = functionDecl.name
120-
val typeManager = functionDecl.ctx?.typeManager ?: return null
120+
val typeManager = functionDecl.ctx.typeManager
121121

122122
// The language and the method name have to match. If a signature is specified, it also has
123123
// to match to the one of the FunctionDeclaration, null indicates that we accept everything.

cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/DFGFunctionSummariesTest.kt

+15-22
Original file line numberDiff line numberDiff line change
@@ -88,32 +88,25 @@ class DFGFunctionSummariesTest {
8888
// We need three types with a type hierarchy.
8989
val objectType = t("test.Object")
9090
val listType = t("test.List")
91-
ctx?.let {
92-
val recordDecl =
93-
startInference(it)?.inferRecordDeclaration(listType)
94-
listType.recordDeclaration = recordDecl
95-
recordDecl?.addSuperClass(objectType)
96-
listType.superTypes.add(objectType)
97-
}
91+
var recordDecl =
92+
startInference(ctx)?.inferRecordDeclaration(listType)
93+
listType.recordDeclaration = recordDecl
94+
recordDecl?.addSuperClass(objectType)
95+
listType.superTypes.add(objectType)
9896

9997
val specialListType = t("test.SpecialList")
100-
ctx?.let {
101-
val recordDecl =
102-
startInference(it)?.inferRecordDeclaration(specialListType)
103-
specialListType.recordDeclaration = recordDecl
104-
recordDecl?.addSuperClass(listType)
105-
specialListType.superTypes.add(listType)
106-
}
98+
recordDecl =
99+
startInference(ctx)?.inferRecordDeclaration(specialListType)
100+
specialListType.recordDeclaration = recordDecl
101+
recordDecl?.addSuperClass(listType)
102+
specialListType.superTypes.add(listType)
107103

108104
val verySpecialListType = t("test.VerySpecialList")
109-
ctx?.let {
110-
val recordDecl =
111-
startInference(it)
112-
?.inferRecordDeclaration(verySpecialListType)
113-
verySpecialListType.recordDeclaration = recordDecl
114-
recordDecl?.addSuperClass(specialListType)
115-
verySpecialListType.superTypes.add(listType)
116-
}
105+
recordDecl =
106+
startInference(ctx)?.inferRecordDeclaration(verySpecialListType)
107+
verySpecialListType.recordDeclaration = recordDecl
108+
recordDecl?.addSuperClass(specialListType)
109+
verySpecialListType.superTypes.add(listType)
117110
}
118111

119112
function("main", t("int")) {

cpg-core/src/test/kotlin/de/fraunhofer/aisec/cpg/graph/ExpressionBuilderTest.kt

+27-24
Original file line numberDiff line numberDiff line change
@@ -25,50 +25,53 @@
2525
*/
2626
package de.fraunhofer.aisec.cpg.graph
2727

28+
import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend
2829
import de.fraunhofer.aisec.cpg.graph.builder.plus
2930
import de.fraunhofer.aisec.cpg.graph.declarations.FieldDeclaration
3031
import de.fraunhofer.aisec.cpg.graph.edges.flows.CallingContextIn
3132
import de.fraunhofer.aisec.cpg.graph.edges.flows.ContextSensitiveDataflow
3233
import de.fraunhofer.aisec.cpg.graph.edges.flows.PartialDataflowGranularity
3334
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
34-
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Literal
35-
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference
3635
import kotlin.test.Test
3736
import kotlin.test.assertEquals
3837
import kotlin.test.assertTrue
3938

4039
class ExpressionBuilderTest {
4140
@Test
4241
fun testDuplicateWithDFGProperties() {
43-
val node1 = Literal<Int>()
44-
val node2 = Reference()
45-
val granularity = PartialDataflowGranularity(FieldDeclaration())
46-
val callingContextIn = CallingContextIn(CallExpression())
47-
node1.prevDFGEdges.addContextSensitive(node2, granularity, callingContextIn)
42+
with(TestLanguageFrontend()) {
43+
val node1 = newLiteral(42)
44+
val node2 = newReference("foo")
45+
val granularity = PartialDataflowGranularity(FieldDeclaration())
46+
val callingContextIn = CallingContextIn(CallExpression())
47+
node1.prevDFGEdges.addContextSensitive(node2, granularity, callingContextIn)
4848

49-
val clone = node1.duplicate(false)
50-
val clonedPrevDFG = clone.prevDFGEdges.single()
51-
assertTrue(clonedPrevDFG is ContextSensitiveDataflow)
52-
assertEquals(callingContextIn, clonedPrevDFG.callingContext)
53-
assertEquals(granularity, clonedPrevDFG.granularity)
49+
val clone = node1.duplicate(false)
50+
val clonedPrevDFG = clone.prevDFGEdges.single()
51+
assertTrue(clonedPrevDFG is ContextSensitiveDataflow)
52+
assertEquals(callingContextIn, clonedPrevDFG.callingContext)
53+
assertEquals(granularity, clonedPrevDFG.granularity)
5454

55-
assertEquals(setOf<Node>(node1, clone), node2.nextDFG)
55+
assertEquals(setOf<Node>(node1, clone), node2.nextDFG)
56+
}
5657
}
5758

5859
@Test
5960
fun testDuplicateWithDFGProperties2() {
60-
val node1 = Literal<Int>()
61-
val node2 = Reference()
62-
val granularity = PartialDataflowGranularity(FieldDeclaration())
63-
val callingContextIn = CallingContextIn(CallExpression())
64-
node1.nextDFGEdges.addContextSensitive(node2, granularity, callingContextIn)
61+
with(TestLanguageFrontend()) {
62+
val node1 = newLiteral(42)
63+
val node2 = newReference("foo")
64+
val granularity = PartialDataflowGranularity(FieldDeclaration())
65+
val callingContextIn = CallingContextIn(CallExpression())
66+
node1.nextDFGEdges.addContextSensitive(node2, granularity, callingContextIn)
6567

66-
val clone = node1.duplicate(false)
67-
val clonedPrevDFG = clone.nextDFGEdges.single()
68-
assertTrue(clonedPrevDFG is ContextSensitiveDataflow)
69-
assertEquals(callingContextIn, clonedPrevDFG.callingContext)
70-
assertEquals(granularity, clonedPrevDFG.granularity)
68+
val clone = node1.duplicate(false)
69+
val clonedPrevDFG = clone.nextDFGEdges.single()
70+
assertTrue(clonedPrevDFG is ContextSensitiveDataflow)
71+
assertEquals(callingContextIn, clonedPrevDFG.callingContext)
72+
assertEquals(granularity, clonedPrevDFG.granularity)
7173

72-
assertEquals(setOf<Node>(node1, clone), node2.prevDFG)
74+
assertEquals(setOf<Node>(node1, clone), node2.prevDFG)
75+
}
7376
}
7477
}

cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/enhancements/types/TypedefTest.kt

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ internal class TypedefTest : BaseTest() {
8282
assertEquals(NumericType.Modifier.UNSIGNED, returnType.modifier)
8383
assertEquals(uintfp1.type, uintfp2?.type)
8484

85-
val type = tu.ctx?.scopeManager?.typedefFor(Name("test"))
85+
val type = tu.ctx.scopeManager.typedefFor(Name("test"))
8686
assertIs<IntegerType>(type)
8787
assertLocalName("uint8_t", type)
8888
}
@@ -161,7 +161,7 @@ internal class TypedefTest : BaseTest() {
161161
val fPtr2 = tu.variables["intFptr2"]
162162
assertEquals(fPtr1?.type, fPtr2?.type)
163163

164-
val type = tu.ctx?.scopeManager?.typedefFor(Name("type_B"))
164+
val type = tu.ctx.scopeManager.typedefFor(Name("type_B"))
165165
assertLocalName("template_class_A", type)
166166
assertIs<ObjectType>(type)
167167
assertEquals(listOf(primitiveType("int"), primitiveType("int")), type.generics)

cpg-language-cxx/src/test/kotlin/de/fraunhofer/aisec/cpg/frontends/cxx/CXXLanguageFrontendTest.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1408,7 +1408,7 @@ internal class CXXLanguageFrontendTest : BaseTest() {
14081408
it.registerLanguage<CLanguage>()
14091409
}
14101410
with(tu) {
1411-
val typedefs = tu.ctx?.scopeManager?.typedefFor(Name("MyStruct"))
1411+
val typedefs = tu.ctx.scopeManager.typedefFor(Name("MyStruct"))
14121412
assertLocalName("__myStruct", typedefs)
14131413

14141414
val main = tu.functions["main"]

cpg-language-java/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/java/JavaCallResolverHelper.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ class JavaCallResolverHelper {
110110
val baseName = callee.base.name.parent ?: return null
111111

112112
val type =
113-
callee.ctx?.typeManager?.lookupResolvedType(baseName.toString())
113+
callee.ctx.typeManager.lookupResolvedType(baseName.toString())
114114
?: callee.unknownType()
115115
if (type in curClass.implementedInterfaces) {
116116
// Basename is an interface -> BaseName.super refers to BaseName itself

cpg-neo4j/src/main/kotlin/de/fraunhofer/aisec/cpg_vis_neo4j/Application.kt

+1
Original file line numberDiff line numberDiff line change
@@ -490,6 +490,7 @@ class Application : Callable<Int> {
490490
val pieces = customPasses.split(",")
491491
for (pass in pieces) {
492492
if (pass.contains(".")) {
493+
@Suppress("UNCHECKED_CAST")
493494
translationConfiguration.registerPass(
494495
Class.forName(pass).kotlin as KClass<out Pass<*>>
495496
)

0 commit comments

Comments
 (0)