metamodel: rename 'universal' to 'enum'
[nit.git] / src / analysis / reachable_from_init_method_analysis_impl.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2009 Jean-Sebastien Gelinas <calestar@gmail.com>
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 # This package introduces an algorithm to find all methods reachable
18 # from at least one reachable initializer
19 package reachable_from_init_method_analysis_impl
20
21 import reachable_from_init_method_analysis
22 import reachable_method_analysis
23
24 class RFIMABuilder
25 readable var _program: Program
26 readable var _context: RFIMAContext = new RFIMAContext
27
28 init (p: Program) do
29 _program = p
30 end
31
32 fun work do
33 program.with_each_live_local_classes !action(c) do
34 # For each reachable constructors for this class
35 for g in c.global_properties do
36 var p = c[g]
37 if not p.global.is_init_for(c) then continue
38 assert p isa MMMethod
39 if not program.rma.as(not null).is_method_reachable(p) then continue
40 if not c.new_instance_iroutine.has_key(p) then continue
41 var ir = c.new_instance_iroutine[p]
42
43 # Process this constructor
44 context.reachable_from_init_iroutines.add(ir)
45 (new RFIMAVisitor(context, program)).visit_iroutine(ir)
46 end
47 end
48 end
49 end
50
51 class RFIMAContext
52 super ReachableFromInitMethodAnalysis
53 readable var _reachable_from_init_iroutines: HashSet[IRoutine] = new HashSet[IRoutine]
54
55 redef fun is_iroutine_reachable_from_init(ir: nullable IRoutine): Bool do
56 return ir != null and reachable_from_init_iroutines.has(ir)
57 end
58
59 redef fun is_method_reachable_from_init(method: MMMethod): Bool do
60 return is_iroutine_reachable_from_init(method.iroutine)
61 end
62 end
63
64 class RFIMAVisitor
65 super ICodeVisitor
66 readable var _context: RFIMAContext
67 readable var _program: Program
68
69 init (context: RFIMAContext, p: Program) do
70 _context = context
71 _program = p
72 end
73
74 fun process_call(iroutine: IRoutine) do
75 if context.is_iroutine_reachable_from_init(iroutine) then return
76 context.reachable_from_init_iroutines.add(iroutine)
77 visit_iroutine(iroutine)
78 end
79
80 redef fun visit_icode(ic)
81 do
82 if ic isa IStaticCall then
83 # FIXME: take only the last property on the redef. hierarchie
84 var ir = ic.property.iroutine
85 if ir != null then process_call(ir)
86 else if ic isa INew then
87 # FIXME: take only the last property on the redef. hierarchie
88 var t = ic.stype
89 var cls = t.for_module(program.main_module).local_class
90 var m = cls[ic.property.global].as(MMMethod)
91 var r = cls.new_instance_iroutine[m]
92 process_call(r)
93 else if ic isa ISuper then
94 # Process possible calls
95 var method = ic.property
96 for greater in method.prhe.greaters_and_self do
97 if greater isa MMMethod then
98 var ir = greater.iroutine
99 if ir != null then process_call(ir)
100 end
101 end
102 else if ic isa ICall then
103 # Process possible calls
104 var method = ic.property
105 var ir = method.iroutine
106 if ir != null then process_call(ir)
107 for other in method.prhe.smallers do
108 if other isa MMMethod then
109 ir = other.iroutine
110 if ir != null then process_call(ir)
111 end
112 end
113 else if ic isa ICheckInstance then
114 var t = ic.stype
115 var cls = t.for_module(program.main_module).local_class
116 var ir = cls.checknew_iroutine
117 if ir != null then process_call(ir)
118 else if ic isa IInitAttributes then
119 var t = ic.stype
120 var cls = t.for_module(program.main_module).local_class
121 var ir = cls.init_var_iroutine
122 if ir != null then process_call(ir)
123 end
124 super
125 end
126 end