Skip to content

Commit e93e8fc

Browse files
authored
Add IWYU support for more stuff (#94 from geoffviola/printing)
2 parents d67ae99 + e3482c5 commit e93e8fc

File tree

9 files changed

+99
-128
lines changed

9 files changed

+99
-128
lines changed

cpplint.py

100644100755
Lines changed: 48 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -5914,7 +5914,26 @@ def ExpectingFunctionArgs(clean_lines, linenum):
59145914
('<utility>', ('forward', 'make_pair', 'move', 'swap')),
59155915
)
59165916

5917-
_RE_PATTERN_STRING = re.compile(r'\bstring\b')
5917+
# Non templated types or global objects
5918+
_HEADERS_TYPES_OR_OBJS = (
5919+
# String and others are special -- it is a non-templatized type in STL.
5920+
('<string>', ('string',)),
5921+
('<iostream>', ('cin', 'cout', 'cerr', 'clog', 'wcin', 'wcout',
5922+
'wcerr', 'wclog')),
5923+
('<cstdio>', ('FILE', 'fpos_t')))
5924+
5925+
# Non templated functions
5926+
_HEADERS_FUNCTIONS = (
5927+
('<cstdio>', ('fopen', 'freopen',
5928+
'fclose', 'fflush', 'setbuf', 'setvbuf', 'fread',
5929+
'fwrite', 'fgetc', 'getc', 'fgets', 'fputc', 'putc',
5930+
'fputs', 'getchar', 'gets', 'putchar', 'puts', 'ungetc',
5931+
'scanf', 'fscanf', 'sscanf', 'vscanf', 'vfscanf',
5932+
'vsscanf', 'printf', 'fprintf', 'sprintf', 'snprintf',
5933+
'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf',
5934+
'ftell', 'fgetpos', 'fseek', 'fsetpos',
5935+
'clearerr', 'feof', 'ferror', 'perror',
5936+
'tmpfile', 'tmpnam'),),)
59185937

59195938
_re_pattern_headers_maybe_templates = []
59205939
for _header, _templates in _HEADERS_MAYBE_TEMPLATES:
@@ -5945,6 +5964,23 @@ def ExpectingFunctionArgs(clean_lines, linenum):
59455964
_template + '<>',
59465965
_header))
59475966

5967+
_re_pattern_types_or_objs = []
5968+
for _header, _types_or_objs in _HEADERS_TYPES_OR_OBJS:
5969+
for _type_or_obj in _types_or_objs:
5970+
_re_pattern_types_or_objs.append(
5971+
(re.compile(r'\b' + _type_or_obj + r'\b'),
5972+
_type_or_obj,
5973+
_header))
5974+
5975+
_re_pattern_functions = []
5976+
for _header, _functions in _HEADERS_FUNCTIONS:
5977+
for _function in _functions:
5978+
# Match printf(..., ...), but not foo->printf, foo.printf or
5979+
# 'type::printf()'.
5980+
_re_pattern_functions.append(
5981+
(re.compile(r'([^>.]|^)\b' + _function + r'\([^\)]'),
5982+
_function,
5983+
_header))
59485984

59495985
def FilesBelongToSameModule(filename_cc, filename_h):
59505986
"""Check if these two filenames belong to the same module.
@@ -6004,34 +6040,6 @@ def FilesBelongToSameModule(filename_cc, filename_h):
60046040
return files_belong_to_same_module, common_path
60056041

60066042

6007-
def UpdateIncludeState(filename, include_dict, io=codecs):
6008-
"""Fill up the include_dict with new includes found from the file.
6009-
6010-
Args:
6011-
filename: the name of the header to read.
6012-
include_dict: a dictionary in which the headers are inserted.
6013-
io: The io factory to use to read the file. Provided for testability.
6014-
6015-
Returns:
6016-
True if a header was successfully added. False otherwise.
6017-
"""
6018-
headerfile = None
6019-
try:
6020-
with io.open(filename, 'r', 'utf8', 'replace') as headerfile:
6021-
linenum = 0
6022-
for line in headerfile:
6023-
linenum += 1
6024-
clean_line = CleanseComments(line)
6025-
match = _RE_PATTERN_INCLUDE.search(clean_line)
6026-
if match:
6027-
include = match.group(2)
6028-
include_dict.setdefault(include, linenum)
6029-
return True
6030-
except IOError:
6031-
return False
6032-
6033-
6034-
60356043
def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
60366044
io=codecs):
60376045
"""Reports for missing stl includes.
@@ -6058,14 +6066,17 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
60586066
if not line or line[0] == '#':
60596067
continue
60606068

