3651aa70f42e78d9dc0320c497086db2b4f04641
[nit.git] / src / metrics / mclasses_metrics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2014 Alexandre Terrasa <alexandre@moz-code.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 common metrics about mclasses
18 module mclasses_metrics
19
20 import model
21 import metrics_base
22 import phase
23 import frontend
24
25 redef class ToolContext
26 var mclasses_metrics_phase = new MClassesMetricsPhase(self, null)
27 end
28
29 # Extract metrics about mclasses from model.
30 private class MClassesMetricsPhase
31 super Phase
32 redef fun process_mainmodule(mainmodule)
33 do
34 if not toolcontext.opt_mclasses.value and not toolcontext.opt_all.value then return
35
36 print "\n# MClasses metrics".yellow.bold
37
38 var metrics = new MClassMetricSet
39 metrics.register(new CNOA, new CNOP, new CNOC, new CNOD, new CDIT)
40 metrics.register(new CNBIP, new CNBRP, new CNBHP)
41 #TODO metrics.register(new CNBI) # nb init
42 #TODO metrics.register(new CNBA) # nb attrs
43 #TODO metrics.register(new CNBM) # nb methods
44 #TODO metrics.register(new CNBV) # nb vtypes
45
46 var model = toolcontext.modelbuilder.model
47 var mclasses = new HashSet[MClass]
48 for mproject in model.mprojects do
49
50 print "\n ## project {mproject}".bold
51
52 for mgroup in mproject.mgroups do
53 if mgroup.mmodules.is_empty then continue
54
55 # Scalar metrics
56 print " `- group {mgroup.full_name}"
57
58 var mod_mclasses = new HashSet[MClass]
59 for mmodule in mgroup.mmodules do mod_mclasses.add_all(mmodule.intro_mclasses)
60 if mod_mclasses.is_empty then continue
61 mclasses.add_all(mod_mclasses)
62 metrics.collect(new HashSet[MClass].from(mod_mclasses), mainmodule)
63 for name, metric in metrics.metrics do
64 print "\t{name}: {metric.desc}".green
65 print "\t avg: {metric.avg}".light_gray
66 var max = metric.max
67 print "\t max: {max.first} ({max.second})".light_gray
68 var min = metric.min
69 print "\t min: {min.first} ({min.second})".light_gray
70 end
71 end
72 end
73 if not mclasses.is_empty then
74 # Global metrics
75 print "\n ## global metrics".bold
76
77 metrics.collect(mclasses, mainmodule)
78 for name, metric in metrics.metrics do
79 print "\t{name}: {metric.desc}".green
80 print "\t avg: {metric.avg}".light_gray
81 var max = metric.max
82 print "\t max: {max.first} ({max.second})".light_gray
83 var min = metric.min
84 print "\t min: {min.first} ({min.second})".light_gray
85 end
86 end
87 end
88 end
89
90 # An MetricSet for MClasses metrics
91 class MClassMetricSet
92 super MetricSet
93 redef type METRIC: MClassMetric
94
95 # Collect all the metrics on the set of MClasses
96 fun collect(mclasses: Set[MClass], mainmodule: MModule) do
97 clear
98 for metric in metrics.values do
99 for mclass in mclasses do
100 metric.collect(mclass, mainmodule)
101 end
102 end
103 end
104 end
105
106 # An abstract metric about MClass
107 abstract class MClassMetric
108 super IntMetric[MClass]
109 # Collect the metric value for this mclass
110 fun collect(mclass: MClass, mainmodule: MModule) is abstract
111 end
112
113 # Class Metric: Number of Ancestors
114 class CNOA
115 super MClassMetric
116 redef fun name do return "cnoa"
117 redef fun desc do return "number of ancestor classes"
118
119 redef fun collect(mclass, mainmodule) do
120 values[mclass] = mclass.in_hierarchy(mainmodule).greaters.length - 1
121 end
122 end
123
124 # Class Metric: Number of Parents
125 class CNOP
126 super MClassMetric
127 redef fun name do return "cnop"
128 redef fun desc do return "number of parent classes"
129
130 redef fun collect(mclass, mainmodule) do
131 values[mclass] = mclass.in_hierarchy(mainmodule).direct_greaters.length
132 end
133 end
134
135 # Class Metric: Number of Children
136 class CNOC
137 super MClassMetric
138 redef fun name do return "cnoc"
139 redef fun desc do return "number of child classes"
140
141 redef fun collect(mclass, mainmodule) do
142 values[mclass] = mclass.in_hierarchy(mainmodule).direct_smallers.length
143 end
144 end
145
146 # Class Metric: Number of Descendants
147 class CNOD
148 super MClassMetric
149 redef fun name do return "cnod"
150 redef fun desc do return "number of descendant classes"
151
152 redef fun collect(mclass, mainmodule) do
153 values[mclass] = mclass.in_hierarchy(mainmodule).smallers.length - 1
154 end
155 end
156
157 # Class Metric: Depth in Inheritance Tree
158 class CDIT
159 super MClassMetric
160 redef fun name do return "cdit"
161 redef fun desc do return "depth in class tree"
162
163 redef fun collect(mclass, mainmodule) do
164 values[mclass] = mclass.in_hierarchy(mainmodule).depth
165 end
166 end
167
168 # Class Metric: Number of Introduced MProperties
169 class CNBIP
170 super MClassMetric
171 redef fun name do return "cnbip"
172 redef fun desc do return "number of introduced properties"
173
174 redef fun collect(mclass, mainmodule) do
175 values[mclass] = mclass.intro_mproperties.length
176 end
177 end
178
179 # Class Metric: Number of Refined MProperties
180 class CNBRP
181 super MClassMetric
182 redef fun name do return "cnbrp"
183 redef fun desc do return "number of redefined properties"
184
185 redef fun collect(mclass, mainmodule) do
186 values[mclass] = mclass.redef_mproperties.length
187 end
188 end
189
190 # Class Metric: Number of Inherited MProperties
191 class CNBHP
192 super MClassMetric
193 redef fun name do return "cnbhp"
194 redef fun desc do return "number of inherited properties"
195
196 redef fun collect(mclass, mainmodule) do
197 values[mclass] = mclass.inherited_mproperties2(mainmodule).length
198 end
199 end
200
201 redef class MClass
202 # FIXME wait for cleaning in model_utils
203 redef fun intro_mproperties: Set[MProperty] do
204 var set = new HashSet[MProperty]
205 for mclassdef in mclassdefs do
206 set.add_all(mclassdef.intro_mproperties)
207 end
208 return set
209 end
210
211 # FIXME wait for cleaning in model_utils
212 redef fun redef_mproperties: Set[MProperty] do
213 var set = new HashSet[MProperty]
214 for mclassdef in mclassdefs do
215 for mpropdef in mclassdef.mpropdefs do
216 if mpropdef.mproperty.intro_mclassdef.mclass != self then set.add(mpropdef.mproperty)
217 end
218 end
219 return set
220 end
221
222 # FIXME wait for cleaning in model_utils
223 fun inherited_mproperties2(mainmodule: MModule): Set[MProperty] do
224 var set = new HashSet[MProperty]
225 for parent in in_hierarchy(mainmodule).direct_greaters do
226 set.add_all(parent.intro_mproperties)
227 set.add_all(parent.inherited_mproperties2(mainmodule))
228 end
229 return set
230 end
231 end