RFC: Pumping Clang-Tidy warnings through the Static Analyzer's BugReporter.

Sorry about the delayed reply, I only saw this thread when it popped up again today.

I would like to suggest something different: move Clang Static
Analyzer to clang-tools-extra. Build it either as a separate binary or
compile it into the clang-tidy binary. Then let clang -analyze
delegate to that binary for backwards compatibility.

Speaking as an outsider in the peanut gallery who does very little static analysis, this is very appealing to me. It would save binary size in clang and make building and testing clang faster, if the developer isn’t working in the static analyzer space.

A bit +1 to this from me as well.

Generally we already have a cmake flag for this, -DCLANG_ENABLE_STATIC_ANALYZER=OFF (defaults to ON). This flag is definitely a must-have for people who try to make their clang binary as tiny as possible. But i understand that this flag is not exceptionally discoverable and a lot of people probably suffer unnecessarily long compile times simply because they didn’t discover it.

I’m aware of this flag, but it doesn’t quite do what I want: I want clang-tidy to have the static analyzer, but I don’t want my compiler to have it. It’d be nice if there was a setting that allowed putting the analyzer in clang-tidy but not in clang, and to make clang -analyze shell out to clang-tidy for backwards compat.

I agree that the analyzer is in the compiler mainly for historical reasons, and that we wouldn’t move it form clang-tidy into the compiler if it was only in clang-tidy. This suggests that that’s the future we should work towards.

Maybe i should do something similar to SemaDiagnosticBuilder, i.e. sub-class DiagnosticBuilder and steal diagnostics from it in my superclass destructor, so that to convert them to our path diagnostics, WDYT?

That's not going to break the source compatibility (apart from the few checks where people put their DiagnosticBuilder into a local variable, they'll have to change the type of that variable), but neither would it introduce a look-alike interface because it's still literally the same interface and it's already kind of expected to be polymorphic.

P.S. We could provide such diagnostic builder to our own AST-based checkers as well. That way we can see if it's indeed a better API for emitting path-insensitive warnings than BugReporter::EmitBasicReport(), which is pretty likely. And if so, i'll readily recommend it for use in any path-insensitive tool that emits warnings. This would also be an indication that our API is the best in long term.

P.P.S. Such API would in its out-of-the-box shape not allow Clang-Tidy to add the typical path-sensitive pieces (event piece, control flow piece, etc.) to the report. But if you ever want to do this sort of stuff, it should be a matter of simply extending our superclass a little bit.

> Maybe i should do something similar to SemaDiagnosticBuilder, i.e.
> sub-class DiagnosticBuilder and steal diagnostics from it in my
> superclass destructor, so that to convert them to our path
> diagnostics, WDYT?

That sounds like abuse of inheritance :slight_smile: Subclassing DiagnosticBuilder
to hijack its output (which is stored in DiagnosticsEngine BTW!) is
too clever. The current Clang's diagnostics subsystem has a lot of
quirks already. I think diagnostics that start from DiagnosticBuilder
should be reported by DiagnosticsEngine to the DiagnosticConsumer.

If we want to reuse DiagnosticBuilder, WDYT about a custom
DiagnosticConsumer instead?

P.S. We could provide such diagnostic builder to our own AST-based
checkers as well. That way we can see if it's indeed a better API for
emitting path-insensitive warnings than BugReporter::EmitBasicReport(),
which is pretty likely. And if so, i'll readily recommend it for use in
any path-insensitive tool that emits warnings. This would also be an
indication that our API is the best in long term.

P.P.S. Such API would in its out-of-the-box shape not allow Clang-Tidy
to add the typical path-sensitive pieces (event piece, control flow
piece, etc.) to the report. But if you ever want to do this sort of
stuff, it should be a matter of simply extending our superclass a little
bit.

That does sound interesting, however, I'd prefer to try to figure out
ways to converge the two APIs (Clang's diagnostic subsystem and
BugReporter) instead of building more ways of doing the same stuff.
However, I'm not sure about the best way to do it. These APIs are
definitely built with different thoughts towards performance. Clang's
diagnostic subsystem is super-optimized to the point of trying hard to
not even dynamically allocate memory; all this while trying to present
an OOP interface, which, however, leaks the underlying implementation
by exposing the concepts of "in-flight diagnostic", "delayed
diagnostic" etc. Static Analyzer diagnostic subsystem is more OOP-like
in its implementation as well, with various path pieces for example.

Dmitri

Maybe i should do something similar to SemaDiagnosticBuilder, i.e.
sub-class DiagnosticBuilder and steal diagnostics from it in my
superclass destructor, so that to convert them to our path
diagnostics, WDYT?

That sounds like abuse of inheritance :slight_smile: Subclassing DiagnosticBuilder
to hijack its output (which is stored in DiagnosticsEngine BTW!) is
too clever. The current Clang's diagnostics subsystem has a lot of
quirks already. I think diagnostics that start from DiagnosticBuilder
should be reported by DiagnosticsEngine to the DiagnosticConsumer.

If we want to reuse DiagnosticBuilder, WDYT about a custom
DiagnosticConsumer instead?

Wait, we already have that? Nice! Will go that way then.