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 7089f436fd..0e3b01f1b8 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 @@ -39,6 +39,7 @@ import de.fraunhofer.aisec.cpg.graph.edge.Properties import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdge.Companion.unwrap import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdgeDelegate +import de.fraunhofer.aisec.cpg.graph.edge.PropertyEdgeSetDelegate import de.fraunhofer.aisec.cpg.graph.scopes.GlobalScope import de.fraunhofer.aisec.cpg.graph.scopes.RecordScope import de.fraunhofer.aisec.cpg.graph.scopes.Scope @@ -187,13 +188,25 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider this.nextEOGEdges = PropertyEdge.transformIntoOutgoingPropertyEdgeList(value, this) } + /** Incoming data flow edges */ @Relationship(value = "DFG", direction = Relationship.Direction.INCOMING) @PopulatedByPass(DFGPass::class, ControlFlowSensitiveDFGPass::class) - var prevDFG: MutableSet = HashSet() + var prevDFGEdges: MutableList> = mutableListOf() + internal set + /** Virtual property for accessing [prevDFGEdges] without property edges. */ @PopulatedByPass(DFGPass::class, ControlFlowSensitiveDFGPass::class) - @Relationship(value = "DFG") - var nextDFG: MutableSet = HashSet() + var prevDFG: MutableSet by PropertyEdgeSetDelegate(Node::prevDFGEdges, false) + + /** Outgoing data flow edges */ + @PopulatedByPass(DFGPass::class, ControlFlowSensitiveDFGPass::class) + @Relationship(value = "DFG", direction = Relationship.Direction.OUTGOING) + var nextDFGEdges: MutableList> = mutableListOf() + internal set + + /** Virtual property for accessing [nextDFGEdges] without property edges. */ + @PopulatedByPass(DFGPass::class, ControlFlowSensitiveDFGPass::class) + var nextDFG: MutableSet by PropertyEdgeSetDelegate(Node::nextDFGEdges, true) var typedefs: MutableSet = HashSet() @@ -244,21 +257,34 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider nextEOGEdges.clear() } - fun addNextDFG(next: Node) { - nextDFG.add(next) - next.prevDFG.add(this) + fun addNextDFG( + next: Node, + properties: MutableMap = EnumMap(Properties::class.java) + ) { + val edge = PropertyEdge(this, next, properties) + nextDFGEdges.add(edge) + next.prevDFGEdges.add(edge) } fun removeNextDFG(next: Node?) { if (next != null) { - nextDFG.remove(next) - next.prevDFG.remove(this) + val thisRemove = + PropertyEdge.findPropertyEdgesByPredicate(nextDFGEdges) { it.end === next } + nextDFGEdges.removeAll(thisRemove) + + val nextRemove = + PropertyEdge.findPropertyEdgesByPredicate(next.prevDFGEdges) { it.start == this } + next.prevDFGEdges.removeAll(nextRemove) } } - fun addPrevDFG(prev: Node) { - prevDFG.add(prev) - prev.nextDFG.add(this) + fun addPrevDFG( + prev: Node, + properties: MutableMap = EnumMap(Properties::class.java) + ) { + val edge = PropertyEdge(prev, this, properties) + prevDFGEdges.add(edge) + prev.nextDFGEdges.add(edge) } fun addPrevCDG(prev: Node) { @@ -267,15 +293,22 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider prev.nextCDGEdges.add(edge) } - fun addAllPrevDFG(prev: Collection) { - prevDFG.addAll(prev) - prev.forEach { it.nextDFG.add(this) } + fun addAllPrevDFG( + prev: Collection, + properties: MutableMap = EnumMap(Properties::class.java) + ) { + prev.forEach { addPrevDFG(it, properties.toMutableMap()) } } fun removePrevDFG(prev: Node?) { if (prev != null) { - prevDFG.remove(prev) - prev.nextDFG.remove(this) + val thisRemove = + PropertyEdge.findPropertyEdgesByPredicate(prevDFGEdges) { it.start === prev } + prevDFGEdges.removeAll(thisRemove) + + val prevRemove = + PropertyEdge.findPropertyEdgesByPredicate(prev.nextDFGEdges) { it.end === this } + prev.nextDFGEdges.removeAll(prevRemove) } } @@ -309,15 +342,19 @@ open class Node : IVisitable, Persistable, LanguageProvider, ScopeProvider * further children that have no alternative connection paths to the rest of the graph. */ fun disconnectFromGraph() { - for (n in nextDFG) { - n.prevDFG.remove(this) + for (n in nextDFGEdges) { + val remove = + PropertyEdge.findPropertyEdgesByPredicate(n.end.prevDFGEdges) { it.start == this } + n.end.prevDFGEdges.removeAll(remove) } - nextDFG.clear() + nextDFGEdges.clear() - for (n in prevDFG) { - n.nextDFG.remove(this) + for (n in prevDFGEdges) { + val remove = + PropertyEdge.findPropertyEdgesByPredicate(n.start.nextDFGEdges) { it.end == this } + n.start.nextDFGEdges.removeAll(remove) } - prevDFG.clear() + prevDFGEdges.clear() for (n in nextEOGEdges) { val remove = diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edge/PropertyEdge.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edge/PropertyEdge.kt index 1b5e59d4f2..8e74020131 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edge/PropertyEdge.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/graph/edge/PropertyEdge.kt @@ -168,7 +168,7 @@ open class PropertyEdge : Persistable { ): MutableList> { val propertyEdges: MutableList> = ArrayList() for (n in nodes) { - var propertyEdge = PropertyEdge(commonRelationshipNode, n) + val propertyEdge = PropertyEdge(commonRelationshipNode, n) propertyEdge.addProperty(Properties.INDEX, propertyEdges.size) propertyEdges.add(propertyEdge) } @@ -373,3 +373,23 @@ class PropertyEdgeDelegate( } } } + +/** Similar to a [PropertyEdgeDelegate], but with a [Set] instead of [List]. */ +@Transient +class PropertyEdgeSetDelegate( + val edge: KProperty1>>, + val outgoing: Boolean = true +) { + operator fun getValue(thisRef: S, property: KProperty<*>): MutableSet { + return PropertyEdge.unwrap(edge.get(thisRef), outgoing).toMutableSet() + } + + operator fun setValue(thisRef: S, property: KProperty<*>, value: MutableSet) { + if (edge is KMutableProperty1) { + edge.setter.call( + thisRef, + PropertyEdge.transformIntoOutgoingPropertyEdgeList(value.toList(), thisRef as Node) + ) + } + } +} diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CXXCallResolverHelper.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CXXCallResolverHelper.kt index 24ba098441..1030524b39 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CXXCallResolverHelper.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/CXXCallResolverHelper.kt @@ -378,10 +378,7 @@ fun applyTemplateInstantiation( // Template. for ((declaration) in initializationSignature) { if (declaration is ParamVariableDeclaration) { - initializationSignature[declaration]?.let { - declaration.addPrevDFG(it) - it.addNextDFG(declaration) // TODO: This should be unnecessary - } + initializationSignature[declaration]?.let { declaration.addPrevDFG(it) } } } diff --git a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt index 76bcd8c09a..6d1af8f6f1 100644 --- a/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt +++ b/cpg-core/src/main/kotlin/de/fraunhofer/aisec/cpg/passes/inference/Inference.kt @@ -293,8 +293,6 @@ class Inference(val start: Node, override val ctx: TranslationContext) : node .startInference(ctx) .inferNonTypeTemplateParameter(inferredNonTypeIdentifier) - - paramVariableDeclaration.addPrevDFG(node) node.addNextDFG(paramVariableDeclaration) nonTypeCounter++ inferred.addParameter(paramVariableDeclaration)