| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 96db7ae commit 6858cbe
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -7,6 +7,7 @@ TBA | |||
| 7 | 7 | ||
| 8 | 8 | * Fixed a whitespace/newline false positive for control conditions containing lambdas. (#410) | |
| 9 | 9 | * We now error on relative include paths (``./``, ``../``). (#432) | |
| 10 | + * For C files, build/include_what_you_use now suggests the C header (e.g. ``<stdio.h>``) instead of its C++ counterpart (e.g. ``<cstdio>``). (#399) | ||
| 10 | 11 | * This makes ``#include "./foo.h"`` produce two separate errors: that foo.cpp should include foo.h and that relative paths are not allowed. | |
| 11 | 12 | ||
| 12 | 13 | 2.0.2 (2025-04-08) | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -916,6 +916,45 @@ | |||
| 916 | 916 | r"vim?:\s*.*(\s*|:)filetype=c(\s*|:|$))" | |
| 917 | 917 | ) | |
| 918 | 918 | ||
| 919 | + # Maps the C++ C-library headers to their C equivalents so that, for C files, | ||
| 920 | + # build/include_what_you_use suggests the C header (e.g. <stdio.h> rather than | ||
| 921 | + # <cstdio>). See https://github.com/cpplint/cpplint/issues/399. | ||
| 922 | + _C_LIBRARY_CPP_HEADERS = { | ||
| 923 | + "<cassert>": "<assert.h>", | ||
| 924 | + "<cctype>": "<ctype.h>", | ||
| 925 | + "<cerrno>": "<errno.h>", | ||
| 926 | + "<cfenv>": "<fenv.h>", | ||
| 927 | + "<cfloat>": "<float.h>", | ||
| 928 | + "<cinttypes>": "<inttypes.h>", | ||
| 929 | + "<climits>": "<limits.h>", | ||
| 930 | + "<clocale>": "<locale.h>", | ||
| 931 | + "<cmath>": "<math.h>", | ||
| 932 | + "<csetjmp>": "<setjmp.h>", | ||
| 933 | + "<csignal>": "<signal.h>", | ||
| 934 | + "<cstdarg>": "<stdarg.h>", | ||
| 935 | + "<cstddef>": "<stddef.h>", | ||
| 936 | + "<cstdint>": "<stdint.h>", | ||
| 937 | + "<cstdio>": "<stdio.h>", | ||
| 938 | + "<cstdlib>": "<stdlib.h>", | ||
| 939 | + "<cstring>": "<string.h>", | ||
| 940 | + "<ctime>": "<time.h>", | ||
| 941 | + "<cuchar>": "<uchar.h>", | ||
| 942 | + "<cwchar>": "<wchar.h>", | ||
| 943 | + "<cwctype>": "<wctype.h>", | ||
| 944 | + } | ||
| 945 | + | ||
| 946 | + | ||
| 947 | + def _IsCFile(filename: str, lines: list[str]) -> bool: | ||
| 948 | + """Whether the file is a C file: a .c/.cu extension or a LINT_C_FILE marker. | ||
| 949 | + | ||
| 950 | + Single source of truth shared by the C-specific error suppression and the | ||
| 951 | + C-vs-C++ header suggestion, so the two never drift. See #399. | ||
| 952 | + """ | ||
| 953 | + return filename.lower().endswith((".c", ".cu")) or any( | ||
| 954 | + _SEARCH_C_FILE.search(line) for line in lines | ||
| 955 | + ) | ||
| 956 | + | ||
| 957 | + | ||
| 919 | 958 | # Match string that indicates we're working on a Linux Kernel file. | |
| 920 | 959 | _SEARCH_KERNEL_FILE = re.compile(r"\b(?:LINT_KERNEL_FILE)") | |
| 921 | 960 | ||
@@ -1206,10 +1245,10 @@ def ProcessGlobalSuppressions(filename: str, lines: list[str]) -> None: | |||
| 1206 | 1245 | last element being empty if the file is terminated with a newline. | |
| 1207 | 1246 | filename: str, the name of the input file. | |
| 1208 | 1247 | """ | |
| 1248 | + if _IsCFile(filename, lines): | ||
| 1249 | + for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: | ||
| 1250 | + _error_suppressions.AddGlobalSuppression(category) | ||
| 1209 | 1251 | for line in lines: | |
| 1210 | - if _SEARCH_C_FILE.search(line) or filename.lower().endswith((".c", ".cu")): | ||
| 1211 | - for category in _DEFAULT_C_SUPPRESSED_CATEGORIES: | ||
| 1212 | - _error_suppressions.AddGlobalSuppression(category) | ||
| 1213 | 1252 | if _SEARCH_KERNEL_FILE.search(line): | |
| 1214 | 1253 | for category in _DEFAULT_KERNEL_SUPPRESSED_CATEGORIES: | |
| 1215 | 1254 | _error_suppressions.AddGlobalSuppression(category) | |
@@ -7119,7 +7158,7 @@ def FilesBelongToSameModule(filename_cc, filename_h): | |||
| 7119 | 7158 | return files_belong_to_same_module, common_path | |
| 7120 | 7159 | ||
| 7121 | 7160 | ||
| 7122 | - def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs): | ||
| 7161 | + def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=codecs, is_c_file=False): | ||
| 7123 | 7162 | """Reports for missing stl includes. | |
| 7124 | 7163 | ||
| 7125 | 7164 | This function will output warnings to make sure you are including the headers | |
@@ -7183,12 +7222,19 @@ def CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error, io=co | |||
| 7183 | 7222 | if header_stripped not in include_dict and not ( | |
| 7184 | 7223 | header_stripped[0] == "c" and (header_stripped[1:] + ".h") in include_dict | |
| 7185 | 7224 | ): | |
| 7225 | + # For C files, suggest the C header (e.g. <stdio.h>) rather than | ||
| 7226 | + # the C++ one (e.g. <cstdio>). See #399. | ||
| 7227 | + suggested = ( | ||
| 7228 | + _C_LIBRARY_CPP_HEADERS[header] | ||
| 7229 | + if is_c_file and header in _C_LIBRARY_CPP_HEADERS | ||
| 7230 | + else header | ||
| 7231 | + ) | ||
| 7186 | 7232 | error( | |
| 7187 | 7233 | filename, | |
| 7188 | 7234 | required[header][0], | |
| 7189 | 7235 | "build/include_what_you_use", | |
| 7190 | 7236 | 4, | |
| 7191 | - "Add #include " + header + " for " + template, | ||
| 7237 | + "Add #include " + suggested + " for " + template, | ||
| 7192 | 7238 | ) | |
| 7193 | 7239 | ||
| 7194 | 7240 | ||
@@ -7578,7 +7624,10 @@ def ProcessFileData(filename, file_extension, lines, error, extra_check_function | |||
| 7578 | 7624 | "NONLINT block never ended", | |
| 7579 | 7625 | ) | |
| 7580 | 7626 | ||
| 7581 | - CheckForIncludeWhatYouUse(filename, clean_lines, include_state, error) | ||
| 7627 | + is_c_file = _IsCFile(filename, clean_lines.raw_lines) | ||
| 7628 | + CheckForIncludeWhatYouUse( | ||
| 7629 | + filename, clean_lines, include_state, error, is_c_file=is_c_file | ||
| 7630 | + ) | ||
| 7582 | 7631 | ||
| 7583 | 7632 | # Check that the .cc file has included its header if it exists. | |
| 7584 | 7633 | 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): | |||
| 223 | 223 | error_collector = ErrorCollector(self.assertTrue) | |
| 224 | 224 | include_state = cpplint._IncludeState() | |
| 225 | 225 | nesting_state = cpplint.NestingState() | |
| 226 | - lines = code.split("\n") | ||
| 226 | + raw_lines = code.split("\n") | ||
| 227 | + lines = raw_lines | ||
| 227 | 228 | cpplint.RemoveMultiLineComments(filename, lines, error_collector) | |
| 228 | 229 | lines = cpplint.CleansedLines(lines) | |
| 229 | 230 | for i in range(lines.NumLines()): | |
@@ -235,7 +236,10 @@ def PerformIncludeWhatYouUse(self, code, filename="foo.h", io=codecs): | |||
| 235 | 236 | # have language problems. | |
| 236 | 237 | ||
| 237 | 238 | # Second, look for missing includes. | |
| 238 | - cpplint.CheckForIncludeWhatYouUse(filename, lines, include_state, error_collector, io) | ||
| 239 | + is_c_file = cpplint._IsCFile(filename, raw_lines) | ||
| 240 | + cpplint.CheckForIncludeWhatYouUse( | ||
| 241 | + filename, lines, include_state, error_collector, io, is_c_file=is_c_file | ||
| 242 | + ) | ||
| 239 | 243 | return error_collector.Results() | |
| 240 | 244 | ||
| 241 | 245 | # Perform lint and make sure one of the errors is what we want | |
@@ -259,8 +263,8 @@ def TestMultiLineLintRE(self, code, expected_message_re): | |||
| 259 | 263 | def TestLanguageRulesCheck(self, file_name, code, expected_message): | |
| 260 | 264 | assert expected_message == self.PerformLanguageRulesCheck(file_name, code) | |
| 261 | 265 | ||
| 262 | - def TestIncludeWhatYouUse(self, code, expected_message): | ||
| 263 | - assert expected_message == self.PerformIncludeWhatYouUse(code) | ||
| 266 | + def TestIncludeWhatYouUse(self, code, expected_message, filename="foo.h"): | ||
| 267 | + assert expected_message == self.PerformIncludeWhatYouUse(code, filename=filename) | ||
| 264 | 268 | ||
| 265 | 269 | def TestBlankLinesCheck(self, lines, start_errors, end_errors): | |
| 266 | 270 | for extension in ["c", "cc", "cpp", "cxx", "c++", "cu"]: | |
@@ -1290,6 +1294,26 @@ def testIncludeWhatYouUse(self): | |||
| 1290 | 1294 | printf("hello world");""", | |
| 1291 | 1295 | "", | |
| 1292 | 1296 | ) # Avoid false positives w/ c-style include | |
| 1297 | + # C files should be told to include the C header (e.g. <stdio.h>) rather | ||
| 1298 | + # than its C++ counterpart (e.g. <cstdio>). See #399. | ||
| 1299 | + self.TestIncludeWhatYouUse( | ||
| 1300 | + 'printf("hello world");', | ||
| 1301 | + "Add #include <stdio.h> for printf [build/include_what_you_use] [4]", | ||
| 1302 | + filename="foo.c", | ||
| 1303 | + ) | ||
| 1304 | + # C++ files are unaffected. | ||
| 1305 | + self.TestIncludeWhatYouUse( | ||
| 1306 | + 'printf("hello world");', | ||
| 1307 | + "Add #include <cstdio> for printf [build/include_what_you_use] [4]", | ||
| 1308 | + filename="foo.cpp", | ||
| 1309 | + ) | ||
| 1310 | + # The "C header already included" behaviour is preserved for C files. | ||
| 1311 | + self.TestIncludeWhatYouUse( | ||
| 1312 | + """#include <stdio.h> | ||
| 1313 | + printf("hello world");""", | ||
| 1314 | + "", | ||
| 1315 | + filename="foo.c", | ||
| 1316 | + ) | ||
| 1293 | 1317 | self.TestIncludeWhatYouUse( | |
| 1294 | 1318 | "void a(const string &foobar);", | |
| 1295 | 1319 | "Add #include <string> for string [build/include_what_you_use] [4]", | |
| Back | FazBrowse Home | New Git URL |
0 commit comments