nitdoc: improve what classes to put in main summary
[nit.git] / src / nitdoc.nit
index 17f5145..5e69d6b 100644 (file)
@@ -24,7 +24,7 @@ import abstracttool
 
 # Store knowledge and facilities to generate files
 class DocContext
-special AbstractCompiler
+       super AbstractCompiler
        # Destination directory
        readable writable var _dir: String = "."
 
@@ -65,8 +65,8 @@ special AbstractCompiler
                f.close
        end
 
-       # Currently computed module
-       readable var _module: nullable MMSrcModule
+       # Currently computed mmmodule
+       readable var _mmmodule: nullable MMSrcModule
 
        # Is the current directory module computed as a simple modude ?
        readable writable var _inside_mode: Bool = false
@@ -80,9 +80,11 @@ special AbstractCompiler
        # Register an entity (for the index)
        fun register(e: MMEntity)
        do
-               _entities.add(e)
-               if e isa MMSrcModule then
-                       _module = e
+               if not _entities.has(e) then
+                       _entities.add(e)
+                       if e isa MMSrcModule then
+                               _mmmodule = e
+                       end
                end
        end
 
@@ -96,7 +98,7 @@ special AbstractCompiler
        fun extract_other_doc
        do
                info("Generating other files",1)
-               _module = null
+               _mmmodule = null
                inside_mode = false
                intrude_mode = false
                clear
@@ -167,6 +169,16 @@ special AbstractCompiler
 
                clear
                add_header("Overview")
+
+               var f = new OFStream.open("{_dir}/all_.module_hierarchy.dot")
+                       f.write(module_hierarchy.to_dot)
+               f.close
+
+               sys.system("dot -Tpng {_dir}/all_.module_hierarchy.dot -o {_dir}/all_.module_hierarchy.png")
+
+               add("<input type=\"button\" value=\"View/Hide module hierarchy\" Onclick=\"show_hide('module_hierarchy');\" />")
+               add("<center><img id=\"module_hierarchy\" src=\"all_.module_hierarchy.png\" alt=\"module hierarchy\" style=\"display:none\" border=\"1\" /></center><br />\n")
+
                add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
                add("<tr bgcolor=\"#CCCCFF\"><th colspan=\"2\"><big>Overview of all Modules</big></th><tr>\n")
                for m in modules do
@@ -182,27 +194,28 @@ special AbstractCompiler
 
        fun add_header(title: String)
        do
-               add("<html><head><title>{title}</title></head>\n<body>\n")
+               add("<html><head><title>{title}</title><script type=\"text/JavaScript\">function show_hide(id)\{if (document.getElementById(id).style.display==\"none\")\{document.getElementById(id).style.display=\"block\";\}else \{document.getElementById(id).style.display=\"none\";\}\}</script></head>\n<body>\n")
                add("<table border=\"0\" width=\"100%\" cellpadding=\"1\" cellspacing=\"0\"><tr><td bgcolor=\"#eeeeff\">\n")
                add("<a href=\"overview.html\"><b>Overview</b></a>&nbsp; <a href=\"index-1.html\"><b>Index</b></a>&nbsp; <a href=\"index.html\" target=\"_top\"><b>With Frames</b></a>\n")
                add("</td></tr></table>")
                add("Visibility: ")
-               if (not inside_mode and not intrude_mode) or module == null then
+               var mod = mmmodule
+               if (not inside_mode and not intrude_mode) or mod == null then
                        add("<b>Public</b>&nbsp; ")
                else
-                       add("<a href=\"{module}.html\"><b>Public</b></a>&nbsp; ")
+                       add("<a href=\"{mod}.html\"><b>Public</b></a>&nbsp; ")
                end
-               if inside_mode or module == null then
+               if inside_mode or mod == null then
                        add("<b>Inside</b>&nbsp; ")
-               else if module.directory.owner != module then
+               else if mod.directory.owner != mod then
                        add("<strike><b>Inside</b></strike>&nbsp; ")
                else
-                       add("<a href=\"{module}_.html\"><b>Inside</b></a>&nbsp; ")
+                       add("<a href=\"{mod}_.html\"><b>Inside</b></a>&nbsp; ")
                end
