c95cb84380a367e65f021d08546c360d7b2896b7
1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Nodes for modules and files.
16 module model
::module_compound
20 import namespace_members
24 # Creates one modules by inner namespace. The full name of the modules begin
25 # with the namespace’s full name, and end with the unqualified name of the file,
26 # without the extension.
28 # Note: If a module associated to the root namespace is needed, it is added to
29 # the graph only when `put_edges` is called.
34 # Modules corresponding to the namespaces defined/redefined in the file.
35 private var inner_namespaces
= new Array[Module]
37 # `model_id` of the classes declared in the file.
38 private var inner_classes
= new Array[String]
40 # The last component of the path, without the extension.
42 # Used as the unqualified name of the modules.
43 private var basename
: String = ""
49 redef fun name_separator
: String do return "/"
51 redef fun location
=(location
: nullable Location) do
53 if location
!= null and location
.path
!= null then
54 full_name
= location
.path
.as(not null)
56 for m
in inner_namespaces
do m
.location
= location
59 redef fun name
=(name
: String) do
60 # Example: `MyClass.java`
62 var match
= name
.search_last
(".")
67 basename
= name
.substring
(0, match
.from
)
69 # Update the modules’ name.
70 for m
in inner_namespaces
do m
.update_name
73 redef fun declare_namespace
(id
: String, full_name
: String) do
76 assert not full_name
.is_empty
or id
.is_empty
else
77 sys
.stderr
.write
"Inner mamespace declarations without name are not yet supported (except for the root namespace).\n"
79 m
= new Module(graph
, self, new NamespaceRef(id
, full_name
))
80 m
.location
= self["location"].as(nullable Location)
81 inner_namespaces
.add m
84 redef fun declare_class
(id
, full_name
, prot
) do
85 assert not id
.is_empty
else
86 sys
.stderr
.write
"Inner class declarations without ID are not yet supported.\n"
91 redef fun put_in_graph
do
92 # Do not add `self` to the Neo4j graph...
93 # ... but add its modules...
94 for m
in inner_namespaces
do m
.put_in_graph
95 # ... and add `self` to the indexes.
96 if model_id
!= "" then graph
.by_id
[model_id
] = self
100 # If the file contains some classes in the root namespace, add an implicit
101 # module to handle them.
103 # This method is called by `ProjectGraph.add_global_modules` and assumes
104 # that all the namespaces are already fully set and put in the graph.
105 fun declare_root_namespace
do
107 declare_namespace
("", "")
108 inner_namespaces
.last
.put_in_graph
112 # Does this file contain classes in the root namespace?
113 private fun has_globals
: Bool do
114 var root
= graph
.by_id
[""]
115 for c
in inner_classes
do
116 if graph
.class_to_ns
[c
] == root
then return true
124 # For each file, there is one module by inner namespace.
129 # The file that declares the module.
130 var file_compound
: FileCompound
132 # The namespace defined or redefined by the module.
133 var namespace
: NamespaceRef
137 self.labels
.add
("MModule")
141 # Update the `full_name` and the `name`.
143 # Update the short name of the module to the `basename` of the file that
146 name
= file_compound
.basename
147 parent_name
= namespace
.full_name
150 redef fun put_in_graph
do
154 redef fun put_edges
do
155 var ns_compound
= namespace
.seek_in
(graph
)
156 var self_class
= ns_compound
.self_class
158 graph
.add_edge
(ns_compound
, "DECLARES", self)
160 for c
in file_compound
.inner_classes
do
161 if graph
.class_to_ns
[c
] != ns_compound
then continue
162 var class_compound
= graph
.by_id
[c
].as(ClassCompound)
163 graph
.add_edge
(self, "INTRODUCES", class_compound
)
164 graph
.add_edge
(self, "DEFINES", class_compound
.class_def
)
167 if self_class
isa SelfClass then
168 # We assume that only one file is linked to the namespace.
169 # TODO When Doxygen will provide a way to know which file defines which member, use it.
170 graph
.add_edge
(self, "INTRODUCES", self_class
)
171 graph
.add_edge
(self, "DEFINES", self_class
.class_def
)
176 # Adds the `add_global_modules` phase to `ProjectGraph`.
177 redef class ProjectGraph
179 # Project’s source files.
180 var files
: SimpleCollection[FileCompound] = new Array[FileCompound]
182 # Add the modules that define the root namespace.
184 # **Must** be called before any call to `put_edges`, and after all the
185 # namespaces are fully set and put in the graph.
187 # Note: This method is not idempotent so it has to be called only once.
188 fun add_global_modules
do
189 for f
in files
do f
.declare_root_namespace