model_collect: uniformize documentation
[nit.git] / src / model / model_collect.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 # Collect things from a `ModelView`
18 #
19 # This module introduce several usefull methods to list and count things from a
20 # ModelView.
21 #
22 # First setup you view from a Model:
23 #
24 # ~~~nitih
25 # var view = new ModelView(model)
26 # ~~~
27 #
28 # Then ask question using the view:
29 #
30 # ~~~nitish
31 # print number of parents for `{my_class}`
32 # print my_class.collect_parents(view).count
33 # ~~~
34 #
35 # **Warning**
36 #
37 # `model_collect` offers a flattened view of the model without considering any
38 # main module.
39 # For this reason, `model_collect` lists all the definitions reachable from all
40 # modules.
41 #
42 # This is usefull for tools that need a global view of a model like `nitdoc`,
43 # `nitx`, `nitmetrics` or `nituml`.
44 # It should not be used for compiling stuffs like computing VFT, where the listed
45 # entities could not be reachable depending on the modules really imported.
46 module model_collect
47
48 import model_views
49
50 redef class MEntity
51
52 # FIXME used to bypass RTA limitation on type resolution
53 type MENTITY: SELF
54
55 # Collect modifier keywords like `redef`, `private` etc
56 fun collect_modifiers: Array[String] do return new Array[String]
57
58 # Collect `self` linearization anchored on `mainmodule`
59 fun collect_linearization(mainmodule: MModule): nullable Array[MEntity] do
60 return null
61 end
62
63 # Collect `self` ancestors (direct and indirect)
64 #
65 # The concept of ancestor is abstract at this stage.
66 fun collect_ancestors(view: ModelView): Set[MENTITY] do
67 var done = new HashSet[MENTITY]
68 var todo = new Array[MENTITY]
69
70 todo.add_all collect_parents(view)
71 while todo.not_empty do
72 var mentity = todo.pop
73 if mentity == self or done.has(mentity) then continue
74 done.add mentity
75 todo.add_all mentity.collect_parents(view)
76 end
77 return done
78 end
79
80 # Collect `self` parents (direct ancestors)
81 #
82 # The concept of parent is abstract at this stage.
83 fun collect_parents(view: ModelView): Set[MENTITY] is abstract
84
85 # Collect `self` children (direct descendants)
86 #
87 # The concept of child is abstract at this stage.
88 fun collect_children(view: ModelView): Set[MENTITY] is abstract
89
90 # Collect `self` descendants (direct and direct)
91 #
92 # The concept of descendant is abstract at this stage.
93 fun collect_descendants(view: ModelView): Set[MENTITY] do
94 var done = new HashSet[MENTITY]
95 var todo = new Array[MENTITY]
96
97 todo.add_all collect_children(view)
98 while todo.not_empty do
99 var mentity = todo.pop
100 if mentity == self or done.has(mentity) then continue
101 done.add mentity
102 todo.add_all mentity.collect_children(view)
103 end
104 return done
105 end
106
107 # Build a poset representing `self` in it's own hierarchy
108 #
109 # The notion of hierarchy depends on the type of MEntity.
110 #
111 # Here a recap:
112 # * `MPackage`: package dependencies
113 # * `MGroup`: group dependencies
114 # * `MModule`: modules imports
115 # * `MClass`: class inheritance (all classdefs flattened)
116 # * `MClassDef`: classdef inheritance
117 # * `MProperty`: property definitions graph (all propdefs flattened)
118 # * `MPropDef`: property definitions graph
119 fun hierarchy_poset(view: ModelView): POSet[MENTITY] do
120 var done = new HashSet[MENTITY]
121 var mentities = new Array[MENTITY]
122 mentities.add self
123 var poset = new POSet[MENTITY]
124 while mentities.not_empty do
125 var mentity = mentities.pop
126 if done.has(mentity) then continue
127 done.add mentity
128 poset.add_node mentity
129 for parent in mentity.collect_parents(view) do
130 poset.add_edge(mentity, parent)
131 mentities.add parent
132 end
133 for child in mentity.collect_children(view) do
134 poset.add_edge(child, mentity)
135 mentities.add child
136 end
137 end
138 return poset
139 end
140 end
141
142 redef class MPackage
143 redef fun collect_modifiers do
144 var res = super
145 res.add "package"
146 return res
147 end
148
149 # Collect all packages directly imported by `self`
150 redef fun collect_parents(view) do
151 var res = new HashSet[MENTITY]
152 for mgroup in mgroups do
153 for parent in mgroup.collect_parents(view) do
154 var mpackage = parent.mpackage
155 if mpackage == self or not view.accept_mentity(mpackage) then continue
156 res.add(mpackage)
157 end
158 end
159 return res
160 end
161
162 # Collect all packages that directly depends on `self`
163 redef fun collect_children(view) do
164 var res = new HashSet[MENTITY]
165 for mpackage in view.mpackages do
166 if mpackage.collect_parents(view).has(self) then res.add mpackage
167 end
168 return res
169 end
170
171 # Collect all modules contained in `self`
172 fun collect_mmodules(view: ModelView): HashSet[MModule] do
173 var res = new HashSet[MModule]
174 for mgroup in mgroups do
175 for mmodule in mgroup.mmodules do
176 if not view.accept_mentity(mmodule) then continue
177 res.add(mmodule)
178 end
179 end
180 return res
181 end
182 end
183
184 redef class MGroup
185 redef fun collect_modifiers do
186 var res = super
187 res.add "group"
188 return res
189 end
190
191 # Collect all groups directly import by `self`
192 redef fun collect_parents(view) do
193 var res = new HashSet[MENTITY]
194 for mmodule in mmodules do
195 for parent in mmodule.collect_parents(view) do
196 var mgroup = parent.mgroup
197 if mgroup == null or mgroup == self then continue
198 if not view.accept_mentity(mgroup) then continue
199 res.add(mgroup)
200 end
201 end
202 return res
203 end
204
205 # Collect all group that directly import `self`
206 redef fun collect_children(view) do
207 var res = new HashSet[MENTITY]
208 for mgroup in view.mgroups do
209 if mgroup == self or not view.accept_mentity(mgroup) then continue
210 if mgroup.collect_parents(view).has(self) then res.add mgroup
211 end
212 return res
213 end
214 end
215
216 redef class MModule
217
218 redef fun collect_modifiers do
219 var res = super
220 res.add "module"
221 return res
222 end
223
224 # Collect all module ancestors of `self` (direct and transitive imports)
225 redef fun collect_ancestors(view) do
226 var res = new HashSet[MENTITY]
227 for mentity in in_importation.greaters do
228 if mentity == self then continue
229 if not view.accept_mentity(mentity) then continue
230 res.add mentity
231 end
232 return res
233 end
234
235 # Collect all modules directly imported by `self`
236 redef fun collect_parents(view) do
237 var res = new HashSet[MENTITY]
238 for mentity in in_importation.direct_greaters do
239 if mentity == self then continue
240 if not view.accept_mentity(mentity) then continue
241 res.add mentity
242 end
243 return res
244 end
245
246 # Collect all modules that directly import `self`
247 redef fun collect_children(view) do
248 var res = new HashSet[MENTITY]
249 for mentity in in_importation.direct_smallers do
250 if mentity == self then continue
251 if not view.accept_mentity(mentity) then continue
252 res.add mentity
253 end
254 return res
255 end
256
257 # Collect all module descendants of `self` (direct and transitive imports)
258 redef fun collect_descendants(view) do
259 var res = new HashSet[MENTITY]
260 for mentity in in_importation.smallers do
261 if mentity == self then continue
262 if not view.accept_mentity(mentity) then continue
263 res.add mentity
264 end
265 return res
266 end
267
268 # Collect all class definitions introduced in `self`
269 fun collect_intro_mclassdefs(view: ModelView): Set[MClassDef] do
270 var res = new HashSet[MClassDef]
271 for mclassdef in mclassdefs do
272 if not mclassdef.is_intro then continue
273 if not view.accept_mentity(mclassdef) then continue
274 res.add mclassdef
275 end
276 return res
277 end
278
279 # Collect all class definitions refined in `self`
280 fun collect_redef_mclassdefs(view: ModelView): Set[MClassDef] do
281 var res = new HashSet[MClassDef]
282 for mclassdef in mclassdefs do
283 if mclassdef.is_intro then continue
284 if not view.accept_mentity(mclassdef) then continue
285 res.add mclassdef
286 end
287 return res
288 end
289
290 # Collect all classes introduced in `self`
291 fun collect_intro_mclasses(view: ModelView): Set[MClass] do
292 var res = new HashSet[MClass]
293 for mclass in intro_mclasses do
294 if not view.accept_mentity(mclass) then continue
295 res.add mclass
296 end
297 return res
298 end
299
300 # Collect all classes refined in `self`
301 fun collect_redef_mclasses(view: ModelView): Set[MClass] do
302 var mclasses = new HashSet[MClass]
303 for mclassdef in mclassdefs do
304 if not view.accept_mentity(mclassdef) then continue
305 if not mclassdef.is_intro then mclasses.add(mclassdef.mclass)
306 end
307 return mclasses
308 end
309 end
310
311 redef class MClass
312
313 redef fun collect_modifiers do return intro.collect_modifiers
314
315 redef fun collect_linearization(mainmodule) do
316 var mclassdefs = self.mclassdefs.to_a
317 mainmodule.linearize_mclassdefs(mclassdefs)
318 return mclassdefs
319 end
320
321 # Collect all direct parents of `self`
322 #
323 # This method uses a flattened hierarchy containing all the mclassdefs.
324 redef fun collect_parents(view) do
325 var res = new HashSet[MENTITY]
326 for mclassdef in mclassdefs do
327 for parent in mclassdef.collect_parents(view) do
328 var mclass = parent.mclass
329 if mclass == self or not view.accept_mentity(parent) then continue
330 res.add mclass
331 end
332 end
333 return res
334 end
335
336 # Collect all ancestors of `self`
337 redef fun collect_ancestors(view) do
338 var res = new HashSet[MENTITY]
339 for mclassdef in mclassdefs do
340 for parent in mclassdef.collect_parents(view) do
341 if not view.accept_mentity(parent) then continue
342 res.add parent.mclass
343 end
344 end
345 return res
346 end
347
348 # Collect all direct children of `self`
349 #
350 # This method uses a flattened hierarchy containing all the mclassdefs.
351 redef fun collect_children(view) do
352 var res = new HashSet[MENTITY]
353 for mclassdef in mclassdefs do
354 for child in mclassdef.collect_children(view) do
355 var mclass = child.mclass
356 if mclass == self or not view.accept_mentity(child) then continue
357 res.add mclass
358 end
359 end
360 return res
361 end
362
363 # Collect all properties introduced in `self`
364 fun collect_intro_mproperties(view: ModelView): Set[MProperty] do
365 var set = new HashSet[MProperty]
366 for mclassdef in mclassdefs do
367 for mprop in mclassdef.intro_mproperties do
368 if not view.accept_mentity(mprop) then continue
369 set.add(mprop)
370 end
371 end
372 return set
373 end
374
375 # Collect all properties redefined in `self`
376 fun collect_redef_mproperties(view: ModelView): Set[MProperty] do
377 var set = new HashSet[MProperty]
378 for mclassdef in mclassdefs do
379 for mpropdef in mclassdef.mpropdefs do
380 if mpropdef.mproperty.intro_mclassdef.mclass == self then continue
381 if not view.accept_mentity(mpropdef) then continue
382 set.add(mpropdef.mproperty)
383 end
384 end
385 return set
386 end
387
388 # Collect all properties introduced and redefined in `self`
389 fun collect_local_mproperties(view: ModelView): Set[MProperty] do
390 var set = new HashSet[MProperty]
391 set.add_all collect_intro_mproperties(view)
392 set.add_all collect_redef_mproperties(view)
393 return set
394 end
395
396 # Collect all properties inehrited by `self`
397 fun collect_inherited_mproperties(view: ModelView): Set[MProperty] do
398 var set = new HashSet[MProperty]
399 for parent in collect_parents(view) do
400 set.add_all(parent.collect_intro_mproperties(view))
401 set.add_all(parent.collect_inherited_mproperties(view))
402 end
403 return set
404 end
405
406 # Collect all properties accessible by `self`
407 #
408 # This include introduced, redefined, inherited properties.
409 fun collect_accessible_mproperties(view: ModelView): Set[MProperty] do
410 var set = new HashSet[MProperty]
411 set.add_all(collect_intro_mproperties(view))
412 set.add_all(collect_redef_mproperties(view))
413 set.add_all(collect_inherited_mproperties(view))
414 return set
415 end
416
417 # Collect all methods introduced in `self`
418 fun collect_intro_mmethods(view: ModelView): Set[MMethod] do
419 var res = new HashSet[MMethod]
420 for mproperty in collect_intro_mproperties(view) do
421 if mproperty isa MMethod then res.add(mproperty)
422 end
423 return res
424 end
425
426 # Collect all methods redefined in `self`
427 fun collect_redef_mmethods(view: ModelView): Set[MMethod] do
428 var res = new HashSet[MMethod]
429 for mproperty in collect_redef_mproperties(view) do
430 if mproperty isa MMethod then res.add(mproperty)
431 end
432 return res
433 end
434
435 # Collect all methods introduced and redefined in `self`
436 fun collect_local_mmethods(view: ModelView): Set[MMethod] do
437 var set = new HashSet[MMethod]
438 set.add_all collect_intro_mmethods(view)
439 set.add_all collect_redef_mmethods(view)
440 return set
441 end
442
443 # Collect all methods inherited by `self`
444 fun collect_inherited_mmethods(view: ModelView): Set[MMethod] do
445 var res = new HashSet[MMethod]
446 for mproperty in collect_inherited_mproperties(view) do
447 if mproperty isa MMethod then res.add(mproperty)
448 end
449 return res
450 end
451
452 # Collect all methods accessible by `self`
453 #
454 # This include introduced, redefined, inherited methods.
455 fun collect_accessible_mmethods(view: ModelView): Set[MMethod] do
456 var set = new HashSet[MMethod]
457 set.add_all(collect_intro_mmethods(view))
458 set.add_all(collect_redef_mmethods(view))
459 set.add_all(collect_inherited_mmethods(view))
460 return set
461 end
462
463 # Collect all attributes introduced in `self`
464 fun collect_intro_mattributes(view: ModelView): Set[MAttribute] do
465 var res = new HashSet[MAttribute]
466 for mproperty in collect_intro_mproperties(view) do
467 if mproperty isa MAttribute then res.add(mproperty)
468 end
469 return res
470 end
471
472 # Collect all attributes redefined in `self`
473 fun collect_redef_mattributes(view: ModelView): Set[MAttribute] do
474 var res = new HashSet[MAttribute]
475 for mproperty in collect_redef_mproperties(view) do
476 if mproperty isa MAttribute then res.add(mproperty)
477 end
478 return res
479 end
480
481 # Collect all attributes introduced and redefined in `self`
482 fun collect_local_mattributes(view: ModelView): Set[MAttribute] do
483 var set = new HashSet[MAttribute]
484 set.add_all collect_intro_mattributes(view)
485 set.add_all collect_redef_mattributes(view)
486 return set
487 end
488
489 # Collect all attributes inherited by `self`
490 fun collect_inherited_mattributes(view: ModelView): Set[MAttribute] do
491 var res = new HashSet[MAttribute]
492 for mproperty in collect_inherited_mproperties(view) do
493 if mproperty isa MAttribute then res.add(mproperty)
494 end
495 return res
496 end
497
498 # Collect all attributes accessible by `self`
499 #
500 # This include introduced, redefined, inherited mattributes.
501 fun collect_accessible_mattributes(view: ModelView): Set[MAttribute] do
502 var set = new HashSet[MAttribute]
503 set.add_all(collect_intro_mattributes(view))
504 set.add_all(collect_redef_mattributes(view))
505 set.add_all(collect_inherited_mattributes(view))
506 return set
507 end
508
509 # Collect all init methods introduced in `self`
510 fun collect_intro_inits(view: ModelView): Set[MMethod] do
511 var res = new HashSet[MMethod]
512 for mproperty in collect_intro_mmethods(view) do
513 if mproperty.is_init then res.add(mproperty)
514 end
515 return res
516 end
517
518 # Collect all init methods redefined in `self`
519 fun collect_redef_inits(view: ModelView): Set[MMethod] do
520 var res = new HashSet[MMethod]
521 for mproperty in collect_redef_mmethods(view) do
522 if mproperty.is_init then res.add(mproperty)
523 end
524 return res
525 end
526
527 # Collect all init methods introduced and redefined in `self`
528 fun collect_local_inits(view: ModelView): Set[MMethod] do
529 var set = new HashSet[MMethod]
530 set.add_all collect_intro_inits(view)
531 set.add_all collect_redef_inits(view)
532 return set
533 end
534
535 # Collect all init methods inherited by `self`
536 fun collect_inherited_inits(view: ModelView): Set[MMethod] do
537 var res = new HashSet[MMethod]
538 for mproperty in collect_inherited_mmethods(view) do
539 if mproperty.is_init then res.add(mproperty)
540 end
541 return res
542 end
543
544 # Collect all init methods accessible by `self`
545 #
546 # This include introduced, redefined, inherited inits.
547 fun collect_accessible_inits(view: ModelView): Set[MMethod] do
548 var set = new HashSet[MMethod]
549 set.add_all(collect_intro_inits(view))
550 set.add_all(collect_redef_inits(view))
551 set.add_all(collect_inherited_inits(view))
552 return set
553 end
554
555 # Collect all virtual types accessible by `self`
556 #
557 # This include introduced, redefined, inherited virtual types.
558 fun collect_accessible_vts(view: ModelView): Set[MVirtualTypeProp] do
559 var set = new HashSet[MVirtualTypeProp]
560 for mproperty in collect_accessible_mproperties(view) do
561 if mproperty isa MVirtualTypeProp then set.add mproperty
562 end
563 return set
564 end
565 end
566
567 redef class MClassDef
568
569 redef fun collect_linearization(mainmodule) do
570 var mclassdefs = new Array[MClassDef]
571 for mclassdef in in_hierarchy.as(not null).greaters do
572 if mclassdef.mclass == self.mclass then mclassdefs.add mclassdef
573 end
574 mainmodule.linearize_mclassdefs(mclassdefs)
575 return mclassdefs
576 end
577
578 redef fun collect_ancestors(view) do
579 var res = new HashSet[MENTITY]
580 var hierarchy = self.in_hierarchy
581 if hierarchy == null then return res
582 for parent in hierarchy.greaters do
583 if parent == self or not view.accept_mentity(parent) then continue
584 res.add parent
585 end
586 return res
587 end
588
589 redef fun collect_parents(view) do
590 var res = new HashSet[MENTITY]
591 var hierarchy = self.in_hierarchy
592 if hierarchy == null then return res
593 for parent in hierarchy.direct_greaters do
594 if parent == self or not view.accept_mentity(parent) then continue
595 res.add parent
596 end
597 return res
598 end
599
600 redef fun collect_children(view) do
601 var res = new HashSet[MENTITY]
602 var hierarchy = self.in_hierarchy
603 if hierarchy == null then return res
604 for child in hierarchy.direct_smallers do
605 if child == self or not view.accept_mentity(child) then continue
606 res.add child
607 end
608 return res
609 end
610
611 # Collect all property definitions in `self`
612 fun collect_mpropdefs(view: ModelView): Set[MPropDef] do
613 var res = new HashSet[MPropDef]
614 for mpropdef in mpropdefs do
615 if not view.accept_mentity(mpropdef) then continue
616 res.add mpropdef
617 end
618 return res
619 end
620
621 # Collect all property definitions that are introduction in `self`
622 fun collect_intro_mpropdefs(view: ModelView): Set[MPropDef] do
623 var res = new HashSet[MPropDef]
624 for mpropdef in mpropdefs do
625 if not mpropdef.is_intro then continue
626 if not view.accept_mentity(mpropdef) then continue
627 res.add mpropdef
628 end
629 return res
630 end
631
632 # Collect all property definitions that are redefinition in `self`
633 fun collect_redef_mpropdefs(view: ModelView): Set[MPropDef] do
634 var res = new HashSet[MPropDef]
635 for mpropdef in mpropdefs do
636 if mpropdef.is_intro then continue
637 if not view.accept_mentity(mpropdef) then continue
638 res.add mpropdef
639 end
640 return res
641 end
642
643 redef fun collect_modifiers do
644 var res = super
645 if not is_intro then
646 res.add "redef"
647 else
648 res.add mclass.visibility.to_s
649 end
650 res.add mclass.kind.to_s
651 return res
652 end
653 end
654
655 redef class MProperty
656 redef fun collect_modifiers do return intro.collect_modifiers
657
658 redef fun collect_linearization(mainmodule) do
659 var mpropdefs = self.mpropdefs.to_a
660 mainmodule.linearize_mpropdefs(mpropdefs)
661 return mpropdefs
662 end
663
664 # Collect all property definitions of `self`
665 fun collect_mpropdefs(view: ModelView): Set[MPropDef] do
666 var res = new HashSet[MPropDef]
667 for mpropdef in mpropdefs do
668 if not view.accept_mentity(mpropdef) then continue
669 res.add mpropdef
670 end
671 return res
672 end
673
674 # Collect all direct super definitions of `self`
675 redef fun collect_parents(view) do
676 var res = new HashSet[MENTITY]
677 for mpropdef in mpropdefs do
678 for parent in mpropdef.collect_parents(view) do
679 if not view.accept_mentity(parent) then continue
680 res.add parent.mproperty
681 end
682 end
683 return res
684 end
685
686 # Collection all definitions that have `self` as a direct super definition
687 redef fun collect_children(view) do
688 var res = new HashSet[MENTITY]
689 for mpropdef in mpropdefs do
690 for child in mpropdef.collect_parents(view) do
691 if not view.accept_mentity(child) then continue
692 res.add child.mproperty
693 end
694 end
695 return res
696 end
697 end
698
699 redef class MPropDef
700
701 redef fun collect_modifiers do
702 var res = super
703 if not is_intro then
704 res.add "redef"
705 else
706 res.add mproperty.visibility.to_s
707 end
708 var mprop = self
709 if mprop isa MVirtualTypeDef then
710 res.add "type"
711 else if mprop isa MMethodDef then
712 if mprop.is_abstract then
713 res.add "abstract"
714 else if mprop.is_intern then
715 res.add "intern"
716 end
717 if mprop.mproperty.is_init then
718 res.add "init"
719 else
720 res.add "fun"
721 end
722 else if mprop isa MAttributeDef then
723 res.add "var"
724 end
725 return res
726 end
727
728 redef fun collect_linearization(mainmodule) do
729 var mpropdefs = new Array[MPropDef]
730 var mentity = self
731 while not mentity.is_intro do
732 mpropdefs.add mentity
733 mentity = mentity.lookup_next_definition(mainmodule, mentity.mclassdef.bound_mtype)
734 end
735 mpropdefs.add mentity
736 mainmodule.linearize_mpropdefs(mpropdefs)
737 return mpropdefs
738 end
739
740 # Collect only the next definition of `self`
741 redef fun collect_parents(view) do
742 var res = new HashSet[MENTITY]
743 var mpropdef = self
744 while not mpropdef.is_intro do
745 mpropdef = mpropdef.lookup_next_definition(mclassdef.mmodule, mclassdef.bound_mtype)
746 res.add mpropdef
747 end
748 return res
749 end
750
751 # Collect all children definitions that directly depend on `self`
752 redef fun collect_children(view) do
753 var res = new HashSet[MENTITY]
754 for mpropdef in mproperty.collect_mpropdefs(view) do
755 if mpropdef.collect_parents(view).has(self) then res.add mpropdef
756 end
757 return res
758 end
759 end