]> git.uio.no Git - u/mrichter/AliRoot.git/blobdiff - doxygen/thtml2doxy.py
doxy: support both ClassImp() and ClassDef()
[u/mrichter/AliRoot.git] / doxygen / thtml2doxy.py
index 3ed09ff91aaad18266a9d3529b5b634bead1de11..1347c549ee09338ba8aa4fd557a7c1d94ea850ec 100755 (executable)
@@ -69,7 +69,9 @@ class Colt(str):
 ## Comment.
 class Comment(object):
 
-  def __init__(self, lines, first_line, first_col, last_line, last_col, indent, func):
+  def __init__(self, lines, first_line, first_col, last_line, last_col, indent, func, \
+    append_empty=True):
+
     assert first_line > 0 and last_line >= first_line, 'Wrong line numbers'
     self.lines = lines
     self.first_line = first_line
@@ -78,6 +80,7 @@ class Comment(object):
     self.last_col = last_col
     self.indent = indent
     self.func = func
+    self.append_empty = append_empty
 
   def has_comment(self, line):
     return line >= self.first_line and line <= self.last_line
@@ -92,9 +95,10 @@ class Comment(object):
 ## Prepend comment.
 class PrependComment(Comment):
 
-  def __init__(self, lines, first_line, first_col, last_line, last_col, indent, func):
+  def __init__(self, lines, first_line, first_col, last_line, last_col, indent, func, \
+    append_empty=False):
     super(PrependComment, self).__init__( \
-      lines, first_line, first_col, last_line, last_col, indent, func)
+      lines, first_line, first_col, last_line, last_col, indent, func, append_empty)
 
 
 ## A data member comment.
@@ -278,7 +282,7 @@ def comment_datamember(cursor, comments):
 
   assert found, 'A line that should exist was not found in file' % cursor.location.file
 
-  recomm = r'(//(!|\|\||->)|///?)(\[([0-9,]+)\])?<?\s*(.*?)\s*$'
+  recomm = r'(//(!|\|\||->)|///?)(\[(.+?)\])?<?\s*(.*?)\s*$'
   recomm_prevline = r'^\s*///\s*(.*?)\s*$'
 
   mcomm = re.search(recomm, raw)
@@ -322,14 +326,15 @@ def comment_datamember(cursor, comments):
 #
 #  @param filename Name of the current file
 #  @param comments Array of comments: new ones will be appended there
-def comment_classdesc(filename, comments):
+#  @param look_no_further_than_line Stop before reaching this line when looking for class comment
+def comment_classdesc(filename, comments, look_no_further_than_line):
 
   recomm = r'^\s*///?(\s*.*?)\s*/*\s*$'
 
   reclass_doxy = r'(?i)^\s*\\(class|file):?\s*([^.]*)'
   class_name_doxy = None
 
-  reauthor = r'(?i)^\s*\\?authors?:?\s*(.*?)\s*(,?\s*([0-9./-]+))?\s*$'
+  reauthor = r'(?i)^\s*\\?(authors?|origin):?\s*(.*?)\s*(,?\s*([0-9./-]+))?\s*$'
   redate = r'(?i)^\s*\\?date:?\s*([0-9./-]+)\s*$'
   author = None
   date = None
@@ -349,6 +354,11 @@ def comment_classdesc(filename, comments):
 
       line_num = line_num + 1
 
+      if look_no_further_than_line is not None and line_num == look_no_further_than_line:
+        logging.debug('Stopping at line %d while looking for class/file description' % \
+          look_no_further_than_line)
+        break
+
       if raw.strip() == '' and start_line > 0:
         # Skip empty lines
         continue
@@ -382,10 +392,10 @@ def comment_classdesc(filename, comments):
         else:
           mauthor = re.search(reauthor, mcomm.group(1))
           if mauthor:
-            author = mauthor.group(1)
+            author = mauthor.group(2)
             if date is None:
               # Date specified in the standalone \date field has priority
-              date = mauthor.group(3)
+              date = mauthor.group(4)
             append = False
           else:
             mdate = re.search(redate, mcomm.group(1))
@@ -410,13 +420,16 @@ def comment_classdesc(filename, comments):
     else:
       assert False, 'Regexp unable to extract classname from file'
 
