src: extract modelize_class.nit from modelbuiler.nit
[nit.git] / src / metrics / metrics_base.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 # Helpers for various statistics tools.
18 module metrics_base
19
20 import modelbuilder
21 import csv
22
23 redef class ToolContext
24
25 # --all
26 var opt_all = new OptionBool("Compute all metrics", "--all")
27
28 # --inheritance
29 var opt_inheritance = new OptionBool("Compute metrics about inheritance usage", "--inheritance")
30 # --genericity
31 var opt_refinement = new OptionBool("Compute metrics about refinement usage", "--refinement")
32 # --self
33 var opt_self = new OptionBool("Compute metrics about the usage of explicit and implicit self", "--self")
34 # --nullables
35 var opt_nullables = new OptionBool("Compute metrics on nullables send", "--nullables")
36 # --static-types
37 var opt_static_types = new OptionBool("Compute explicit static types metrics", "--static-types")
38 # --tables
39 var opt_tables = new OptionBool("Compute tables metrics", "--tables")
40 # --rta
41 var opt_rta = new OptionBool("Compute RTA metrics", "--rta")
42 # --generate-csv
43 var opt_generate_csv = new OptionBool("Generate CVS format metrics", "--generate-csv")
44 # --generate_hyperdoc
45 var opt_generate_hyperdoc = new OptionBool("Generate Hyperdoc", "--generate_hyperdoc")
46
47 var opt_dir = new OptionString("Directory where some statistics files are generated", "-d", "--dir")
48 var output_dir: String = "."
49
50 redef init
51 do
52 super
53 self.option_context.add_option(opt_all)
54 self.option_context.add_option(opt_inheritance)
55 self.option_context.add_option(opt_refinement)
56 self.option_context.add_option(opt_self)
57 self.option_context.add_option(opt_nullables)
58 self.option_context.add_option(opt_static_types)
59 self.option_context.add_option(opt_tables)
60 self.option_context.add_option(opt_rta)
61 self.option_context.add_option(opt_generate_csv)
62 self.option_context.add_option(opt_generate_hyperdoc)
63 self.option_context.add_option(opt_dir)
64 end
65
66 redef fun process_options
67 do
68 super
69 var val = self.opt_dir.value
70 if val != null then
71 val = val.simplify_path
72 val.mkdir
73 self.output_dir = val
74 end
75 end
76 end
77
78 redef class Model
79
80 # List of modules in std lib
81 # FIXME this is quite ugly, find a dynamic way...
82 fun std_modules: Set[String] do
83 if self.std_modules_cache == null then
84 self.std_modules_cache = new HashSet[String]
85 self.std_modules_cache.add("collection")
86 self.std_modules_cache.add("abstract_collection")
87 self.std_modules_cache.add("array")
88 self.std_modules_cache.add("hash_collection")
89 self.std_modules_cache.add("list")
90 self.std_modules_cache.add("range")
91 self.std_modules_cache.add("sorter")
92 self.std_modules_cache.add("environ")
93 self.std_modules_cache.add("exec")
94 self.std_modules_cache.add("file")
95 self.std_modules_cache.add("gc")
96 self.std_modules_cache.add("hash")
97 self.std_modules_cache.add("kernel")
98 self.std_modules_cache.add("math")
99 self.std_modules_cache.add("standard")
100 self.std_modules_cache.add("stream")
101 self.std_modules_cache.add("string")
102 self.std_modules_cache.add("string_search")
103 self.std_modules_cache.add("time")
104 end
105 return self.std_modules_cache.as(not null)
106 end
107 private var std_modules_cache: nullable Set[String]
108 end
109
110 redef class MClass
111 fun is_class: Bool do
112 return self.kind == concrete_kind or self.kind == abstract_kind
113 end
114
115 fun is_interface: Bool do
116 return self.kind == interface_kind
117 end
118
119 fun is_enum: Bool do
120 return self.kind == enum_kind
121 end
122
123 fun is_abstract: Bool do
124 return self.kind == abstract_kind
125 end
126
127 fun is_user_defined: Bool do
128 return self.intro_mmodule.is_user_defined
129 end
130 end
131
132 redef class MModule
133 fun is_user_defined: Bool do
134 return not self.model.std_modules.has(self.name)
135 end
136 end
137
138 # A counter counts occurence of things
139 # Use this instead of a HashMap[E, Int]
140 class Counter[E: Object]
141 # Total number of counted occurences
142 var total: Int = 0
143
144 private var map = new HashMap[E, Int]
145
146 # The number of counted occurences of `e'
147 fun [](e: E): Int
148 do
149 var map = self.map
150 if map.has_key(e) then return map[e]
151 return 0
152 end
153
154 # Count one more occurence of `e'
155 fun inc(e: E)
156 do
157 self.map[e] = self[e] + 1
158 total += 1
159 end
160
161 # Return an array of elements sorted by occurences
162 fun sort: Array[E]
163 do
164 var res = map.keys.to_a
165 var sorter = new CounterSorter[E](self)
166 sorter.sort(res)
167 #res.sort !cmp a, b = map[a] <=> map[b]
168 return res
169 end
170 end
171
172 private class CounterSorter[E: Object]
173 super AbstractSorter[E]
174 var counter: Counter[E]
175 redef fun compare(a,b) do return self.counter.map[a] <=> self.counter.map[b]
176 end
177
178 # Helper function to display n/d and handle division by 0
179 fun div(n: Int, d: Int): String
180 do
181 if d == 0 then return "na"
182 return ((100*n/d).to_f/100.0).to_precision(2)
183 end