Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Merge branch 'master' of framagit.org:Adrien.Gougeon/simgrid into master
[simgrid.git] / docs / source / _ext / autodoxy.py
index 4d36e79..5811d2a 100644 (file)
@@ -18,7 +18,12 @@ import sys
 
 from six import itervalues
 from lxml import etree as ET
-from sphinx.ext.autodoc import Documenter, AutoDirective, members_option, ALL
+from sphinx.ext.autodoc import Documenter, members_option, ALL
+try:
+    from sphinx.ext.autodoc import AutoDirective
+    sphinxVersion = 1
+except ImportError:
+    sphinxVersion = 2
 from sphinx.errors import ExtensionError
 from sphinx.util import logging
 
@@ -130,7 +135,7 @@ class _DoxygenXmlParagraphFormatter(object):
         self.continue_line = True
 
     def visit_parameterlist(self, node):
-        lines = [l for l in type(self)().generic_visit(node).lines if l is not '']
+        lines = [l for l in type(self)().generic_visit(node).lines if l != '']
         self.lines.extend([':parameters:', ''] + ['* %s' % l for l in lines] + [''])
 
     def visit_simplesect(self, node):
@@ -191,12 +196,12 @@ class DoxygenDocumenter(Documenter):
         'members': members_option,
     }
 
-    def __init__(self, directive, name, indent=u'', id=None):
+    def __init__(self, directive, name, indent=u'', my_id = None):
         super(DoxygenDocumenter, self).__init__(directive, name, indent)
-        if id is not None:
-            self.parse_id(id)
+        if my_id is not None:
+            self.parse_id(my_id)
 
-    def parse_id(self, id):
+    def parse_id(self, id_to_parse):
         return False
 
     def parse_name(self):
@@ -224,9 +229,11 @@ class DoxygenDocumenter(Documenter):
 
         if '::' in self.name:
             parts = self.name.split('::')
+            self.klassname = parts[-2]
             self.objname = parts[-1]
         else:
             self.objname = self.name
+            self.klassname = ""
 
         return True
 
@@ -236,6 +243,7 @@ class DoxygenDocumenter(Documenter):
         directive = getattr(self, 'directivetype', self.objtype)
         name = self.format_name()
         sourcename = self.get_sourcename()
+        #print('.. %s:%s:: %s%s' % (domain, directive, name, sig))
         self.add_line(u'.. %s:%s:: %s%s' % (domain, directive, name, sig),
                       sourcename)
 
@@ -257,8 +265,12 @@ class DoxygenDocumenter(Documenter):
         # document non-skipped members
         memberdocumenters = []
         for (mname, member, isattr) in self.filter_members(members, want_all):
-            classes = [cls for cls in itervalues(AutoDirective._registry)
-                       if cls.can_document_member(member, mname, isattr, self)]
+            if sphinxVersion >= 2:
+                classes = [cls for cls in itervalues(self.env.app.registry.documenters)
+                            if cls.can_document_member(member, mname, isattr, self)]
+            else:
+                classes = [cls for cls in itervalues(AutoDirective._registry)
+                            if cls.can_document_member(member, mname, isattr, self)]
             if not classes:
                 # don't know how to document this member
                 continue
@@ -308,7 +320,7 @@ class DoxygenClassDocumenter(DoxygenDocumenter):
         xpath_query = './/compoundname[text()="%s"]/..' % self.fullname
         match = get_doxygen_root().xpath(xpath_query)
         if len(match) != 1:
