github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/scripts/find-bad-doc-comments.py (about)

     1  #!/usr/bin/python
     2  
     3  """
     4  This quick-and-dirty tool locates Go doc comments in a source tree
     5  that don't follow the convention of the first word of the comment
     6  matching the function name. It highlights cases where doc comments
     7  haven't been updated in step with function name changes or where doc
     8  comments have been copied and pasted but not updated.
     9  
    10  Tests are excluded by the check, unless --tests is given.
    11  Unexported methods and functions are also excluded, unless --unexported
    12  is given.
    13  
    14  By default, all problems found are emitted but there is also an
    15  interactive edit mode is available via --fix.
    16  """
    17  
    18  import argparse
    19  import fnmatch
    20  import os
    21  import re
    22  import subprocess
    23  from os import path
    24  
    25  def find_go_files(root):
    26      for directory, _, files in os.walk(root):
    27          for filename in fnmatch.filter(files, '*.go'):
    28              yield path.join(directory, filename)
    29  
    30  DOC_COMMENT_PATT = '\n\n//.+\n(//.+\n)*func.+\n'
    31  FIRST_WORD_PATT = '// *(\w+)'
    32  FUNC_NAME_PATT = 'func(?: \([^)]+\))? (\S+)\('
    33  
    34  def extract_doc_comments(text):
    35      for match in re.finditer(DOC_COMMENT_PATT, text, re.MULTILINE):
    36          yield match.group(0).strip()
    37  
    38  def find_bad_doc_comments(comments):
    39      for comment in comments:
    40          lines = comment.splitlines()
    41          first_word_match = re.match(FIRST_WORD_PATT, lines[0])
    42          if first_word_match:
    43              first_word = first_word_match.group(1)
    44              func_name = re.match(FUNC_NAME_PATT, lines[-1]).group(1)
    45              if first_word != func_name:
    46                  yield func_name, comment
    47  
    48  def cmdline():
    49      parser = argparse.ArgumentParser(description=__doc__)
    50      parser.add_argument('--fix', default=False, action='store_true',
    51                          help='Interactive fix-up mode')
    52      parser.add_argument('--tests', default=False, action='store_true',
    53                          help='Include test methods in the check')
    54      parser.add_argument('--unexported', default=False, action='store_true',
    55                          help='Include unexported methods in the check')
    56      parser.add_argument('root', nargs='?', default=os.getcwd())
    57      return parser.parse_args()
    58  
    59  def emit(filename, comment):
    60      print
    61      print '%s: ' % filename
    62      print comment
    63  
    64  def fix(filename, func_name, comment):
    65      emit(filename, comment)
    66      resp = raw_input('Fix? [Y/n] ').strip().lower()
    67      if resp in ('', 'y'):
    68          subprocess.check_call(['vim', '-c', '/func .*'+func_name+'(', filename])
    69  
    70  def main():
    71      args = cmdline()
    72  
    73      count = 0
    74      for filename in find_go_files(args.root):
    75          with open(filename) as sourceFile:
    76              source = sourceFile.read()
    77          comments = extract_doc_comments(source)
    78          for func_name, bad_comment in find_bad_doc_comments(comments):
    79              if func_name.startswith('Test') and not args.tests:
    80                  # Skip tests unless told otherwise.
    81                  continue
    82              if 'export_test.go' in filename and not args.tests:
    83                  # Skip export_test.go unless --tests is given.
    84                  continue
    85              if func_name[0].islower() and not args.unexported:
    86                  # Skip unexported unless told otherwise.
    87                  continue
    88              if args.fix:
    89                  fix(filename, func_name, bad_comment)
    90              else:
    91                  emit(filename, bad_comment)
    92              count += 1
    93  
    94      print
    95      print "Problems found:", count
    96  
    97  if __name__ == '__main__':
    98      main()