-
Notifications
You must be signed in to change notification settings - Fork 312
fix(iwyu): suggest C headers instead of C++ ones for C files #456
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -916,6 +916,45 @@ | |||||
| r"vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))" | ||||||
| ) | ||||||
|
|
||||||
| # Maps the C++ C-library headers to their C equivalents so that, for C files, | ||||||
| # build/include_what_you_use suggests the C header (e.g. <stdio.h> rather than | ||||||
| # <cstdio>). See https://github.com/cpplint/cpplint/issues/399. | ||||||
|
Member
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.
Suggested change
|
||||||
| _C_LIBRARY_CPP_HEADERS = { | ||||||
| "<cassert>": "<assert.h>", | ||||||
| "<cctype>": "<ctype.h>", | ||||||
| "<cerrno>": "<errno.h>", | ||||||
| "<cfenv>": "<fenv.h>", | ||||||
| "<cfloat>": "<float.h>", | ||||||
| "<cinttypes>": "<inttypes.h>", | ||||||
| "<climits>": "<limits.h>", | ||||||
| "<clocale>": "<locale.h>", | ||||||
| "<cmath>": "<math.h>", | ||||||
| "<csetjmp>": "<setjmp.h>", | ||||||
| "<csignal>": "<signal.h>", | ||||||
| "<cstdarg>": "<stdarg.h>", | ||||||
| "<cstddef>": "<stddef.h>", | ||||||
| "<cstdint>": "<stdint.h>", | ||||||
| "<cstdio>": "<stdio.h>", | ||||||
| "<cstdlib>": "<stdlib.h>", | ||||||
| "<cstring>": "<string.h>", | ||||||
| "<ctime>": "<time.h>", | ||||||
| "<cuchar>": "<uchar.h>", | ||||||
| "<cwchar>": "<wchar.h>", | ||||||
| "<cwctype>": "<wctype.h>", | ||||||
| } | ||||||
|
|
||||||
|
|
||||||
| def _IsCFile(filename: str, lines: list[str]) -> bool: | ||||||
| """Whether the file is a C file: a .c/.cu extension or a LINT_C_FILE marker. | ||||||
|
|
||||||
| Single source of truth shared by the C-specific error suppression and the | ||||||
| C-vs-C++ header suggestion, so the two never drift. See #399. | ||||||
| """ | ||||||
| return filename.lower().endswith((".c", ".cu")) or any( | ||||||
| _SEARCH_C_FILE.search(line) for line in lines | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
| # Match string that indicates we're working on a Linux Kernel file. | ||||||
| _SEARCH_KERNEL_FILE = re.compile(r"\b(?:LINT_KERNEL_FILE)") | ||||||
|
|
||||||
|
|
@@ -1206,10 +1245,10 @@ def ProcessGlobalSuppressions(filename: str, lines: list[str]) -> None: | |||||
| last element being empty if the file is terminated with a newline. | ||||||
| filename: str, the name of the input file. | ||||||
| """ | ||||||
| if _IsCFile(filename, lines): | ||||||
| for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: | ||||||
| _error_suppressions.AddGlobalSuppression(category) | ||||||
| for line in lines: | ||||||
| if _SEARCH_C_FILE.search(line) or filename.lower().endswith((".c", ".cu")): | ||||||
| for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: | ||||||
| _error_suppressions.AddGlobalSuppression(category) | ||||||
| if _SEARCH_KERNEL_FILE.search(line): | ||||||
| for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: | ||||||
| _error_suppressions.AddGlobalSuppression(category) | ||||||
|
|
@@ -7119,7 +7158,9 @@ def FilesBelongToSameModule(filename_cc, filename_h): | |||||
| return files_belong_to_same_module, common_path | ||||||
|
|
||||||
|
|
||||||
| def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs): | ||||||
| def CheckForIncludeWhatYouUse( | ||||||
| filename, clean_lines, include_state, error, io=codecs, is_c_file=False | ||||||
| ): | ||||||
| """Reports for missing stl includes. | ||||||
|
|
||||||
| This function will output warnings to make sure you are including the headers | ||||||
|
|
@@ -7183,12 +7224,19 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=co | |||||
| if header_stripped not in include_dict and not ( | ||||||
| header_stripped[0] == "c" and (header_stripped[1:] + ".h") in include_dict | ||||||
| ): | ||||||
| # For C files, suggest the C header (e.g. <stdio.h>) rather than | ||||||
| # the C++ one (e.g. <cstdio>). See #399. | ||||||
|
Member
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.
Suggested change
|
||||||
| suggested = ( | ||||||
| _C_LIBRARY_CPP_HEADERS[header] | ||||||
| if is_c_file and header in _C_LIBRARY_CPP_HEADERS | ||||||
| else header | ||||||
| ) | ||||||
| error( | ||||||
| filename, | ||||||
| required[header][0], | ||||||
| "build/include_what_you_use", | ||||||
| 4, | ||||||
| "Add #include " + header + " for " + template, | ||||||
| "Add #include " + suggested + " for " + template, | ||||||
| ) | ||||||
|
|
||||||
|
|
||||||
|
|
@@ -7578,7 +7626,8 @@ def ProcessFileData(filename, file_extension, lines, error, extra_check_function | |||||
| "NONLINT block never ended", | ||||||
| ) | ||||||
|
|
||||||
| CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) | ||||||
| is_c_file = _IsCFile(filename, clean_lines.raw_lines) | ||||||
| CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, is_c_file=is_c_file) | ||||||
|
|
||||||
| # Check that the .cc file has included its header if it exists. | ||||||
| if _IsSourceExtension(file_extension): | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -223,7 +223,8 @@ def PerformIncludeWhatYouUse(self, code, filename="foo.h", io=codecs): | |||||||||
| error_collector = ErrorCollector(self.assertTrue) | ||||||||||
| include_state = cpplint._IncludeState() | ||||||||||
| nesting_state = cpplint.NestingState() | ||||||||||
| lines = code.split("\n") | ||||||||||
| raw_lines = code.split("\n") | ||||||||||
|
Member
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. What is the point of making a new variable here? |
||||||||||
| lines = raw_lines | ||||||||||
|
Comment on lines
+226
to
+227
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. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win Keep
Proposed fix raw_lines = code.split("\n")
-lines = raw_lines
+lines = raw_lines[:]📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||
| cpplint.RemoveMultiLineComments(filename, lines, error_collector) | ||||||||||
| lines = cpplint.CleansedLines(lines) | ||||||||||
| for i in range(lines.NumLines()): | ||||||||||
|
|
@@ -235,7 +236,10 @@ def PerformIncludeWhatYouUse(self, code, filename="foo.h", io=codecs): | |||||||||
| # have language problems. | ||||||||||
|
|
||||||||||
| # Second, look for missing includes. | ||||||||||
| cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state, error_collector, io) | ||||||||||
| is_c_file = cpplint._IsCFile(filename, raw_lines) | ||||||||||
|
Member
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. This means we still run this twice for each file, which was exactly what we were trying to avoid with the move to state. |
||||||||||
| cpplint.CheckForIncludeWhatYouUse( | ||||||||||
| filename, lines, include_state, error_collector, io, is_c_file=is_c_file | ||||||||||
| ) | ||||||||||
| return error_collector.Results() | ||||||||||
|
|
||||||||||
| # Perform lint and make sure one of the errors is what we want | ||||||||||
|
|
@@ -259,8 +263,8 @@ def TestMultiLineLintRE(self, code, expected_message_re): | |||||||||
| def TestLanguageRulesCheck(self, file_name, code, expected_message): | ||||||||||
| assert expected_message == self.PerformLanguageRulesCheck(file_name, code) | ||||||||||
|
|
||||||||||
| def TestIncludeWhatYouUse(self, code, expected_message): | ||||||||||
| assert expected_message == self.PerformIncludeWhatYouUse(code) | ||||||||||
| def TestIncludeWhatYouUse(self, code, expected_message, filename="foo.h"): | ||||||||||
| assert expected_message == self.PerformIncludeWhatYouUse(code, filename=filename) | ||||||||||
|
|
||||||||||
| def TestBlankLinesCheck(self, lines, start_errors, end_errors): | ||||||||||
| for extension in ["c", "cc", "cpp", "cxx", "c++", "cu"]: | ||||||||||
|
|
@@ -1290,6 +1294,26 @@ def testIncludeWhatYouUse(self): | |||||||||
| printf("hello world");""", | ||||||||||
| "", | ||||||||||
| ) # Avoid false positives w/ c-style include | ||||||||||
| # C files should be told to include the C header (e.g. <stdio.h>) rather | ||||||||||
| # than its C++ counterpart (e.g. <cstdio>). See #399. | ||||||||||
|
Member
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.
Suggested change
|
||||||||||
| self.TestIncludeWhatYouUse( | ||||||||||
| 'printf("hello world");', | ||||||||||
| "Add #include <stdio.h> for printf [build/include_what_you_use] [4]", | ||||||||||
| filename="foo.c", | ||||||||||
| ) | ||||||||||
| # C++ files are unaffected. | ||||||||||
| self.TestIncludeWhatYouUse( | ||||||||||
| 'printf("hello world");', | ||||||||||
| "Add #include <cstdio> for printf [build/include_what_you_use] [4]", | ||||||||||
| filename="foo.cpp", | ||||||||||
| ) | ||||||||||
| # The "C header already included" behaviour is preserved for C files. | ||||||||||
| self.TestIncludeWhatYouUse( | ||||||||||
| """#include <stdio.h> | ||||||||||
| printf("hello world");""", | ||||||||||
| "", | ||||||||||
| filename="foo.c", | ||||||||||
| ) | ||||||||||
|
aaronliu0130 marked this conversation as resolved.
Comment on lines
+1310
to
+1316
Member
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. This is already tested |
||||||||||
| self.TestIncludeWhatYouUse( | ||||||||||
| "void a(const string &foobar);", | ||||||||||
| "Add #include <string> for string [build/include_what_you_use] [4]", | ||||||||||
|
|
||||||||||
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.
https://github.com/cpplint/cpplint/compare/57db60e7ba2f234f856f7caacfff23f4595aafa6..6858cbead66f11a5d588358d7baaf45c836b10ac#diff-2c623f3c6a917be56c59d43279244996836262cb1e12d9d0786c9c49eef6b43c