Skip to content

Commit 91883f7

Browse files
committed
Added translationUnitForInference
1 parent 457d092 commit 91883f7

File tree

4 files changed

+66
-4
lines changed

4 files changed

+66
-4
lines changed

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

+21
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,27 @@ class ScopeManager : ScopeProvider {
868868

869869
return symbols.singleOrNull()
870870
}
871+
872+
/**
873+
* Returns the [TranslationUnitDeclaration] that should be used for inference, especially for
874+
* global declarations.
875+
*
876+
* @param TypeToInfer the type of the node that should be inferred
877+
* @param source the source that was responsible for the inference
878+
*/
879+
fun <TypeToInfer : Node> translationUnitForInference(
880+
source: Node
881+
): TranslationUnitDeclaration? {
882+
// TODO(oxisto): This workaround is needed because it seems that not all types have a proper
883+
// 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) {
887+
globalScope?.astNode as? TranslationUnitDeclaration
888+
} else {
889+
source.language.translationUnitForInference<TypeToInfer>(source)
890+
}
891+
}
871892
}
872893

873894
/**

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

+38-1
Original file line numberDiff line numberDiff line change
@@ -30,20 +30,28 @@ import com.fasterxml.jackson.core.JsonGenerator
3030
import com.fasterxml.jackson.databind.JsonSerializer
3131
import com.fasterxml.jackson.databind.SerializerProvider
3232
import com.fasterxml.jackson.databind.annotation.JsonSerialize
33-
import de.fraunhofer.aisec.cpg.*
33+
import de.fraunhofer.aisec.cpg.CallResolutionResult
34+
import de.fraunhofer.aisec.cpg.SignatureResult
35+
import de.fraunhofer.aisec.cpg.TranslationContext
36+
import de.fraunhofer.aisec.cpg.ancestors
3437
import de.fraunhofer.aisec.cpg.graph.Name
3538
import de.fraunhofer.aisec.cpg.graph.Node
3639
import de.fraunhofer.aisec.cpg.graph.OverlayNode
3740
import de.fraunhofer.aisec.cpg.graph.declarations.Declaration
3841
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
42+
import de.fraunhofer.aisec.cpg.graph.declarations.NamespaceDeclaration
43+
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
3944
import de.fraunhofer.aisec.cpg.graph.edges.ast.TemplateArguments
45+
import de.fraunhofer.aisec.cpg.graph.scopes.GlobalScope
46+
import de.fraunhofer.aisec.cpg.graph.scopes.Scope
4047
import de.fraunhofer.aisec.cpg.graph.statements.expressions.BinaryOperator
4148
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
4249
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference
4350
import de.fraunhofer.aisec.cpg.graph.types.*
4451
import de.fraunhofer.aisec.cpg.graph.unknownType
4552
import de.fraunhofer.aisec.cpg.helpers.Util
4653
import de.fraunhofer.aisec.cpg.passes.SymbolResolver
54+
import de.fraunhofer.aisec.cpg.passes.inference.Inference
4755
import java.io.File
4856
import kotlin.reflect.KClass
4957
import kotlin.reflect.full.primaryConstructor
@@ -388,6 +396,35 @@ abstract class Language<T : LanguageFrontend<*, *>> : Node() {
388396
ref.candidates.singleOrNull()
389397
}
390398
}
399+
400+
/**
401+
* There are some cases where our [Inference] system needs to place declarations, e.g., a
402+
* [NamespaceDeclaration] in the [GlobalScope]. The issue with that is that the [Scope.astNode]
403+
* of the global scope is always the last parsed [TranslationUnitDeclaration] and we might end
404+
* up adding the declaration to some random translation unit, where it does not really belong.
405+
*
406+
* Therefore, we give the language a chance to return a [TranslationUnitDeclaration] where the
407+
* declaration should be placed. If the language does not override this function, the default
408+
* implementation will return the first [TranslationUnitDeclaration] in
409+
* [TranslationContext.currentComponent].
410+
*
411+
* But languages might choose to take the information of [TypeToInfer] and [source] and create a
412+
* specific [TranslationUnitDeclaration], e.g., for each namespace that is inferred globally or
413+
* try to put all inferred declarations into one specific (inferred) new translation unit.
414+
*
415+
* @param TypeToInfer the type of the node that should be inferred
416+
* @param source the source that was responsible for the inference
417+
*/
418+
fun <TypeToInfer : Node> translationUnitForInference(source: Node): TranslationUnitDeclaration {
419+
val tu = source.ctx?.currentComponent?.translationUnits?.firstOrNull()
420+
if (tu == null) {
421+
throw TranslationException(
422+
"No translation unit found that should be used for inference"
423+
)
424+
}
425+
426+
return tu
427+
}
391428
}
392429

393430
/**

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

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ open class TypeResolver(ctx: TranslationContext) : ComponentPass(ctx) {
4949
lateinit var walker: SubgraphWalker.ScopedWalker
5050

5151
override fun accept(component: Component) {
52+
ctx.currentComponent = component
5253
resolveFirstOrderTypes()
5354
refreshNames()
5455

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

+6-3
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ fun Pass<*>.tryNamespaceInference(name: Name, source: Node): NamespaceDeclaratio
8383
holder = tryScopeInference(parentName, source)
8484
}
8585

86-
return (holder ?: source.translationUnit ?: scopeManager.globalScope?.astNode)
86+
return (holder ?: scopeManager.translationUnitForInference<NamespaceDeclaration>(source))
8787
?.startInference(ctx)
8888
?.inferNamespaceDeclaration(name, null, source)
8989
}
@@ -133,7 +133,7 @@ internal fun Pass<*>.tryRecordInference(type: Type, source: Node): RecordDeclara
133133
}
134134

135135
val record =
136-
(holder ?: source.translationUnit ?: scopeManager.globalScope?.astNode)
136+
(holder ?: scopeManager.translationUnitForInference<RecordDeclaration>(source))
137137
?.startInference(ctx)
138138
?.inferRecordDeclaration(type, kind, source)
139139

@@ -197,7 +197,10 @@ internal fun Pass<*>.tryVariableInference(ref: Reference): VariableDeclaration?
197197
} else if (ref.language is HasGlobalVariables) {
198198
// We can try to infer a possible global variable (at top-level), if the language
199199
// supports this
200-
scopeManager.globalScope?.astNode?.startInference(this.ctx)?.inferVariableDeclaration(ref)
200+
scopeManager
201+
.translationUnitForInference<VariableDeclaration>(ref)
202+
?.startInference(this.ctx)
203+
?.inferVariableDeclaration(ref)
201204
} else {
202205
// Nothing to infer
203206
null

0 commit comments

Comments
 (0)