Page MenuHomePhabricator

[clangd] Add fix-it for inserting IWYU pragma: keep
Needs ReviewPublic

Authored by njames93 on Jun 20 2022, 7:20 AM.

Details

Summary

Since IncludeCleaner has some support for IWYU keep pragmas, we can suggest it as a fix-it.

Diff Detail

Event Timeline

njames93 created this revision.Jun 20 2022, 7:20 AM
Herald added a project: Restricted Project. · View Herald TranscriptJun 20 2022, 7:20 AM
njames93 requested review of this revision.Jun 20 2022, 7:20 AM

This is a bit tricky - we'd like to offer more fixes in several scenarios (e.g. replace a header with the transitive includes you're relying on), but some of those require more complex implementation.

On one hand, presenting only one automated fix will bias users towards that option.
On the other hand, it's not clear when the more complex fixes will be ready and this solves a real problem.

I'm inclined toward landing it, but will leave this up to @kadircet

clang-tools-extra/clangd/IncludeCleaner.cpp
502

this FIXME is addressed by this change

511

"directive" isn't accurate here I think

What about just: "add IWYU pragma: keep"?

as discussed offline I agree that we should have this, as no matter how hard we try there are going to be cases that we can't get right due to ADL/template instantiations or depending on 3rd party code that cannot be edited and also doesn't have relevant pragmas inside.

my hesitation about having them at this stage is, we won't be able to:

  • get feedback around most of these issues as people will just put a pragma and be done with it.
  • fix them going forward, even after implementation gets better, we won't be able to diagnose these headers and "falsely" issued pragmas will keep includes around.

Hence i'd like to hear a little bit more about what kind of false positives you're facing often enough to need this as an automated fix at this stage, to see if there's something we can do to improve the implementation first.

clang-tools-extra/clangd/unittests/DiagnosticsTests.cpp
1795

can you also have a test with an include that already has a trailing comment?

I had another idea about offering the export pragma when in a header file but I don't know if that's going too far

Hence i'd like to hear a little bit more about what kind of false positives you're facing often enough to need this as an automated fix at this stage, to see if there's something we can do to improve the implementation first.

One of the main issues I have is due to templates not being instantiated which can result in symbols that are actually used not being picked up as the template instantiation that uses them isn't actually instantiated.
Unfortunately this isn't something that can be easily fixed without tanking performance.

I had another idea about offering the export pragma when in a header file but I don't know if that's going too far

There are definitely cases where this is conceptually "right" fix, but it's hard to guess that in clangd (well at least without having some codebase wide analysis), and offering it all the time would definitely confuse users.

One of the main issues I have is due to templates not being instantiated which can result in symbols that are actually used not being picked up as the template instantiation that uses them isn't actually instantiated.

I guess you're talking about having the template pattern in the main file, but all the instantiations are in dependents of the code. My mental model was around making the dependents have the include for the type, instead of having it in the file providing the template pattern (header). Does that make sense?
This kind of breaks down when there's actually some types used by all the instantiations, as you'd want them to be included by the header. But I think we should be able to diagnose these cases, as usage of this type should be non-dependent (at least in the cases I can think of), so this sounds like a bug/improvement.

One of the main issues I have is due to templates not being instantiated which can result in symbols that are actually used not being picked up as the template instantiation that uses them isn't actually instantiated.

I guess you're talking about having the template pattern in the main file, but all the instantiations are in dependents of the code. My mental model was around making the dependents have the include for the type, instead of having it in the file providing the template pattern (header). Does that make sense?
This kind of breaks down when there's actually some types used by all the instantiations, as you'd want them to be included by the header. But I think we should be able to diagnose these cases, as usage of this type should be non-dependent (at least in the cases I can think of), so this sounds like a bug/improvement.

A specific example i encountered is clang/Tooling/DiagnosticsYaml.h Which defines template specializations for inputting/outputting yaml io. That file must be included if you ever want to emit diagnostics as YAML, but the typical use case is to just use the operator<< on a yaml stream. This function internally will use those specializations, but as clangd doesn't look into the function calls and expand all those instantiations, they are treated as being unused(There's many bugs already related to this) and as such the header is marked as being unused.

A specific example i encountered is clang/Tooling/DiagnosticsYaml.h Which defines template specializations for inputting/outputting yaml io. That file must be included if you ever want to emit diagnostics as YAML, but the typical use case is to just use the operator<< on a yaml stream. This function internally will use those specializations, but as clangd doesn't look into the function calls and expand all those instantiations, they are treated as being unused(There's many bugs already related to this) and as such the header is marked as being unused.

i see makes sense. this falls in the "adl through templates" bucket, which is annoying and doesn't seem to be as rare in the wild. so we probably need to figure something out here.
as mentioned above i've hesitations for having this automatically available but it's a state we want to get at eventually. i guess there's not much point in delaying that, so LGTM (after comments already raised are addressed), sorry for the late reply and thanks for the patch!