+  # Macro or class?
+  if is_macro:
+    file_class_line = '\\file ' + class_name_doxy + '.C'
+  else:
+    file_class_line = '\\class ' + class_name_doxy
+
   if start_line > 0:
 
     # Prepend \class or \file specifier (and an empty line)
-    if is_macro:
-      comment_lines[:0] = [ '\\file ' + class_name_doxy + '.C' ]
-    else:
-      comment_lines[:0] = [ '\\class ' + class_name_doxy ]
+    comment_lines[:0] = [ file_class_line ]
     comment_lines.append('')
 
     # Append author and date if they exist
@@ -436,7 +449,14 @@ def comment_classdesc(filename, comments):
 
   else:
 
-    logging.warning('No comment found for class %s' % Colt(class_name_doxy).magenta())
+    logging.warning('No comment found for class %s: creating a dummy entry at the beginning' % \
+      Colt(class_name_doxy).magenta())
+
+    comments.append(PrependComment(
+      [ file_class_line ],
+      1, 1, 1, 1,
+      0, class_name_doxy, append_empty=True
+    ))
 
 
 ## Looks for a special ROOT ClassImp() entry.
@@ -452,36 +472,85 @@ def comment_classimp(filename, comments):
   recomm = r'^\s*///?(\s*.*?)\s*/*\s*$'
 
   line_num = 0
-  reclassimp = r'^(\s*)ClassImp\((.*?)\)\s*;?\s*$'
+  reclassimp = r'^(\s*)Class(Imp|Def)\((.*?)\).*$'
+
+  in_classimp_cond = False
+  restartcond = r'^\s*///\s*\\cond\s+CLASSIMP\s*$'
+  reendcond = r'^\s*///\s*\\endcond\s*$'
 
   with open(filename, 'r') as fp:
 
+    line_classimp = -1
+    line_startcond = -1
+    line_endcond = -1
+    classimp_class = None
+    classimp_indent = None
+
     for line in fp:
 
       line_num = line_num + 1
+
       mclassimp = re.search(reclassimp, line)
       if mclassimp:
 
         # Adjust indent
-        indent_len = len( mclassimp.group(1) )
+        classimp_indent = len( mclassimp.group(1) )
 
+        line_classimp = line_num
+        classimp_class = mclassimp.group(3)
+        imp_or_def = mclassimp.group(2)
         logging.debug(
           'Comment found for ' +
-          Colt( 'ClassImp(' ).magenta() +
-          Colt( mclassimp.group(2) ).cyan() +
+          Colt( 'Class%s(' % imp_or_def ).magenta() +
+          Colt( classimp_class ).cyan() +
           Colt( ')' ).magenta() )
 
-        comments.append(PrependComment(
-          ['\cond CLASSIMP'],
-          line_num, 1, line_num, 1,
-          indent_len, 'ClassImp(%s)' % mclassimp.group(2)
-        ))
+      else:
 
-        comments.append(PrependComment(
-          ['\endcond'],
-          line_num+1, 1, line_num+1, 1,
-          indent_len, 'ClassImp(%s)' % mclassimp.group(2)
-        ))
+        mstartcond = re.search(restartcond, line)
+        if mstartcond:
+          logging.debug('Found Doxygen opening condition for ClassImp in {%s}' % line)
+          in_classimp_cond = True
+          line_startcond = line_num
+
+        elif in_classimp_cond:
+
+          mendcond = re.search(reendcond, line)
+          if mendcond:
+            logging.debug('Found Doxygen closing condition for ClassImp')
+            in_classimp_cond = False
+            line_endcond = line_num
+
+  # Did we find something?
+  if line_classimp != -1:
+
+    if line_startcond != -1:
+      comments.append(Comment(
+        ['\cond CLASSIMP'],
+        line_startcond, 1, line_startcond, 1,
+        classimp_indent, 'ClassImp/Def(%s)' % classimp_class,
+        append_empty=False
+      ))
+    else:
+      comments.append(PrependComment(
+        ['\cond CLASSIMP'],
+        line_classimp, 1, line_classimp, 1,
+        classimp_indent, 'ClassImp/Def(%s)' % classimp_class
+      ))
+
+    if line_endcond != -1:
+      comments.append(Comment(
+        ['\endcond'],
+        line_endcond, 1, line_endcond, 1,
+        classimp_indent, 'ClassImp/Def(%s)' % classimp_class,
+        append_empty=False
+      ))
+    else:
+      comments.append(PrependComment(
+        ['\endcond'],
+        line_classimp+1, 1, line_classimp+1, 1,
+        classimp_indent, 'ClassImp/Def(%s)' % classimp_class
+      ))
 
 
 ## Traverse the AST recursively starting from the current cursor.