-               if intrude_mode or module == null then
+               if intrude_mode or mod == null then
                        add("<b>Intrude</b>&nbsp; ")
                else
-                       add("<a href=\"{module}__.html\"><b>Intrude</b></a>&nbsp; ")
+                       add("<a href=\"{mod}__.html\"><b>Intrude</b></a>&nbsp; ")
                end
                add("<br/>")
        end
@@ -222,11 +235,11 @@ special AbstractCompiler
        # if inside_mode is set, it could be a different result
        fun known_owner_of(m: MMModule): MMModule
        do
-               var module = module
-               if module == null then return m
-               var res = module.known_owner_of(m)
-               if not inside_mode and not intrude_mode and res.directory.owner == module then
-                       return module
+               var mod = mmmodule
+               if mod == null then return m
+               var res = mod.known_owner_of(m)
+               if not inside_mode and not intrude_mode and res.directory.owner == mod then
+                       return mod
                else
                        return res
                end
@@ -247,6 +260,7 @@ special AbstractCompiler
 
        init
        do
+               keep_ast = true
                super("nitdoc")
                option_context.add_option(opt_dir)
        end
@@ -276,7 +290,7 @@ end
 
 # Efficiently sort object with their to_s method
 class AlphaSorter[E: Object]
-special AbstractSorter[E]
+       super AbstractSorter[E]
        redef fun compare(a, b)
        do
                var sa: String
@@ -329,9 +343,9 @@ class MMEntity
 end
 
 redef class MMModule
-special MMEntity
+       super MMEntity
        redef fun html_link(dctx) do 
-               if dctx.module == self then 
+               if dctx.mmmodule == self then
                        return "{self}"
                else
                        return "<a href=\"{self}.html\">{self}</a>"
@@ -341,16 +355,20 @@ special MMEntity
        redef fun prototype_head(dctx) do return "module "
 
        var _known_owner_of_cache: Map[MMModule, MMModule] = new HashMap[MMModule, MMModule]
-       fun known_owner_of(module: MMModule): MMModule
-       do 
-               if _known_owner_of_cache.has_key(module) then return _known_owner_of_cache[module]
-               var res = module
-               if mhe < module and visibility_for(module) != 0 then 
-                       res = known_owner_of_intern(module, self, false)
+
+       # Return the owner of `module` from the point of view of `self`
+       fun known_owner_of(mod: MMModule): MMModule
+       do
+               if _known_owner_of_cache.has_key(mod) then return _known_owner_of_cache[mod]
+               var res = mod
+               # is module is publicly imported by self?
+               if mhe < mod and visibility_for(mod) != 0 then
+                       res = known_owner_of_intern(mod, self, false)
                else
-                       res = module.owner(self)
+                       # Return the canonnical owner of module from the point of view of self
+                       res = mod.owner(self)
                end
-               _known_owner_of_cache[module] = res
+               _known_owner_of_cache[mod] = res
                return res
        end
 
@@ -367,16 +385,18 @@ special MMEntity
                return res
        end
 
-       private fun known_owner_of_intern(module: MMModule, from: MMModule, as_owner: Bool): MMModule
+       # ???
+       private fun known_owner_of_intern(mod: MMModule, from: MMModule, as_owner: Bool): MMModule
        do
-               if module == self then return self
+               if mod == self then return self
                var candidates = new Array[MMModule]
                for m in explicit_imported_modules do
                        if from.visibility_for(m) == 0 then continue
-                       if not m.mhe <= module then continue
-                       candidates.add(m.known_owner_of_intern(module, from, true))
+                       if not m.mhe <= mod then continue
+                       candidates.add(m.known_owner_of_intern(mod, from, true))
                end
-               assert not candidates.is_empty
+               # FIXME: I do not know what this does
+               if candidates.is_empty then return mod.owner(from)
                var max = candidates.first
                for m in candidates do
                        if max.mhe < m then max = m
@@ -391,7 +411,7 @@ special MMEntity
 end
 
 redef class MMLocalProperty
-special MMEntity
+       super MMEntity
        # Anchor of the property description in the module html file
        fun html_anchor: String
        do
