|
52 | 52 | import sys |
53 | 53 | import unicodedata |
54 | 54 |
|
| 55 | +# Files with any of these extensions are considered to be |
| 56 | +# header files (and will undergo different style checks). |
| 57 | +# This set can be extended by using the --headers |
| 58 | +# option (also supported in CPPLINT.cfg) |
| 59 | +_header_extensions = ['h', 'hpp', 'hxx', 'h++', 'cuh'] |
| 60 | + |
| 61 | + |
55 | 62 | # The allowed extensions for file names |
56 | 63 | # This is set by --extensions flag. |
57 | | -_valid_extensions = set(['c', 'cc', 'cpp', 'cxx', 'c++', 'h', 'hpp', 'hxx', |
58 | | - 'h++']) |
| 64 | +_valid_extensions = set(['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'] + _header_extensions) |
| 65 | + |
59 | 66 |
|
60 | 67 | _USAGE = """ |
61 | 68 | Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] |
62 | 69 | [--counting=total|toplevel|detailed] [--root=subdir] |
63 | 70 | [--linelength=digits] |
| 71 | + [--headers=ext1,ext2] |
64 | 72 | <file> [file] ... |
65 | 73 |
|
66 | 74 | The style guidelines this tries to follow are those in |
|
139 | 147 | Examples: |
140 | 148 | --extensions=hpp,cpp |
141 | 149 |
|
| 150 | + headers=extension,extension,... |
| 151 | + The allowed header extensions that cpplint will consider to be header files |
| 152 | + (by default, only .h files will be assumed to be headers) |
| 153 | +
|
| 154 | + Examples: |
| 155 | + --headers=h,hpp |
| 156 | +
|
142 | 157 | cpplint.py supports per-directory configurations specified in CPPLINT.cfg |
143 | 158 | files. CPPLINT.cfg file can contain a number of key=value pairs. |
144 | 159 | Currently the following options are supported: |
@@ -1804,21 +1819,22 @@ def CheckHeaderFileIncluded(filename, include_state, error): |
1804 | 1819 | return |
1805 | 1820 |
|
1806 | 1821 | 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] |
| 1822 | + for ext in _header_extensions: |
| 1823 | + headerfile = filename[0:len(filename) - 2] + ext |
| 1824 | + if not os.path.exists(headerfile): |
| 1825 | + continue |
| 1826 | + headername = FileInfo(headerfile).RepositoryName() |
| 1827 | + first_include = None |
| 1828 | + for section_list in include_state.include_list: |
| 1829 | + for f in section_list: |
| 1830 | + if headername in f[0] or f[0] in headername: |
| 1831 | + return |
| 1832 | + if not first_include: |
| 1833 | + first_include = f[1] |
1818 | 1834 |
|
1819 | | - error(filename, first_include, 'build/include', 5, |
1820 | | - '%s should include its header file %s' % (fileinfo.RepositoryName(), |
1821 | | - headername)) |
| 1835 | + error(filename, first_include, 'build/include', 5, |
| 1836 | + '%s should include its header file %s' % (fileinfo.RepositoryName(), |
| 1837 | + headername)) |
1822 | 1838 |
|
1823 | 1839 |
|
1824 | 1840 | def CheckForBadCharacters(filename, lines, error): |
@@ -4459,7 +4475,7 @@ def CheckStyle(filename, clean_lines, linenum, file_extension, nesting_state, |
4459 | 4475 |
|
4460 | 4476 | # Check if the line is a header guard. |
4461 | 4477 | is_header_guard = False |
4462 | | - if file_extension == 'h': |
| 4478 | + if file_extension in _header_extensions: |
4463 | 4479 | cppvar = GetHeaderGuardCPPVariable(filename) |
4464 | 4480 | if (line.startswith('#ifndef %s' % cppvar) or |
4465 | 4481 | line.startswith('#define %s' % cppvar) or |
@@ -4828,7 +4844,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, |
4828 | 4844 | CheckGlobalStatic(filename, clean_lines, linenum, error) |
4829 | 4845 | CheckPrintf(filename, clean_lines, linenum, error) |
4830 | 4846 |
|
4831 | | - if file_extension == 'h': |
| 4847 | + if file_extension in _header_extensions: |
4832 | 4848 | # TODO(unknown): check that 1-arg constructors are explicit. |
4833 | 4849 | # How to tell it's a constructor? |
4834 | 4850 | # (handled in CheckForNonStandardConstructs for now) |
@@ -4935,7 +4951,7 @@ def CheckLanguage(filename, clean_lines, linenum, file_extension, |
4935 | 4951 | # Check for use of unnamed namespaces in header files. Registration |
4936 | 4952 | # macros are typically OK, so we allow use of "namespace {" on lines |
4937 | 4953 | # that end with backslashes. |
4938 | | - if (file_extension == 'h' |
| 4954 | + if (file_extension in _header_extensions |
4939 | 4955 | and Search(r'\bnamespace\s*{', line) |
4940 | 4956 | and line[-1] != '\\'): |
4941 | 4957 | error(filename, linenum, 'build/namespaces', 4, |
@@ -6051,7 +6067,7 @@ def ProcessFileData(filename, file_extension, lines, error, |
6051 | 6067 | RemoveMultiLineComments(filename, lines, error) |
6052 | 6068 | clean_lines = CleansedLines(lines) |
6053 | 6069 |
|
6054 | | - if file_extension == 'h': |
| 6070 | + if file_extension in _header_extensions: |
6055 | 6071 | CheckForHeaderGuard(filename, clean_lines, error) |
6056 | 6072 |
|
6057 | 6073 | for line in range(clean_lines.NumLines()): |
@@ -6131,6 +6147,22 @@ def ProcessConfigOverrides(filename): |
6131 | 6147 | _line_length = int(val) |
6132 | 6148 | except ValueError: |
6133 | 6149 | sys.stderr.write('Line length must be numeric.') |
| 6150 | + elif name == 'extensions': |
| 6151 | + global _valid_extensions |
| 6152 | + try: |
| 6153 | + extensions = [ext.strip() for ext in val.split(',')] |
| 6154 | + _valid_extensions = _valid_extensions.union(set(extensions)) |
| 6155 | + except ValueError: |
| 6156 | + sys.stderr.write('Extensions should be a comma-separated list of values;' |
| 6157 | + 'for example: extensions=hpp,cpp\n' |
| 6158 | + 'This could not be parsed: "%s"' % (val,)) |
| 6159 | + try: |
| 6160 | + extensions = [ext.strip() for ext in val.split(',')] |
| 6161 | + _valid_extensions = _valid_extensions.union(set(extensions)) |
| 6162 | + except ValueError: |
| 6163 | + sys.stderr.write('Extensions should be a comma-separated list of values;' |
| 6164 | + 'for example: extensions=hpp,cpp\n' |
| 6165 | + 'This could not be parsed: "%s"' % (values,)) |
6134 | 6166 | else: |
6135 | 6167 | sys.stderr.write( |
6136 | 6168 | 'Invalid configuration option (%s) in file %s\n' % |
@@ -6277,7 +6309,8 @@ def ParseArguments(args): |
6277 | 6309 | 'filter=', |
6278 | 6310 | 'root=', |
6279 | 6311 | 'linelength=', |
6280 | | - 'extensions=']) |
| 6312 | + 'extensions=', |
| 6313 | + 'headers=']) |
6281 | 6314 | except getopt.GetoptError: |
6282 | 6315 | PrintUsage('Invalid arguments.') |
6283 | 6316 |
|
@@ -6318,6 +6351,12 @@ def ParseArguments(args): |
6318 | 6351 | _valid_extensions = set(val.split(',')) |
6319 | 6352 | except ValueError: |
6320 | 6353 | PrintUsage('Extensions must be comma seperated list.') |
| 6354 | + elif opt == '--headers': |
| 6355 | + global _header_extensions |
| 6356 | + try: |
| 6357 | + _header_extensions = set(val.split(',')) |
| 6358 | + except ValueError: |
| 6359 | + PrintUsage('Extensions must be comma seperated list.') |
6321 | 6360 |
|
6322 | 6361 | if not filenames: |
6323 | 6362 | PrintUsage('No files were specified.') |
|
0 commit comments