6061-
# String is special -- it is a non-templatized type in STL.
6062-
matched = _RE_PATTERN_STRING.search(line)
6063-
if matched:
6064-
# Don't warn about strings in non-STL namespaces:
6065-
# (We check only the first match per line; good enough.)
6066-
prefix = line[:matched.start()]
6067-
if prefix.endswith('std::') or not prefix.endswith('::'):
6068-
required['<string>'] = (linenum, 'string')
6069+
_re_patterns = []
6070+
_re_patterns.extend(_re_pattern_types_or_objs)
6071+
_re_patterns.extend(_re_pattern_functions)
6072+
for pattern, item, header in _re_patterns:
6073+
matched = pattern.search(line)
6074+
if matched:
6075+
# Don't warn about strings in non-STL namespaces:
6076+
# (We check only the first match per line; good enough.)
6077+
prefix = line[:matched.start()]
6078+
if prefix.endswith('std::') or not prefix.endswith('::'):
6079+
required[header] = (linenum, item)
60696080

60706081
for pattern, template, header in _re_pattern_headers_maybe_templates:
60716082
if pattern.search(line):
@@ -6084,46 +6095,10 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error,
60846095
if prefix.endswith('std::') or not prefix.endswith('::'):
60856096
required[header] = (linenum, template)
60866097

6087-
# The policy is that if you #include something in foo.h you don't need to
6088-
# include it again in foo.cc. Here, we will look at possible includes.
60896098
# Let's flatten the include_state include_list and copy it into a dictionary.
60906099
include_dict = dict([item for sublist in include_state.include_list
60916100
for item in sublist])
60926101

6093-
# Did we find the header for this file (if any) and successfully load it?
6094-
header_found = False
6095-
6096-
# Use the absolute path so that matching works properly.
6097-
abs_filename = FileInfo(filename).FullName()
6098-
6099-
# For Emacs's flymake.
6100-
# If cpplint is invoked from Emacs's flymake, a temporary file is generated
6101-
# by flymake and that file name might end with '_flymake.cc'. In that case,
6102-
# restore original file name here so that the corresponding header file can be
6103-
# found.
6104-
# e.g. If the file name is 'foo_flymake.cc', we should search for 'foo.h'
6105-
# instead of 'foo_flymake.h'
6106-
abs_filename = re.sub(r'_flymake\.cc$', '.cc', abs_filename)
6107-
6108-
# include_dict is modified during iteration, so we iterate over a copy of
6109-
# the keys.
6110-
header_keys = list(include_dict.keys())
6111-
for header in header_keys:
6112-
(same_module, common_path) = FilesBelongToSameModule(abs_filename, header)
6113-
fullpath = common_path + header
6114-
if same_module and UpdateIncludeState(fullpath, include_dict, io):
6115-
header_found = True
6116-
6117-
# If we can't find the header file for a .cc, assume it's because we don't
6118-
# know where to look. In that case we'll give up as we're not sure they
6119-
# didn't include it in the .h file.
6120-
# TODO(unknown): Do a better job of finding .h files so we are confident that
6121-
# not having the .h file means there isn't one.
6122-
if not header_found:
6123-
for extension in GetNonHeaderExtensions():
6124-
if filename.endswith('.' + extension):
6125-
return
6126-
61276102
# All the lines have been processed, report the errors found.
61286103
for required_header_unstripped in sorted(required, key=required.__getitem__):
61296104
template = required[required_header_unstripped][1]

