Skip to content

TNO/Dependency_Graph_Extractor-Ada

Repository files navigation

Dependency Graph Extractor

The Dependency Graph Extractor generates a GraphML file with dependency information derived from the Ada source files contained within the given project files.

Running

Run the Dependency Graph Extractor as follows:

dependency_graph_extractor.exe -o output.graphml [-p directory] project_1.gpr ... project_n.gpr

 -h, --help           Display help
 -o, --output=ARG     The output GraphML file
 -p, --prefix=ARG     Directory prefix stripped from the file names in the output graph

The output GraphML file is required, as is at least one GPR file. If the output GraphML file already exists, it will be overwritten.

Optionally, a directory prefix can be passed to the extractor using the -p option. When done so, the extractor removes the prefix from every filename in the generated GraphML file. Note that, if a filename does not start with the specified prefix, it wil occur in the GraphML file as-is.

Note. Although Dependency Graph Extractor can analyse multiple projects, it can't analyze an aggregate project with more than one sub-project.

Example

Suppose we want to extract source code dependency information from the GPR project named rejuvenation.gpr, which is located in C:\path\to\Renaissance-Ada\src\libraries\rejuvenation. Moreover, suppose we do not want have the C:\path\to\Renaissance-Ada\src\libraries\rejuvenation prefix occurring in the generated GraphML file. To achieve this, we can run the Dependency Graph Extractor directly from alire as follows:

alr run --args="-o rejuvenation.graphml -p C:\path\to\Renaissance-Ada\src\libraries\rejuvenation C:\path\to\Renaissance-Ada\src\libraries\rejuvenation\rejuvenation.gpr"

Or just as a normal program:

dependency_graph_extractor.exe -o rejuvenation.graphml -p C:\path\to\Renaissance-Ada\src\libraries\rejuvenation C:\path\to\Renaissance-Ada\src\libraries\rejuvenation\rejuvenation.gpr

when either dependency_graph_extractor.exe is on the system PATH or the current directory is the obj directory of the Dependency_Graph_Extractor project.

This will create the GraphML file rejuvenation.graphml in the current directory.

Usage

Open the generated graphml file with Neo4j according to the import instructions. Note, your cypher query should resemble

CALL apoc.import.graphml("movies.graphml", {readLabels: true})

Prepare yourself by reading the Node and Edge Types present in the graph database.

You can now interactively query the graph database using Cypher. For more info on Cypher, see the Cypher resources, including the Neo4j Cypher refcard.

Below, you find some example Cypher queries. Note that all example queries are rather general. So add LIMIT 25 to the end of the queries whenever your code base contains a lot of matches to still get a fast response.

Analyze recursion

Find recursive functions

Run the Cypher query

MATCH (f)-[:Calls]->(f) RETURN *

to find all recursive functions.

Find all recursion

Run the Cypher query

MATCH (f)-[:Calls*]->(f) RETURN *

to find all recursion.

Find indirect recursion

Run the Cypher query

MATCH (a)-[:Calls*]->(b)-[:Calls*]->(a) RETURN *

to find indirect recursion only.

Analyze references

Chain of references between two files

Run the Cypher query

MATCH
 p = (decl_begin:AdaDeclaration)-[:References*]->(decl_end:AdaDeclaration),
 (decl_begin)-[source_begin:Source]->(file_begin:File),
 (decl_end)-[source_end:Source]->(file_end:File)
WHERE
 file_begin.relativeName = "rejuvenation-patterns.adb" AND
 file_end.relativeName = "rejuvenation-simple_factory.ads"
RETURN p

to find all chains of references that begin with a declaration in "rejuvenation-patterns.adb" and end on a declaration in "rejuvenation-simple_factory.ads"

Number of references to declarations in file

Run the Cypher query

CALL 
{
    MATCH 
       (provider:AdaDeclaration)-[:Source]->(adsFile:AdaSpecificationFile)
    WHERE
       adsFile.name ENDS WITH "rejuvenation-string_utils.ads"
    RETURN provider
}
WITH provider,
     size (()-[:References]->(provider)) as refCount
RETURN provider.relativeName, refCount ORDER BY refCount DESC

to get a table of all declarations in "rejuvenation-string_utils.ads" and how often each declaration is directly referenced.

Refering entities to declarations in file

Run the Cypher query

MATCH 
   (provider:AdaDeclaration)-[:Source]->(adsFile:AdaSpecificationFile),
   (user)-[:References]->(provider)
WHERE
   adsFile.name ENDS WITH "rejuvenation-string_utils.ads"
RETURN user, provider

to get the declarations in "rejuvenation-string_utils.ads" that are referenced together with the refering entities.

Refering external declarations

Run the Cypher query

MATCH
  (depProject:GnatProject)-[:Contains]->(depFile)<-[:Source]-(dep:AdaDeclaration),
  (dge)-[:References]->(dep),
  (dgeProject:GnatProject)-[:Contains]->(dgeFile)<-[:Source]-(dge:AdaDeclaration)
WHERE 
  depProject.relativeName <> "Dependency_Graph_Extractor" AND 
  dgeProject.relativeName = "Dependency_Graph_Extractor"
RETURN 
  dep.fullyQualifiedName, count(dge) as depCount 
ORDER BY depCount DESC

to get the declarations outside the Dependency_Graph_Extractor project, that are used by the Dependency_Graph_Extractor project together with their number of references. The textual output is similar to

╒══════════════════════════════════════════════════════════════════════╤══════════╕
│"dep.fullyQualifiedName"                                              │"depCount"│
╞══════════════════════════════════════════════════════════════════════╪══════════╡
│"Libadalang.Analysis.Ada_Node"                                        │67        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
│"Libadalang.Analysis.Basic_Decl"                                      │61        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
│"GNATCOLL.VFS.Virtual_File"                                           │46        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
│"Libadalang.Analysis.Kind"                                            │41        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
│"GNATCOLL.Projects.Project_Type"                                      │24        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
│"Libadalang.Analysis.Defining_Name"                                   │23        │
├──────────────────────────────────────────────────────────────────────┼──────────┤
...

Building

Alire

  1. Install Alire.
  2. Install Git.
  3. Clone the Dependency Graph Extractor project: git clone https://github.com/TNO/Dependency_Graph_Extractor-Ada.git.
  4. Start the PowerShell terminal with Alire in the environment PATH (installed by Alire by default on your desktop).
  5. Navigate to the directory containing the Dependency Graph Extractor.
  6. Ensure alire has the latest information by running alr update --online in that directory.
  7. Execute alr build in that directory.