-            raise ExtensionError('[autodoxy] could not find class (fullname="%s"). I tried'
+            raise ExtensionError('[autodoxy] could not find class (fullname="%s"). I tried '
                                  'the following xpath: "%s"' % (self.fullname, xpath_query))
 
         self.object = match[0]
@@ -320,7 +332,7 @@ class DoxygenClassDocumenter(DoxygenDocumenter):
     def format_name(self):
         return self.fullname
 
-    def get_doc(self, encoding):
+    def get_doc(self, encoding=None): # This method is called with 1 parameter in Sphinx 2.x and 2 parameters in Sphinx 1.x
         detaileddescription = self.object.find('detaileddescription')
         doc = [format_xml_paragraph(detaileddescription)]
         return doc
@@ -331,12 +343,9 @@ class DoxygenClassDocumenter(DoxygenDocumenter):
 
         if want_all:
             return False, ((m.find('name').text, m) for m in all_members)
-        else:
-            if not self.options.members:
-                return False, []
-            else:
-                return False, ((m.find('name').text, m) for m in all_members
-                               if m.find('name').text in self.options.members)
+        if not self.options.members:
+            return False, []
+        return False, ((m.find('name').text, m) for m in all_members if m.find('name').text in self.options.members)
 
     def filter_members(self, members, want_all):
         ret = []
@@ -349,6 +358,13 @@ class DoxygenClassDocumenter(DoxygenDocumenter):
         # Uncomment to view the generated rst for the class.
         # print('\n'.join(self.directive.result))
 
+autodoxy_requalified_identifiers = []
+def fix_namespaces(str):
+    for unqualified,fullyqualif in autodoxy_requalified_identifiers:
+        p = re.compile("(^| ){:s}".format(unqualified))
+        str = p.sub(' {:s}'.format(fullyqualif), str)
+    return str
+
 class DoxygenMethodDocumenter(DoxygenDocumenter):
     objtype = 'doxymethod'
     directivetype = 'function'
@@ -361,10 +377,10 @@ class DoxygenMethodDocumenter(DoxygenDocumenter):
             return True
         return False
 
-    def parse_id(self, id):
-        xp = './/*[@id="%s"]' % id
+    def parse_id(self, id_to_parse):
+        xp = './/*[@id="%s"]' % id_to_parse
         match = get_doxygen_root().xpath(xp)
-        if len(match) > 0:
+        if match:
             match = match[0]
             self.fullname = match.find('./definition').text.split()[-1]
             self.modname = self.fullname
@@ -379,38 +395,45 @@ class DoxygenMethodDocumenter(DoxygenDocumenter):
             # classname or method name
             return True
 
-        (obj, meth) = self.fullname.rsplit('::', 1)
+        if '::' in self.fullname:
+            (obj, meth) = self.fullname.rsplit('::', 1)
+            # 'public-func' and 'public-static-func' are for classes while 'func' alone is for namespaces
+            prefix = './/compoundname[text()="{:s}"]/../sectiondef[@kind="public-func" or @kind="public-static-func" or @kind="func"]'.format(obj)
+            obj = "{:s}::".format(obj)
+        else:
+            meth = self.fullname
+            prefix = './'
+            obj = ''
 
-        xpath_query_noparam = ('.//compoundname[text()="{:s}"]/../sectiondef[@kind="public-func" or @kind="public-static-func"]'
-                               '/memberdef[@kind="function"]/name[text()="{:s}"]/..').format(obj, meth)
+        xpath_query_noparam = ('{:s}/memberdef[@kind="function"]/name[text()="{:s}"]/..').format(prefix, meth)
         xpath_query = ""
-#        print("fullname {}".format(self.fullname))
         if self.argsstring != None:
-            xpath_query = ('.//compoundname[text()="{:s}"]/../sectiondef[@kind="public-func" or @kind="public-static-func"]'
-                           '/memberdef[@kind="function" and argsstring/text()="{:s}"]/name[text()="{:s}"]/..').format(obj,self.argsstring,meth)
+            xpath_query = ('{:s}/memberdef[@kind="function" and argsstring/text()="{:s}"]/name[text()="{:s}"]/..').format(prefix,self.argsstring,meth)
         else:
             xpath_query = xpath_query_noparam
         match = get_doxygen_root().xpath(xpath_query)
-        if len(match) == 0:
+        if not match:
             logger = logging.getLogger(__name__)
 
             if self.argsstring != None:
                 candidates = get_doxygen_root().xpath(xpath_query_noparam)
                 if len(candidates) == 1:
-                    logger.warning("[autodoxy] Using method '{}::{}{}' instead of '{}::{}{}'. You may want to drop your specification of the signature, or to fix it."
-                                   .format(obj, meth, candidates[0].find('argsstring').text, obj, meth, self.argsstring))
+                    logger.warning("[autodoxy] Using method '{}{}{}' instead of '{}{}{}'. You may want to drop your specification of the signature, or to fix it."
+                                       .format(obj, meth, candidates[0].find('argsstring').text, obj, meth, self.argsstring))
                     self.object = candidates[0]
                     return True
-                logger.warning("[autodoxy] WARNING: Could not find method {}::{}{}".format(obj, meth, self.argsstring))
+                logger.warning("[autodoxy] WARNING: Could not find method {}{}{}".format(obj, meth, self.argsstring))
+                if not candidates:
+                    logger.warning("[autodoxy] WARNING:  (no candidate found)")
                 for cand in candidates:
-                    logger.warning("[autodoxy] WARNING:   Existing candidate: {}::{}{}".format(obj, meth, cand.find('argsstring').text))
+                    logger.warning("[autodoxy] WARNING:   Existing candidate: {}{}{}".format(obj, meth, cand.find('argsstring').text))
             else:
-                logger.warning("[autodoxy] WARNING: could not find method {}::{} in Doxygen files".format(obj, meth))
+                logger.warning("[autodoxy] WARNING: Could not find method {}{} in Doxygen files\nQuery: {}".format(obj, meth, xpath_query))
             return False
         self.object = match[0]
         return True
 
-    def get_doc(self, encoding):
+    def get_doc(self, encoding=None): # This method is called with 1 parameter in Sphinx 2.x and 2 parameters in Sphinx 1.x
         detaileddescription = self.object.find('detaileddescription')
         doc = [format_xml_paragraph(detaileddescription)]
         return doc
@@ -434,19 +457,21 @@ class DoxygenMethodDocumenter(DoxygenDocumenter):
             rtype = rtype_el.text
 
  #       print("rtype: {}".format(rtype))
-        signame = (rtype and (rtype + ' ') or '') + self.objname
+        signame = fix_namespaces((rtype and (rtype + ' ') or '') + self.klassname + "::"+ self.objname )
+#        print("signame: '{}'".format(signame))
         return self.format_template_name() + signame
 
     def format_template_name(self):
         types = [e.text for e in self.object.findall('templateparamlist/param/type')]
-        if len(types) == 0:
+        if not types:
             return ''
         ret = 'template <%s>' % ','.join(types)
 #        print ("template: {}".format(ret))
         return ret
 
     def format_signature(self):
-        args = self.object.find('argsstring').text
+        args = fix_namespaces(self.object.find('argsstring').text)
+#        print ("signature: {}".format(args))
         return args
 
     def document_members(self, all_members=False):
@@ -477,7 +502,7 @@ class DoxygenVariableDocumenter(DoxygenDocumenter):
                        '/memberdef[@kind="variable"]/name[text()="{:s}"]/..').format(obj, var)
 #        print("fullname {}".format(self.fullname))
         match = get_doxygen_root().xpath(xpath_query)
