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,...]
@@ -1073,7 +1084,7 @@ def BaseName(self):
10731084 return self .Split ()[1 ]
10741085
10751086 def Extension (self ):
1076- """File extension - text following the final period."""
1087+ """File extension - text following the final period, includes that period ."""
10771088 return self .Split ()[2 ]
10781089
10791090 def NoExtension (self ):
@@ -1797,28 +1808,29 @@ def CheckForHeaderGuard(filename, clean_lines, error):
17971808
17981809
17991810def CheckHeaderFileIncluded (filename , include_state , error ):
1800- """Logs an error if a .cc file does not include its header."""
1811+ """Logs an error if a source file does not include its header."""
18011812
18021813 # Do not check test files
1803- if filename . endswith ( '_test.cc' ) or filename . endswith ( '_unittest.cc' ):
1814+ if _IsTestFilename ( filename ):
18041815 return
18051816
18061817 fileinfo = FileInfo (filename )
1807- headerfile = filename [0 :len (filename ) - 2 ] + 'h'
1808- if not os .path .exists (headerfile ):
1809- return
1810- headername = FileInfo (headerfile ).RepositoryName ()
1811- first_include = 0
1812- for section_list in include_state .include_list :
1813- for f in section_list :
1814- if headername in f [0 ] or f [0 ] in headername :
1815- return
1816- if not first_include :
1817- first_include = f [1 ]
1818+ for ext in _header_extensions :
1819+ headerfile = filename [:filename .rfind ('.' ) + 1 ] + ext
1820+ if not os .path .exists (headerfile ):
1821+ continue
1822+ headername = FileInfo (headerfile ).RepositoryName ()
1823+ first_include = None
1824+ for section_list in include_state .include_list :
1825+ for f in section_list :
1826+ if headername in f [0 ] or f [0 ] in headername :
1827+ return
1828+ if not first_include :
1829+ first_include = f [1 ]
18181830
1819- error (filename , first_include , 'build/include' , 5 ,
1820- '%s should include its header file %s' % (fileinfo .RepositoryName (),
1821- headername ))
1831+ error (filename , first_include , 'build/include' , 5 ,
1832+ '%s should include its header file %s' % (fileinfo .RepositoryName (),
1833+ headername ))
18221834
18231835
18241836def CheckForBadCharacters (filename , lines , error ):
@@ -4459,7 +4471,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state,
44594471
44604472 # Check if the line is a header guard.
44614473 is_header_guard = False
4462- if file_extension == 'h' :
4474+ if file_extension in _header_extensions :
44634475 cppvar = GetHeaderGuardCPPVariable (filename )
44644476 if (line .startswith ('#ifndef %s' % cppvar ) or
44654477 line .startswith ('#define %s' % cppvar ) or
@@ -4548,8 +4560,11 @@ def _DropCommonSuffixes(filename):
45484560 Returns:
45494561 The filename with the common suffix removed.
45504562 """
4551- for suffix in ('test.cc' , 'regtest.cc' , 'unittest.cc' ,
4552- 'inl.h' , 'impl.h' , 'internal.h' ):
4563+ for suffix in itertools .chain (
4564+ ('%s.%s' % (test_suffix .lstrip ('_' ), ext )
4565+ for test_suffix , ext in itertools .product (_test_suffixes , _nonheader_extensions )),
4566+ ('%s.%s' % (suffix , ext )
4567+ for suffix , ext in itertools .product (['inl' , 'imp' , 'internal' ], _header_extensions ))):
45534568 if (filename .endswith (suffix ) and len (filename ) > len (suffix ) and
45544569 filename [- len (suffix ) - 1 ] in ('-' , '_' )):
45554570 return filename [:- len (suffix ) - 1 ]
@@ -4565,12 +4580,10 @@ def _IsTestFilename(filename):
45654580 Returns:
45664581 True if 'filename' looks like a test, False otherwise.
45674582 """
4568- if (filename .endswith ('_test.cc' ) or
4569- filename .endswith ('_unittest.cc' ) or
4570- filename .endswith ('_regtest.cc' )):
4571- return True
4572- else :
4573- return False
4583+ for test_suffix , ext in itertools .product (_test_suffixes , _nonheader_extensions ):
4584+ if filename .endswith (test_suffix + '.' + ext ):
4585+ return True
4586+ return False
45744587
45754588
45764589def _ClassifyInclude (fileinfo , include , is_system ):
@@ -4674,11 +4687,16 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error):
46744687 error (filename , linenum , 'build/include' , 4 ,
46754688 '"%s" already included at %s:%s' %
46764689 (include , filename , duplicate_line ))
4677- elif (include .endswith ('.cc' ) and
4690+ return
4691+
4692+ for extension in _nonheader_extensions :
4693+ if (include .endswith ('.' + extension ) and
46784694 os .path .dirname (fileinfo .RepositoryName ()) != os .path .dirname (include )):
4679- error (filename , linenum , 'build/include' , 4 ,
4680- 'Do not include .cc files from other packages' )
4681- elif not _THIRD_PARTY_HEADERS_PATTERN .match (include ):
4695+ error (filename , linenum , 'build/include' , 4 ,
4696+ 'Do not include .' + extension + ' files from other packages' )
4697+ return
4698+
4699+ if not _THIRD_PARTY_HEADERS_PATTERN .match (include ):
46824700 include_state .include_list [- 1 ].append ((include , linenum ))
46834701
46844702 # We want to ensure that headers appear in the right order:
@@ -4828,7 +4846,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
48284846 CheckGlobalStatic (filename , clean_lines , linenum , error )
48294847 CheckPrintf (filename , clean_lines , linenum , error )
48304848
4831- if file_extension == 'h' :
4849+ if file_extension in _header_extensions :
48324850 # TODO(unknown): check that 1-arg constructors are explicit.
48334851 # How to tell it's a constructor?
48344852 # (handled in CheckForNonStandardConstructs for now)
@@ -4935,7 +4953,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension,
49354953 # Check for use of unnamed namespaces in header files. Registration
49364954 # macros are typically OK, so we allow use of "namespace {" on lines
49374955 # that end with backslashes.
4938- if (file_extension == 'h'
4956+ if (file_extension in _header_extensions
49394957 and Search (r'\bnamespace\s*{' , line )
49404958 and line [- 1 ] != '\\ ' ):
49414959 error (filename , linenum , 'build/namespaces' , 4 ,
@@ -5568,28 +5586,32 @@ def FilesBelongToSameModule(filename_cc, filename_h):
55685586 some false positives. This should be sufficiently rare in practice.
55695587
55705588 Args:
5571- filename_cc: is the path for the .cc file
5589+ filename_cc: is the path for the source (e.g. .cc) file
55725590 filename_h: is the path for the header path
55735591
55745592 Returns:
55755593 Tuple with a bool and a string:
55765594 bool: True if filename_cc and filename_h belong to the same module.
55775595 string: the additional prefix needed to open the header file.
55785596 """
5597+ fileinfo_cc = FileInfo (filename_cc )
5598+ if not fileinfo_cc .Extension ().lstrip ('.' ) in _nonheader_extensions :
5599+ return (False , '' )
55795600
5580- if not filename_cc .endswith ('.cc' ):
5601+ fileinfo_h = FileInfo (filename_h )
5602+ if not fileinfo_h .Extension ().lstrip ('.' ) in _header_extensions :
55815603 return (False , '' )
5582- filename_cc = filename_cc [:- len ('.cc' )]
5583- if filename_cc .endswith ('_unittest' ):
5584- filename_cc = filename_cc [:- len ('_unittest' )]
5585- elif filename_cc .endswith ('_test' ):
5586- filename_cc = filename_cc [:- len ('_test' )]
5604+
5605+ filename_cc = filename_cc [:- (len (fileinfo_cc .Extension ()))]
5606+ for suffix in _test_suffixes :
5607+ if filename_cc .endswith (suffix ):
5608+ filename_cc = filename_cc [:- len (suffix )]
5609+ break
5610+
55875611 filename_cc = filename_cc .replace ('/public/' , '/' )
55885612 filename_cc = filename_cc .replace ('/internal/' , '/' )
55895613
5590- if not filename_h .endswith ('.h' ):
5591- return (False , '' )
5592- filename_h = filename_h [:- len ('.h' )]
5614+ filename_h = filename_h [:- (len (fileinfo_h .Extension ()))]
55935615 if filename_h .endswith ('-inl' ):
55945616 filename_h = filename_h [:- len ('-inl' )]
55955617 filename_h = filename_h .replace ('/public/' , '/' )
@@ -5711,8 +5733,10 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
57115733 # didn't include it in the .h file.
57125734 # TODO(unknown): Do a better job of finding .h files so we are confident that
57135735 # not having the .h file means there isn't one.
5714- if filename .endswith ('.cc' ) and not header_found :
5715- return
5736+ if not header_found :
5737+ for extension in _nonheader_extensions :
5738+ if filename .endswith ('.' + extension ):
5739+ return
57165740
57175741 # All the lines have been processed, report the errors found.
57185742 for required_header_unstripped in required :
@@ -6051,7 +6075,7 @@ def ProcessFileData(filename, file_extension, lines, error,
60516075 RemoveMultiLineComments (filename , lines , error )
60526076 clean_lines = CleansedLines (lines )
60536077
6054- if file_extension == 'h' :
6078+ if file_extension in _header_extensions :
60556079 CheckForHeaderGuard (filename , clean_lines , error )
60566080
60576081 for line in range (clean_lines .NumLines ()):
@@ -6064,7 +6088,7 @@ def ProcessFileData(filename, file_extension, lines, error,
60646088 CheckForIncludeWhatYouUse (filename , clean_lines , include_state , error )
60656089
60666090 # Check that the .cc file has included its header if it exists.
6067- if file_extension == 'cc' :
6091+ if file_extension in _nonheader_extensions :
60686092 CheckHeaderFileIncluded (filename , include_state , error )
60696093
60706094 # We check here rather than inside ProcessLine so that we see raw
0 commit comments