This is an archive of the discontinued LLVM Phabricator instance.

Expose the name of the checker producing each diagnostic message.
ClosedPublic

Authored by alexfh on Jan 15 2014, 9:19 AM.

Details

Summary

In clang-tidy we'd like to know the name of the checker producing each
diagnostic message. PathDiagnostic has BugType and Category fields, which are
both arbitrary human-readable strings, but we need to know the exact name of the
checker in the form that can be used in the CheckersControlList option to
enable/disable the specific checker.

This patch adds the CheckName field to the CheckerBase class, and sets it in
the CheckerManager::registerChecker() method, which gets them from the
CheckerRegistry.

Checkers that implement multiple checks have to store the names of each check
in the respective registerXXXChecker method.

Diff Detail

Event Timeline

I'm sorry, but again, it's not okay to output a random name or all of the names associated with a checker. Each diagnostic a checker prints has to do with a specific user-visible checker name, not just any old name. It's fine to do something like this for checkers that only implement one set of checks, but for MallocChecker we need to actually get this right or not do it at all.

alexfh updated this revision to Unknown Object (????).Jan 21 2014, 6:11 AM

Output correct check names for checkers implementing multiple sets of checks.

I'm sorry, but again, it's not okay to output a random name or all of the
names associated with a checker. Each diagnostic a checker prints has to do
with a specific user-visible checker name, not just any old name.
It's fine to do something like this for checkers that only implement one set
of checks, but for MallocChecker we need to actually get this right or not do
it at all.

You are right, I didn't get the real complexity of what's going on in
MallocChecker with regard to various check types and possible messages. There
are a few other checkers, that implement multiple check sets, but MallocChecker
is the most convoluted one.

Now I've fixed them all to store the names associated with the specific check
sets and use the right name when reporting a bug. I have a test for the new
functionality in a local patch to clang-tidy (as it's the only front-end, that
currently outputs checker names, and making it a unit-test would be rather
complicated, I guess).

alexfh updated this revision to Unknown Object (????).Jan 21 2014, 6:16 AM

Removed debug output. Fixed a comment.

Much better! :-) I wish we could cut down a bit on the copying of the name, but to do that we'd have to rely on the CheckerRegistry always living longer than the diagnostics. We could probably assume that for BugType, though. (If we did that, we'd want to use a wrapper data type so that people didn't accidentally pass random strings.)

At the very least, though, even the combined checkers can use StringRef instead of std::string to track the names of the individual checks.

It might be nice to have a BugType constructor overload that takes a Checker and just immediately calls getCheckerName(), just so 90% the clients could pass "this", but that's getting fairly nitpicky.

I'd also like Ted to at least give a thumbs-up before this goes in.

alexfh updated this revision to Unknown Object (????).Jan 22 2014, 5:32 AM

Avoid copying strings when creating BugTypes or reporting errors.
Introduced a wrapper type for checker names to ensure we only get StringRefs
from the CheckerRegistry.

Much better! :-) I wish we could cut down a bit on the copying of the name, but
to do that we'd have to rely on the CheckerRegistry always living longer than
the diagnostics. We could probably assume that for BugType, though. (If we did
that, we'd want to use a wrapper data type so that people didn't accidentally
pass random strings.)

Done.

At the very least, though, even the combined checkers can use StringRef instead
of std::string to track the names of the individual checks.

Done.

It might be nice to have a BugType constructor overload that takes a Checker and
just immediately calls getCheckerName(), just so 90% the clients could pass
"this", but that's getting fairly nitpicky.

Done for BugType and all its descendants.

I'd also like Ted to at least give a thumbs-up before this goes in.

Yes, would be nice to hear from Ted on this.

alexfh updated this revision to Unknown Object (????).Jan 29 2014, 7:45 AM

Don't pass checker names through register.*Checker functions. Store the current checker name in the CheckerManager instead.

Renamed CheckerNameWrapper to CheckerName

This approach seems fine to me. The shared state is a bit ugly, but seems like a reasonable tradeoff here.

I like "CheckName"; it matches where we want to go a bit better. (Or my impression of where we want to go, anyway.)

Waiting on Ted for final thumbs-up.

include/clang/StaticAnalyzer/Core/CheckerManager.h
135–136 ↗(On Diff #6747)

English nitpick: no comma after "ensure". Also, we should explain why this is important: we want to make sure all checker name strings have a lifetime that keeps them alive at least until the path diagnostics have been processed.

190 ↗(On Diff #6747)

The one thing I would say about this is that it doesn't make sense for checkers that implement multiple checks. If we really cared, we could make it so that if there's already a check name set, we mark the checker as implementing multiple names somehow, and then we can catch cases where such a checker is accidentally used to identify a bug, rather than a specific name. But we don't have to do this now.

alexfh updated this revision to Unknown Object (????).Feb 3 2014, 11:27 AM

CheckerName -> CheckName + fixed a comment.

Ted and I talked offline about this and other changes and agreed that this is a good move. We have some notions about future work on the analyzer that I'll try to write up and send to you and cfe-dev tomorrow, but they don't seem like goals that would conflict with clang-tidy's.

I've done a pass over the entire patch this time and come up with a few comments, but this mostly looks good. Thank you for doing all the boring work of getting this up and running in all the existing checkers!

include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
40–41 ↗(On Diff #6830)

We try not to shadow class names with field or parameter names. Just "const CheckName Check", maybe?

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
309–312 ↗(On Diff #6830)

Possible alternative:

Optional<CheckKind> getCheckIfTracked(AllocationFamily Family) const;

I personally tend to avoid returning values by reference. What do you think of this version?

2276–2280 ↗(On Diff #6830)

Good work here: if only the leak-checker is enabled, it becomes responsible for the use-after-delete checks, but if both are enabled the normal NewDelete checker will show up. Nice!

lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
68–71 ↗(On Diff #6830)

There are no more utility functions, so let's drop this header.

Yes, this all looks great to me. Sorry for the delay.

Jordan, Ted, thanks for the review!

Is it now fine to commit? ;)

include/clang/StaticAnalyzer/Core/BugReporter/BugType.h
40–41 ↗(On Diff #6830)

Done.

lib/StaticAnalyzer/Checkers/MallocChecker.cpp
309–312 ↗(On Diff #6830)

With Optional the user code becomes somewhat less elegant, but if you like it more, I'm fine with it.

2276–2280 ↗(On Diff #6830)

MallocChecker is particularly convoluted. It should be possible to have the same functionality with a simpler structure, then this code would not be necessary =\

lib/StaticAnalyzer/Checkers/UnixAPIChecker.cpp
68–71 ↗(On Diff #6830)

Sure. Done.

alexfh updated this revision to Unknown Object (????).Feb 11 2014, 9:49 AM

Addressed reviewer's comments.

jordan_rose accepted this revision.Feb 11 2014, 9:53 AM

Yes, this looks good!

(Two possible ways to make the Optional change less wordy: use * for getValue(), and name the variable something else so that you don't have to qualify CheckKind with MallocChecker::.)

alexfh closed this revision.Feb 11 2014, 1:55 PM
alexfh closed this revision.

Closed by commit rL201186 (authored by @alexfh).