nitmetrics: implements metrics as global phases
[nit.git] / src / metrics / static_types_metrics.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
3 # Copyright 2012 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 # Metrics on the usage of explicit static types.
18 module static_types_metrics
19
20 private import metrics_base
21 import modelbuilder
22 import modelize_class
23 import frontend
24
25 redef class ToolContext
26 var static_types_metrics_phase = new StaticTypesMetricsPhase(self, null)
27 end
28
29 private class StaticTypesMetricsPhase
30 super Phase
31 redef fun process_mainmodule(mainmodule)
32 do
33 if not toolcontext.opt_static_types.value and not toolcontext.opt_all.value then return
34 compute_static_types_metrics(toolcontext.modelbuilder)
35 end
36 end
37
38 # The job of this visitor is to resolve all types found
39 private class ATypeCounterVisitor
40 super Visitor
41 var modelbuilder: ModelBuilder
42 var nclassdef: AClassdef
43
44 var typecount: Counter[MType]
45
46 # Get a new visitor on a classef to add type count in `typecount'.
47 init(modelbuilder: ModelBuilder, nclassdef: AClassdef, typecount: Counter[MType])
48 do
49 self.modelbuilder = modelbuilder
50 self.nclassdef = nclassdef
51 self.typecount = typecount
52 end
53
54 redef fun visit(n)
55 do
56 if n isa AType then
57 var mtype = modelbuilder.resolve_mtype(self.nclassdef, n)
58 if mtype != null then
59 self.typecount.inc(mtype)
60 end
61 end
62 n.visit_all(self)
63 end
64 end
65
66 # Visit the AST and print metrics on the usage of explicit static types.
67 fun compute_static_types_metrics(modelbuilder: ModelBuilder)
68 do
69 # Count each occurence of a specific static type
70 var typecount = new Counter[MType]
71
72 # Visit all the source code to collect data
73 for nmodule in modelbuilder.nmodules do
74 for nclassdef in nmodule.n_classdefs do
75 var visitor = new ATypeCounterVisitor(modelbuilder, nclassdef, typecount)
76 visitor.enter_visit(nclassdef)
77 end
78 end
79
80 # Display data
81 print "--- Metrics of the explitic static types ---"
82 print "Total number of explicit static types: {typecount.total}"
83 if typecount.total == 0 then return
84
85 # types sorted by usage
86 var types = typecount.sort
87
88 # Display most used types (ie the last of `types')
89 print "Most used types: "
90 var min = 10
91 if types.length < min then min = types.length
92 for i in [0..min[ do
93 var t = types[types.length-i-1]
94 print " {t}: {typecount[t]}"
95 end
96
97 # Compute the distribution of type usage
98 print "Distribution of type usage:"
99 var count = 0
100 var sum = 0
101 var limit = 1
102 for t in types do
103 if typecount[t] > limit then
104 print " <={limit}: {count} ({div(count*100,types.length)}% of types; {div(sum*100,typecount.total)}% of usage)"
105 count = 0
106 sum = 0
107 while typecount[t] > limit do limit = limit * 2
108 end
109 count += 1
110 sum += typecount[t]
111 end
112 print " <={limit}: {count} ({div(count*100,types.length)}% of types; {div(sum*100,typecount.total)}% of usage)"
113 end