@@ -400,10 +420,10 @@ special MMEntity
 
        redef fun html_link(dctx)
        do
-               var m = module
-               if not need_doc(dctx) then m = global.intro.module
-               var m = dctx.known_owner_of(m)
-               if m == dctx.module then
+               var m = mmmodule
+               if not need_doc(dctx) then m = global.intro.mmmodule
+               m = dctx.known_owner_of(m)
+               if m == dctx.mmmodule then
                        return "<a href=\"#{html_anchor}\">{self}</a>"
                else
                        return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
@@ -415,12 +435,12 @@ special MMEntity
 
        redef fun locate(dctx)
        do
-               return "in {module.html_link(dctx)}::{local_class.html_link(dctx)}"
+               return "in {mmmodule.html_link(dctx)}::{local_class.html_link(dctx)}"
        end
 
        fun known_intro_class(dctx: DocContext): MMLocalClass
        do
-               var mod = dctx.known_owner_of(global.intro.local_class.module)
+               var mod = dctx.known_owner_of(global.intro.local_class.mmmodule)
                var cla = mod[global.intro.local_class.global]
                return cla
        end
@@ -441,9 +461,9 @@ special MMEntity
                if is_redef then
                        var gp = global.intro
                        if intro_class.global != local_class.global then
-                               res.append(" {module[intro_class.global].html_link(dctx)}::")
-                       else if intro_class.module != module then
-                               res.append(" {intro_class.module.html_link(dctx)}::")
+                               res.append(" {mmmodule[intro_class.global].html_link(dctx)}::")
+                       else if intro_class.mmmodule != mmmodule then
+                               res.append(" {intro_class.mmmodule.html_link(dctx)}::")
                        end
                end
                return res.to_s
@@ -452,12 +472,12 @@ special MMEntity
        redef fun prototype_body(dctx)
        do
                var res = new Buffer
-               res.append(signature.to_html(dctx))
+               res.append(signature.to_html(dctx, true))
                var s = self
-               if s.node != null then
-                       if s.node isa ADeferredMethPropdef then
+               if s isa MMMethod then
+                       if s.is_abstract then
                                res.append(" is abstract")
-                       else if s.node isa AInternMethPropdef then
+                       else if s.is_intern then
                                res.append(" is intern")
                        end
                end
@@ -468,7 +488,7 @@ special MMEntity
        do
                if global.visibility_level >= 3 or self isa MMAttribute then
                        if not dctx.intrude_mode then return false
-                       if dctx.module.visibility_for(module) == 0 then return false
+                       if dctx.mmmodule.visibility_for(mmmodule) == 0 then return false
                end
                if global.intro == self then
                        return true
@@ -491,15 +511,13 @@ special MMEntity
        redef fun doc
        do
                var n = node
-               if n == null or not node isa PPropdef then
+               if n == null or not n isa APropdef then
                        return null
                end
-               assert n isa PPropdef
                var d = n.n_doc
                if d == null then
                        return null
                end
-               assert d isa ADoc
                if d.n_comment.is_empty then
                        return null
                else
@@ -508,10 +526,10 @@ special MMEntity
        end
 end
 redef class MMMethod
-       redef fun kind do return if global.is_init then "init" else "meth"
+       redef fun kind do return if global.is_init then "init" else "fun"
 end
 redef class MMAttribute
-       redef fun kind do return "attr"
+       redef fun kind do return "var"
 end
 redef class MMTypeProperty
        redef fun kind do return "type"
@@ -549,7 +567,7 @@ redef class MMSrcModule
                dctx.add("<h1>Module {self}</h1>\n<dl>")
                var s = ""
                var d: nullable MMDirectory = directory
-               while d == null do
+               while d != null do
                        if d.owner != null and (d.owner != self or dctx.inside_mode or dctx.intrude_mode) then
                                s = "{d.owner.html_link(dctx)}::{s}"
                        end
@@ -619,6 +637,31 @@ redef class MMSrcModule
                        end
                end
 
