4444import codecs
4545import copy
4646import getopt
47+ import itertools
4748import math # for log
4849import os
4950import re
5253import sys
5354import unicodedata
5455
56+ # Files with any of these extensions are considered to be
57+ # header files (and will undergo different style checks).
58+ # This set can be extended by using the --headers
59+ # option (also supported in CPPLINT.cfg)
60+ _header_extensions = set (['h' , 'hpp' , 'hxx' , 'h++' , 'cuh' ])
61+ _nonheader_extensions = set (['c' , 'cc' , 'cpp' , 'cxx' , 'c++' , 'cu' ])
62+
63+
5564# The allowed extensions for file names
5665# This is set by --extensions flag.
57- _valid_extensions = set (['c' , 'cc' , 'cpp' , 'cxx' , 'c++' , 'h' , 'hpp' , 'hxx' ,
58- 'h++' ])
66+ _valid_extensions = _nonheader_extensions .union (_header_extensions )
67+
68+ # files with this suffix before the extension will be treated as test files
69+ _test_suffixes = set (['_unittest' , '_test' , '_regtest' ])
5970
6071_USAGE = """
6172Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...]
@@ -1074,7 +1085,7 @@ def BaseName(self):
10741085 return self .Split ()[1 ]
10751086
10761087 def Extension (self ):
1077- """File extension - text following the final period."""
1088+ """File extension - text following the final period, includes that period ."""
10781089 return self .Split ()[2 ]
10791090
10801091 def NoExtension (self ):
@@ -1798,28 +1809,29 @@ def CheckForHeaderGuard(filename, clean_lines, error):
17981809
17991810
18001811def CheckHeaderFileIncluded (filename , include_state , error ):
1801- """Logs an error if a .cc file does not include its header."""
1812+ """Logs an error if a source file does not include its header."""
18021813
18031814 # Do not check test files
1804- if filename . endswith ( '_test.cc' ) or filename . endswith ( '_unittest.cc' ):
1815+ if _IsTestFilename ( filename ):
18051816 return
18061817
18071818 fileinfo = FileInfo (filename )
1808- headerfile = filename [0 :len (filename ) - 2 ] + 'h'
1809- if not os .path .exists (headerfile ):
1810- return
1811- headername = FileInfo (headerfile ).RepositoryName ()
1812- first_include = 0
1813- for section_list in include_state .include_list :
1814- for f in section_list :
1815- if headername in f [0 ] or f [0 ] in headername :
1816- return
1817- if not first_include :
1818- first_include = f [1 ]
1819+ for ext in _header_extensions :
1820+ headerfile = filename [:filename .rfind ('.' ) + 1 ] + ext
1821+ if not os .path .exists (headerfile ):
1822+ continue
1823+ headername = FileInfo (headerfile ).RepositoryName ()
1824+ first_include = None
1825+ for section_list in include_state .include_list :
1826+ for f in section_list :
1827+ if headername in f [0 ] or f [0 ] in headername :
1828+ return
1829+ if not first_include :
1830+ first_include = f [1 ]
18191831
1820- error (filename , first_include , 'build/include' , 5 ,
1821- '%s should include its header file %s' % (fileinfo .RepositoryName (),
1822- headername ))
1832+ error (filename , first_include , 'build/include' , 5 ,
1833+ '%s should include its header file %s' % (fileinfo .RepositoryName (),
1834+ headername ))
18231835
18241836
18251837def CheckForBadCharacters (filename , lines , error ):
@@ -4460,7 +4472,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
44604472
44614473 # Check if the line is a header guard.
44624474 is_header_guard = False
4463- if file_extension == 'h' :
4475+ if file_extension in _header_extensions :
44644476 cppvar = GetHeaderGuardCPPVariable (filename )
44654477 if (line .startswith ('#ifndef %s' % cppvar ) or
44664478 line .startswith ('#define %s' % cppvar ) or
@@ -4553,8 +4565,11 @@ def _DropCommonSuffixes(filename):
45534565 Returns:
45544566 The filename with the common suffix removed.
45554567 """
4556- for suffix in ('test.cc' , 'regtest.cc' , 'unittest.cc' ,
4557- 'inl.h' , 'impl.h' , 'internal.h' ):
4568+ for suffix in itertools .chain (
4569+ ('%s.%s' % (test_suffix .lstrip ('_' ), ext )
4570+ for test_suffix , ext in itertools .product (_test_suffixes , _nonheader_extensions )),
4571+ ('%s.%s' % (suffix , ext )
4572+ for suffix , ext in itertools .product (['inl' , 'imp' , 'internal' ], _header_extensions ))):
45584573 if (filename .endswith (suffix ) and len (filename ) > len (suffix ) and
45594574 filename [- len (suffix ) - 1 ] in ('-' , '_' )):
45604575 return filename [:- len (suffix ) - 1 ]
@@ -4570,12 +4585,10 @@ def _IsTestFilename(filename):
45704585 Returns:
45714586 True if 'filename' looks like a test, False otherwise.
45724587 """
4573- if (filename .endswith ('_test.cc' ) or
4574- filename .endswith ('_unittest.cc' ) or
4575- filename .endswith ('_regtest.cc' )):
4576- return True
4577- else :
4578- return False
4588+ for test_suffix , ext in itertools .product (_test_suffixes , _nonheader_extensions ):
4589+ if filename .endswith (test_suffix + '.' + ext ):
4590+ return True
4591+ return False
45794592
45804593
45814594def _ClassifyInclude (fileinfo , include , is_system ):
@@ -4679,11 +4692,16 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
46794692 error (filename , linenum , 'build/include' , 4 ,
46804693 '"%s" already included at %s:%s' %
46814694 (include , filename , duplicate_line ))
4682- elif (include .endswith ('.cc' ) and
4695+ return
4696+
4697+ for extension in _nonheader_extensions :
4698+ if (include .endswith ('.' + extension ) and
46834699 os .path .dirname (fileinfo .RepositoryName ()) != os .path .dirname (include )):
4684- error (filename , linenum , 'build/include' , 4 ,
4685- 'Do not include .cc files from other packages' )
4686- elif not _THIRD_PARTY_HEADERS_PATTERN .match (include ):
4700+ error (filename , linenum , 'build/include' , 4 ,
4701+ 'Do not include .' + extension + ' files from other packages' )
4702+ return
4703+
4704+ if not _THIRD_PARTY_HEADERS_PATTERN .match (include ):
46874705 include_state .include_list [- 1 ].append ((include , linenum ))
46884706
46894707 # We want to ensure that headers appear in the right order:
@@ -4833,7 +4851,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
48334851 CheckGlobalStatic (filename , clean_lines , linenum , error )
48344852 CheckPrintf (filename , clean_lines , linenum , error )
48354853
4836- if file_extension == 'h' :
4854+ if file_extension in _header_extensions :
48374855 # TODO(unknown): check that 1-arg constructors are explicit.
48384856 # How to tell it's a constructor?
48394857 # (handled in CheckForNonStandardConstructs for now)
@@ -4940,7 +4958,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
49404958 # Check for use of unnamed namespaces in header files. Registration
49414959 # macros are typically OK, so we allow use of "namespace {" on lines
49424960 # that end with backslashes.
4943- if (file_extension == 'h'
4961+ if (file_extension in _header_extensions
49444962 and Search (r'\bnamespace\s*{' , line )
49454963 and line [- 1 ] != '\\ ' ):
49464964 error (filename , linenum , 'build/namespaces' , 4 ,
@@ -5573,28 +5591,32 @@ def FilesBelongToSameModule(filename_cc, filename_h):
55735591 some false positives. This should be sufficiently rare in practice.
55745592
55755593 Args:
5576- filename_cc: is the path for the .cc file
5594+ filename_cc: is the path for the source (e.g. .cc) file
55775595 filename_h: is the path for the header path
55785596
55795597 Returns:
55805598 Tuple with a bool and a string:
55815599 bool: True if filename_cc and filename_h belong to the same module.
55825600 string: the additional prefix needed to open the header file.
55835601 """
5602+ fileinfo_cc = FileInfo (filename_cc )
5603+ if not fileinfo_cc .Extension ().lstrip ('.' ) in _nonheader_extensions :
5604+ return (False , '' )
55845605
5585- if not filename_cc .endswith ('.cc' ):
5606+ fileinfo_h = FileInfo (filename_h )
5607+ if not fileinfo_h .Extension ().lstrip ('.' ) in _header_extensions :
55865608 return (False , '' )
5587- filename_cc = filename_cc [:- len ('.cc' )]
5588- if filename_cc .endswith ('_unittest' ):
5589- filename_cc = filename_cc [:- len ('_unittest' )]
5590- elif filename_cc .endswith ('_test' ):
5591- filename_cc = filename_cc [:- len ('_test' )]
5609+
5610+ filename_cc = filename_cc [:- (len (fileinfo_cc .Extension ()))]
5611+ for suffix in _test_suffixes :
5612+ if filename_cc .endswith (suffix ):
5613+ filename_cc = filename_cc [:- len (suffix )]
5614+ break
5615+
55925616 filename_cc = filename_cc .replace ('/public/' , '/' )
55935617 filename_cc = filename_cc .replace ('/internal/' , '/' )
55945618
5595- if not filename_h .endswith ('.h' ):
5596- return (False , '' )
5597- filename_h = filename_h [:- len ('.h' )]
5619+ filename_h = filename_h [:- (len (fileinfo_h .Extension ()))]
55985620 if filename_h .endswith ('-inl' ):
55995621 filename_h = filename_h [:- len ('-inl' )]
56005622 filename_h = filename_h .replace ('/public/' , '/' )
@@ -5716,8 +5738,10 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
57165738 # didn't include it in the .h file.
57175739 # TODO(unknown): Do a better job of finding .h files so we are confident that
57185740 # not having the .h file means there isn't one.
5719- if filename .endswith ('.cc' ) and not header_found :
5720- return
5741+ if not header_found :
5742+ for extension in _nonheader_extensions :
5743+ if filename .endswith ('.' + extension ):
5744+ return
57215745
57225746 # All the lines have been processed, report the errors found.
57235747 for required_header_unstripped in required :
@@ -6056,7 +6080,7 @@ def ProcessFileData(filename, file_extension, lines, error,
60566080 RemoveMultiLineComments (filename , lines , error )
60576081 clean_lines = CleansedLines (lines )
60586082
6059- if file_extension == 'h' :
6083+ if file_extension in _header_extensions :
60606084 CheckForHeaderGuard (filename , clean_lines , error )
60616085
60626086 for line in range (clean_lines .NumLines ()):
@@ -6069,7 +6093,7 @@ def ProcessFileData(filename, file_extension, lines, error,
60696093 CheckForIncludeWhatYouUse (filename , clean_lines , include_state , error )
60706094
60716095 # Check that the .cc file has included its header if it exists.
6072- if file_extension == 'cc' :
6096+ if file_extension in _nonheader_extensions :
60736097 CheckHeaderFileIncluded (filename , include_state , error )
60746098
60756099 # We check here rather than inside ProcessLine so that we see raw
0 commit comments