| Index: cpplint.py
|
| diff --git a/cpplint.py b/cpplint.py
|
| index 92384dc37181f6e982d0e6f74afe93d393c5de19..62f475b0d6cf2807c0762440c732e6c599e2e0ca 100755
|
| --- a/cpplint.py
|
| +++ b/cpplint.py
|
| @@ -133,6 +133,38 @@ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
|
|
|
| Examples:
|
| --extensions=hpp,cpp
|
| +
|
| + cpplint.py supports per-directory configurations specified in CPPLINT.cfg
|
| + files. CPPLINT.cfg file can contain a number of key=value pairs.
|
| + Currently the following options are supported:
|
| +
|
| + set noparent
|
| + filter=+filter1,-filter2,...
|
| + exclude_files=regex
|
| +
|
| + "set noparent" option prevents cpplint from traversing directory tree
|
| + upwards looking for more .cfg files in parent directories. This option
|
| + is usually placed in the top-level project directory.
|
| +
|
| + The "filter" option is similar in function to --filter flag. It specifies
|
| + message filters in addition to the |_DEFAULT_FILTERS| and those specified
|
| + through --filter command-line flag.
|
| +
|
| + "exclude_files" allows to specify a regular expression to be matched against
|
| + a file name. If the expression matches, the file is skipped and not run
|
| + through liner.
|
| +
|
| + CPPLINT.cfg has an effect on files in the same directory and all
|
| + sub-directories, unless overridden by a nested configuration file.
|
| +
|
| + Example file:
|
| + filter=-build/include_order,+build/include_alpha
|
| + exclude_files=.*\.cc
|
| +
|
| + The above example disables build/include_order warning and enables
|
| + build/include_alpha as well as excludes all .cc from being
|
| + processed by linter, in the current directory (where the .cfg
|
| + file is located) and all sub-directories.
|
| """
|
|
|
| # We categorize each error message we print. Here are the categories.
|
| @@ -682,6 +714,8 @@ class _CppLintState(object):
|
| self.error_count = 0 # global count of reported errors
|
| # filters to apply when emitting error messages
|
| self.filters = _DEFAULT_FILTERS[:]
|
| + # backup of filter list. Used to restore the state after each file.
|
| + self._filters_backup = self.filters[:]
|
| self.counting = 'total' # In what way are we counting errors?
|
| self.errors_by_category = {} # string to int dict storing error counts
|
|
|
| @@ -720,6 +754,10 @@ class _CppLintState(object):
|
| """
|
| # Default filters always have less priority than the flag ones.
|
| self.filters = _DEFAULT_FILTERS[:]
|
| + self.AddFilters(filters)
|
| +
|
| + def AddFilters(self, filters):
|
| + """ Adds more filters to the existing list of error-message filters. """
|
| for filt in filters.split(','):
|
| clean_filt = filt.strip()
|
| if clean_filt:
|
| @@ -729,6 +767,14 @@ class _CppLintState(object):
|
| raise ValueError('Every filter in --filters must start with + or -'
|
| ' (%s does not)' % filt)
|
|
|
| + def BackupFilters(self):
|
| + """ Saves the current filter list to backup storage."""
|
| + self._filters_backup = self.filters[:]
|
| +
|
| + def RestoreFilters(self):
|
| + """ Restores filters previously backed up."""
|
| + self.filters = self._filters_backup[:]
|
| +
|
| def ResetErrorCounts(self):
|
| """Sets the module's error statistic back to zero."""
|
| self.error_count = 0
|
| @@ -796,6 +842,25 @@ def _SetFilters(filters):
|
| """
|
| _cpplint_state.SetFilters(filters)
|
|
|
| +def _AddFilters(filters):
|
| + """Adds more filter overrides.
|
| +
|
| + Unlike _SetFilters, this function does not reset the current list of filters
|
| + available.
|
| +
|
| + Args:
|
| + filters: A string of comma-separated filters (eg "whitespace/indent").
|
| + Each filter should start with + or -; else we die.
|
| + """
|
| + _cpplint_state.AddFilters(filters)
|
| +
|
| +def _BackupFilters():
|
| + """ Saves the current filter list to backup storage."""
|
| + _cpplint_state.BackupFilters()
|
| +
|
| +def _RestoreFilters():
|
| + """ Restores filters previously backed up."""
|
| + _cpplint_state.RestoreFilters()
|
|
|
| class _FunctionState(object):
|
| """Tracks current function name and the number of lines in its body."""
|
| @@ -5328,7 +5393,7 @@ def ProcessLine(filename, file_extension, clean_lines, line,
|
| CheckDefaultLambdaCaptures(filename, clean_lines, line, error)
|
| for check_fn in extra_check_functions:
|
| check_fn(filename, clean_lines, line, error)
|
| -
|
| +
|
| def FlagCxx11Features(filename, clean_lines, linenum, error):
|
| """Flag those c++11 features that we only allow in certain places.
|
|
|
| @@ -5424,6 +5489,75 @@ def ProcessFileData(filename, file_extension, lines, error,
|
|
|
| CheckForNewlineAtEOF(filename, lines, error)
|
|
|
| +def ProcessConfigOverrides(filename):
|
| + """ Loads the configuration files and processes the config overrides.
|
| +
|
| + Args:
|
| + filename: The name of the file being processed by the linter.
|
| +
|
| + Returns:
|
| + False if the current |filename| should not be processed further.
|
| + """
|
| +
|
| + abs_filename = os.path.abspath(filename)
|
| + cfg_filters = []
|
| + keep_looking = True
|
| + while keep_looking:
|
| + abs_path, base_name = os.path.split(abs_filename)
|
| + if not base_name:
|
| + break # Reached the root directory.
|
| +
|
| + cfg_file = os.path.join(abs_path, "CPPLINT.cfg")
|
| + abs_filename = abs_path
|
| + if not os.path.isfile(cfg_file):
|
| + continue
|
| +
|
| + try:
|
| + with open(cfg_file) as file_handle:
|
| + for line in file_handle:
|
| + line, _, _ = line.partition('#') # Remove comments.
|
| + if not line.strip():
|
| + continue
|
| +
|
| + name, _, val = line.partition('=')
|
| + name = name.strip()
|
| + val = val.strip()
|
| + if name == 'set noparent':
|
| + keep_looking = False
|
| + elif name == 'filter':
|
| + cfg_filters.append(val)
|
| + elif name == 'exclude_files':
|
| + # When matching exclude_files pattern, use the base_name of
|
| + # the current file name or the directory name we are processing.
|
| + # For example, if we are checking for lint errors in /foo/bar/baz.cc
|
| + # and we found the .cfg file at /foo/CPPLINT.cfg, then the config
|
| + # file's "exclude_files" filter is meant to be checked against "bar"
|
| + # and not "baz" nor "bar/baz.cc".
|
| + if base_name:
|
| + pattern = re.compile(val)
|
| + if pattern.match(base_name):
|
| + sys.stderr.write('Ignoring "%s": file excluded by "%s". '
|
| + 'File path component "%s" matches '
|
| + 'pattern "%s"\n' %
|
| + (filename, cfg_file, base_name, val))
|
| + return False
|
| + else:
|
| + sys.stderr.write(
|
| + 'Invalid configuration option (%s) in file %s\n' %
|
| + (name, cfg_file))
|
| +
|
| + except IOError:
|
| + sys.stderr.write(
|
| + "Skipping config file '%s': Can't open for reading\n" % cfg_file)
|
| + keep_looking = False
|
| +
|
| + # Apply all the accumulated filters in reverse order (top-level directory
|
| + # config options having the least priority).
|
| + for filter in reversed(cfg_filters):
|
| + _AddFilters(filter)
|
| +
|
| + return True
|
| +
|
|
|
| def ProcessFile(filename, vlevel, extra_check_functions=[]):
|
| """Does google-lint on a single file.
|
| @@ -5440,6 +5574,11 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
|
| """
|
|
|
| _SetVerboseLevel(vlevel)
|
| + _BackupFilters()
|
| +
|
| + if not ProcessConfigOverrides(filename):
|
| + _RestoreFilters()
|
| + return
|
|
|
| lf_lines = []
|
| crlf_lines = []
|
| @@ -5471,6 +5610,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
|
| except IOError:
|
| sys.stderr.write(
|
| "Skipping input '%s': Can't open for reading\n" % filename)
|
| + _RestoreFilters()
|
| return
|
|
|
| # Note, if no dot is found, this will give the entire filename as the ext.
|
| @@ -5504,6 +5644,7 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]):
|
| 'Unexpected \\r (^M) found; better to use only \\n')
|
|
|
| sys.stderr.write('Done processing %s\n' % filename)
|
| + _RestoreFilters()
|
|
|
|
|
| def PrintUsage(message):
|
|
|