+               if not new_classes.is_empty then
+                       dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
+                       dctx.add("<tr bgcolor=\"#FF6347\"><th colspan=\"2\"><big>Main Summary of {self}</big></th><tr>\n")
+                       for c in new_classes do
+                               if c.global.intro == c or owned_modules.has(c.global.intro.mmmodule) then
+                                       var add = true
+                                       for p in c.cshe.direct_greaters do
+                                               if p.global.intro.mmmodule == self or owned_modules.has(p.global.intro.mmmodule) then
+                                                       add = false
+                                               end
+                                       end
+                                       if add then
+                                               dctx.add("<tr><td width=\"20%\" align=\"right\"><u>Introduce</u> {c.prototype_head(dctx)}</td><td><b>{c.html_link(dctx)}</b>{c.prototype_body(dctx)}<br/>{c.short_doc}</td><tr>\n")
+                                       end
+                               else
+                                       for p in c.local_local_properties do
+                                               if p.global.is_method and p.global.intro == p then
+                                                       dctx.add("<tr><td width=\"20%\" align=\"right\"><u>Refine</u> <b>{c.html_link(dctx)}</b> <u>Introduce</u> {p.prototype_head(dctx)}</td><td><b>{p.html_link(dctx)}</b>{p.prototype_body(dctx)}<br/>&nbsp;&nbsp;&nbsp;&nbsp;{p.short_doc}</td></tr>\n")
+                                               end
+                                       end
+                               end
+                       end
+                       dctx.add("</table><br/>\n")
+               end
+
                if not new_classes.is_empty then 
                        dctx.sort(new_classes)
                        dctx.add("<table border=\"1\" width=\"100%\" cellpadding=\"3\" cellspacing=\"0\">\n")
@@ -655,16 +698,14 @@ redef class MMSrcModule
        redef fun doc
        do
                var n = node
-               if n.n_packagedecl == null then
+               if n.n_moduledecl == null then
                        return null
                end
-               var np = n.n_packagedecl
-               assert np isa APackagedecl
+               var np = n.n_moduledecl
                var d = np.n_doc
                if d == null then
                        return null
                end
-               assert d isa ADoc
                if d.n_comment.is_empty then
                        return null
                else
@@ -692,16 +733,16 @@ redef class ADoc
 end
 
 redef class MMLocalClass
-special MMEntity
+       super MMEntity
        # Anchor of the class description in the module html file
        fun html_anchor: String do return "CLASS_{self}"
 
        redef fun html_link(dctx)
        do
-               var m = module
-               if not need_doc(dctx) then m = global.module
-               var m = dctx.known_owner_of(m)
-               if m == dctx.module then
+               var m = mmmodule
+               if not need_doc(dctx) then m = global.mmmodule
+               m = dctx.known_owner_of(m)
+               if m == dctx.mmmodule then
                        return "<a href=\"#{html_anchor}\">{self}</a>"
                else
                        return "<a href=\"{m}.html#{html_anchor}\">{self}</a>"
@@ -713,7 +754,7 @@ special MMEntity
        redef fun doc do return global.intro.doc
 
        redef fun need_doc(dctx) do
-               if module == dctx.module then
+               if mmmodule == dctx.mmmodule then
                        for m in dctx.owned_modules do
                                if m.global_classes.has(global) then
                                        var c = m[global]
@@ -724,9 +765,9 @@ special MMEntity
                return false
        end
 
-       redef fun locate(dctx) do return "in {module.html_link(dctx)}"
+       redef fun locate(dctx) do return "in {mmmodule.html_link(dctx)}"
 
-       fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.module)[global]
+       fun known_intro(dctx: DocContext): MMLocalClass do return dctx.known_owner_of(global.intro.mmmodule)[global]
 
        redef fun prototype_head(dctx)
        do
@@ -736,7 +777,7 @@ special MMEntity
                if is_redef then res.append("redef ")
                if global.visibility_level == 3 then res.append("private ")
                res.append("class ")
-               if is_redef then res.append("{ki.module.html_link(dctx)}::")
+               if is_redef then res.append("{ki.mmmodule.html_link(dctx)}::")
                return res.to_s
        end
 
@@ -759,26 +800,26 @@ special MMEntity
        # Extract the doc of a class
        fun extract_class_doc(dctx: DocContext)
        do
