+++ /dev/null
-# This file is part of NIT ( http://www.nitlanguage.org ).
-#
-# 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.
-
-# Nodes for modules and files.
-module model::module_compound
-
-import graph
-import class_compound
-import namespace_members
-
-# A source file.
-#
-# Creates one modules by inner namespace. The full name of the modules begin
-# with the namespace’s full name, and end with the unqualified name of the file,
-# without the extension.
-#
-# Note: If a module associated to the root namespace is needed, it is added to
-# the graph only when `put_edges` is called.
-class FileCompound
- super Compound
- super CodeBlock
-
- # Modules corresponding to the namespaces defined/redefined in the file.
- private var inner_namespaces = new Array[Module]
-
- # `model_id` of the classes declared in the file.
- private var inner_classes = new Array[String]
-
- # The last component of the path, without the extension.
- #
- # Used as the unqualified name of the modules.
- private var basename: String = ""
-
- init do
- super
- end
-
- redef fun location=(location) do
- super
- for m in inner_namespaces do m.location = location
- end
-
- redef fun name=(name) do
- # Example: `MyClass.java`
- super
- var match = name.search_last(".")
-
- if match == null then
- basename = name
- else
- basename = name.substring(0, match.from)
- end
- # Update the modules’ name.
- for m in inner_namespaces do m.update_name
- end
-
- redef fun declare_namespace(id, full_name) do
- var m: Module
-
- assert not full_name.is_empty or id.is_empty else
- sys.stderr.write "Inner mamespace declarations without name are not yet supported (except for the root namespace).\n"
- end
- m = new Module(graph, self, new NamespaceRef(id, full_name))
- m.location = location
- inner_namespaces.add m
- 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
- inner_classes.add id
- end
-
- redef fun put_in_graph do
- # Do not add `self` to the Neo4j graph...
- # ... but add its modules...
- for m in inner_namespaces do m.put_in_graph
- # ... and add `self` to the indexes.
- if model_id != "" then graph.by_id[model_id] = self
- graph.files.add self
- end
-
- # If the file contains some classes in the root namespace, add an implicit
- # module to handle them.
- #
- # This method is called by `ProjectGraph.add_global_modules` and assumes
- # that all the namespaces are already fully set and put in the graph.
- fun declare_root_namespace do
- if has_globals then
- declare_namespace("", "")
- inner_namespaces.last.put_in_graph
- end
- end
-
- # Does this file contain classes in the root namespace?
- private fun has_globals: Bool do
- var root = graph.by_id[""]
- for c in inner_classes do
- if graph.class_to_ns[c] == root then return true
- end
- return false
- end
-end
-
-# A `MModule` node.
-#
-# For each file, there is one module by inner namespace.
-private class Module
- super Compound
- super CodeBlock
-
- # The file that declares the module.
- var file_compound: FileCompound
-
- # The namespace defined or redefined by the module.
- var namespace: NamespaceRef
-
- init do
- super
- self.labels.add("MModule")
- update_name
- end
-
- # Update the `name`.
- #
- # Update the short name of the module to the `basename` of the file that
- # declares it.
- fun update_name do name = file_compound.basename
-
- redef fun put_edges do
- var ns_compound = namespace.seek_in(graph)
- var self_class = ns_compound.self_class
- var class_count = 0
- var last_class: nullable ClassCompound = null
-
- graph.add_edge(ns_compound, "DECLARES", self)
-
- for c in file_compound.inner_classes do
- if graph.class_to_ns[c] != ns_compound then continue
- var class_compound = graph.by_id[c].as(ClassCompound)
- last_class = class_compound
- class_count += 1
- graph.add_edge(self, "INTRODUCES", class_compound)
- graph.add_edge(self, "DEFINES", class_compound.class_def)
- end
-
- if self_class isa SelfClass then
- # We assume that only one file is linked to the namespace.
- # TODO When Doxygen will provide a way to know which file defines which member, use it.
- self_class.location = file_compound.location
- graph.add_edge(self, "INTRODUCES", self_class)
- graph.add_edge(self, "DEFINES", self_class.class_def)
- end
-
- if doc.is_empty and class_count == 1 then
- doc = last_class.as(not null).doc
- end
- if doc.is_empty then doc = file_compound.doc
- if doc.is_empty then doc = ns_compound.doc
- if not doc.is_empty then set_mdoc
- end
-end
-
-# Adds the `add_global_modules` phase to `ProjectGraph`.
-redef class ProjectGraph
-
- # Project’s source files.
- var files: SimpleCollection[FileCompound] = new Array[FileCompound]
-
- # Add the modules that define the root namespace.
- #
- # **Must** be called before any call to `put_edges`, and after all the
- # namespaces are fully set and put in the graph.
- #
- # Note: This method is not idempotent so it has to be called only once.
- fun add_global_modules do
- for f in files do f.declare_root_namespace
- end
-end