diff --git a/cpplint.py b/cpplint.py old mode 100644 new mode 100755 index 78c9860..dadd142 --- a/cpplint.py +++ b/cpplint.py @@ -5914,7 +5914,26 @@ def ExpectingFunctionArgs(clean_lines, linenum): ('', ('forward', 'make_pair', 'move', 'swap')), ) -_RE_PATTERN_STRING = re.compile(r'\bstring\b') +# Non templated types or global objects +_HEADERS_TYPES_OR_OBJS = ( + # String and others are special -- it is a non-templatized type in STL. + ('', ('string',)), + ('', ('cin', 'cout', 'cerr', 'clog', 'wcin', 'wcout', + 'wcerr', 'wclog')), + ('', ('FILE', 'fpos_t'))) + +# Non templated functions +_HEADERS_FUNCTIONS = ( + ('', ('fopen', 'freopen', + 'fclose', 'fflush', 'setbuf', 'setvbuf', 'fread', + 'fwrite', 'fgetc', 'getc', 'fgets', 'fputc', 'putc', + 'fputs', 'getchar', 'gets', 'putchar', 'puts', 'ungetc', + 'scanf', 'fscanf', 'sscanf', 'vscanf', 'vfscanf', + 'vsscanf', 'printf', 'fprintf', 'sprintf', 'snprintf', + 'vprintf', 'vfprintf', 'vsprintf', 'vsnprintf', + 'ftell', 'fgetpos', 'fseek', 'fsetpos', + 'clearerr', 'feof', 'ferror', 'perror', + 'tmpfile', 'tmpnam'),),) _re_pattern_headers_maybe_templates = [] for _header, _templates in _HEADERS_MAYBE_TEMPLATES: @@ -5945,6 +5964,23 @@ def ExpectingFunctionArgs(clean_lines, linenum): _template + '<>', _header)) +_re_pattern_types_or_objs = [] +for _header, _types_or_objs in _HEADERS_TYPES_OR_OBJS: + for _type_or_obj in _types_or_objs: + _re_pattern_types_or_objs.append( + (re.compile(r'\b' + _type_or_obj + r'\b'), + _type_or_obj, + _header)) + +_re_pattern_functions = [] +for _header, _functions in _HEADERS_FUNCTIONS: + for _function in _functions: + # Match printf(..., ...), but not foo->printf, foo.printf or + # 'type::printf()'. + _re_pattern_functions.append( + (re.compile(r'([^>.]|^)\b' + _function + r'\([^\)]'), + _function, + _header)) def FilesBelongToSameModule(filename_cc, filename_h): """Check if these two filenames belong to the same module. @@ -6004,34 +6040,6 @@ def FilesBelongToSameModule(filename_cc, filename_h): return files_belong_to_same_module, common_path -def UpdateIncludeState(filename, include_dict, io=codecs): - """Fill up the include_dict with new includes found from the file. - - Args: - filename: the name of the header to read. - include_dict: a dictionary 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 successfully added. False otherwise. - """ - headerfile = None - try: - with io.open(filename, 'r', 'utf8', 'replace') as headerfile: - 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) - include_dict.setdefault(include, linenum) - return True - except IOError: - return False - - - def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs): """Reports for missing stl includes. @@ -6058,14 +6066,17 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, 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[''] = (linenum, 'string') + _re_patterns = [] + _re_patterns.extend(_re_pattern_types_or_objs) + _re_patterns.extend(_re_pattern_functions) + for pattern, item, header in _re_patterns: + matched = pattern.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[header] = (linenum, item) for pattern, template, header in _re_pattern_headers_maybe_templates: if pattern.search(line): @@ -6084,46 +6095,10 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, if prefix.endswith('std::') or not prefix.endswith('::'): 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 flatten the include_state include_list and copy it into a dictionary. include_dict = dict([item for sublist in include_state.include_list for item in sublist]) - # Did we find the header for this file (if any) and successfully 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_dict is modified during iteration, so we iterate over a copy of - # the keys. - header_keys = list(include_dict.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_dict, 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 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 sorted(required, key=required.__getitem__): template = required[required_header_unstripped][1] diff --git a/cpplint_unittest.py b/cpplint_unittest.py index fc96e61..4bab1c9 100755 --- a/cpplint_unittest.py +++ b/cpplint_unittest.py @@ -571,6 +571,7 @@ def testErrorSuppression(self): error_collector = ErrorCollector(self.assertTrue) cpplint.ProcessFileData('test.cc', 'cc', ['// Copyright 2014 Your Company.', + '#include ', 'for (int i = 0; i != 100; ++i) {', ' std::cout << i << std::endl;', '}; // NOLINT', @@ -932,13 +933,11 @@ def testTypedefForPointerToFunction(self): def testIncludeWhatYouUseNoImplementationFiles(self): code = 'std::vector foo;' - for extension in ['h', 'hpp', 'hxx', 'h++', 'cuh']: - self.assertEqual('Add #include for vector<>' + for extension in ['h', 'hpp', 'hxx', 'h++', 'cuh', + 'c', 'cc', 'cpp', 'cxx', 'c++', 'cu']: + self.assertEquals('Add #include for vector<>' ' [build/include_what_you_use] [4]', self.PerformIncludeWhatYouUse(code, 'foo.' + extension)) - for extension in ['c', 'cc', 'cpp', 'cxx', 'c++', 'cu']: - self.assertEqual('', - self.PerformIncludeWhatYouUse(code, 'foo.' + extension)) def testIncludeWhatYouUse(self): self.TestIncludeWhatYouUse( @@ -1025,6 +1024,12 @@ def testIncludeWhatYouUse(self): bool foobar = min(0,1); """, 'Add #include for min [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + 'cout << "hello world" << endl;', + 'Add #include for cout [build/include_what_you_use] [4]') + self.TestIncludeWhatYouUse( + 'printf("hello world");', + 'Add #include for printf [build/include_what_you_use] [4]') self.TestIncludeWhatYouUse( 'void a(const string &foobar);', 'Add #include for string [build/include_what_you_use] [4]') @@ -1152,50 +1157,6 @@ def testIncludeWhatYouUse(self): """, '') - # Test the UpdateIncludeState code path. - mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"'] - message = self.PerformIncludeWhatYouUse( - '#include "blah/a.h"', - filename='blah/a.cc', - io=MockIo(mock_header_contents)) - self.assertEqual(message, '') - - mock_header_contents = ['#include '] - message = self.PerformIncludeWhatYouUse( - """#include "blah/a.h" - std::set foo;""", - filename='blah/a.cc', - io=MockIo(mock_header_contents)) - self.assertEqual(message, '') - - # Make sure we can find the correct header file if the cc file seems to be - # a temporary file generated by Emacs's flymake. - mock_header_contents = [''] - message = self.PerformIncludeWhatYouUse( - """#include "blah/a.h" - std::set foo;""", - filename='blah/a_flymake.cc', - io=MockIo(mock_header_contents)) - self.assertEqual(message, 'Add #include for set<> ' - '[build/include_what_you_use] [4]') - - # If there's just a cc and the header can't be found then it's ok. - message = self.PerformIncludeWhatYouUse( - """#include "blah/a.h" - std::set foo;""", - filename='blah/a.cc') - self.assertEqual(message, '') - - # Make sure we find the headers with relative paths. - mock_header_contents = [''] - message = self.PerformIncludeWhatYouUse( - """#include "%s/a.h" - std::set foo;""" % os.path.basename(os.getcwd()), - filename='a.cc', - io=MockIo(mock_header_contents)) - self.assertEqual(message, 'Add #include for set<> ' - '[build/include_what_you_use] [4]') - def testFilesBelongToSameModule(self): f = cpplint.FilesBelongToSameModule self.assertEqual((True, ''), f('a.cc', 'a.h')) @@ -2452,6 +2413,8 @@ def testNonConstReference(self): cpplint.ProcessFileData( 'foo.cc', 'cc', ['// Copyright 2014 Your Company. All Rights Reserved.', + '#include ', + '#include ', 'void swap(int &x,', ' int &y) {', '}', @@ -3084,6 +3047,7 @@ def testStaticOrGlobalSTLStrings(self): error_collector = ErrorCollector(self.assertTrue) cpplint.ProcessFileData('foo.cc', 'cc', ['// Copyright 2014 Your Company.', + '#include ', 'string Class', '::MemberFunction1();', 'string Class::', @@ -5025,6 +4989,7 @@ def testBuildPrintfFormat(self): cpplint.ProcessFileData( 'foo.cc', 'cc', ['// Copyright 2014 Your Company.', + '#include ', r'printf("\\%%%d", value);', r'printf(R"(\[)");', r'printf(R"(\[%s)", R"(\])");', diff --git a/samples/chromium-sample/simple.def b/samples/chromium-sample/simple.def index d1c4a68..6d0351d 100644 --- a/samples/chromium-sample/simple.def +++ b/samples/chromium-sample/simple.def @@ -5,11 +5,15 @@ Done processing src/chrome_content_renderer_client.cc Done processing src/chrome_content_renderer_client.h Done processing src/io_thread.cc Done processing src/io_thread.h -Total errors found: 13 +Total errors found: 21 src/chrome_content_renderer_client.cc:113: Include the directory when naming header files [build/include_subdir] [4] src/chrome_content_renderer_client.cc:1156: Use int16/int64/etc, rather than the C type long [runtime/int] [4] src/chrome_content_renderer_client.cc:1161: Use int16/int64/etc, rather than the C type long [runtime/int] [4] +src/chrome_content_renderer_client.cc:1203: Add #include for set<> [build/include_what_you_use] [4] +src/chrome_content_renderer_client.cc:1245: Add #include for vector<> [build/include_what_you_use] [4] +src/chrome_content_renderer_client.cc:1359: Add #include for map<> [build/include_what_you_use] [4] +src/chrome_content_renderer_client.cc:1366: Add #include for string [build/include_what_you_use] [4] 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] 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] 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] @@ -17,6 +21,10 @@ src/chrome_content_renderer_client.h:115: Use int16/int64/etc, rather than the src/chrome_content_renderer_client.h:117: Use int16/int64/etc, rather than the C type long [runtime/int] [4] src/io_thread.cc:1148: Closing ) should be moved to the previous line [whitespace/parens] [2] src/io_thread.cc:1547: Missing space around colon in range-based for loop [whitespace/forcolon] [2] +src/io_thread.cc:651: Add #include for map<> [build/include_what_you_use] [4] +src/io_thread.cc:1546: Add #include for unordered_set<> [build/include_what_you_use] [4] +src/io_thread.cc:1609: Add #include for string [build/include_what_you_use] [4] +src/io_thread.cc:1731: Add #include for unique_ptr<> [build/include_what_you_use] [4] 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] src/io_thread.h:5: #ifndef header guard has wrong style, please use: SAMPLES_CHROMIUM_SAMPLE_SRC_IO_THREAD_H_ [build/header_guard] [5] src/io_thread.h:565: #endif line should be "#endif // SAMPLES_CHROMIUM_SAMPLE_SRC_IO_THREAD_H_" [build/header_guard] [5] diff --git a/samples/codelite-sample/simple.def b/samples/codelite-sample/simple.def index 4e45c6b..88c9bf0 100644 --- a/samples/codelite-sample/simple.def +++ b/samples/codelite-sample/simple.def @@ -3,7 +3,7 @@ src/* 4 Done processing src/pptable.cpp Done processing src/pptable.h -Total errors found: 681 +Total errors found: 685 src/pptable.cpp:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] 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] src/pptable.cpp:661: Tab found; better to use spaces [whitespace/tab] [1] src/pptable.cpp:662: Tab found; better to use spaces [whitespace/tab] [1] src/pptable.cpp:663: Tab found; better to use spaces [whitespace/tab] [1] +src/pptable.cpp:526: Add #include for map<> [build/include_what_you_use] [4] +src/pptable.cpp:592: Add #include for vector<> [build/include_what_you_use] [4] +src/pptable.cpp:602: Add #include for sprintf [build/include_what_you_use] [4] +src/pptable.cpp:648: Add #include for string [build/include_what_you_use] [4] src/pptable.h:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] src/pptable.h:1: #ifndef header guard has wrong style, please use: SAMPLES_CODELITE_SAMPLE_SRC_PPTABLE_H_ [build/header_guard] [5] src/pptable.h:131: #endif line should be "#endif // SAMPLES_CODELITE_SAMPLE_SRC_PPTABLE_H_" [build/header_guard] [5] diff --git a/samples/protobuf-sample/simple.def b/samples/protobuf-sample/simple.def index 6135da6..393995b 100644 --- a/samples/protobuf-sample/simple.def +++ b/samples/protobuf-sample/simple.def @@ -4,7 +4,7 @@ src/* Done processing src/descriptor.pb.cc Done processing src/descriptor.pb.h Done processing src/descriptor_unittest.cc -Total errors found: 2643 +Total errors found: 2646 src/descriptor.pb.cc:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] 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/ src/descriptor.pb.cc:15146: Lines should be <= 80 characters long [whitespace/line_length] [2] src/descriptor.pb.cc:15150: Lines should be <= 80 characters long [whitespace/line_length] [2] src/descriptor.pb.cc:15155: Lines should be <= 80 characters long [whitespace/line_length] [2] +src/descriptor.pb.cc:14981: Add #include for swap [build/include_what_you_use] [4] +src/descriptor.pb.cc:15069: Add #include for string [build/include_what_you_use] [4] 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] src/descriptor.pb.h:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] 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 src/descriptor_unittest.cc:5929: Single-parameter constructors should be marked explicit. [runtime/explicit] [5] src/descriptor_unittest.cc:5968: Single-parameter constructors should be marked explicit. [runtime/explicit] [5] src/descriptor_unittest.cc:6486: Redundant blank line at the end of a code block should be deleted. [whitespace/blank_line] [3] +src/descriptor_unittest.cc:6437: Add #include for string [build/include_what_you_use] [4] diff --git a/samples/silly-sample/includeorder_cfirst.def b/samples/silly-sample/includeorder_cfirst.def index 05e8e66..f0e5ada 100644 --- a/samples/silly-sample/includeorder_cfirst.def +++ b/samples/silly-sample/includeorder_cfirst.def @@ -2,7 +2,7 @@ 1 3 Done processing src/sillycode.cpp -Total errors found: 106 +Total errors found: 111 src/sillycode.cpp:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] 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] src/sillycode.cpp:257: At least two spaces is best between code and comments [whitespace/comments] [2] src/sillycode.cpp:260: Empty loop bodies should use {} or continue [whitespace/empty_loop_body] [5] src/sillycode.cpp:260: At least two spaces is best between code and comments [whitespace/comments] [2] +src/sillycode.cpp:126: Add #include for swap [build/include_what_you_use] [4] +src/sillycode.cpp:168: Add #include for unique_ptr<> [build/include_what_you_use] [4] +src/sillycode.cpp:224: Add #include for numeric_limits<> [build/include_what_you_use] [4] +src/sillycode.cpp:237: Add #include for string [build/include_what_you_use] [4] +src/sillycode.cpp:244: Add #include for cout [build/include_what_you_use] [4] diff --git a/samples/silly-sample/sed.def b/samples/silly-sample/sed.def index 7a0ff19..47c910d 100644 --- a/samples/silly-sample/sed.def +++ b/samples/silly-sample/sed.def @@ -109,4 +109,9 @@ sed -i '208s/\([^ ]\){/\1 {/' src/sillycode.cpp # Missing space before { [white # src/sillycode.cpp:257: "At least two spaces is best between code and comments" [whitespace/comments] [2] # src/sillycode.cpp:260: "Empty loop bodies should use {} or continue" [whitespace/empty_loop_body] [5] # src/sillycode.cpp:260: "At least two spaces is best between code and comments" [whitespace/comments] [2] +# src/sillycode.cpp:126: "Add #include for swap" [build/include_what_you_use] [4] +# src/sillycode.cpp:168: "Add #include for unique_ptr<>" [build/include_what_you_use] [4] +# src/sillycode.cpp:224: "Add #include for numeric_limits<>" [build/include_what_you_use] [4] +# src/sillycode.cpp:237: "Add #include for string" [build/include_what_you_use] [4] +# src/sillycode.cpp:244: "Add #include for cout" [build/include_what_you_use] [4] diff --git a/samples/silly-sample/simple.def b/samples/silly-sample/simple.def index 5b11478..0e4b5a1 100644 --- a/samples/silly-sample/simple.def +++ b/samples/silly-sample/simple.def @@ -2,7 +2,7 @@ src/*.cpp 1 3 Done processing src/sillycode.cpp -Total errors found: 107 +Total errors found: 112 src/sillycode.cpp:0: No copyright message found. You should have a line: "Copyright [year] " [legal/copyright] [5] src/sillycode.cpp:3: Found C system header after C++ system header. Should be: sillycode.h, c system, c++ system, other. [build/include_order] [4] @@ -111,4 +111,9 @@ src/sillycode.cpp:257: Tab found; better to use spaces [whitespace/tab] [1] src/sillycode.cpp:257: At least two spaces is best between code and comments [whitespace/comments] [2] src/sillycode.cpp:260: Empty loop bodies should use {} or continue [whitespace/empty_loop_body] [5] src/sillycode.cpp:260: At least two spaces is best between code and comments [whitespace/comments] [2] +src/sillycode.cpp:126: Add #include for swap [build/include_what_you_use] [4] +src/sillycode.cpp:168: Add #include for unique_ptr<> [build/include_what_you_use] [4] +src/sillycode.cpp:224: Add #include for numeric_limits<> [build/include_what_you_use] [4] +src/sillycode.cpp:237: Add #include for string [build/include_what_you_use] [4] +src/sillycode.cpp:244: Add #include for cout [build/include_what_you_use] [4] diff --git a/samples/vlc-sample/simple.def b/samples/vlc-sample/simple.def index 174819e..19c9563 100644 --- a/samples/vlc-sample/simple.def +++ b/samples/vlc-sample/simple.def @@ -4,7 +4,7 @@ src/* Done processing src/libvlc.c Done processing src/libvlc.h Done processing src/missing.c -Total errors found: 601 +Total errors found: 602 src/libvlc.c:41: Found C system header after other header. Should be: libvlc.h, c system, c++ system, other. [build/include_order] [4] src/libvlc.c:47: Found C system header after other header. Should be: libvlc.h, c system, c++ system, other. [build/include_order] [4] @@ -367,6 +367,7 @@ src/libvlc.c:627: Missing space before ( in if( [whitespace/parens] [5] src/libvlc.c:629: Extra space after ( in function call [whitespace/parens] [4] src/libvlc.c:629: Extra space before ) [whitespace/parens] [2] src/libvlc.c:640: { should almost always be at the end of the previous line [whitespace/braces] [4] +src/libvlc.c:223: Add #include for fclose [build/include_what_you_use] [4] src/libvlc.h:0: No #ifndef header guard found, suggested CPP variable is: SAMPLES_VLC_SAMPLE_SRC_LIBVLC_H_ [build/header_guard] [5] src/libvlc.h:34: Extra space before ( in function call [whitespace/parens] [4] src/libvlc.h:35: Extra space before ( in function call [whitespace/parens] [4]