-               dctx.add("<a name=\"{html_anchor}\"></a><h2>{self}</h2><small>{module.html_link(dctx)}::</small><br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}\n")
+               dctx.add("<a name=\"{html_anchor}\"></a><h2>{self}</h2><small>{mmmodule.html_link(dctx)}::</small><br/>{prototype_head(dctx)}<b>{self}</b>{prototype_body(dctx)}\n")
                dctx.add("<blockquote>\n")
                dctx.add("<dl>\n")
 
                var sup2 = new Array[String]
-               var intro_module = dctx.known_owner_of(global.module)
-               if intro_module != module then
+               var intro_module = dctx.known_owner_of(global.mmmodule)
+               if intro_module != mmmodule then
                        dctx.add("<dt>Refine {self} from: <dd>{intro_module.html_link(dctx)}\n")
                        sup2.clear
                        var mods = new Array[MMModule]
                        for c in crhe.greaters do
                                if c.need_doc(dctx) then
-                                       var km = dctx.known_owner_of(c.module)
-                                       if km != module and km != intro_module and not mods.has(km) then
+                                       var km = dctx.known_owner_of(c.mmmodule)
+                                       if km != mmmodule and km != intro_module and not mods.has(km) then
                                                mods.add(km)
                                        end
                                end
                        end
                        for c in crhe.linear_extension do
-                               if mods.has(c.module) then sup2.add(c.module.html_link(dctx))
+                               if mods.has(c.mmmodule) then sup2.add(c.mmmodule.html_link(dctx))
                        end
                        if not sup2.is_empty then dctx.add("<dt>Previous refinements in: <dd>{sup2.join(", ")}\n")
                end
@@ -805,11 +846,10 @@ special MMEntity
                sup2.clear
                for c in crhe.smallers do
                        c.compute_super_classes
-                       for c2 in c.module.local_classes do
+                       for c2 in c.mmmodule.local_classes do
                                if not c2 isa MMConcreteClass then continue
                                c2.compute_super_classes
                                c2.compute_ancestors
-                               c2.inherit_global_properties
                        end
                        for c2 in c.cshe.direct_smallers do
                                if c2.global.intro == c2 then
@@ -822,8 +862,8 @@ special MMEntity
                end
                sup2.clear
                for c in crhe.order do
-                       if not module.mhe <= c.module and c.need_doc(dctx) then
-                               sup2.add(c.module.html_link(dctx))
+                       if not mmmodule.mhe <= c.mmmodule and c.need_doc(dctx) then
+                               sup2.add(c.mmmodule.html_link(dctx))
                        end
                end
                if not sup2.is_empty then
@@ -873,7 +913,7 @@ special MMEntity
                var new_props = new Array[MMLocalProperty]
                for g in global_properties do
                        if not accept_prop(g.intro, pass) then continue
-                       if module.visibility_for(g.intro.module) < g.visibility_level then continue
+                       if mmmodule.visibility_for(g.intro.mmmodule) < g.visibility_level then continue
                        var p = self[g]
                        if p.local_class != self or not p.need_doc(dctx) then
                                var cla = new Array[MMLocalClass]
@@ -907,14 +947,13 @@ special MMEntity
                        # skip pass 1 because constructors are not inherited
                        var cmap = new HashMap[MMLocalClass, Array[MMLocalProperty]]
                        var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
-                       var props = new Array[MMLocalClass]
                        for c in che.greaters do
                                if c isa MMSrcLocalClass then
-                                       var km = dctx.known_owner_of(c.module)
+                                       var km = dctx.known_owner_of(c.mmmodule)
                                        var kc = km[c.global]
                                        if kc == self then continue
                                        var props: Array[MMLocalProperty]
-                                       if km == module then
+                                       if km == mmmodule then
                                                if cmap.has_key(kc) then
                                                        props = cmap[kc]
                                                else
@@ -952,7 +991,7 @@ special MMEntity
 
                        dctx.open_stage
                        dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Imported {passname}</small></th><tr>\n")
-                       for m in module.mhe.linear_extension do
+                       for m in mmmodule.mhe.linear_extension do
                                if not mmap.has_key(m) then continue
                                var props = mmap[m]
                                if props.is_empty then continue
