Skip to content

Commit

Permalink
ada: improve handling of filenames
Browse files Browse the repository at this point in the history
  • Loading branch information
Ptival committed Nov 30, 2020
1 parent 83d9ebb commit 2ab1bd7
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 20 deletions.
24 changes: 18 additions & 6 deletions ada/run_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from rdflib import Graph, Namespace

from ada_print_visitor import AdaPrintVisitor
from ontology import Component, ComponentType, FileFormat
from ontology import Component, ComponentType, File, FileFormat
import static_call_graph as SCG

# In order to do resolution at call sites, the analysis needs to resolve
Expand Down Expand Up @@ -65,25 +65,37 @@ def register_component(components, component: SCG.GraphNode) -> None:
# TODO: check what we know about the actual component type
components[key] = Component(DATA[uri], name, ComponentType.SOURCE_FUNCTION)

def register_ada_file(files: Dict[str, File], file_key: str) -> File:
if file_key not in files:
files[file_key] = File(DATA[file_key], file_key, ada_format)
return files[file_key]

def analyze_unit(unit: lal.AnalysisUnit) -> None:
"""Computes and displays the static call graph of some unit."""
if unit.root:
if DEBUG:
ada_visitor = AdaPrintVisitor(max_depth=20)
ada_visitor.visit(unit.root)
static_call_graph_visitor = SCG.StaticCallGraphVisitor(
caller_being_defined = SCG.ToplevelNode(unit.filename),
edges = dict(),
nodes = dict()
context=context,
caller_being_defined=SCG.ToplevelNode(unit.filename),
edges=dict(),
nodes=dict()
)

static_call_graph_visitor.visit(unit.root)

components: Dict[str, Component] = dict()
files: Dict[str, File] = dict()

# register all components
# register all files and components (so as to have one unique instance
# for each)
for component_key in static_call_graph_visitor.nodes:
register_component(components, static_call_graph_visitor.nodes[component_key])
component = static_call_graph_visitor.nodes[component_key]
register_component(components, component)
if isinstance(component, SCG.CallableNode):
file = register_ada_file(files, component.get_definition_file())
components[component_key].defined_in = file

# add "mentions" to all components that mention other components
for caller in static_call_graph_visitor.edges:
Expand Down
32 changes: 18 additions & 14 deletions ada/static_call_graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,25 +61,25 @@ class CallableNode(GraphNode):
the analyzed Ada code.
"""

def __init__(self, node: lal.Name):
def __init__(self, context: lal.AnalysisContext, node: lal.Name):
self.context = context
self.node = node

def get_key(self):
return node_key(self.node)

def get_name_for_lal_name(self, name: lal.Name):
name_as_string = name.p_relative_name.p_canonical_text
location = name.full_sloc_image[:-2]
return f"{name_as_string} ({location})"
def get_definition_file(self) -> str:
xref = self.node.p_gnat_xref()
if not xref:
raise Exception(f"The reference to node {self} could not be resolved.")
# NOTE: if we need the full path, we can use:
# xref.p_basic_decl.unit.filename
# NOTE: full_sloc_image returns "file.ada:<line>:<column>: " but we just
# want the filename
return xref.p_basic_decl.full_sloc_image.split(":")[0]

def get_name(self) -> str:
if isinstance(self.node, lal.DefiningName):
return self.get_name_for_lal_name(self.node.f_name)
if isinstance(self.node, lal.DottedName):
return self.get_name_for_lal_name(self.node)
if isinstance(self.node, lal.Identifier):
return f"{self.node.p_canonical_text} ({self.node.full_sloc_image[:-2]})"
raise Exception(f"get_name: no implementation for CallableNode {self.node}")
return self.node.text

def get_uri(self) -> str:
xref = self.node.p_gnat_xref()
Expand All @@ -96,6 +96,7 @@ class StaticCallGraphVisitor(AdaVisitor):

def __init__(
self,
context: lal.AnalysisContext,
caller_being_defined: GraphNode,
nodes: Dict[str, GraphNode],
edges: Dict[str, Set[str]]
Expand All @@ -108,6 +109,8 @@ def __init__(
creating a bunch of short-lived instances.
"""

self.context = context

self.caller_being_defined: GraphNode = caller_being_defined
"""
Name of the caller currently being defined, that will be deemed the
Expand Down Expand Up @@ -140,7 +143,7 @@ def get_graph_node_for_name(self, node: lal.Name) -> GraphNode:
"""Returns the graph node for a name, creating it if none exists yet."""
key = node_key(node)
if key not in self.nodes:
self.nodes[key] = CallableNode(node)
self.nodes[key] = CallableNode(self.context, node)
return self.nodes[key]

def record_call(self, callee: lal.Name) -> None:
Expand All @@ -161,6 +164,7 @@ def locally_visit(
variables.
"""
local_visitor = StaticCallGraphVisitor(
context=self.context,
caller_being_defined=caller_being_defined,
nodes=self.nodes,
edges=self.edges
Expand Down Expand Up @@ -191,6 +195,6 @@ def callback(visitor):
visitor.visit(node.f_stmts)

self.locally_visit(
caller_being_defined=CallableNode(name),
caller_being_defined=CallableNode(self.context, name),
callback=callback
)

0 comments on commit 2ab1bd7

Please sign in to comment.