X-Git-Url: http://nitlanguage.org diff --git a/contrib/neo_doxygen/src/model/graph.nit b/contrib/neo_doxygen/src/model/graph.nit index 98244eb..9df491a 100644 --- a/contrib/neo_doxygen/src/model/graph.nit +++ b/contrib/neo_doxygen/src/model/graph.nit @@ -16,7 +16,9 @@ module model::graph import neo4j +import more_collections import location +import descriptions # A Neo4j graph. class NeoGraph @@ -35,6 +37,22 @@ class NeoGraph end # A project’s graph. +# +# Here is the usual steps to build a project graph: +# +# class ProjectGraph super NeoGraph @@ -49,6 +67,21 @@ class ProjectGraph # Entities by `model_id`. var by_id: Map[String, Entity] = new HashMap[String, Entity] + # Namespaces by `full_name`. + var namespaces: Map[String, Namespace] = new HashMap[String, Namespace] + + # For each `ClassCompound` in the graph, the mapping between its `model_id` and its namespace. + # + # Defaults to the root namespace. An entry is added each time + # `Namespace.declare_class` is called. + # + # Note: In the graph, there is no direct link between a namespace and a + # class. It is the role of a module (created internally by a `FileCompound`) + # to link a class with its namespace. So, this collection is used by modules + # to know which class in a file belong to their related namespace. It is + # also used by `FileCompound` to detect classes in the root namespace. + var class_to_ns: Map[String, Namespace] is noinit + # Initialize a new project graph using the specified project name. # # The specified name will label all nodes of the project’s graph. @@ -62,9 +95,15 @@ class ProjectGraph var root = new RootNamespace(self) root.put_in_graph by_id[""] = root + class_to_ns = new DefaultMap[String, Namespace](root) end # Request to all nodes in the graph to add their related edges. + # + # Note: For the rare cases where a node need to wait the `put_edges` to add + # an implicit node, this method makes sure to call the `put_edges` method + # of the newly added nodes only after processing all the nodes that was + # already there. fun put_edges do all_edges.clear add_edge(project, "ROOT", by_id[""]) @@ -90,8 +129,14 @@ abstract class Entity # Is empty for entities without an ID. var model_id: String = "" is writable + # The full (qualified) name, as presented by the original model. + # + # Fully independant of `name`. By default, equals to `""` for the root + # namespace. + var full_name: nullable String = null is writable + # Associated documentation. - var doc = new JsonArray is writable + var doc = new Documentation is writable init do self.labels.add(graph.project_name) @@ -99,8 +144,6 @@ abstract class Entity end # The short (unqualified) name. - # - # May be also set by `full_name=`. fun name=(name: String) do self["name"] = name end @@ -118,47 +161,26 @@ abstract class Entity end # The namespace separator of Nit/C++. - fun ns_separator: String do return "::" - - # The name separator used when calling `full_name=`. - fun name_separator: String do return ns_separator - - # The full (qualified) name. # - # Also set `name` using `name_separator`. - fun full_name=(full_name: String) do - var m: nullable Match = full_name.search_last(name_separator) - - self["full_name"] = full_name - if m == null then - name = full_name - else - name = full_name.substring_from(m.after) - end - end - - # The full (qualified) name. - fun full_name: String do - var full_name = self["full_name"] - assert full_name isa String - return full_name - end - - # Set the full name using the current name and the specified parent name. - fun parent_name=(parent_name: String) do - self["full_name"] = parent_name + name_separator + self["name"].as(not null).to_s - end + # Used to join two or more names when we need to work around some + # limitations of the Nit model. + fun ns_separator: String do return "::" # Set the location of the entity in the source code. - fun location=(location: nullable Location) do + fun location=(location: nullable neo_doxygen::Location) do self["location"] = location end + # Get the location of the entity in the source code. + fun location: nullable neo_doxygen::Location do + return self["location"].as(nullable neo_doxygen::Location) + end + # Put the entity in the graph. # # Called by the loader when it has finished to read the entity. fun put_in_graph do - if doc.length > 0 then + if not doc.is_empty then set_mdoc end graph.all_nodes.add(self) @@ -180,12 +202,12 @@ abstract class CodeBlock super Entity init do - self["location"] = new Location + self["location"] = new neo_doxygen::Location end - redef fun location=(location: nullable Location) do + redef fun location=(location) do if location == null then - super(new Location) + super(new neo_doxygen::Location) else super end @@ -199,7 +221,7 @@ end abstract class Compound super Entity - # Set the declared visibility (the proctection) of the compound. + # Set the declared visibility (the protection) of the compound. fun visibility=(visibility: String) do self["visibility"] = visibility end @@ -211,26 +233,28 @@ abstract class Compound # Declare an inner namespace. # - # Note: Althought Doxygen indicates that the name is optional, - # declarations with an empty name are not supported yet. + # Note: Although Doxygen indicates that the name is optional, + # declarations with an empty name are not supported yet, except for the root + # namespace. For the root namespace, both arguments are empty. # # Parameters: # # * `id`: `model_id` of the inner namespace. May be empty. - # * `full_name`: qualified name of the inner namespace. + # * `full_name`: qualified name of the inner namespace. Use an empty name + # for the root namespace. fun declare_namespace(id: String, full_name: String) do end # Declare an inner class. # - # Note: Althought Doxygen indicates that both arguments are optional, - # declarations with either an empty name or an empty ID are not - # supported yet. + # Note: Although Doxygen indicates that both arguments are optional, + # declarations with an empty ID are not supported yet. # # Parameters: # # * `id`: `model_id` of the inner class. - # * `full_name`: qualified name of the inner class. - fun declare_class(id: String, full_name: String) do end + # * `name`: short name of the inner class. + # * `prot`: visibility (proctection). + fun declare_class(id: String, name: String, prot: String) do end # Declare a base compound (usually, a base class). # @@ -260,37 +284,71 @@ end class Namespace super Compound - # Inner namespaces (IDs). - # - # Left empty for the root namespace. - var inner_namespaces: SimpleCollection[String] = new Array[String] + # The inner namespaces. + var inner_namespaces: SimpleCollection[NamespaceRef] = new Array[NamespaceRef] init do super self.labels.add("MGroup") end - redef fun declare_namespace(id: String, name: String) do - inner_namespaces.add(id) + redef fun declare_namespace(id, full_name) do + inner_namespaces.add new NamespaceRef(id, full_name) + end + + redef fun declare_class(id, name, prot) do + assert not id.is_empty else + sys.stderr.write "Inner class declarations without ID are not yet supported.\n" + end + graph.class_to_ns[id] = self + end + + redef fun put_in_graph do + super + var full_name = self.full_name + if full_name isa String then graph.namespaces[full_name] = self end redef fun put_edges do super graph.add_edge(self, "PROJECT", graph.project) - if self["name"] == self["full_name"] and self["full_name"] != "" then - # The root namespace does not know its children. - var root = graph.by_id[""] - graph.add_edge(self, "PARENT", root) - graph.add_edge(root, "NESTS", self) - end for ns in inner_namespaces do - var node = graph.by_id[ns] + var node = ns.seek_in(graph) graph.add_edge(node, "PARENT", self) graph.add_edge(self, "NESTS", node) end end end +# A reference to a namespace. +class NamespaceRef + # The `model_id` of the target. + # + # Empty when unknown or for the root namespace. + var model_id: String + + # The `full_name` of the target. + # + # Empty only for the root namespace. + var full_name: String + + # Look for the targeted namespace in the specified graph. + fun seek_in(graph: ProjectGraph): Namespace do + var ns_compound: Namespace + + if model_id.is_empty and not full_name.is_empty then + # ID unspecified. => We have to look by name + assert graph.namespaces.has_key(full_name) else + sys.stderr.write "Namespace `{full_name}` not found." + end + ns_compound = graph.namespaces[full_name] + else + ns_compound = graph.by_id[model_id].as(Namespace) + end + return ns_compound + end +end + # The root namespace of a `ProjectGraph`. # # This the only entity in the graph whose `model_id` is really `""`. @@ -300,9 +358,7 @@ class RootNamespace init do super - self["full_name"] = "" - self["name"] = graph.project["name"] + full_name = "" + name = graph.project_name end - - redef fun declare_namespace(id: String, name: String) do end end