diff --git a/cpplint.py b/cpplint.py index b5f9b84..95333aa 100644 --- a/cpplint.py +++ b/cpplint.py @@ -52,15 +52,23 @@ import sys import unicodedata +# Files with any of these extensions are considered to be +# header files (and will undergo different style checks). +# This set can be extended by using the --headers +# option (also supported in CPPLINT.cfg) +_header_extensions = ['h', 'hpp', 'hxx', 'h++', 'cuh'] + + # The allowed extensions for file names # This is set by --extensions flag. -_valid_extensions = set(['c', 'cc', 'cpp', 'cxx', 'c++', 'h', 'hpp', 'hxx', - 'h++']) +_valid_extensions = set(['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'] + _header_extensions) + _USAGE = """ Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] [--counting=total|toplevel|detailed] [--root=subdir] [--linelength=digits] + [--headers=ext1,ext2] [file] ... The style guidelines this tries to follow are those in @@ -139,6 +147,13 @@ Examples: --extensions=hpp,cpp + headers=extension,extension,... + The allowed header extensions that cpplint will consider to be header files + (by default, only .h files will be assumed to be headers) + + Examples: + --headers=h,hpp + 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: @@ -1804,21 +1819,22 @@ def CheckHeaderFileIncluded(filename, include_state, error): return fileinfo = FileInfo(filename) - headerfile = filename[0:len(filename) - 2] + 'h' - if not os.path.exists(headerfile): - return - headername = FileInfo(headerfile).RepositoryName() - first_include = 0 - for section_list in include_state.include_list: - for f in section_list: - if headername in f[0] or f[0] in headername: - return - if not first_include: - first_include = f[1] + for ext in _header_extensions: + headerfile = filename[0:len(filename) - 2] + ext + if not os.path.exists(headerfile): + continue + headername = FileInfo(headerfile).RepositoryName() + first_include = None + for section_list in include_state.include_list: + for f in section_list: + if headername in f[0] or f[0] in headername: + return + if not first_include: + first_include = f[1] - error(filename, first_include, 'build/include', 5, - '%s should include its header file %s' % (fileinfo.RepositoryName(), - headername)) + error(filename, first_include, 'build/include', 5, + '%s should include its header file %s' % (fileinfo.RepositoryName(), + headername)) def CheckForBadCharacters(filename, lines, error): @@ -4459,7 +4475,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, # Check if the line is a header guard. is_header_guard = False - if file_extension == 'h': + if file_extension in _header_extensions: cppvar = GetHeaderGuardCPPVariable(filename) if (line.startswith('#ifndef %s' % cppvar) or line.startswith('#define %s' % cppvar) or @@ -4828,7 +4844,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, CheckGlobalStatic(filename, clean_lines, linenum, error) CheckPrintf(filename, clean_lines, linenum, error) - if file_extension == 'h': + if file_extension in _header_extensions: # TODO(unknown): check that 1-arg constructors are explicit. # How to tell it's a constructor? # (handled in CheckForNonStandardConstructs for now) @@ -4935,7 +4951,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, # Check for use of unnamed namespaces in header files. Registration # macros are typically OK, so we allow use of "namespace {" on lines # that end with backslashes. - if (file_extension == 'h' + if (file_extension in _header_extensions and Search(r'\bnamespace\s*{', line) and line[-1] != '\\'): error(filename, linenum, 'build/namespaces', 4, @@ -6051,7 +6067,7 @@ def ProcessFileData(filename, file_extension, lines, error, RemoveMultiLineComments(filename, lines, error) clean_lines = CleansedLines(lines) - if file_extension == 'h': + if file_extension in _header_extensions: CheckForHeaderGuard(filename, clean_lines, error) for line in range(clean_lines.NumLines()): @@ -6131,6 +6147,22 @@ def ProcessConfigOverrides(filename): _line_length = int(val) except ValueError: sys.stderr.write('Line length must be numeric.') + elif name == 'extensions': + global _valid_extensions + try: + extensions = [ext.strip() for ext in val.split(',')] + _valid_extensions = _valid_extensions.union(set(extensions)) + except ValueError: + sys.stderr.write('Extensions should be a comma-separated list of values;' + 'for example: extensions=hpp,cpp\n' + 'This could not be parsed: "%s"' % (val,)) + try: + extensions = [ext.strip() for ext in val.split(',')] + _valid_extensions = _valid_extensions.union(set(extensions)) + except ValueError: + sys.stderr.write('Extensions should be a comma-separated list of values;' + 'for example: extensions=hpp,cpp\n' + 'This could not be parsed: "%s"' % (values,)) else: sys.stderr.write( 'Invalid configuration option (%s) in file %s\n' % @@ -6277,7 +6309,8 @@ def ParseArguments(args): 'filter=', 'root=', 'linelength=', - 'extensions=']) + 'extensions=', + 'headers=']) except getopt.GetoptError: PrintUsage('Invalid arguments.') @@ -6318,6 +6351,12 @@ def ParseArguments(args): _valid_extensions = set(val.split(',')) except ValueError: PrintUsage('Extensions must be comma seperated list.') + elif opt == '--headers': + global _header_extensions + try: + _header_extensions = set(val.split(',')) + except ValueError: + PrintUsage('Extensions must be comma seperated list.') if not filenames: PrintUsage('No files were specified.')