Open Quuxplusone opened 6 years ago
The exclusion of extern "C" blocks is done for each check independently. This bug seems to refer to modernize-use-using. If you have other examples, please report them as well.
Attached use-using.patch
(2204 bytes, text/plain): Ignore entries when the MatcheDecl is ExternCContext
What needs to be done to get more traction on resolving this issue?
modernize-use-using isn't the only check to have the issue, modernize-
deprecated-headers and modernize-use-nullptr have it too.
example:
/* This block simulates a C header */
#ifdef __cplusplus
extern "C" {
#endif
#include <stdlib.h> // for NULL
int* A = NULL;
#ifdef __cplusplus
} // extern "C"
#endif
// This block simulates a C++ implementation/use of the C header's API
#include <iostream>
int main()
{
std::cout << A << std::endl;
return 0;
}
Run clang-tidy as:
$ clang-tidy test.cpp -checks='*' -- -std=c++14 -Wall
output:
15925 warnings generated.
test.cpp:7:10: warning: inclusion of deprecated C++ header 'stdlib.h'; consider
using 'cstdlib' instead [modernize-deprecated-headers]
#include <stdlib.h> // for NULL
^~~~~~~~~~
<cstdlib>
test.cpp:9:10: warning: use nullptr [modernize-use-nullptr]
int* A = NULL;
^~~~
nullptr
Suppressed 15922 warnings (15922 in non-user code).
Use -header-filter=.* to display errors from all non-system headers. Use -
system-headers to display errors from system headers as well.
Probably all checks have this issue, as its very uncommon to check for the extern "C"
/extern "C++"
constructs, as the language-options for the translation unit is just assumes everywhere.
It would be best, to have something central and not do that process manually for every single matcher, as that would be cumbersome, error-prone and not scalable.
So I've been thinking about this problem a bit, and wanted to dump what I've got so far + see if I can revive the discussion here.
Ideally, what we want here is knowledge of whether code has to be parseable as C or not. Lacking a -c-header-filter=
(and the will of users to populate that accurately), I agree our best bet is a bundle o' heuristics, which will probably lead to tidy being over-conservative or over-aggressive in some cases:
extern "C" inline void foo() { char cs[4]; // modernize-loop-convert says we should transform this. Can we? Who knows. for (unsigned i = 0; i < sizeof(cs); ++i) bar(&cs[i]); }
The most straightforward way I can see to do that would be to get all tidy checks to declare their C-compatibility somehow, and have the matchers of C-incompatible checks implicitly wrapped in essentially unless(Matcher, probablyHasToBeSourceCompatibleWithC())
by default. For checks that want to control their own destiny, we can add the capability to opt-in/opt-out per matcher, but the default will depend on the check's general C compatibility.
I have an idea of how to do the above with a few (unfortunately) broad refactors. Before I dump a wall o' words describing that, does anyone have thoughts on this approach at a high level?
Hi George.
Could you talk more about your thoughts?
Right -- I think I can summarize in a small fence o' words, instead of a wall of them ;)
IIRC, my idea involved essentially two broad steps:
registerMatchers
to use isLanguageVersionSupported
insteadisLanguageVersionSupported
return something in terms of compatible languages/versions, instead of "yeah, this LangOpts LGTM." The simplest thing would be returning a struct { bool isEnabledForCurrentLangOpts; bool isCCompatible; }
. This'd probably also need a rename of this method.After these, we'd end up with per-check info about whether a given check provides C-compatible diagnostics. The second step would (unfortunately) break the build of any downstream checks which use override
on isLanguageVersionSupported
, but it should be a super simple cleanup.
If we could then funnel this new isCCompatible bit into clang-tidy's core matching logic somehow (waves hands), we could selectively disable checks if tidy thinks we're in a context in which doing so is necessary (e.g., in an extern "C"
block).
I think I got most of the refactor I mentioned done, but didn't put time into the "making the matching logic make use of this information" part. Happy to share unfinished patches on an old version of tidy if they'd be of use.
Do share please.
Attached pr35924-patches.tgz
(54831 bytes, application/gzip): patch bundle to supplement comment 8
Thanks for sharing.
Another patch is taking a bit more time than I expected.
I will be back on this soon.
_Bug 49181 has been marked as a duplicate of this bug._
> If you have other examples, please report them as well.
modernize-use-trailing-return-type has this problem.
a.cpp:
extern "C" {
int f();
}
Console:
$ clang-tidy --version
LLVM (http://llvm.org/):
LLVM version 11.1.0
Optimized build.
Default target: x86_64-pc-linux-gnu
Host CPU: broadwell
$ clang-tidy a.cpp -checks=modernize-use-trailing-return-type
Error while trying to load a compilation database:
Could not auto-detect compilation database for file "a.cpp"
No compilation database found in /home/jmcfarla/eg or any parent directory
fixed-compilation-database: Error while opening fixed database: No such file or
directory
json-compilation-database: Error while opening JSON database: No such file or
directory
Running without flags.
1 warning generated.
/home/jmcfarla/eg/a.cpp:2:5: warning: use a trailing return type for this
function [modernize-use-trailing-return-type]
int f();
~~~ ^
auto -> int
Another check: cppcoreguidelines-pro-bounds-constant-array-index
I count five so far (excluding aliases):
- modernize-deprecated-headers
- modernize-use-using
- modernize-use-trailing-return-type
- cppcoreguidelines-pro-bounds-constant-array-index
- modernize-use-nullptr
I've started a menagerie (https://godbolt.org/z/4ss8bGjzr). It triggers the
checks for which we might consider setting IsCCompatible=false. It does so for
Clang 14.0.0git.
recommends using span
as an alternative.
https://godbolt.org/z/xc1zrGdjM
(LMK if these are not helpful. Updating as I discover them.)
use-using.patch
(2204 bytes, text/plain)pr35924-patches.tgz
(54831 bytes, application/gzip)