src: transform all old writable in annotations
[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 fun concern_rank is cached 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 fun concern_rank is cached 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 fun in_nesting_intro_mclasses(min_visibility: MVisibility): Set[MClass] do
167 var res = new HashSet[MClass]
168 for mmodule in in_nesting.greaters do
169 for mclass in mmodule.filter_intro_mclasses(min_visibility) do
170 if mclass.visibility < min_visibility then continue
171 res.add mclass
172 end
173 end
174 return res
175 end
176
177 fun in_nesting_redef_mclasses(min_visibility: MVisibility): Set[MClass] do
178 var res = new HashSet[MClass]
179 for mmodule in self.in_nesting.greaters do
180 for mclass in mmodule.filter_redef_mclasses(min_visibility) do
181 if mclass.visibility < min_visibility then continue
182 res.add mclass
183 end
184 end
185 return res
186 end
187
188 fun in_nesting_intro_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
189 var res = new HashSet[MClassDef]
190 for mmodule in in_nesting.greaters do
191 res.add_all mmodule.intro_mclassdefs(min_visibility)
192 end
193 return res
194 end
195
196 fun in_nesting_redef_mclassdefs(min_visibility: MVisibility): Set[MClassDef] do
197 var res = new HashSet[MClassDef]
198 for mmodule in self.in_nesting.greaters do
199 res.add_all mmodule.redef_mclassdefs(min_visibility)
200 end
201 return res
202 end
203
204 redef fun concern_rank is cached do
205 var max = 0
206 for p in in_importation.direct_greaters do
207 var pmax = p.concern_rank
208 if pmax > max then max = pmax
209 end
210 return max + 1
211 end
212 end
213
214 redef class MClass
215
216 # Get the public owner of 'self'.
217 fun public_owner: MModule do
218 var public_owner = self.intro_mmodule.public_owner
219 if public_owner == null then
220 return self.intro_mmodule
221 else
222 return public_owner
223 end
224 end
225
226 # Get direct parents of 'self'.
227 fun parents: Set[MClass] do
228 var ret = new HashSet[MClass]
229 for mclassdef in mclassdefs do
230 for mclasstype in mclassdef.supertypes do
231 ret.add(mclasstype.mclass)
232 end
233 end
234 return ret
235 end
236
237 # Get all ancestors of 'self'.
238 fun ancestors: Set[MClass] do
239 var lst = new HashSet[MClass]
240 for mclassdef in self.mclassdefs do
241 for super_mclassdef in mclassdef.in_hierarchy.greaters do
242 if super_mclassdef == mclassdef then continue # skip self
243 lst.add(super_mclassdef.mclass)
244 end
245 end
246 return lst
247 end
248
249 # Get direct children of 'self'.
250 fun children: Set[MClass] do
251 var lst = new HashSet[MClass]
252 for mclassdef in self.mclassdefs do
253 for sub_mclassdef in mclassdef.in_hierarchy.direct_smallers do
254 if sub_mclassdef == mclassdef then continue # skip self
255 lst.add(sub_mclassdef.mclass)
256 end
257 end
258 return lst
259 end
260
261 # Get all children of 'self'.
262 fun descendants: Set[MClass] do
263 var lst = new HashSet[MClass]
264 for mclassdef in self.mclassdefs do
265 for sub_mclassdef in mclassdef.in_hierarchy.smallers do
266 if sub_mclassdef == mclassdef then continue # skip self
267 lst.add(sub_mclassdef.mclass)
268 end
269 end
270 return lst
271 end
272
273 # Get the list of constructors available for 'self'.
274 fun constructors: Set[MMethod] do
275 var res = new HashSet[MMethod]
276 for mclassdef in mclassdefs do
277 for mpropdef in mclassdef.mpropdefs do
278 if mpropdef isa MMethodDef then
279 if mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
280 end
281 end
282 end
283 return res
284 end
285
286 # Get the list of methods introduced in 'self'.
287 fun intro_methods: Set[MMethod] do
288 var res = new HashSet[MMethod]
289 for mclassdef in mclassdefs do
290 for mpropdef in mclassdef.mpropdefs do
291 if mpropdef isa MMethodDef then
292 if mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
293 end
294 end
295 end
296 return res
297 end
298
299 # the set of properties introduced in 'self'.
300 fun intro_mproperties(min_visibility: MVisibility): Set[MProperty] do
301 var set = new HashSet[MProperty]
302 for mclassdef in mclassdefs do
303 for mprop in mclassdef.intro_mproperties do
304 if mprop.visibility < min_visibility then continue
305 set.add(mprop)
306 end
307 end
308 return set
309 end
310
311 fun intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
312 var set = new HashSet[MPropDef]
313 for mclassdef in mclassdefs do
314 for mpropdef in mclassdef.mpropdefs do
315 if not mpropdef.is_intro then continue
316 if mpropdef.mproperty.visibility < min_visibility then continue
317 set.add(mpropdef)
318 end
319 end
320 return set
321 end
322
323 # the set of locally refined properties in 'self'.
324 fun redef_mproperties(min_visibility: MVisibility): Set[MProperty] do
325 var set = new HashSet[MProperty]
326 for mclassdef in mclassdefs do
327 for mpropdef in mclassdef.mpropdefs do
328 if mpropdef.mproperty.visibility < min_visibility then continue
329 if mpropdef.mproperty.intro_mclassdef.mclass != self then set.add(mpropdef.mproperty)
330 end
331 end
332 return set
333 end
334
335 fun redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
336 var set = new HashSet[MPropDef]
337 for mclassdef in mclassdefs do
338 for mpropdef in mclassdef.mpropdefs do
339 if mpropdef.is_intro then continue
340 if mpropdef.mproperty.visibility < min_visibility then continue
341 set.add(mpropdef)
342 end
343 end
344 return set
345 end
346
347 # the set of methods inherited by 'self'.
348 fun inherited_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
349 var set = new HashSet[MProperty]
350 for parent in in_hierarchy(mainmodule).direct_greaters do
351 set.add_all(parent.intro_mproperties(min_visibility))
352 set.add_all(parent.inherited_mproperties(mainmodule, min_visibility))
353 end
354 return set
355 end
356
357 # the set of introduced and redefined mproperties
358 fun local_mproperties(min_visibility: MVisibility): Set[MProperty] do
359 var set = new HashSet[MProperty]
360 set.add_all(intro_mproperties(min_visibility))
361 set.add_all(redef_mproperties(min_visibility))
362 return set
363 end
364
365 # the set of all accessible mproperties for this class
366 fun all_mproperties(mainmodule: MModule, min_visibility: MVisibility): Set[MProperty] do
367 var set = new HashSet[MProperty]
368 set.add_all(local_mproperties(min_visibility))
369 set.add_all(inherited_mproperties(mainmodule, min_visibility))
370 return set
371 end
372
373 # the set of all accessible mattributes for this class
374 fun all_mattributes(mainmodule: MModule, min_visibility: MVisibility): Set[MAttribute] do
375 var set = new HashSet[MAttribute]
376 for mprop in all_mproperties(mainmodule, min_visibility) do
377 if mprop isa MAttribute then set.add(mprop)
378 end
379 return set
380 end
381
382 # Get the list of locally refined methods in 'self'.
383 fun redef_methods: Set[MMethod] do
384 var res = new HashSet[MMethod]
385 for mclassdef in mclassdefs do
386 for mpropdef in mclassdef.mpropdefs do
387 if mpropdef isa MMethodDef then
388 if not mpropdef.is_intro and not mpropdef.mproperty.is_init then res.add(mpropdef.mproperty)
389 end
390 end
391 end
392 return res
393 end
394
395 fun inherited_methods: Set[MMethod] do
396 var res = new HashSet[MMethod]
397 for s in ancestors do
398 for m in s.intro_methods do
399 if not self.intro_methods.has(m) and not self.redef_methods.has(m) then res.add(m)
400 end
401 end
402 return res
403 end
404
405 # Get the list of all virtual types available in 'self'.
406 fun virtual_types: Set[MVirtualTypeProp] do
407 var res = new HashSet[MVirtualTypeProp]
408 for mclassdef in mclassdefs do
409 for mpropdef in mclassdef.mpropdefs do
410 if mpropdef isa MVirtualTypeDef then
411 res.add(mpropdef.mproperty)
412 end
413 end
414 end
415 for ancestor in ancestors do
416 for mclassdef in ancestor.mclassdefs do
417 for mpropdef in mclassdef.mpropdefs do
418 if mpropdef isa MVirtualTypeDef then
419 res.add(mpropdef.mproperty)
420 end
421 end
422 end
423 end
424 return res
425 end
426
427 # Get the list of all parameter types in 'self'.
428 fun parameter_types: Map[String, MType] do
429 var res = new HashMap[String, MType]
430 for i in [0..intro.parameter_names.length[ do
431 res[intro.parameter_names[i]] = intro.bound_mtype.arguments[i]
432 end
433 return res
434 end
435
436 fun is_class: Bool do
437 return self.kind == concrete_kind or self.kind == abstract_kind
438 end
439
440 fun is_interface: Bool do
441 return self.kind == interface_kind
442 end
443
444 fun is_enum: Bool do
445 return self.kind == enum_kind
446 end
447
448 fun is_abstract: Bool do
449 return self.kind == abstract_kind
450 end
451 end
452
453 redef class MAttribute
454 # Is this attribute nullable for sure?
455 #
456 # This mean that its introduction is declarred with a nullable static type
457 # since attributes are invariant this will work on most cases
458 # attributes with static type anchored with a virtual type are not "nullable for-sure"
459 # because this type can be redefined in subclasses
460 fun is_nullable: Bool do return intro.static_mtype isa MNullableType
461 end
462
463 redef class MClassDef
464 # modifiers are keywords like redef, private etc.
465 fun modifiers: Array[String] do
466 var res = new Array[String]
467 if not is_intro then
468 res.add "redef"
469 else
470 res.add mclass.visibility.to_s
471 end
472 res.add mclass.kind.to_s
473 return res
474 end
475
476 fun collect_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
477 var res = new HashSet[MPropDef]
478 for mpropdef in mpropdefs do
479 if mpropdef.mproperty.visibility < min_visibility then continue
480 res.add mpropdef
481 end
482 return res
483 end
484
485 fun collect_intro_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
486 var res = new HashSet[MPropDef]
487 for mpropdef in mpropdefs do
488 if not mpropdef.is_intro then continue
489 if mpropdef.mproperty.visibility < min_visibility then continue
490 res.add mpropdef
491 end
492 return res
493 end
494
495 fun collect_redef_mpropdefs(min_visibility: MVisibility): Set[MPropDef] do
496 var res = new HashSet[MPropDef]
497 for mpropdef in mpropdefs do
498 if mpropdef.is_intro then continue
499 if mpropdef.mproperty.visibility < min_visibility then continue
500 res.add mpropdef
501 end
502 return res
503 end
504 end
505
506 redef class MPropDef
507 # modifiers are keywords like redef, private etc.
508 fun modifiers: Array[String] do
509 var res = new Array[String]
510 if not is_intro then
511 res.add "redef"
512 else
513 res.add mproperty.visibility.to_s
514 end
515 var mprop = self
516 if mprop isa MVirtualTypeDef then
517 res.add "type"
518 else if mprop isa MMethodDef then
519 if mprop.is_abstract then
520 res.add "abstract"
521 else if mprop.is_intern then
522 res.add "intern"
523 end
524 if mprop.mproperty.is_init then
525 res.add "init"
526 else
527 res.add "fun"
528 end
529 end
530 return res
531 end
532 end
533
534 # Sorters
535
536 # Sort mentities by their name
537 class MEntityNameSorter
538 super AbstractSorter[MEntity]
539 redef fun compare(a, b) do return a.name <=> b.name
540 init do end
541 end
542
543 # Sort MConcerns based on the module importation hierarchy ranking
544 # see also: `MConcern::concern_rank` and `MConcern::booster_rank`
545 #
546 # Comparison is made with the formula:
547 #
548 # a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_ran
549 #
550 # If both `a` and `b` have the same ranking,
551 # ordering is based on lexicographic comparison of `a.name` and `b.name`
552 class MConcernRankSorter
553 super AbstractSorter[MConcern]
554
555 init do end
556
557 redef fun compare(a, b) do
558 if a.concern_rank == b.concern_rank then
559 return a.name <=> b.name
560 end
561 return a.concern_rank + a.booster_rank <=> b.concern_rank + b.booster_rank
562 end
563 end