cpplint_unittest.py

Lines changed: 14 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -571,6 +571,7 @@ def testErrorSuppression(self):
571571
error_collector = ErrorCollector(self.assertTrue)
572572
cpplint.ProcessFileData('test.cc', 'cc',
573573
['// Copyright 2014 Your Company.',
574+
'#include <iostream>',
574575
'for (int i = 0; i != 100; ++i) {',
575576
' std::cout << i << std::endl;',
576577
'}; // NOLINT',
@@ -932,13 +933,11 @@ def testTypedefForPointerToFunction(self):
932933

933934
def testIncludeWhatYouUseNoImplementationFiles(self):
934935
code = 'std::vector<int> foo;'
935-
for extension in ['h', 'hpp', 'hxx', 'h++', 'cuh']:
936-
self.assertEqual('Add #include <vector> for vector<>'
936+
for extension in ['h', 'hpp', 'hxx', 'h++', 'cuh',
937+
'c', 'cc', 'cpp', 'cxx', 'c++', 'cu']:
938+
self.assertEquals('Add #include <vector> for vector<>'
937939
' [build/include_what_you_use] [4]',
938940
self.PerformIncludeWhatYouUse(code, 'foo.' + extension))
939-
for extension in ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu']:
940-
self.assertEqual('',
941-
self.PerformIncludeWhatYouUse(code, 'foo.' + extension))
942941

943942
def testIncludeWhatYouUse(self):
944943
self.TestIncludeWhatYouUse(
@@ -1025,6 +1024,12 @@ def testIncludeWhatYouUse(self):
10251024
bool foobar = min<int>(0,1);
10261025
""",
10271026
'Add #include <algorithm> for min [build/include_what_you_use] [4]')
1027+
self.TestIncludeWhatYouUse(
1028+
'cout << "hello world" << endl;',
1029+
'Add #include <iostream> for cout [build/include_what_you_use] [4]')
1030+
self.TestIncludeWhatYouUse(
1031+
'printf("hello world");',
1032+
'Add #include <cstdio> for printf [build/include_what_you_use] [4]')
10281033
self.TestIncludeWhatYouUse(
10291034
'void a(const string &foobar);',
10301035
'Add #include <string> for string [build/include_what_you_use] [4]')
@@ -1152,50 +1157,6 @@ def testIncludeWhatYouUse(self):
11521157
""",
11531158
'')
11541159

1155-
# Test the UpdateIncludeState code path.
1156-
mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"']
1157-
message = self.PerformIncludeWhatYouUse(
1158-
'#include "blah/a.h"',
1159-
filename='blah/a.cc',
1160-
io=MockIo(mock_header_contents))
1161-
self.assertEqual(message, '')
1162-
1163-
mock_header_contents = ['#include <set>']
1164-
message = self.PerformIncludeWhatYouUse(
1165-
"""#include "blah/a.h"
1166-
std::set<int> foo;""",
1167-
filename='blah/a.cc',
1168-
io=MockIo(mock_header_contents))
1169-
self.assertEqual(message, '')
1170-
1171-
# Make sure we can find the correct header file if the cc file seems to be
1172-
# a temporary file generated by Emacs's flymake.
1173-
mock_header_contents = ['']
1174-
message = self.PerformIncludeWhatYouUse(
1175-
"""#include "blah/a.h"
1176-
std::set<int> foo;""",
1177-
filename='blah/a_flymake.cc',
1178-
io=MockIo(mock_header_contents))
1179-
self.assertEqual(message, 'Add #include <set> for set<> '
1180-
'[build/include_what_you_use] [4]')
1181-
1182-
# If there's just a cc and the header can't be found then it's ok.
1183-
message = self.PerformIncludeWhatYouUse(
1184-
"""#include "blah/a.h"
1185-
std::set<int> foo;""",
1186-
filename='blah/a.cc')
1187-
self.assertEqual(message, '')
1188-
1189-
# Make sure we find the headers with relative paths.
1190-
mock_header_contents = ['']
1191-
message = self.PerformIncludeWhatYouUse(
1192-
"""#include "%s/a.h"
1193-
std::set<int> foo;""" % os.path.basename(os.getcwd()),
1194-
filename='a.cc',
1195-
io=MockIo(mock_header_contents))
1196-
self.assertEqual(message, 'Add #include <set> for set<> '
1197-
'[build/include_what_you_use] [4]')
1198-
11991160
def testFilesBelongToSameModule(self):
12001161
f = cpplint.FilesBelongToSameModule
12011162
self.assertEqual((True, ''), f('a.cc', 'a.h'))
@@ -2452,6 +2413,8 @@ def testNonConstReference(self):
24522413
cpplint.ProcessFileData(
24532414
'foo.cc', 'cc',
24542415
['// Copyright 2014 Your Company. All Rights Reserved.',
2416+
'#include <string>',
2417+
'#include <utility>',
24552418
'void swap(int &x,',
24562419
' int &y) {',
24572420
'}',
@@ -3084,6 +3047,7 @@ def testStaticOrGlobalSTLStrings(self):
30843047
error_collector = ErrorCollector(self.assertTrue)
30853048
cpplint.ProcessFileData('foo.cc', 'cc',
30863049
['// Copyright 2014 Your Company.',
3050+
'#include <string>',
30873051
'string Class',
30883052
'::MemberFunction1();',
30893053
'string Class::',
@@ -5025,6 +4989,7 @@ def testBuildPrintfFormat(self):
50254989
cpplint.ProcessFileData(
50264990
'foo.cc', 'cc',
50274991
['// Copyright 2014 Your Company.',
4992+
'#include <cstdio>',
50284993
r'printf("\\%%%d", value);',
50294994
r'printf(R"(\[)");',
50304995
r'printf(R"(\[%s)", R"(\])");',

samples/chromium-sample/simple.def

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,26 @@ Done processing src/chrome_content_renderer_client.cc
55
Done processing src/chrome_content_renderer_client.h
66
Done processing src/io_thread.cc
77
Done processing src/io_thread.h
8-
Total errors found: 13
8+
Total errors found: 21
99

1010
src/chrome_content_renderer_client.cc:113: Include the directory when naming header files [build/include_subdir] [4]
1111
src/chrome_content_renderer_client.cc:1156: Use int16/int64/etc, rather than the C type long [runtime/int] [4]
1212
src/chrome_content_renderer_client.cc:1161: Use int16/int64/etc, rather than the C type long [runtime/int] [4]
13+
src/chrome_content_renderer_client.cc:1203: Add #include <set> for set<> [build/include_what_you_use] [4]
14+
src/chrome_content_renderer_client.cc:1245: Add #include <vector> for vector<> [build/include_what_you_use] [4]
15+
src/chrome_content_renderer_client.cc:1359: Add #include <map> for map<> [build/include_what_you_use] [4]
16+
src/chrome_content_renderer_client.cc:1366: Add #include <string> for string [build/include_what_you_use] [4]
1317
src/chrome_content_renderer_client.cc:5: samples/chromium-sample/src/chrome_content_renderer_client.cc should include its header file samples/chromium-sample/src/chrome_content_renderer_client.h [build/include] [5]
1418
src/chrome_content_renderer_client.h:5: #ifndef header guard has wrong style, please use: SAMPLES_CHROMIUM_SAMPLE_SRC_CHROME_CONTENT_RENDERER_CLIENT_H_ [build/header_guard] [5]
1519
src/chrome_content_renderer_client.h:225: #endif line should be "#endif // SAMPLES_CHROMIUM_SAMPLE_SRC_CHROME_CONTENT_RENDERER_CLIENT_H_" [build/header_guard] [5]
1620
src/chrome_content_renderer_client.h:115: Use int16/int64/etc, rather than the C type long [runtime/int] [4]
1721
src/chrome_content_renderer_client.h:117: Use int16/int64/etc, rather than the C type long [runtime/int] [4]
1822
src/io_thread.cc:1148: Closing ) should be moved to the previous line [whitespace/parens] [2]
1923
src/io_thread.cc:1547: Missing space around colon in range-based for loop [whitespace/forcolon] [2]
24+
src/io_thread.cc:651: Add #include <map> for map<> [build/include_what_you_use] [4]
25+
src/io_thread.cc:1546: Add #include <unordered_set> for unordered_set<> [build/include_what_you_use] [4]
26+
src/io_thread.cc:1609: Add #include <string> for string [build/include_what_you_use] [4]
27+
src/io_thread.cc:1731: Add #include <memory> for unique_ptr<> [build/include_what_you_use] [4]
2028
src/io_thread.cc:5: samples/chromium-sample/src/io_thread.cc should include its header file samples/chromium-sample/src/io_thread.h [build/include] [5]
2129
src/io_thread.h:5: #ifndef header guard has wrong style, please use: SAMPLES_CHROMIUM_SAMPLE_SRC_IO_THREAD_H_ [build/header_guard] [5]
2230
src/io_thread.h:565: #endif line should be "#endif // SAMPLES_CHROMIUM_SAMPLE_SRC_IO_THREAD_H_" [build/header_guard] [5]

samples/codelite-sample/simple.def

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ src/*
33
4
44
Done processing src/pptable.cpp
55
Done processing src/pptable.h
6-
Total errors found: 681
6+
Total errors found: 685
77

88
src/pptable.cpp:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
99
src/pptable.cpp:1: Include the directory when naming header files [build/include_subdir] [4]
@@ -605,6 +605,10 @@ src/pptable.cpp:660: Tab found; better to use spaces [whitespace/tab] [1]
605605
src/pptable.cpp:661: Tab found; better to use spaces [whitespace/tab] [1]
606606
src/pptable.cpp:662: Tab found; better to use spaces [whitespace/tab] [1]
607607
src/pptable.cpp:663: Tab found; better to use spaces [whitespace/tab] [1]
608+
src/pptable.cpp:526: Add #include <map> for map<> [build/include_what_you_use] [4]
609+
src/pptable.cpp:592: Add #include <vector> for vector<> [build/include_what_you_use] [4]
610+
src/pptable.cpp:602: Add #include <cstdio> for sprintf [build/include_what_you_use] [4]
611+
src/pptable.cpp:648: Add #include <string> for string [build/include_what_you_use] [4]
608612
src/pptable.h:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
609613
src/pptable.h:1: #ifndef header guard has wrong style, please use: SAMPLES_CODELITE_SAMPLE_SRC_PPTABLE_H_ [build/header_guard] [5]
610614
src/pptable.h:131: #endif line should be "#endif // SAMPLES_CODELITE_SAMPLE_SRC_PPTABLE_H_" [build/header_guard] [5]

samples/protobuf-sample/simple.def

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ src/*
44
Done processing src/descriptor.pb.cc
55
Done processing src/descriptor.pb.h
66
Done processing src/descriptor_unittest.cc
7-
Total errors found: 2643
7+
Total errors found: 2646
88

99
src/descriptor.pb.cc:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
1010
src/descriptor.pb.cc:9: Found C system header after C++ system header. Should be: descriptor.pb.h, c system, c++ system, other. [build/include_order] [4]
@@ -1626,6 +1626,8 @@ src/descriptor.pb.cc:15142: Lines should be <= 80 characters long [whitespace/
16261626
src/descriptor.pb.cc:15146: Lines should be <= 80 characters long [whitespace/line_length] [2]
16271627
src/descriptor.pb.cc:15150: Lines should be <= 80 characters long [whitespace/line_length] [2]
16281628
src/descriptor.pb.cc:15155: Lines should be <= 80 characters long [whitespace/line_length] [2]
1629+
src/descriptor.pb.cc:14981: Add #include <utility> for swap [build/include_what_you_use] [4]
1630+
src/descriptor.pb.cc:15069: Add #include <string> for string [build/include_what_you_use] [4]
16291631
src/descriptor.pb.cc:5: samples/protobuf-sample/src/descriptor.pb.cc should include its header file samples/protobuf-sample/src/descriptor.pb.h [build/include] [5]
16301632
src/descriptor.pb.h:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
16311633
src/descriptor.pb.h:4: #ifndef header guard has wrong style, please use: SAMPLES_PROTOBUF_SAMPLE_SRC_DESCRIPTOR_PB_H_ [build/header_guard] [5]
@@ -2649,4 +2651,5 @@ src/descriptor_unittest.cc:5125: Closing ) should be moved to the previous line
26492651
src/descriptor_unittest.cc:5929: Single-parameter constructors should be marked explicit. [runtime/explicit] [5]
26502652
src/descriptor_unittest.cc:5968: Single-parameter constructors should be marked explicit. [runtime/explicit] [5]
26512653
src/descriptor_unittest.cc:6486: Redundant blank line at the end of a code block should be deleted. [whitespace/blank_line] [3]
2654+
src/descriptor_unittest.cc:6437: Add #include <string> for string [build/include_what_you_use] [4]
26522655

samples/silly-sample/includeorder_cfirst.def

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
1
33
3
44
Done processing src/sillycode.cpp
5-
Total errors found: 106
5+
Total errors found: 111
66

77
src/sillycode.cpp:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
88
src/sillycode.cpp:8: public: should be indented +1 space inside class Date [whitespace/indent] [3]
@@ -110,4 +110,9 @@ src/sillycode.cpp:257: Tab found; better to use spaces [whitespace/tab] [1]
110110
src/sillycode.cpp:257: At least two spaces is best between code and comments [whitespace/comments] [2]
111111
src/sillycode.cpp:260: Empty loop bodies should use {} or continue [whitespace/empty_loop_body] [5]
112112
src/sillycode.cpp:260: At least two spaces is best between code and comments [whitespace/comments] [2]
113+
src/sillycode.cpp:126: Add #include <utility> for swap [build/include_what_you_use] [4]
114+
src/sillycode.cpp:168: Add #include <memory> for unique_ptr<> [build/include_what_you_use] [4]
115+
src/sillycode.cpp:224: Add #include <limits> for numeric_limits<> [build/include_what_you_use] [4]
116+
src/sillycode.cpp:237: Add #include <string> for string [build/include_what_you_use] [4]
117+
src/sillycode.cpp:244: Add #include <iostream> for cout [build/include_what_you_use] [4]
113118

samples/silly-sample/sed.def

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,4 +109,9 @@ sed -i '208s/\([^ ]\){/\1 {/' src/sillycode.cpp # Missing space before { [white
109109
# src/sillycode.cpp:257: "At least two spaces is best between code and comments" [whitespace/comments] [2]
110110
# src/sillycode.cpp:260: "Empty loop bodies should use {} or continue" [whitespace/empty_loop_body] [5]
111111
# src/sillycode.cpp:260: "At least two spaces is best between code and comments" [whitespace/comments] [2]
112+
# src/sillycode.cpp:126: "Add #include <utility> for swap" [build/include_what_you_use] [4]
113+
# src/sillycode.cpp:168: "Add #include <memory> for unique_ptr<>" [build/include_what_you_use] [4]
114+
# src/sillycode.cpp:224: "Add #include <limits> for numeric_limits<>" [build/include_what_you_use] [4]
115+
# src/sillycode.cpp:237: "Add #include <string> for string" [build/include_what_you_use] [4]
116+
# src/sillycode.cpp:244: "Add #include <iostream> for cout" [build/include_what_you_use] [4]
112117

0 commit comments

Comments
 (0)