Cypher query for shortest path with end node constraint

I have created a call graph from java bytecode and have to find the closest parent of the class that the method generates. I have a solution, I just want to check that it cannot be simplified.

The graph has the following relationships and labels:

+---------[ :Class ] -[hasMethod]-> [ :Method ] --+
|            ^                        ^           |
+-[inherits]-+                        +-[invokes]-+

      

Now consider the following code:

class Parent {
   protected void hello() {
   }
}

class Foo extends Parent {
   @Override
   protected void hello() {
   }
}

class Bar extends Foo {
   public void test() {
      hello();
   }
}

      

Parsing the bytecode, I get the following nodes and relationships (only relevant ones are shown here:

(Parent:Class)-[:hasMethod]-(:Method{name:"Parent#hello()V", 
   simpleName:"hello", signature:"()V"})
(Foo:Class)-[:inherits]->Parent
Foo-[:hasMethod]->(:Method{name: "Foo#hello()V", 
   simpleName:"hello", signature:"()V"})
(Bar:Class)-[:inherits]->Foo
Bar->[:hasMethod]->(test:Method{simpleName: "test"})
test->[:invokes]->(:Method{name: "Bar#hello()V",
  simpleName:"hello", signature: "()V"

      

I want to find the declared closest parent method that will be called in such a case. My solution looks like this:

match (m:Method) where not m<-[:hasMethod]-()
// method.name is Class#name(signature) 
with m, split(m.name,'#')[0] as className

// find a method with same name and signature
match (superMethod:Method{methodName:m.methodName, signature:m.signature}),

// which is declared in a superclass
p=(c:Class{name:className})-[:inherits*]->(super)-[:hasMethod]->superMethod

// and group them in a collection
with m, collect(p) as allPossibleSuperMethods

// and now keep the closest method (with the shortest path to it)
with m, reduce(path = null, p in allPossibleSuperMethods |
  case
    // the candidate is either better than nothing or shorter than previous
    when path is null or length(p) < length(path) then p
   // or we've got our winner already 
   else path
end) as superMethodPath

// and the last on the path is the closest declared method
with m,last(superMethodPath) as superMethod

// so we mark the replacement
create m-[:implementedBy]->superMethod

      

As you can see, the challenge is to create a link between an undeclared method (which has no hasMethod relationship) and exactly one declared method of the parent class. The question is, can you make it easier? As far as I understand, the shortestPath function cannot have restrictions on target nodes if we omit the fact that we need to intersect two different types of relationships.

An example is also available in the interactive version http://console.neo4j.org/?id=9cmwaf

The task of the request is to return only one string - Foo # hello ()

+3


source to share





All Articles