@@ -965,11 +1004,10 @@ special MMEntity
                end
 
                var mmap = new HashMap[MMModule, Array[MMLocalProperty]]
-               var props = new Array[MMLocalClass]
                for c in crhe.order do
-                       if module.mhe <= c.module or dctx.owned_modules.has(c.module) or not c isa MMSrcLocalClass then continue
-                       var km = dctx.known_owner_of(c.module)
-                       if module.mhe <= km then continue
+                       if mmmodule.mhe <= c.mmmodule or dctx.owned_modules.has(c.mmmodule) or not c isa MMSrcLocalClass then continue
+                       var km = dctx.known_owner_of(c.mmmodule)
+                       if mmmodule.mhe <= km then continue
                        var kc = km[c.global]
                        var props: Array[MMLocalProperty]
                        if mmap.has_key(km) then
@@ -990,7 +1028,7 @@ special MMEntity
                dctx.open_stage
                dctx.stage("<tr bgcolor=\"#EEEEFF\"><th colspan=\"2\"><small>Added {passname} in known modules</small></th><tr>\n")
                for c in crhe.order do
-                       var m = c.module
+                       var m = c.mmmodule
                        if not mmap.has_key(m) then continue
                        var props = mmap[m]
                        if props.is_empty then continue
@@ -1017,7 +1055,7 @@ special MMEntity
 
                dctx.open_stage
                for p in new_props do
-                       dctx.add("<a name=\"{p.html_anchor}\"></a><h3>{p}</h3><p><small>{p.module.html_link(dctx)}::{p.local_class.html_link(dctx)}::</small><br/>{p.prototype_head(dctx)} <b>{p.name}</b>{p.prototype_body(dctx)}</p>\n")
+                       dctx.add("<a name=\"{p.html_anchor}\"></a><h3>{p}</h3><p><small>{p.mmmodule.html_link(dctx)}::{p.local_class.html_link(dctx)}::</small><br/>{p.prototype_head(dctx)} <b>{p.name}</b>{p.prototype_body(dctx)}</p>\n")
                        dctx.add("<blockquote>")
                        var doc = p.doc
                        if doc != null then
@@ -1047,7 +1085,7 @@ special MMEntity
                if not properties.is_empty then
                        var s: String
                        if heir.global == global then
-                               s = module.html_link(dctx)
+                               s = mmmodule.html_link(dctx)
                        else
                                s = self.html_link(dctx)
                        end
@@ -1072,16 +1110,14 @@ redef class MMSrcLocalClass
 
        redef fun doc
        do
-               var n = nodes.first
-               if not n isa AClassdef then
+               var n = node
+               if not n isa AStdClassdef then
                        return null
                end
-               assert n isa AClassdef
                var d = n.n_doc
                if d == null then
                        return null
                end
-               assert d isa ADoc
                if d.n_comment.is_empty then
                        return null
                else
@@ -1093,7 +1129,7 @@ redef class MMSrcLocalClass
        do
                if global.visibility_level >= 3 then
                        if not dctx.intrude_mode then return false
-                       if dctx.module.visibility_for(module) == 0 then return false
+                       if dctx.mmmodule.visibility_for(mmmodule) == 0 then return false
                end
                if global.intro == self then
                        return true
@@ -1109,7 +1145,7 @@ end
 
 redef class MMSignature
        # Htlm transcription of the signature (with nested links)
-       fun to_html(dctx: DocContext): String
+       fun to_html(dctx: DocContext, with_closure: Bool): String
        do
                var res = new Buffer
                if arity > 0 then
@@ -1125,6 +1161,16 @@ redef class MMSignature
                        res.append(": ")
                        res.append(return_type.html_link(dctx))
                end
+               if with_closure then
+                       for c in closures do
+                               res.append(" ")
+                               if c.is_optional then res.append("[")
+                               if c.is_break then res.append("break ")
+                               res.append("!{c.name}")
+                               res.append(c.signature.to_html(dctx, false))
+                               if c.is_optional then res.append("]")
+                       end
+               end
                return res.to_s
        end
 end