Rename REAMDE to README.md
[nit.git] / src / model_utils.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2008 Jean Privat <jean@pryen.org>
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 # http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16
17 # Model exploration and traversing facilities
18 module model_utils
19
20 import model
21
22 redef class MConcern
23
24 # Boost a MConcern rank
25 # see: `MConcernRankSorter`
26 # Use a positive booster to push down a result in the list
27 # A negative booster can be used to push up the result
28 var booster_rank: Int = 0 is writable
29
30 # Concern ranking used for ordering
31 # see: `MConcernRankSorter`
32 # Rank can be positive or negative
33 fun concern_rank: Int is abstract
34 end
35
36 redef class MProject
37 redef var concern_rank is lazy do
38 var max = 0
39 for mgroup in mgroups do
40 var mmax = mgroup.concern_rank
41 if mmax > max then max = mmax
42 end
43 return max + 1
44 end
45 end
46
47 redef class MGroup
48 fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
49 var res = new HashSet[MClass]
50 var lst = in_nesting.direct_smallers
51 for mmodule in mmodules do res.add_all mmodule.filter_intro_mclasses(min_visibility)
52 for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclasses(min_visibility)
53 return res
54 end
55
56 fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
57 var res = new HashSet[MClass]
58 var lst = in_nesting.direct_smallers
59 for mmodule in mmodules do res.add_all mmodule.filter_redef_mclasses(min_visibility)
60 for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclasses(min_visibility)
61 return res
62 end
63
64 fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
65 var res = new HashSet[MClassDef]
66 var lst = in_nesting.direct_smallers
67 for mmodule in mmodules do res.add_all mmodule.intro_mclassdefs(min_visibility)
68 for mgrp in lst do res.add_all mgrp.in_nesting_intro_mclassdefs(min_visibility)
69 return res
70 end
71
72 fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
73 var res = new HashSet[MClassDef]
74 var lst = in_nesting.direct_smallers
75 for mmodule in mmodules do res.add_all mmodule.redef_mclassdefs(min_visibility)
76 for mgrp in lst do res.add_all mgrp.in_nesting_redef_mclassdefs(min_visibility)
77 return res
78 end
79
80 # Collect nested modules
81 fun collect_mmodules: Set[MModule] do
82 var res = new HashSet[MModule]
83 res.add_all mmodules
84 for mgroup in in_nesting.direct_smallers do
85 res.add_all mgroup.collect_mmodules
86 end
87 return res
88 end
89
90 redef var concern_rank is lazy do
91 var max = 0
92 for mmodule in collect_mmodules do
93 var mmax = mmodule.concern_rank
94 if mmax > max then max = mmax
95 end
96 return max + 1
97 end
98 end
99
100 redef class MModule
101
102 # The list of intro mclassdef in the module.
103 # with visibility >= to min_visibility
104 fun intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
105 var res = new HashSet[MClassDef]
106 for mclassdef in mclassdefs do
107 if not mclassdef.is_intro then continue
108 if mclassdef.mclass.visibility < min_visibility then continue
109 res.add mclassdef
110 end
111 return res
112 end
113
114 # The list of redef mclassdef in the module.
115 # with visibility >= to min_visibility
116 fun redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
117 var res = new HashSet[MClassDef]
118 for mclassdef in mclassdefs do
119 if mclassdef.is_intro then continue
120 if mclassdef.mclass.visibility < min_visibility then continue
121 res.add mclassdef
122 end
123 return res
124 end
125
126 # The list of intro mclass in the module.
127 # with visibility >= to min_visibility
128 fun filter_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
129 var res = new HashSet[MClass]
130 for mclass in intro_mclasses do
131 if mclass.visibility < min_visibility then continue
132 res.add mclass
133 end
134 return res
135 end
136
137 # Get the list of mclasses refined in 'self'.
138 fun redef_mclasses: Set[MClass] do
139 var mclasses = new HashSet[MClass]
140 for c in mclassdefs do
141 if not c.is_intro then mclasses.add(c.mclass)
142 end
143 return mclasses
144 end
145
146 # Get the list of mclasses refined in 'self'.
147 fun filter_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
148 var mclasses = new HashSet[MClass]
149 for c in mclassdefs do
150 if c.mclass.visibility < min_visibility then continue
151 if not c.is_intro then mclasses.add(c.mclass)
152 end
153 return mclasses
154 end
155
156 # Get the list of all mclasses imported by 'self'.
157 fun imported_mclasses: Set[MClass] do
158 var mclasses = new HashSet[MClass]
159 for m in in_importation.greaters do
160 if m == self then continue
161 for c in m.mclassdefs do mclasses.add(c.mclass)
162 end
163 return mclasses
164 end
165
166 redef var concern_rank is lazy do
167 var max = 0
168 for p in in_importation.direct_greaters do
169 var pmax = p.concern_rank
170 if pmax > max then max = pmax
171 end
172 return max + 1
173 end
174
175 # Find all mmodules nested in `self` if `self` is the default module of a `MGroup`.
176 fun nested_mmodules: Array[MModule] do
177 var res = new Array[MModule]
178 var mgroup = mgroup
179 if mgroup == null or self != mgroup.default_mmodule then return res
180 for mmodule in mgroup.mmodules do
181 if mmodule == self then continue
182 res.add mmodule
183 end
184 for nested in mgroup.in_nesting.direct_smallers do
185 var default = nested.default_mmodule
186 if default == null then continue
187 res.add default
188 end
189 return res
190 end
191 end
192
193 redef class MClass
194
195 # Get direct parents of 'self'.
196 fun parents: Set[MClass] do
197 var ret = new HashSet[MClass]
198 for mclassdef in mclassdefs do
199 for mclasstype in mclassdef.supertypes do
200 ret.add(mclasstype.mclass)
201 end
202 end
203 return ret
204 end
205
206 # Get all ancestors of 'self'.
207 fun ancestors: Set[MClass] do
208 var lst = new HashSet[MClass]
209 for mclassdef in self.mclassdefs do
210 for super_mclassdef in mclassdef.in_hierarchy.greaters do
211 if super_mclassdef == mclassdef then continue # skip self
212 lst.add(super_mclassdef.mclass)
213 end
214 end
215 return lst
216 end
217
218 # Get direct children of 'self'.
219 fun children: Set[MClass] do
220 var lst = new HashSet[MClass]
221 for mclassdef in self.mclassdefs do
222 for sub_mclassdef in mclassdef.in_hierarchy.direct_smallers do
223 if sub_mclassdef == mclassdef then continue # skip self
224 lst.add(sub_mclassdef.mclass)
225 end
226 end
227 return lst
228 end
229
230 # Get all children of 'self'.
231 fun descendants: Set[MClass] do
232 var lst = new HashSet[MClass]
233 for mclassdef in self.mclassdefs do
234 for sub_mclassdef in mclassdef.in_hierarchy.smallers do
235 if sub_mclassdef == mclassdef then continue # skip self
236 lst.add(sub_mclassdef.mclass)
237 end
238 end
239 return lst
240 end
241
242 # Get the list of constructors available for 'self'.
243 fun constructors: Set[MMethod] do
244 var res = new HashSet[MMethod]
245 for mclassdef in mclassdefs do
246 for mpropdef in mclassdef.mpropdefs do
247 if mpropdef isa MMethodDef then
248 if mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
249 end
250 end
251 end
252 return res
253 end
254
255 # Get the list of methods introduced in 'self'.
256 fun intro_methods: Set[MMethod] do
257 var res = new HashSet[MMethod]
258 for mclassdef in mclassdefs do
259 for mpropdef in mclassdef.mpropdefs do
260 if mpropdef isa MMethodDef then
261 if mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
262 end
263 end
264 end
265 return res
266 end
267
268 # the set of properties introduced in 'self'.
269 fun intro_mproperties(min_visibility: MVisibility): Set[MProperty] do
270 var set = new HashSet[MProperty]
271 for mclassdef in mclassdefs do
272 for mprop in mclassdef.intro_mproperties do
273 if mprop.visibility < min_visibility then continue
274 set.add(mprop)
275 end
276 end
277 return set
278 end
279
280 fun intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
281 var set = new HashSet[MPropDef]
282 for mclassdef in mclassdefs do
283 for mpropdef in mclassdef.mpropdefs do
284 if not mpropdef.is_intro then continue
285 if mpropdef.mproperty.visibility < min_visibility then continue
286 set.add(mpropdef)
287 end
288 end
289 return set
290 end
291
292 # the set of locally refined properties in 'self'.
293 fun redef_mproperties(min_visibility: MVisibility): Set[MProperty] do
294 var set = new HashSet[MProperty]
295 for mclassdef in mclassdefs do
296 for mpropdef in mclassdef.mpropdefs do
297 if mpropdef.mproperty.visibility < min_visibility then continue
298 if mpropdef.mproperty.intro_mclassdef.mclass != self then set.add(mpropdef.mproperty)
299 end
300 end
301 return set
302 end
303
304 fun redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
305 var set = new HashSet[MPropDef]
306 for mclassdef in mclassdefs do
307 for mpropdef in mclassdef.mpropdefs do
308 if mpropdef.is_intro then continue
309 if mpropdef.mproperty.visibility < min_visibility then continue
310 set.add(mpropdef)
311 end
312 end
313 return set
314 end
315
316 # the set of methods inherited by 'self'.
317 fun inherited_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
318 var set = new HashSet[MProperty]
319 for parent in in_hierarchy(mainmodule).direct_greaters do
320 set.add_all(parent.intro_mproperties(min_visibility))
321 set.add_all(parent.inherited_mproperties(mainmodule, min_visibility))
322 end
323 return set
324 end
325
326 # the set of introduced and redefined mproperties
327 fun local_mproperties(min_visibility: MVisibility): Set[MProperty] do
328 var set = new HashSet[MProperty]
329 set.add_all(intro_mproperties(min_visibility))
330 set.add_all(redef_mproperties(min_visibility))
331 return set
332 end
333
334 # the set of all accessible mproperties for this class
335 fun all_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
336 var set = new HashSet[MProperty]
337 set.add_all(local_mproperties(min_visibility))
338 set.add_all(inherited_mproperties(mainmodule, min_visibility))
339 return set
340 end
341
342 # the set of all accessible mattributes for this class
343 fun all_mattributes(mainmodule: MModule, min_visibility: MVisibility): Set[MAttribute] do
344 var set = new HashSet[MAttribute]
345 for mprop in all_mproperties(mainmodule, min_visibility) do
346 if mprop isa MAttribute then set.add(mprop)
347 end
348 return set
349 end
350
351 # Get the list of locally refined methods in 'self'.
352 fun redef_methods: Set[MMethod] do
353 var res = new HashSet[MMethod]
354 for mclassdef in mclassdefs do
355 for mpropdef in mclassdef.mpropdefs do
356 if mpropdef isa MMethodDef then
357 if not mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
358 end
359 end
360 end
361 return res
362 end
363
364 fun inherited_methods: Set[MMethod] do
365 var res = new HashSet[MMethod]
366 for s in ancestors do
367 for m in s.intro_methods do
368 if not self.intro_methods.has(m) and not self.redef_methods.has(m) then res.add(m)
369 end
370 end
371 return res
372 end
373
374 # Get the list of all virtual types available in 'self'.
375 fun virtual_types: Set[MVirtualTypeProp] do
376 var res = new HashSet[MVirtualTypeProp]
377 for mclassdef in mclassdefs do
378 for mpropdef in mclassdef.mpropdefs do
379 if mpropdef isa MVirtualTypeDef then
380 res.add(mpropdef.mproperty)
381 end
382 end
383 end
384 for ancestor in ancestors do
385 for mclassdef in ancestor.mclassdefs do
386 for mpropdef in mclassdef.mpropdefs do
387 if mpropdef isa MVirtualTypeDef then
388 res.add(mpropdef.mproperty)
389 end
390 end
391 end
392 end
393 return res
394 end
395
396 # Get the list of all parameter types in 'self'.
397 fun parameter_types: Map[String, MType] do
398 var res = new HashMap[String, MType]
399 for p in mparameters do
400 res[p.name] = p
401 end
402 return res
403 end
404
405 fun is_class: Bool do
406 return self.kind == concrete_kind or self.kind == abstract_kind
407 end
408
409 fun is_interface: Bool do
410 return self.kind == interface_kind
411 end
412
413 fun is_enum: Bool do
414 return self.kind == enum_kind
415 end
416
417 fun is_abstract: Bool do
418 return self.kind == abstract_kind
419 end
420 end
421
422 redef class MAttribute
423 # Is this attribute nullable for sure?
424 #
425 # This mean that its introduction is declarred with a nullable static type
426 # since attributes are invariant this will work on most cases
427 # attributes with static type anchored with a virtual type are not "nullable for-sure"
428 # because this type can be redefined in subclasses
429 fun is_nullable: Bool do return intro.static_mtype isa MNullableType
430 end
431
432 redef class MClassDef
433 # modifiers are keywords like redef, private etc.
434 fun modifiers: Array[String] do
435 var res = new Array[String]
436 if not is_intro then
437 res.add "redef"
438 else
439 res.add mclass.visibility.to_s
440 end
441 res.add mclass.kind.to_s
442 return res
443 end
444
445 fun collect_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
446 var res = new HashSet[MPropDef]
447 for mpropdef in mpropdefs do
448 if mpropdef.mproperty.visibility < min_visibility then continue
449 res.add mpropdef
450 end
451 return res
452 end
453
454 fun collect_intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
455 var res = new HashSet[MPropDef]
456 for mpropdef in mpropdefs do
457 if not mpropdef.is_intro then continue
458 if mpropdef.mproperty.visibility < min_visibility then continue
459 res.add mpropdef
460 end
461 return res
462 end
463
464 fun collect_redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
465 var res = new HashSet[MPropDef]
466 for mpropdef in mpropdefs do
467 if mpropdef.is_intro then continue
468 if mpropdef.mproperty.visibility < min_visibility then continue
469 res.add mpropdef
470 end
471 return res
472 end
473 end
474
475 redef class MPropDef
476 # modifiers are keywords like redef, private etc.
477 fun modifiers: Array[String] do
478 var res = new Array[String]
479 if not is_intro then
480 res.add "redef"
481 else
482 res.add mproperty.visibility.to_s
483 end
484 var mprop = self
485 if mprop isa MVirtualTypeDef then
486 res.add "type"
487 else if mprop isa MMethodDef then
488 if mprop.is_abstract then
489 res.add "abstract"
490 else if mprop.is_intern then
491 res.add "intern"
492 end
493 if mprop.mproperty.is_init then
494 res.add "init"
495 else
496 res.add "fun"
497 end
498 end
499 return res
500 end
501 end
502
503 # Sorters
504
505 # Sort mentities by their name
506 class MEntityNameSorter
507 super Comparator
508 redef type COMPARED: MEntity
509 redef fun compare(a, b) do return a.name <=> b.name
510 end
511
512 # Sort MConcerns based on the module importation hierarchy ranking
513 # see also: `MConcern::concern_rank` and `MConcern::booster_rank`
514 #
515 # Comparison is made with the formula:
516 #
517 # ~~~nitish
518 # a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
519 # ~~~
520 #
521 # If both `a` and `b` have the same ranking,
522 # ordering is based on lexicographic comparison of `a.name` and `b.name`
523 class MConcernRankSorter
524 super Comparator
525 redef type COMPARED: MConcern
526
527 redef fun compare(a, b) do
528 if a.concern_rank == b.concern_rank then
529 return a.name <=> b.name
530 end
531 return a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_rank
532 end
533 end