mirror of
https://github.com/neovim/neovim.git
synced 2024-12-19 18:55:14 -07:00
remove CheckForIncludeWhatYouUse
Only checks C++ related headers
This commit is contained in:
parent
cfa070edc5
commit
38eaa7ed32
235
clint.py
235
clint.py
@ -4241,241 +4241,6 @@ def CheckCStyleCast(filename, linenum, line, raw_line, cast_type, pattern,
|
||||
return True
|
||||
|
||||
|
||||
_HEADERS_CONTAINING_TEMPLATES = (
|
||||
('<deque>', ('deque',)),
|
||||
('<functional>', ('unary_function', 'binary_function',
|
||||
'plus', 'minus', 'multiplies', 'divides', 'modulus',
|
||||
'negate',
|
||||
'equal_to', 'not_equal_to', 'greater', 'less',
|
||||
'greater_equal', 'less_equal',
|
||||
'logical_and', 'logical_or', 'logical_not',
|
||||
'unary_negate', 'not1', 'binary_negate', 'not2',
|
||||
'bind1st', 'bind2nd',
|
||||
'pointer_to_unary_function',
|
||||
'pointer_to_binary_function',
|
||||
'ptr_fun',
|
||||
'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
|
||||
'mem_fun_ref_t',
|
||||
'const_mem_fun_t', 'const_mem_fun1_t',
|
||||
'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
|
||||
'mem_fun_ref',
|
||||
)),
|
||||
('<limits>', ('numeric_limits',)),
|
||||
('<list>', ('list',)),
|
||||
('<map>', ('map', 'multimap',)),
|
||||
('<memory>', ('allocator',)),
|
||||
('<queue>', ('queue', 'priority_queue',)),
|
||||
('<set>', ('set', 'multiset',)),
|
||||
('<stack>', ('stack',)),
|
||||
('<string>', ('char_traits', 'basic_string',)),
|
||||
('<utility>', ('pair',)),
|
||||
('<vector>', ('vector',)),
|
||||
|
||||
# gcc extensions.
|
||||
# Note: std::hash is their hash, ::hash is our hash
|
||||
('<hash_map>', ('hash_map', 'hash_multimap',)),
|
||||
('<hash_set>', ('hash_set', 'hash_multiset',)),
|
||||
('<slist>', ('slist',)),
|
||||
)
|
||||
|
||||
_RE_PATTERN_STRING = re.compile(r'\bstring\b')
|
||||
|
||||
_re_pattern_algorithm_header = []
|
||||
for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
|
||||
'transform'):
|
||||
# Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
|
||||
# type::max().
|
||||
_re_pattern_algorithm_header.append(
|
||||
(re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
|
||||
_template,
|
||||
'<algorithm>'))
|
||||
|
||||
_re_pattern_templates = []
|
||||
for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
|
||||
for _template in _templates:
|
||||
_re_pattern_templates.append(
|
||||
(re.compile(r'(\<|\b)' + _template + r'\s*\<'),
|
||||
_template + '<>',
|
||||
_header))
|
||||
|
||||
|
||||
def FilesBelongToSameModule(filename_cc, filename_h):
|
||||
"""Check if these two filenames belong to the same module.
|
||||
|
||||
The concept of a 'module' here is a as follows:
|
||||
foo.h, foo-inl.h, foo.cc, foo_test.cc and foo_unittest.cc belong to the
|
||||
same 'module' if they are in the same directory.
|
||||
some/path/public/xyzzy and some/path/internal/xyzzy are also considered
|
||||
to belong to the same module here.
|
||||
|
||||
If the filename_cc contains a longer path than the filename_h, for example,
|
||||
'/absolute/path/to/base/sysinfo.cc', and this file would include
|
||||
'base/sysinfo.h', this function also produces the prefix needed to open the
|
||||
header. This is used by the caller of this function to more robustly open the
|
||||
header file. We don't have access to the real include paths in this context,
|
||||
so we need this guesswork here.
|
||||
|
||||
Known bugs: tools/base/bar.cc and base/bar.h belong to the same module
|
||||
according to this implementation. Because of this, this function gives
|
||||
some false positives. This should be sufficiently rare in practice.
|
||||
|
||||
Args:
|
||||
filename_cc: is the path for the .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.
|
||||
"""
|
||||
|
||||
if not filename_cc.endswith('.cc'):
|
||||
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.replace('/public/', '/')
|
||||
filename_cc = filename_cc.replace('/internal/', '/')
|
||||
|
||||
if not filename_h.endswith('.h'):
|
||||
return (False, '')
|
||||
filename_h = filename_h[:-len('.h')]
|
||||
if filename_h.endswith('-inl'):
|
||||
filename_h = filename_h[:-len('-inl')]
|
||||
filename_h = filename_h.replace('/public/', '/')
|
||||
filename_h = filename_h.replace('/internal/', '/')
|
||||
|
||||
files_belong_to_same_module = filename_cc.endswith(filename_h)
|
||||
common_path = ''
|
||||
if files_belong_to_same_module:
|
||||
common_path = filename_cc[:-len(filename_h)]
|
||||
return files_belong_to_same_module, common_path
|
||||
|
||||
|
||||
def UpdateIncludeState(filename, include_state, io=codecs):
|
||||
"""Fill up the include_state with new includes found from the file.
|
||||
|
||||
Args:
|
||||
filename: the name of the header to read.
|
||||
include_state: an _IncludeState instance in which the headers are inserted.
|
||||
io: The io factory to use to read the file. Provided for testability.
|
||||
|
||||
Returns:
|
||||
True if a header was succesfully added. False otherwise.
|
||||
"""
|
||||
headerfile = None
|
||||
try:
|
||||
headerfile = io.open(filename, 'r', 'utf8', 'replace')
|
||||
except IOError:
|
||||
return False
|
||||
linenum = 0
|
||||
for line in headerfile:
|
||||
linenum += 1
|
||||
clean_line = CleanseComments(line)
|
||||
match = _RE_PATTERN_INCLUDE.search(clean_line)
|
||||
if match:
|
||||
include = match.group(2)
|
||||
# The value formatting is cute, but not really used right now.
|
||||
# What matters here is that the key is in include_state.
|
||||
include_state.setdefault(include, '%s:%d' % (filename, linenum))
|
||||
return True
|
||||
|
||||
|
||||
def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
|
||||
io=codecs):
|
||||
"""Reports for missing stl includes.
|
||||
|
||||
This function will output warnings to make sure you are including the headers
|
||||
necessary for the stl containers and functions that you use. We only give one
|
||||
reason to include a header. For example, if you use both equal_to<> and
|
||||
less<> in a .h file, only one (the latter in the file) of these will be
|
||||
reported as a reason to include the <functional>.
|
||||
|
||||
Args:
|
||||
filename: The name of the current file.
|
||||
clean_lines: A CleansedLines instance containing the file.
|
||||
include_state: An _IncludeState instance.
|
||||
error: The function to call with any errors found.
|
||||
io: The IO factory to use to read the header file. Provided for unittest
|
||||
injection.
|
||||
"""
|
||||
required = {} # A map of header name to linenumber and the template entity.
|
||||
# Example of required: { '<functional>': (1219, 'less<>') }
|
||||
|
||||
for linenum in range(clean_lines.NumLines()):
|
||||
line = clean_lines.elided[linenum]
|
||||
if not line or line[0] == '#':
|
||||
continue
|
||||
|
||||
# String is special -- it is a non-templatized type in STL.
|
||||
matched = _RE_PATTERN_STRING.search(line)
|
||||
if matched:
|
||||
# Don't warn about strings in non-STL namespaces:
|
||||
# (We check only the first match per line; good enough.)
|
||||
prefix = line[:matched.start()]
|
||||
if prefix.endswith('std::') or not prefix.endswith('::'):
|
||||
required['<string>'] = (linenum, 'string')
|
||||
|
||||
for pattern, template, header in _re_pattern_algorithm_header:
|
||||
if pattern.search(line):
|
||||
required[header] = (linenum, template)
|
||||
|
||||
# The following function is just a speed up, no semantics are changed.
|
||||
if not '<' in line: # Reduces the cpu time usage by skipping lines.
|
||||
continue
|
||||
|
||||
for pattern, template, header in _re_pattern_templates:
|
||||
if pattern.search(line):
|
||||
required[header] = (linenum, template)
|
||||
|
||||
# The policy is that if you #include something in foo.h you don't need to
|
||||
# include it again in foo.cc. Here, we will look at possible includes.
|
||||
# Let's copy the include_state so it is only messed up within this function.
|
||||
include_state = include_state.copy()
|
||||
|
||||
# Did we find the header for this file (if any) and succesfully load it?
|
||||
header_found = False
|
||||
|
||||
# Use the absolute path so that matching works properly.
|
||||
abs_filename = FileInfo(filename).FullName()
|
||||
|
||||
# For Emacs's flymake.
|
||||
# If cpplint is invoked from Emacs's flymake, a temporary file is generated
|
||||
# by flymake and that file name might end with '_flymake.cc'. In that case,
|
||||
# restore original file name here so that the corresponding header file can be
|
||||
# found.
|
||||
# e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
|
||||
# instead of 'foo_flymake.h'
|
||||
abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
|
||||
|
||||
# include_state is modified during iteration, so we iterate over a copy of
|
||||
# the keys.
|
||||
header_keys = list(include_state.keys())
|
||||
for header in header_keys:
|
||||
(same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
|
||||
fullpath = common_path + header
|
||||
if same_module and UpdateIncludeState(fullpath, include_state, io):
|
||||
header_found = True
|
||||
|
||||
# If we can't find the header file for a .cc, assume it's because we don't
|
||||
# know where to look. In that case we'll give up as we're not sure they
|
||||
# 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
|
||||
|
||||
# All the lines have been processed, report the errors found.
|
||||
for required_header_unstripped in required:
|
||||
template = required[required_header_unstripped][1]
|
||||
if required_header_unstripped.strip('<>"') not in include_state:
|
||||
error(filename, required[required_header_unstripped][0],
|
||||
'build/include_what_you_use', 4,
|
||||
'Add #include ' + required_header_unstripped + ' for ' + template)
|
||||
|
||||
|
||||
def ProcessLine(filename, file_extension, clean_lines, line,
|
||||
include_state, function_state, nesting_state, error,
|
||||
extra_check_functions=[]):
|
||||
|
Loading…
Reference in New Issue
Block a user