Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Convert Neo4j pre-save hooks to cpg pass #1224

Merged
merged 2 commits into from
Jul 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2023, Fraunhofer AISEC. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* $$$$$$\ $$$$$$$\ $$$$$$\
* $$ __$$\ $$ __$$\ $$ __$$\
* $$ / \__|$$ | $$ |$$ / \__|
* $$ | $$$$$$$ |$$ |$$$$\
* $$ | $$ ____/ $$ |\_$$ |
* $$ | $$\ $$ | $$ | $$ |
* \$$$$$ |$$ | \$$$$$ |
* \______/ \__| \______/
*
*/
package de.fraunhofer.aisec.cpg.passes

import de.fraunhofer.aisec.cpg.TranslationContext
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.allChildren
import de.fraunhofer.aisec.cpg.graph.declarations.TranslationUnitDeclaration
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker
import de.fraunhofer.aisec.cpg.passes.order.ExecuteBefore
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField

/** Pass with some graph transformations useful when doing serialization. */
@ExecuteBefore(FilenameMapper::class)
class PrepareSerialization(ctx: TranslationContext) : TranslationUnitPass(ctx) {
private val nodeNameField =
Node::class
.memberProperties
.first() { it.name == "name" }
.javaField
.also { it?.isAccessible = true }

override fun cleanup() {
// nothing to do
}

override fun accept(tr: TranslationUnitDeclaration) {
tr.allChildren<Node>().map { node ->
// Add explicit AST edge
node.astChildren = SubgraphWalker.getAstChildren(node)
// CallExpression overwrites name property and must be copied to JvmField
// to be visible by Neo4jOGM
if (node is CallExpression) nodeNameField?.set(node, node.name)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,28 +27,20 @@ package de.fraunhofer.aisec.cpg_vis_neo4j

import de.fraunhofer.aisec.cpg.*
import de.fraunhofer.aisec.cpg.frontends.CompilationDatabase.Companion.fromFile
import de.fraunhofer.aisec.cpg.graph.Node
import de.fraunhofer.aisec.cpg.graph.statements.expressions.CallExpression
import de.fraunhofer.aisec.cpg.helpers.Benchmark
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker
import de.fraunhofer.aisec.cpg.passes.*
import de.fraunhofer.aisec.cpg.passes.order.*
import java.io.File
import java.lang.Class
import java.net.ConnectException
import java.nio.file.Paths
import java.util.concurrent.Callable
import kotlin.reflect.KClass
import kotlin.reflect.full.memberProperties
import kotlin.reflect.jvm.javaField
import kotlin.system.exitProcess
import org.neo4j.driver.exceptions.AuthenticationException
import org.neo4j.ogm.config.Configuration
import org.neo4j.ogm.exception.ConnectionException
import org.neo4j.ogm.session.Session
import org.neo4j.ogm.session.SessionFactory
import org.neo4j.ogm.session.event.Event
import org.neo4j.ogm.session.event.EventListenerAdapter
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import picocli.CommandLine
Expand Down Expand Up @@ -303,7 +295,6 @@ class Application : Callable<Int> {
"de.fraunhofer.aisec.cpg.graph",
"de.fraunhofer.aisec.cpg.frontends"
)
sessionFactory.register(AstChildrenEventListener())

session = sessionFactory.openSession()
} catch (ex: ConnectionException) {
Expand Down Expand Up @@ -351,7 +342,7 @@ class Application : Callable<Int> {
* point to a file, is a directory or point to a hidden file or the paths does not have the
* same top level path.
*/
private fun setupTranslationConfiguration(): TranslationConfiguration {
fun setupTranslationConfiguration(): TranslationConfiguration {
val translationConfiguration =
TranslationConfiguration.builder()
.topLevel(topLevel)
Expand Down Expand Up @@ -394,6 +385,7 @@ class Application : Callable<Int> {
}
}
}
translationConfiguration.registerPass(PrepareSerialization::class)

mutuallyExclusiveParameters.jsonCompilationDatabase?.let {
val db = fromFile(it)
Expand Down Expand Up @@ -477,27 +469,6 @@ class Application : Callable<Int> {
}
}

class AstChildrenEventListener : EventListenerAdapter() {
private val nodeNameField =
Node::class
.memberProperties
.first() { it.name == "name" }
.javaField
.also { it?.isAccessible = true }

override fun onPreSave(event: Event?) {
val node = event?.`object` as? Node ?: return
node.astChildren = SubgraphWalker.getAstChildren(node)
if (node is CallExpression) fixBackingFields(node)
}

private fun fixBackingFields(node: CallExpression) {
// CallExpression overwrites name property and must be copied to JvmField
// to be visible by Neo4jOGM
nodeNameField?.set(node, node.name)
}
}

/**
* Starts a command line application of the cpg-vis-neo4j.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,47 +25,35 @@
*/
package de.fraunhofer.aisec.cpg_vis_neo4j

import de.fraunhofer.aisec.cpg.TranslationConfiguration
import de.fraunhofer.aisec.cpg.TranslationManager
import de.fraunhofer.aisec.cpg.TranslationResult
import de.fraunhofer.aisec.cpg.graph.declarations.FunctionDeclaration
import de.fraunhofer.aisec.cpg.graph.functions
import java.io.File
import java.nio.file.Paths
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import org.junit.jupiter.api.Tag
import picocli.CommandLine

@Tag("integration")
class ApplicationTest {

private var translationResult: TranslationResult? = null

@Test
@Throws(InterruptedException::class)
fun testPush() {
val topLevel = Paths.get("src").resolve("test").resolve("resources").toAbsolutePath()
val path = topLevel.resolve("client.cpp").toAbsolutePath()
val file = File(path.toString())
assert(file.exists() && !file.isDirectory && !file.isHidden)
val translationConfiguration =
TranslationConfiguration.builder()
.sourceLocations(file)
.topLevel(topLevel.toFile())
.defaultPasses()
.defaultLanguages()
.debugParser(true)
.build()
val translationManager =
TranslationManager.builder().config(translationConfiguration).build()
translationResult = translationManager.analyze().get()

assertEquals(31, translationResult.functions.size)
val cmd = CommandLine(Application::class.java)
cmd.parseArgs(path.toString())
val application = cmd.getCommand<Application>()

val application = Application()
val translationConfiguration = application.setupTranslationConfiguration()
val translationResult =
TranslationManager.builder().config(translationConfiguration).build().analyze().get()

assertEquals(31, translationResult.functions.size)

application.pushToNeo4j(translationResult!!)
application.pushToNeo4j(translationResult)

val sessionAndSessionFactoryPair = application.connect()

Expand Down