-        if len(match) == 0:
+        if not match:
             logger = logging.getLogger(__name__)
 
             logger.warning("[autodoxy] WARNING: could not find variable {}::{} in Doxygen files".format(obj, var))
@@ -485,10 +510,10 @@ class DoxygenVariableDocumenter(DoxygenDocumenter):
         self.object = match[0]
         return True
 
-    def parse_id(self, id):
-        xp = './/*[@id="%s"]' % id
+    def parse_id(self, id_to_parse):
+        xp = './/*[@id="%s"]' % id_to_parse
         match = get_doxygen_root().xpath(xp)
-        if len(match) > 0:
+        if match:
             match = match[0]
             self.fullname = match.find('./definition').text.split()[-1]
             self.modname = self.fullname
@@ -514,18 +539,18 @@ class DoxygenVariableDocumenter(DoxygenDocumenter):
         else:
             rtype = rtype_el.text
 
- #       print("rtype: {}".format(rtype))
-        signame = (rtype and (rtype + ' ') or '') + self.objname
-        return self.format_template_name() + signame
+       print("rtype: {}".format(rtype))
+        signame = (rtype and (rtype + ' ') or '') + self.klassname + "::" + self.objname
+        return fix_namespaces(self.format_template_name() + signame)
 
-    def get_doc(self, encoding):
+    def get_doc(self, encoding=None): # This method is called with 1 parameter in Sphinx 2.x and 2 parameters in Sphinx 1.x
         detaileddescription = self.object.find('detaileddescription')
         doc = [format_xml_paragraph(detaileddescription)]
         return doc
 
     def format_template_name(self):
         types = [e.text for e in self.object.findall('templateparamlist/param/type')]
-        if len(types) == 0:
+        if not types:
             return ''
         ret = 'template <%s>' % ','.join(types)
 #        print ("template: {}".format(ret))
@@ -552,15 +577,18 @@ def set_doxygen_xml(app):
     files = [os.path.join(app.config.doxygen_xml, f)
              for f in os.listdir(app.config.doxygen_xml)
              if f.lower().endswith('.xml') and not f.startswith('._')]
-    if len(files) == 0:
+    if not files:
         raise err
 
     setup.DOXYGEN_ROOT = ET.ElementTree(ET.Element('root')).getroot()
-    for file in files:
-        root = ET.parse(file).getroot()
+    for current_file in files:
+        root = ET.parse(current_file).getroot()
         for node in root:
             setup.DOXYGEN_ROOT.append(node)
 
+    if app.config.autodoxy_requalified_identifiers is not None:
+        global autodoxy_requalified_identifiers
+        autodoxy_requalified_identifiers = app.config.autodoxy_requalified_identifiers
 
 def get_doxygen_root():
     """Get the root element of the doxygen XML document.
@@ -583,6 +611,7 @@ def setup(app):
     app.add_autodocumenter(DoxygenMethodDocumenter)
     app.add_autodocumenter(DoxygenVariableDocumenter)
     app.add_config_value("doxygen_xml", "", True)
+    app.add_config_value("autodoxy_requalified_identifiers", [], True)
 
 #    app.add_directive('autodoxysummary', DoxygenAutosummary)
 #    app.add_directive('autodoxyenum', DoxygenAutoEnum)