This repository was archived by the owner on Jul 13, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4
Fix extensions #22
Closed
Closed
Fix extensions #22
Changes from all commits
Commits
Show all changes
3 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -44,6 +44,7 @@ | |
| import codecs | ||
| import copy | ||
| import getopt | ||
| import itertools | ||
| import math # for log | ||
| import os | ||
| import re | ||
|
|
@@ -52,15 +53,42 @@ | |
| import sys | ||
| import unicodedata | ||
|
|
||
| # if empty, use defaults | ||
| _header_extensions = set([]) | ||
|
|
||
| # if empty, use defaults | ||
| _valid_extensions = set([]) | ||
|
|
||
|
|
||
| # 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) | ||
| def GetHeaderExtensions(): | ||
| if not _header_extensions: | ||
| return set(['h', 'hpp', 'hxx', 'h++', 'cuh']) | ||
| return _header_extensions | ||
|
|
||
| # The allowed extensions for file names | ||
| # This is set by --extensions flag. | ||
| _valid_extensions = set(['c', 'cc', 'cpp', 'cxx', 'c++', 'h', 'hpp', 'hxx', | ||
| 'h++']) | ||
| # This is set by --extensions flag | ||
| def GetAllExtensions(): | ||
| if not _valid_extensions: | ||
| return GetHeaderExtensions().union(set(['c', 'cc', 'cpp', 'cxx', 'c++', 'cu'])) | ||
| return _valid_extensions | ||
|
|
||
| def GetNonHeaderExtensions(): | ||
| return GetAllExtensions().difference(GetHeaderExtensions()) | ||
|
|
||
|
|
||
| # files with this suffix before the extension will be treated as test files | ||
| _test_suffixes = set(['_unittest', '_test', '_regtest']) | ||
|
|
||
| _USAGE = """ | ||
| Syntax: cpplint.py [--verbose=#] [--output=vs7] [--filter=-x,+y,...] | ||
| [--counting=total|toplevel|detailed] [--root=subdir] | ||
| [--linelength=digits] | ||
| [--headers=ext1,ext2] | ||
| [--extensions=ext1,ext2] | ||
| <file> [file] ... | ||
|
|
||
| The style guidelines this tries to follow are those in | ||
|
|
@@ -137,7 +165,15 @@ | |
| The allowed file extensions that cpplint will check | ||
|
|
||
| Examples: | ||
| --extensions=hpp,cpp | ||
| --extensions=%s | ||
|
|
||
| headers=extension,extension,... | ||
| The allowed header extensions that cpplint will consider to be header files | ||
| (by default, only files with extensions %s | ||
| will be assumed to be headers) | ||
|
|
||
| Examples: | ||
| --headers=%s | ||
|
|
||
| cpplint.py supports per-directory configurations specified in CPPLINT.cfg | ||
| files. CPPLINT.cfg file can contain a number of key=value pairs. | ||
|
|
@@ -173,7 +209,10 @@ | |
| 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. | ||
| """ % (list(_valid_extensions)) | ||
| """ % (list(GetAllExtensions()), | ||
| ','.join(list(GetAllExtensions())), | ||
| GetHeaderExtensions(), | ||
| ','.join(GetHeaderExtensions())) | ||
|
|
||
| # We categorize each error message we print. Here are the categories. | ||
| # We want an explicit list so we can list them all in cpplint --filter=. | ||
|
|
@@ -525,6 +564,7 @@ def u(x): | |
| itervalues = dict.values | ||
| iteritems = dict.items | ||
|
|
||
|
|
||
| def ParseNolintSuppressions(filename, raw_line, linenum, error): | ||
| """Updates the global list of error-suppressions. | ||
|
|
||
|
|
@@ -1074,7 +1114,7 @@ def BaseName(self): | |
| return self.Split()[1] | ||
|
|
||
| def Extension(self): | ||
| """File extension - text following the final period.""" | ||
| """File extension - text following the final period, includes that period.""" | ||
| return self.Split()[2] | ||
|
|
||
| def NoExtension(self): | ||
|
|
@@ -1083,7 +1123,7 @@ def NoExtension(self): | |
|
|
||
| def IsSource(self): | ||
| """File has a source file extension.""" | ||
| return self.Extension()[1:] in _valid_extensions | ||
| return self.Extension()[1:] in GetAllExtensions() | ||
|
|
||
|
|
||
| def _ShouldPrintError(category, confidence, linenum): | ||
|
|
@@ -1798,28 +1838,29 @@ def CheckForHeaderGuard(filename, clean_lines, error): | |
|
|
||
|
|
||
| def CheckHeaderFileIncluded(filename, include_state, error): | ||
| """Logs an error if a .cc file does not include its header.""" | ||
| """Logs an error if a source file does not include its header.""" | ||
|
|
||
| # Do not check test files | ||
| if filename.endswith('_test.cc') or filename.endswith('_unittest.cc'): | ||
| if _IsTestFilename(filename): | ||
| 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 GetHeaderExtensions(): | ||
| headerfile = filename[:filename.rfind('.') + 1] + 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): | ||
|
|
@@ -4460,7 +4501,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 GetHeaderExtensions(): | ||
| cppvar = GetHeaderGuardCPPVariable(filename) | ||
| if (line.startswith('#ifndef %s' % cppvar) or | ||
| line.startswith('#define %s' % cppvar) or | ||
|
|
@@ -4553,8 +4594,11 @@ def _DropCommonSuffixes(filename): | |
| Returns: | ||
| The filename with the common suffix removed. | ||
| """ | ||
| for suffix in ('test.cc', 'regtest.cc', 'unittest.cc', | ||
| 'inl.h', 'impl.h', 'internal.h'): | ||
| for suffix in itertools.chain( | ||
| ('%s.%s' % (test_suffix.lstrip('_'), ext) | ||
| for test_suffix, ext in itertools.product(_test_suffixes, GetNonHeaderExtensions())), | ||
| ('%s.%s' % (suffix, ext) | ||
| for suffix, ext in itertools.product(['inl', 'imp', 'internal'], GetHeaderExtensions()))): | ||
| if (filename.endswith(suffix) and len(filename) > len(suffix) and | ||
| filename[-len(suffix) - 1] in ('-', '_')): | ||
| return filename[:-len(suffix) - 1] | ||
|
|
@@ -4570,12 +4614,10 @@ def _IsTestFilename(filename): | |
| Returns: | ||
| True if 'filename' looks like a test, False otherwise. | ||
| """ | ||
| if (filename.endswith('_test.cc') or | ||
| filename.endswith('_unittest.cc') or | ||
| filename.endswith('_regtest.cc')): | ||
| return True | ||
| else: | ||
| return False | ||
| for test_suffix, ext in itertools.product(_test_suffixes, GetNonHeaderExtensions()): | ||
| if filename.endswith(test_suffix + '.' + ext): | ||
| return True | ||
| return False | ||
|
|
||
|
|
||
| def _ClassifyInclude(fileinfo, include, is_system): | ||
|
|
@@ -4679,11 +4721,16 @@ def CheckIncludeLine(filename, clean_lines, linenum, include_state, error): | |
| error(filename, linenum, 'build/include', 4, | ||
| '"%s" already included at %s:%s' % | ||
| (include, filename, duplicate_line)) | ||
| elif (include.endswith('.cc') and | ||
| return | ||
|
|
||
| for extension in GetNonHeaderExtensions(): | ||
| if (include.endswith('.' + extension) and | ||
| os.path.dirname(fileinfo.RepositoryName()) != os.path.dirname(include)): | ||
| error(filename, linenum, 'build/include', 4, | ||
| 'Do not include .cc files from other packages') | ||
| elif not _THIRD_PARTY_HEADERS_PATTERN.match(include): | ||
| error(filename, linenum, 'build/include', 4, | ||
| 'Do not include .' + extension + ' files from other packages') | ||
| return | ||
|
|
||
| if not _THIRD_PARTY_HEADERS_PATTERN.match(include): | ||
| include_state.include_list[-1].append((include, linenum)) | ||
|
|
||
| # We want to ensure that headers appear in the right order: | ||
|
|
@@ -4833,7 +4880,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 GetHeaderExtensions(): | ||
| # TODO(unknown): check that 1-arg constructors are explicit. | ||
| # How to tell it's a constructor? | ||
| # (handled in CheckForNonStandardConstructs for now) | ||
|
|
@@ -4940,7 +4987,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 GetHeaderExtensions() | ||
| and Search(r'\bnamespace\s*{', line) | ||
| and line[-1] != '\\'): | ||
| error(filename, linenum, 'build/namespaces', 4, | ||
|
|
@@ -5573,28 +5620,32 @@ def FilesBelongToSameModule(filename_cc, filename_h): | |
| some false positives. This should be sufficiently rare in practice. | ||
|
|
||
| Args: | ||
| filename_cc: is the path for the .cc file | ||
| filename_cc: is the path for the source (e.g. .cc) file | ||
| filename_h: is the path for the header path | ||
|
|
||
| Returns: | ||
| Tuple with a bool and a string: | ||
| bool: True if filename_cc and filename_h belong to the same module. | ||
| string: the additional prefix needed to open the header file. | ||
| """ | ||
| fileinfo_cc = FileInfo(filename_cc) | ||
| if not fileinfo_cc.Extension().lstrip('.') in GetNonHeaderExtensions(): | ||
| return (False, '') | ||
|
|
||
| if not filename_cc.endswith('.cc'): | ||
| fileinfo_h = FileInfo(filename_h) | ||
| if not fileinfo_h.Extension().lstrip('.') in GetHeaderExtensions(): | ||
| return (False, '') | ||
| filename_cc = filename_cc[:-len('.cc')] | ||
| if filename_cc.endswith('_unittest'): | ||
| filename_cc = filename_cc[:-len('_unittest')] | ||
| elif filename_cc.endswith('_test'): | ||
| filename_cc = filename_cc[:-len('_test')] | ||
|
|
||
| filename_cc = filename_cc[:-(len(fileinfo_cc.Extension()))] | ||
| for suffix in _test_suffixes: | ||
| if filename_cc.endswith(suffix): | ||
| filename_cc = filename_cc[:-len(suffix)] | ||
| break | ||
|
|
||
| filename_cc = filename_cc.replace('/public/', '/') | ||
| filename_cc = filename_cc.replace('/internal/', '/') | ||
|
|
||
| if not filename_h.endswith('.h'): | ||
| return (False, '') | ||
| filename_h = filename_h[:-len('.h')] | ||
| filename_h = filename_h[:-(len(fileinfo_h.Extension()))] | ||
| if filename_h.endswith('-inl'): | ||
| filename_h = filename_h[:-len('-inl')] | ||
| filename_h = filename_h.replace('/public/', '/') | ||
|
|
@@ -5716,8 +5767,10 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, | |
| # didn't include it in the .h file. | ||
| # TODO(unknown): Do a better job of finding .h files so we are confident that | ||
| # not having the .h file means there isn't one. | ||
| if filename.endswith('.cc') and not header_found: | ||
| return | ||
| if not header_found: | ||
| for extension in GetNonHeaderExtensions(): | ||
| if filename.endswith('.' + extension): | ||
| return | ||
|
|
||
| # All the lines have been processed, report the errors found. | ||
| for required_header_unstripped in required: | ||
|
|
@@ -6056,7 +6109,7 @@ def ProcessFileData(filename, file_extension, lines, error, | |
| RemoveMultiLineComments(filename, lines, error) | ||
| clean_lines = CleansedLines(lines) | ||
|
|
||
| if file_extension == 'h': | ||
| if file_extension in GetHeaderExtensions(): | ||
| CheckForHeaderGuard(filename, clean_lines, error) | ||
|
|
||
| for line in range(clean_lines.NumLines()): | ||
|
|
@@ -6069,7 +6122,7 @@ def ProcessFileData(filename, file_extension, lines, error, | |
| CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) | ||
|
|
||
| # Check that the .cc file has included its header if it exists. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. change also the comment accordingly |
||
| if file_extension == 'cc': | ||
| if file_extension in GetNonHeaderExtensions(): | ||
| CheckHeaderFileIncluded(filename, include_state, error) | ||
|
|
||
| # We check here rather than inside ProcessLine so that we see raw | ||
|
|
@@ -6136,6 +6189,24 @@ 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 = 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,)) | ||
| elif name == 'headers': | ||
| global _header_extensions | ||
| try: | ||
| extensions = [ext.strip() for ext in val.split(',')] | ||
| _header_extensions = 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,)) | ||
| else: | ||
| sys.stderr.write( | ||
| 'Invalid configuration option (%s) in file %s\n' % | ||
|
|
@@ -6213,9 +6284,9 @@ def ProcessFile(filename, vlevel, extra_check_functions=[]): | |
|
|
||
| # When reading from stdin, the extension is unknown, so no cpplint tests | ||
| # should rely on the extension. | ||
| if filename != '-' and file_extension not in _valid_extensions: | ||
| if filename != '-' and file_extension not in GetAllExtensions(): | ||
| sys.stderr.write('Ignoring %s; not a valid file name ' | ||
| '(%s)\n' % (filename, ', '.join(_valid_extensions))) | ||
| '(%s)\n' % (filename, ', '.join(GetAllExtensions()))) | ||
| else: | ||
| ProcessFileData(filename, file_extension, lines, Error, | ||
| extra_check_functions) | ||
|
|
@@ -6282,7 +6353,8 @@ def ParseArguments(args): | |
| 'filter=', | ||
| 'root=', | ||
| 'linelength=', | ||
| 'extensions=']) | ||
| 'extensions=', | ||
| 'headers=']) | ||
| except getopt.GetoptError: | ||
| PrintUsage('Invalid arguments.') | ||
|
|
||
|
|
@@ -6323,6 +6395,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.') | ||
|
|
||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this configurable using flags / CPPLINT.cfg?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so, that may be a nice additional feature, but maybe that would go well into #11