Skip to content

Commit 096c652

Browse files
committed
Providing a new HasDynamicVariable language trait
Merging the old python extra pass into the `SymbolResolver` using the trait.
1 parent b45fb46 commit 096c652

File tree

12 files changed

+697
-576
lines changed

12 files changed

+697
-576
lines changed

Diff for: cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/frontends/LanguageTraits.kt

+30-6
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,20 @@ package de.fraunhofer.aisec.cpg.frontends
2727

2828
import de.fraunhofer.aisec.cpg.ScopeManager
2929
import de.fraunhofer.aisec.cpg.TranslationContext
30-
import de.fraunhofer.aisec.cpg.graph.HasOperatorCode
31-
import de.fraunhofer.aisec.cpg.graph.HasOverloadedOperation
32-
import de.fraunhofer.aisec.cpg.graph.LanguageProvider
33-
import de.fraunhofer.aisec.cpg.graph.Name
30+
import de.fraunhofer.aisec.cpg.graph.*
31+
import de.fraunhofer.aisec.cpg.graph.declarations.Declaration
3432
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
3533
import de.fraunhofer.aisec.cpg.graph.declarations.RecordDeclaration
3634
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
37-
import de.fraunhofer.aisec.cpg.graph.scopes.*
35+
import de.fraunhofer.aisec.cpg.graph.edges.flows.*
36+
import de.fraunhofer.aisec.cpg.graph.scopes.GlobalScope
37+
import de.fraunhofer.aisec.cpg.graph.scopes.RecordScope
38+
import de.fraunhofer.aisec.cpg.graph.scopes.Scope
39+
import de.fraunhofer.aisec.cpg.graph.scopes.Symbol
3840
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
39-
import de.fraunhofer.aisec.cpg.passes.*
41+
import de.fraunhofer.aisec.cpg.passes.ResolveCallExpressionAmbiguityPass
42+
import de.fraunhofer.aisec.cpg.passes.ResolveMemberExpressionAmbiguityPass
43+
import de.fraunhofer.aisec.cpg.passes.SymbolResolver
4044
import kotlin.reflect.KClass
4145

4246
/**
@@ -298,6 +302,26 @@ inline infix fun <reified T : HasOverloadedOperation> KClass<T>.of(
298302
return Pair(T::class, operatorCode)
299303
}
300304

305+
/**
306+
* A language trait that specifies that this language has dynamic declarations, meaning that
307+
* declarations can be added to the symbol table at runtime. Since we are a static analysis tools,
308+
* we can only deliver an approximation to the actual behaviour.
309+
*/
310+
interface HasDynamicDeclarations : LanguageTrait {
311+
312+
/**
313+
* A callback that can be used by a language to provide a declaration for a reference. The
314+
* language is responsible for
315+
* - Adding the declaration to the symbol table (using [ScopeManager.addDeclaration]; as well as
316+
* adding it to the AST
317+
* - Injecting the declaration into the EOG path (if necessary). Since this reference might be
318+
* part of different AST expressions different approaches might be necessary. The utility
319+
* functions [Node.insertNodeBeforeInEOGPath] and [Node.insertNodeAfterwardInEOGPath] should
320+
* be used.
321+
*/
322+
fun SymbolResolver.provideDeclaration(ref: Reference): Declaration?
323+
}
324+
301325
/** Checks whether the name for a function (as [CharSequence]) is a known operator name. */
302326
context(LanguageProvider)
303327
val CharSequence.isKnownOperatorName: Boolean

Diff for: cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/EvaluationOrderGraphPass.kt

+26
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import de.fraunhofer.aisec.cpg.graph.Node
3434
import de.fraunhofer.aisec.cpg.graph.StatementHolder
3535
import de.fraunhofer.aisec.cpg.graph.declarations.*
3636
import de.fraunhofer.aisec.cpg.graph.edges.flows.EvaluationOrder
37+
import de.fraunhofer.aisec.cpg.graph.edges.flows.insertNodeBeforeInEOGPath
3738
import de.fraunhofer.aisec.cpg.graph.firstParentOrNull
3839
import de.fraunhofer.aisec.cpg.graph.statements.*
3940
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
@@ -1482,3 +1483,28 @@ open class EvaluationOrderGraphPass(ctx: TranslationContext) : TranslationUnitPa
14821483
nextEdgeBranch = tmpBranchLabel
14831484
}
14841485
}
1486+
1487+
/**
1488+
* This adds an extra declaration (see [AssignExpression.declarations] to the EOG of the
1489+
* [AssignExpression]. This is needed if we somehow add the declaration after the pass has initially
1490+
* run.
1491+
*
1492+
* This mimics the behaviour in [EvaluationOrderGraphPass.handleAssignExpression].
1493+
*/
1494+
fun AssignExpression.addDeclarationToEOG(decl: Declaration): Boolean? {
1495+
// We need to insert the declaration before the first lhs ref
1496+
return this.lhs.firstOrNull()?.insertNodeBeforeInEOGPath(decl)
1497+
}
1498+
1499+
/**
1500+
* This adds an extra local declaration (see [ForEachStatement.locals]) to the EOG of the
1501+
* [ForEachStatement]. This is needed if we somehow add the declaration after the pass has initially
1502+
* run.
1503+
*
1504+
* This mimics the behaviour in [EvaluationOrderGraphPass.handleForEachStatement].
1505+
*/
1506+
fun ForEachStatement.addDeclarationToEOG(decl: Declaration): Boolean? {
1507+
// Actually, it seems like we are not adding the declaration of a local variable to the EOG of
1508+
// the ForEachStatement at all.
1509+
return true
1510+
}

Diff for: cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/SymbolResolver.kt

+14
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
194194
val language = ref.language
195195
val helperType = ref.resolutionHelper?.type
196196

197+
// Before we resolve anything, we give languages with dynamic declarations a chance to
198+
// declare any variables they need. This is most likely only needed for WRITE references,
199+
// but we let the language decide that
200+
if (language is HasDynamicDeclarations) {
201+
with(language) { provideDeclaration(ref) }
202+
}
203+
197204
// Ignore references to anonymous identifiers, if the language supports it (e.g., the _
198205
// identifier in Go)
199206
if (
@@ -312,6 +319,13 @@ open class SymbolResolver(ctx: TranslationContext) : ComponentPass(ctx) {
312319
val base = current.base
313320
val language = current.language
314321

322+
// Before we resolve anything, we give languages with dynamic declarations a chance to
323+
// declare any variables they need. This is most likely only needed for WRITE references,
324+
// but we let the language decide that
325+
if (language is HasDynamicDeclarations) {
326+
with(language) { provideDeclaration(current) }
327+
}
328+
315329
// We need to adjust certain types of the base in case of a "super" expression, and we
316330
// delegate this to the language. If that is successful, we can continue with regular
317331
// resolving.

0 commit comments

Comments
 (0)