Skip to content

Commit

Permalink
Implementing AST properties using singleton edge lists (#1646)
Browse files Browse the repository at this point in the history
* Implementing AST properties using singleton edge lists

This PR is a tryout

* Adding mission relationship annotation

* remove one more addStatement

* Some additional cleanup

* Slightly better naeming for delegate
  • Loading branch information
oxisto authored Aug 29, 2024
1 parent 58c304c commit 9a57367
Show file tree
Hide file tree
Showing 102 changed files with 1,081 additions and 780 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,10 @@ import de.fraunhofer.aisec.cpg.graph.invoke
import de.fraunhofer.aisec.cpg.graph.statements.DeclarationStatement
import de.fraunhofer.aisec.cpg.graph.statements.ForStatement
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
import de.fraunhofer.aisec.cpg.passes.EdgeCachePass
import de.fraunhofer.aisec.cpg.passes.astParent
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/**
* This [ValueEvaluator] can resolve multiple possible values of a node.
*
* It requires running the [EdgeCachePass] after the translation to add all necessary edges.
*/
/** This [ValueEvaluator] can resolve multiple possible values of a node. */
class MultiValueEvaluator : ValueEvaluator() {
companion object {
const val MAX_DEPTH: Int = 20
Expand Down Expand Up @@ -268,7 +262,8 @@ class MultiValueEvaluator : ValueEvaluator() {
forStatement.initializerStatement == node || // The node is the initialization
(initializerDecl != null &&
initializerDecl ==
node.astParent) || // The parent of the node is the initializer of the loop
node.astParent) || // The parent of the node is the initializer of the
// loop
// variable
forStatement.iterationStatement ==
node || // The node or its parent are the iteration statement of the loop
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.ConstructExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.MemberCallExpression
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Reference
import de.fraunhofer.aisec.cpg.passes.astParent
import org.slf4j.Logger
import org.slf4j.LoggerFactory

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ import de.fraunhofer.aisec.cpg.frontends.TestLanguage
import de.fraunhofer.aisec.cpg.frontends.TestLanguageFrontend
import de.fraunhofer.aisec.cpg.graph.array
import de.fraunhofer.aisec.cpg.graph.builder.*
import de.fraunhofer.aisec.cpg.passes.EdgeCachePass
import de.fraunhofer.aisec.cpg.passes.UnreachableEOGPass

class GraphExamples {
Expand All @@ -45,7 +44,6 @@ class GraphExamples {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down Expand Up @@ -244,7 +242,6 @@ class GraphExamples {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import de.fraunhofer.aisec.cpg.graph.array
import de.fraunhofer.aisec.cpg.graph.builder.*
import de.fraunhofer.aisec.cpg.graph.newNewArrayExpression
import de.fraunhofer.aisec.cpg.graph.pointer
import de.fraunhofer.aisec.cpg.passes.EdgeCachePass

class Query {
companion object {
Expand Down Expand Up @@ -99,7 +98,6 @@ class Query {
TranslationConfiguration.builder()
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<EdgeCachePass>()
.inferenceConfiguration(InferenceConfiguration.builder().enabled(false).build())
.build()
) =
Expand Down Expand Up @@ -176,7 +174,6 @@ class Query {
TranslationConfiguration.builder()
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<EdgeCachePass>()
.inferenceConfiguration(
InferenceConfiguration.builder().inferFunctions(false).build()
)
Expand Down Expand Up @@ -255,7 +252,6 @@ class Query {
TranslationConfiguration.builder()
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down Expand Up @@ -392,7 +388,6 @@ class Query {
config: TranslationConfiguration =
TranslationConfiguration.builder()
.defaultPasses()
.registerPass<EdgeCachePass>()
.registerLanguage(TestLanguage("."))
.build()
) =
Expand Down Expand Up @@ -438,7 +433,6 @@ class Query {
config: TranslationConfiguration =
TranslationConfiguration.builder()
.defaultPasses()
.registerPass<EdgeCachePass>()
.registerLanguage(TestLanguage("."))
.build()
) =
Expand Down Expand Up @@ -498,7 +492,6 @@ class Query {
config: TranslationConfiguration =
TranslationConfiguration.builder()
.defaultPasses()
.registerPass<EdgeCachePass>()
.registerLanguage(TestLanguage("."))
.build()
) =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ import de.fraunhofer.aisec.cpg.TranslationConfiguration
import de.fraunhofer.aisec.cpg.frontends.TestLanguage
import de.fraunhofer.aisec.cpg.graph.*
import de.fraunhofer.aisec.cpg.graph.builder.*
import de.fraunhofer.aisec.cpg.passes.EdgeCachePass
import de.fraunhofer.aisec.cpg.passes.UnreachableEOGPass

class ValueEvaluationTests {
Expand All @@ -40,7 +39,6 @@ class ValueEvaluationTests {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down Expand Up @@ -100,7 +98,6 @@ class ValueEvaluationTests {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down Expand Up @@ -143,7 +140,6 @@ class ValueEvaluationTests {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down Expand Up @@ -249,7 +245,6 @@ class ValueEvaluationTests {
.defaultPasses()
.registerLanguage(TestLanguage("."))
.registerPass<UnreachableEOGPass>()
.registerPass<EdgeCachePass>()
.build()
) =
testFrontend(config).build {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,16 +26,18 @@
package de.fraunhofer.aisec.cpg

import de.fraunhofer.aisec.cpg.frontends.LanguageFrontend
import de.fraunhofer.aisec.cpg.graph.AST
import de.fraunhofer.aisec.cpg.graph.Component
import de.fraunhofer.aisec.cpg.graph.Name
import de.fraunhofer.aisec.cpg.graph.Node
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
import de.fraunhofer.aisec.cpg.helpers.MeasurementHolder
import de.fraunhofer.aisec.cpg.helpers.StatisticsHolder
import de.fraunhofer.aisec.cpg.passes.Pass
import java.util.*
import java.util.concurrent.ConcurrentHashMap
import org.neo4j.ogm.annotation.Relationship

/**
* The global (intermediate) result of the translation. A [LanguageFrontend] will initially populate
Expand All @@ -52,11 +54,12 @@ class TranslationResult(
var finalCtx: TranslationContext,
) : Node(), StatisticsHolder {

@Relationship("COMPONENTS") val componentEdges = astEdgesOf<Component>()
/**
* Entry points to the CPG: "SoftwareComponent" refer to programs, application, other "bundles"
* of software.
*/
@AST val components = mutableListOf<Component>()
val components by unwrapping(TranslationResult::componentEdges)

/**
* Scratch storage that can be used by passes to store additional information in this result.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,13 +137,13 @@ class FrontendUtils {
val smallestEnclosingNode =
enclosingNodes.sortedWith(compareBy { it.code?.length ?: 10000 }).first()

val children = SubgraphWalker.getAstChildren(smallestEnclosingNode).toMutableList()
val children = smallestEnclosingNode.astChildren.toMutableList()

// Because in GO we wrap all elements into a NamespaceDeclaration we have to extract the
// natural children
children.addAll(
children.filterIsInstance<NamespaceDeclaration>().flatMap { namespace ->
SubgraphWalker.getAstChildren(namespace).filter { it !in children }
namespace.astChildren.filter { it !in children }
}
)

Expand Down
35 changes: 0 additions & 35 deletions cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/AST.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
package de.fraunhofer.aisec.cpg.graph

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
import org.neo4j.ogm.annotation.Relationship

/**
* A node which presents some kind of complete piece of software, e.g., an application, a library,
Expand All @@ -35,8 +38,10 @@ import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
* entry points or interactions with other software.
*/
open class Component : Node() {
@Relationship("TRANSLATION_UNITS")
val translationUnitEdges = astEdgesOf<TranslationUnitDeclaration>()
/** All translation units belonging to this application. */
@AST val translationUnits: MutableList<TranslationUnitDeclaration> = mutableListOf()
val translationUnits by unwrapping(Component::translationUnitEdges)

@Synchronized
fun addTranslationUnit(tu: TranslationUnitDeclaration) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ fun LanguageProvider.newTupleDeclaration(

// Also all our elements need to have an auto-type
elements.forEach { it.type = autoType() }
node.elements = elements
node.elements = elements.toMutableList()

node.initializer = initializer

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ fun MetadataProvider.newAssignExpression(
val node = AssignExpression()
node.applyMetadata(this, operatorCode, rawNode, true)
node.operatorCode = operatorCode
node.lhs = lhs
node.rhs = rhs
node.lhs = lhs.toMutableList()
node.rhs = rhs.toMutableList()

log(node)

Expand Down Expand Up @@ -207,8 +207,8 @@ fun MetadataProvider.newConditionalExpression(
*/
@JvmOverloads
fun MetadataProvider.newKeyValueExpression(
key: Expression? = null,
value: Expression? = null,
key: Expression,
value: Expression,
rawNode: Any? = null
): KeyValueExpression {
val node = KeyValueExpression()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ import de.fraunhofer.aisec.cpg.graph.statements.WhileStatement
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker
import de.fraunhofer.aisec.cpg.passes.astParent
import kotlin.math.absoluteValue

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import de.fraunhofer.aisec.cpg.frontends.Handler
import de.fraunhofer.aisec.cpg.frontends.Language
import de.fraunhofer.aisec.cpg.graph.declarations.*
import de.fraunhofer.aisec.cpg.graph.edges.*
import de.fraunhofer.aisec.cpg.graph.edges.ast.astEdgesOf
import de.fraunhofer.aisec.cpg.graph.edges.flows.ControlDependences
import de.fraunhofer.aisec.cpg.graph.edges.flows.Dataflows
import de.fraunhofer.aisec.cpg.graph.edges.flows.EvaluationOrders
Expand Down Expand Up @@ -165,6 +166,8 @@ abstract class Node :
var astChildren: List<Node> = listOf()
get() = SubgraphWalker.getAstChildren(this)

@Transient var astParent: Node? = null

/** Virtual property for accessing [prevEOGEdges] without property edges. */
@PopulatedByPass(EvaluationOrderGraphPass::class) var prevEOG by unwrapping(Node::prevEOGEdges)

Expand Down Expand Up @@ -251,7 +254,8 @@ abstract class Node :
var argumentIndex = 0

/** List of annotations associated with that node. */
@AST var annotations: MutableList<Annotation> = ArrayList()
@Relationship("ANNOTATIONS") var annotationEdges = astEdgesOf<Annotation>()
var annotations by unwrapping(Node::annotationEdges)

/**
* If a node should be removed from the graph, just removing it from the AST is not enough (see
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,22 +50,6 @@ interface StatementHolder : Holder<Statement> {
*/
var statements: MutableList<Statement>

/**
* Adds the specified statement to this statement holder. The statements have to be stored as a
* list of statements as we try to avoid adding new AST-nodes that do not exist, e.g. a code
* body to hold statements
*
* This only exists because of
* [de.fraunhofer.aisec.cpg.graph.statements.ForEachStatement.addStatement] which is needed
* until we re-design the Fluent DSL.
*
* @param s the statement
*/
@Deprecated(message = "This should be replaced by a direct call to statementEdges.add.")
fun addStatement(s: Statement) {
statementEdges.add(s)
}

override operator fun plusAssign(node: Statement) {
statementEdges += node
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1310,7 +1310,7 @@ fun Expression.conditional(
context(LanguageFrontend<*, *>, StatementHolder)
infix fun Expression.assign(init: AssignExpression.() -> Expression): AssignExpression {
val node = (this@LanguageFrontend).newAssignExpression("=")
node.lhs = listOf(this)
node.lhs = mutableListOf(this)
init(node)
// node.rhs = listOf(init(node))

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@
*/
package de.fraunhofer.aisec.cpg.graph.declarations

import de.fraunhofer.aisec.cpg.graph.AST
import de.fraunhofer.aisec.cpg.graph.HasInitializer
import de.fraunhofer.aisec.cpg.graph.edges.ast.astOptionalEdgeOf
import de.fraunhofer.aisec.cpg.graph.edges.unwrapping
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Expression
import org.neo4j.ogm.annotation.Relationship

/**
* Represents a constant within an [EnumDeclaration]. Depending on the language, this might have an
* explicit initializer value.
*/
class EnumConstantDeclaration : ValueDeclaration(), HasInitializer {
@AST override var initializer: Expression? = null
@Relationship("INITIALIZER") var initializerEdge = astOptionalEdgeOf<Expression>()
override var initializer by unwrapping(EnumConstantDeclaration::initializerEdge)
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,14 @@
*/
package de.fraunhofer.aisec.cpg.graph.declarations

import de.fraunhofer.aisec.cpg.graph.AST
import de.fraunhofer.aisec.cpg.graph.edges.ast.astEdgesOf
import de.fraunhofer.aisec.cpg.graph.edges.unwrapping
import org.apache.commons.lang3.builder.ToStringBuilder
import org.neo4j.ogm.annotation.Relationship

class EnumDeclaration : RecordDeclaration() {
@Relationship(value = "ENTRIES", direction = Relationship.Direction.OUTGOING)
@AST
var entryEdges = astEdgesOf<EnumConstantDeclaration>()

var entries by unwrapping(EnumDeclaration::entryEdges)

override fun toString(): String {
Expand Down
Loading

0 comments on commit 9a57367

Please sign in to comment.