Merge remote-tracking branch 'alexandre/ni-merge' into HEAD
[nit.git] / src / metrics / generate_hierarchies.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 # Create dot files for various hierarchies of a model.
18 # See graphviz http://www.graphviz.org/
19 module generate_hierarchies
20
21 import model
22 private import metrics_base
23 import frontend
24
25 redef class ToolContext
26 var generate_hierarchies_phase: Phase = new GenerateHierarchyPhase(self, null)
27 end
28
29 private class GenerateHierarchyPhase
30 super Phase
31
32 redef fun process_mainmodule(mainmodule)
33 do
34 if not toolcontext.opt_generate_hyperdoc.value and not toolcontext.opt_all.value then return
35 var model = toolcontext.modelbuilder.model
36 generate_module_hierarchy(toolcontext, model)
37 generate_classdef_hierarchy(toolcontext, model)
38 generate_class_hierarchy(toolcontext, mainmodule)
39 end
40 end
41
42 # Create a dot file representing the module hierarchy of a model.
43 # Importation relation is represented with arrow
44 # Nesting relation is represented with nested boxes
45 fun generate_module_hierarchy(toolcontext: ToolContext, model: Model)
46 do
47 var buf = new Buffer
48 buf.append("digraph \{\n")
49 buf.append("node [shape=box];\n")
50 buf.append("rankdir=BT;\n")
51 for mmodule in model.mmodules do
52 if mmodule.direct_owner == null then
53 generate_module_hierarchy_for(mmodule, buf)
54 end
55 end
56 for mmodule in model.mmodules do
57 for s in mmodule.in_importation.direct_greaters do
58 buf.append("\"{mmodule}\" -> \"{s}\";\n")
59 end
60 end
61 buf.append("\}\n")
62 var f = new OFStream.open(toolcontext.output_dir.join_path("module_hierarchy.dot"))
63 f.write(buf.to_s)
64 f.close
65 end
66
67 # Helper function for `generate_module_hierarchy'.
68 # Create graphviz nodes for the module and recusrively for its nested modules
69 private fun generate_module_hierarchy_for(mmodule: MModule, buf: Buffer)
70 do
71 if mmodule.in_nesting.direct_greaters.is_empty then
72 buf.append("\"{mmodule.name}\";\n")
73 else
74 buf.append("subgraph \"cluster_{mmodule.name}\" \{label=\"\"\n")
75 buf.append("\"{mmodule.name}\";\n")
76 for s in mmodule.in_nesting.direct_greaters do
77 generate_module_hierarchy_for(s, buf)
78 end
79 buf.append("\}\n")
80 end
81 end
82
83 # Create a dot file representing the class hierarchy of a model.
84 fun generate_class_hierarchy(toolcontext: ToolContext, mmodule: MModule)
85 do
86 var buf = new Buffer
87 buf.append("digraph \{\n")
88 buf.append("node [shape=box];\n")
89 buf.append("rankdir=BT;\n")
90 var hierarchy = mmodule.flatten_mclass_hierarchy
91 for mclass in hierarchy do
92 buf.append("\"{mclass}\" [label=\"{mclass}\"];\n")
93 for s in hierarchy[mclass].direct_greaters do
94 buf.append("\"{mclass}\" -> \"{s}\";\n")
95 end
96 end
97 buf.append("\}\n")
98 var f = new OFStream.open(toolcontext.output_dir.join_path("class_hierarchy.dot"))
99 f.write(buf.to_s)
100 f.close
101 end
102
103 # Create a dot file representing the classdef hierarchy of a model.
104 # For a simple user of the model, the classdef hierarchy is not really usefull, it is more an internal thing.
105 fun generate_classdef_hierarchy(toolcontext: ToolContext, model: Model)
106 do
107 var buf = new Buffer
108 buf.append("digraph \{\n")
109 buf.append("node [shape=box];\n")
110 buf.append("rankdir=BT;\n")
111 for mmodule in model.mmodules do
112 for mclassdef in mmodule.mclassdefs do
113 buf.append("\"{mclassdef} {mclassdef.bound_mtype}\" [label=\"{mclassdef.mmodule}\\n{mclassdef.bound_mtype}\"];\n")
114 for s in mclassdef.in_hierarchy.direct_greaters do
115 buf.append("\"{mclassdef} {mclassdef.bound_mtype}\" -> \"{s} {s.bound_mtype}\";\n")
116 end
117 end
118 end
119 buf.append("\}\n")
120 var f = new OFStream.open(toolcontext.output_dir.join_path("classdef_hierarchy.dot"))
121 f.write(buf.to_s)
122 f.close
123 end