diff options
author | Andreas Sandberg <andreas.sandberg@arm.com> | 2016-03-30 15:30:32 +0100 |
---|---|---|
committer | Andreas Sandberg <andreas.sandberg@arm.com> | 2016-03-30 15:30:32 +0100 |
commit | 2580fcd9d79e2be5933c2575ce1a6eb26380f8a5 (patch) | |
tree | af2a53678e963c06f63972ddd77363d5ea55f8c0 /util/sort_includes.py | |
parent | 062b6c4c9db83c91ef475b09425a1b844d93c72a (diff) | |
download | gem5-2580fcd9d79e2be5933c2575ce1a6eb26380f8a5.tar.xz |
style: Refactor the style checker as a Python package
Refactor the style checker into a Python module that can be reused by
command line tools that integrate with git. In particular:
* Create a style package in util
* Move style validators from style.py to the style/validators.py.
* Move style verifiers from style.py to the style/verifiers.py.
* Move utility functions (sort_includes, region handling,
file_types) into the style package
* Move generic code from style.py to style/style.py.
Signed-off-by: Andreas Sandberg <andreas.sandberg@arm.com>
Reviewed-by: Curtis Dunham <curtis.dunham@arm.com>
Reviewed-by: Steve Reinhardt <steve.reinhardt@amd.com>
--HG--
rename : util/style.py => util/hgstyle.py
rename : util/sort_includes.py => util/style/sort_includes.py
extra : rebase_source : ad6cf9b9a18c48350dfc7b7c77bea6c5344fb53c
Diffstat (limited to 'util/sort_includes.py')
-rw-r--r-- | util/sort_includes.py | 317 |
1 files changed, 0 insertions, 317 deletions
diff --git a/util/sort_includes.py b/util/sort_includes.py deleted file mode 100644 index 334d9e29e..000000000 --- a/util/sort_includes.py +++ /dev/null @@ -1,317 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2014-2015 ARM Limited -# All rights reserved -# -# The license below extends only to copyright in the software and shall -# not be construed as granting a license to any other intellectual -# property including but not limited to intellectual property relating -# to a hardware implementation of the functionality of the software -# licensed hereunder. You may use the software subject to the license -# terms below provided that you ensure that this notice is replicated -# unmodified and in its entirety in all distributions of the software, -# modified or unmodified, in source code or in binary form. -# -# Copyright (c) 2011 The Hewlett-Packard Development Company -# All rights reserved. -# -# Redistribution and use in source and binary forms, with or without -# modification, are permitted provided that the following conditions are -# met: redistributions of source code must retain the above copyright -# notice, this list of conditions and the following disclaimer; -# redistributions in binary form must reproduce the above copyright -# notice, this list of conditions and the following disclaimer in the -# documentation and/or other materials provided with the distribution; -# neither the name of the copyright holders nor the names of its -# contributors may be used to endorse or promote products derived from -# this software without specific prior written permission. -# -# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -# -# Authors: Nathan Binkert -# Andreas Sandberg - -import os -import re -import sys - -from file_types import * - -cpp_c_headers = { - 'assert.h' : 'cassert', - 'ctype.h' : 'cctype', - 'errno.h' : 'cerrno', - 'float.h' : 'cfloat', - 'limits.h' : 'climits', - 'locale.h' : 'clocale', - 'math.h' : 'cmath', - 'setjmp.h' : 'csetjmp', - 'signal.h' : 'csignal', - 'stdarg.h' : 'cstdarg', - 'stddef.h' : 'cstddef', - 'stdio.h' : 'cstdio', - 'stdlib.h' : 'cstdlib', - 'string.h' : 'cstring', - 'time.h' : 'ctime', - 'wchar.h' : 'cwchar', - 'wctype.h' : 'cwctype', -} - -include_re = re.compile(r'([#%])(include|import).*[<"](.*)[">]') -def include_key(line): - '''Mark directories with a leading space so directories - are sorted before files''' - - match = include_re.match(line) - assert match, line - keyword = match.group(2) - include = match.group(3) - - # Everything but the file part needs to have a space prepended - parts = include.split('/') - if len(parts) == 2 and parts[0] == 'dnet': - # Don't sort the dnet includes with respect to each other, but - # make them sorted with respect to non dnet includes. Python - # guarantees that sorting is stable, so just clear the - # basename part of the filename. - parts[1] = ' ' - parts[0:-1] = [ ' ' + s for s in parts[0:-1] ] - key = '/'.join(parts) - - return key - - -def _include_matcher(keyword="#include", delim="<>"): - """Match an include statement and return a (keyword, file, extra) - duple, or a touple of None values if there isn't a match.""" - - rex = re.compile(r'^(%s)\s*%s(.*)%s(.*)$' % (keyword, delim[0], delim[1])) - - def matcher(context, line): - m = rex.match(line) - return m.groups() if m else (None, ) * 3 - - return matcher - -def _include_matcher_fname(fname, **kwargs): - """Match an include of a specific file name. Any keyword arguments - are forwarded to _include_matcher, which is used to match the - actual include line.""" - - rex = re.compile(fname) - base_matcher = _include_matcher(**kwargs) - - def matcher(context, line): - (keyword, fname, extra) = base_matcher(context, line) - if fname and rex.match(fname): - return (keyword, fname, extra) - else: - return (None, ) * 3 - - return matcher - - -def _include_matcher_main(): - """Match a C/C++ source file's primary header (i.e., a file with - the same base name, but a header extension).""" - - base_matcher = _include_matcher(delim='""') - rex = re.compile(r"^src/(.*)\.([^.]+)$") - header_map = { - "c" : "h", - "cc" : "hh", - "cpp" : "hh", - } - def matcher(context, line): - m = rex.match(context["filename"]) - if not m: - return (None, ) * 3 - base, ext = m.groups() - (keyword, fname, extra) = base_matcher(context, line) - try: - if fname == "%s.%s" % (base, header_map[ext]): - return (keyword, fname, extra) - except KeyError: - pass - - return (None, ) * 3 - - return matcher - -class SortIncludes(object): - # different types of includes for different sorting of headers - # <Python.h> - Python header needs to be first if it exists - # <*.h> - system headers (directories before files) - # <*> - STL headers - # <*.(hh|hxx|hpp|H)> - C++ Headers (directories before files) - # "*" - M5 headers (directories before files) - includes_re = ( - ('main', '""', _include_matcher_main()), - ('python', '<>', _include_matcher_fname("^Python\.h$")), - ('c', '<>', _include_matcher_fname("^.*\.h$")), - ('stl', '<>', _include_matcher_fname("^\w+$")), - ('cc', '<>', _include_matcher_fname("^.*\.(hh|hxx|hpp|H)$")), - ('m5header', '""', _include_matcher_fname("^.*\.h{1,2}$", delim='""')), - ('swig0', '<>', _include_matcher(keyword="%import")), - ('swig1', '<>', _include_matcher(keyword="%include")), - ('swig2', '""', _include_matcher(keyword="%import", delim='""')), - ('swig3', '""', _include_matcher(keyword="%include", delim='""')), - ) - - block_order = ( - ('main', ), - ('python', ), - ('c', ), - ('stl', ), - ('cc', ), - ('m5header', ), - ('swig0', 'swig1', 'swig2', 'swig3', ), - ) - - def __init__(self): - self.block_priority = {} - for prio, keys in enumerate(self.block_order): - for key in keys: - self.block_priority[key] = prio - - def reset(self): - # clear all stored headers - self.includes = {} - - def dump_blocks(self, block_types): - """Merge includes of from several block types into one large - block of sorted includes. This is useful when we have multiple - include block types (e.g., swig includes) with the same - priority.""" - - includes = [] - for block_type in block_types: - try: - includes += self.includes[block_type] - except KeyError: - pass - - return sorted(set(includes)) - - def dump_includes(self): - includes = [] - for types in self.block_order: - block = self.dump_blocks(types) - if includes and block: - includes.append("") - includes += block - - self.reset() - return includes - - def __call__(self, lines, filename, language): - self.reset() - - context = { - "filename" : filename, - "language" : language, - } - - def match_line(line): - if not line: - return (None, line) - - for include_type, (ldelim, rdelim), matcher in self.includes_re: - keyword, include, extra = matcher(context, line) - if keyword: - # if we've got a match, clean up the #include line, - # fix up stl headers and store it in the proper category - if include_type == 'c' and language == 'C++': - stl_inc = cpp_c_headers.get(include, None) - if stl_inc: - include = stl_inc - include_type = 'stl' - - return (include_type, - keyword + ' ' + ldelim + include + rdelim + extra) - - return (None, line) - - processing_includes = False - for line in lines: - include_type, line = match_line(line) - if include_type: - try: - self.includes[include_type].append(line) - except KeyError: - self.includes[include_type] = [ line ] - - processing_includes = True - elif processing_includes and not line.strip(): - # Skip empty lines while processing includes - pass - elif processing_includes: - # We are now exiting an include block - processing_includes = False - - # Output pending includes, a new line between, and the - # current l. - for include in self.dump_includes(): - yield include - yield '' - yield line - else: - # We are not in an include block, so just emit the line - yield line - - # We've reached EOF, so dump any pending includes - if processing_includes: - for include in self.dump_includes(): - yield include - -# default language types to try to apply our sorting rules to -default_languages = frozenset(('C', 'C++', 'isa', 'python', 'scons', 'swig')) - -def options(): - import optparse - options = optparse.OptionParser() - add_option = options.add_option - add_option('-d', '--dir_ignore', metavar="DIR[,DIR]", type='string', - default=','.join(default_dir_ignore), - help="ignore directories") - add_option('-f', '--file_ignore', metavar="FILE[,FILE]", type='string', - default=','.join(default_file_ignore), - help="ignore files") - add_option('-l', '--languages', metavar="LANG[,LANG]", type='string', - default=','.join(default_languages), - help="languages") - add_option('-n', '--dry-run', action='store_true', - help="don't overwrite files") - - return options - -def parse_args(parser): - opts,args = parser.parse_args() - - opts.dir_ignore = frozenset(opts.dir_ignore.split(',')) - opts.file_ignore = frozenset(opts.file_ignore.split(',')) - opts.languages = frozenset(opts.languages.split(',')) - - return opts,args - -if __name__ == '__main__': - parser = options() - opts, args = parse_args(parser) - - for base in args: - for filename,language in find_files(base, languages=opts.languages, - file_ignore=opts.file_ignore, dir_ignore=opts.dir_ignore): - if opts.dry_run: - print "%s: %s" % (filename, language) - else: - update_file(filename, filename, language, SortIncludes()) |