@@ -491,7 +560,10 @@ def comment_classimp(filename, comments):
 #  @param comments  Array of comments: new ones will be appended there
 #  @param recursion Current recursion depth
 #  @param in_func   True if we are inside a function or method
-def traverse_ast(cursor, filename, comments, recursion=0, in_func=False):
+#  @param classdesc_line_limit  Do not look for comments after this line
+#
+#  @return A tuple containing the classdesc_line_limit as first item
+def traverse_ast(cursor, filename, comments, recursion=0, in_func=False, classdesc_line_limit=None):
 
   # libclang traverses included files as well: we do not want this behavior
   if cursor.location.file is not None and str(cursor.location.file) != filename:
@@ -510,6 +582,9 @@ def traverse_ast(cursor, filename, comments, recursion=0, in_func=False):
   if cursor.kind in [ clang.cindex.CursorKind.CXX_METHOD, clang.cindex.CursorKind.CONSTRUCTOR,
     clang.cindex.CursorKind.DESTRUCTOR, clang.cindex.CursorKind.FUNCTION_DECL ]:
 
+    if classdesc_line_limit is None:
+      classdesc_line_limit = cursor.location.line
+
     # cursor ran into a C++ method
     logging.debug( "%5d %s%s(%s)" % (cursor.location.line, indent, Colt(kind).magenta(), Colt(text).blue()) )
     comment_method(cursor, comments)
@@ -518,6 +593,9 @@ def traverse_ast(cursor, filename, comments, recursion=0, in_func=False):
   elif not is_macro and not in_func and \
     cursor.kind in [ clang.cindex.CursorKind.FIELD_DECL, clang.cindex.CursorKind.VAR_DECL ]:
 
+    if classdesc_line_limit is None:
+      classdesc_line_limit = cursor.location.line
+
     # cursor ran into a data member declaration
     logging.debug( "%5d %s%s(%s)" % (cursor.location.line, indent, Colt(kind).magenta(), Colt(text).blue()) )
     comment_datamember(cursor, comments)
@@ -527,11 +605,13 @@ def traverse_ast(cursor, filename, comments, recursion=0, in_func=False):
     logging.debug( "%5d %s%s(%s)" % (cursor.location.line, indent, kind, text) )
 
   for child_cursor in cursor.get_children():
-    traverse_ast(child_cursor, filename, comments, recursion+1, in_func)
+    classdesc_line_limit = traverse_ast(child_cursor, filename, comments, recursion+1, in_func, classdesc_line_limit)
 
   if recursion == 0:
     comment_classimp(filename, comments)
-    comment_classdesc(filename, comments)
+    comment_classdesc(filename, comments, classdesc_line_limit)
+
+  return classdesc_line_limit
 
 
 ## Strip some HTML tags from the given string. Returns clean string.
@@ -771,7 +851,7 @@ def rewrite_comments(fhin, fhout, comments):
       fhout.write('\n')
 
     # Empty new line at the end of the comment
-    if not isinstance(cmt, PrependComment):
+    if cmt.append_empty:
       fhout.write('\n')
       ask_skip_empty = True
 
@@ -799,7 +879,8 @@ def rewrite_comments(fhin, fhout, comments):
     if comm:
 
       # First thing to check: are we in the same comment as before?
-      if comm is not prev_comm and isinstance(comm, Comment) and isinstance(prev_comm, Comment):
+      if comm is not prev_comm and isinstance(comm, Comment) and isinstance(prev_comm, Comment) \
+        and not isinstance(prev_comm, RemoveComment):
 
         skip_empty = dump_comment_block(prev_comm, restore_lines)
         in_comment = False