This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Populate #include insertions as additional edits in completion items.
ClosedPublic

Authored by ioeric on May 5 2018, 2:17 PM.

Details

Summary

o Remove IncludeInsertion LSP command.
o Populate include insertion edits synchromously in completion items.
o Share the code completion compiler instance and precompiled preamble to get existing inclusions in main file.
o Include insertion logic lives only in CodeComplete now.
o Use tooling::HeaderIncludes for inserting new includes.
o Refactored tests.

Diff Detail

Event Timeline

ioeric created this revision.May 5 2018, 2:17 PM

I'm concerned about the scope of this patch - it does too many things and touches too many files for me to feel comfortable that I understand it well enough to review.
Is it possible to split it up? (You mention 6 distinct things in the description).

Have tried to focus comments on what seems to be the core parts.

clangd/CodeComplete.cpp
247

I can't parse this name as it relates to this class. This inserts includes, it isn't itself an insertion.
Maybe IncludeInserter?

clangd/CodeComplete.h
79

IncLocations isn't an appropriate name for the variable - it's coupled to the preamble

clangd/Headers.h
1

The interface to this header looks a bit complex and entangled after this change.

  • The construction/lifecycle of IncludePaths is confusing (comments below)
  • here we provide all the information needed to compute the edits (style, code...) but don't actually do so

it would be nice to achieve a simpler interface with the restricted set of functionality, or expand the functionality...

28

I had some trouble working out the role of this struct (e.g. that it might have been a *proposed* inclusion).
Strictly it's not just the location, but also identifies the header being included.

So this could maybe be

// An #include directive that we found in the main file.
struct Inclusion

but it does also seem a little strange that this is part of the public interface at all (other than for testing)

39

This doesn't seem to add any semantics over the vector, so it just seems to obscure a bit.
In fact it does have semantics: it's the stored list of inclusion locations for the preamble. But those semantics don't belong in this layer. I'd suggest moving it back to the preamble code, or avoiding the typedef altogether.

67–102

the main value-add of this class over HeaderSearch is that it determines whether to insert, so that should probably be mentioned.

68

can you describe the design a little bit here?
e.g. "We simply keep track of which files were already inserted, and delegate to clang's HeaderSearch if a header is new"

69

This name suggests a set or sequence of include path entries (-I flags).
Can we merge this with IncludeInsertion and call it IncludeInserter or similar?

72

hmm, if we require the InclusionLocations to be prebuilt for the preamble, why can't we do the same for non-preamble includes? i.e. can't we split up the "collect existing includes" and "calculate new includes" parts to simplify the interface here? Among other things, testing would be a ton easier.

75

The contract around PP is really confusing: we need to be able to mutate it (to add PP hooks), we need someone to use it in the middle, we need to use its HeaderSearch structure later, and to add more confusion we have shared ownership.

Maybe instead something like:

  • this class takes an IncludeSearch& (sadly not const-correct) to use for lookups
  • it exposes a function like std::unique_ptr<PPCallbacks> record() which returns a callback hook which writes into this includeptahs object.

Then usage looks like:

IncludePaths Paths(SM, PreambleLocs, PP.getHeaderSearch());
PP.addPPCallbacks(Paths.record());
// do something with PP
Paths.calculate(...);

and AFAICT, all the lifetime issues/interactions would be communicated by the types.

76

consider adding a addExistingInclude(InclusionLocation) instead of the InclusionLocations parameter here. This gives you somewhere to document what this does and what it's for (constructors are always crowded), and makes the callsites a little more self-documenting.

It also lets you take InclusionLocations out of the public interface here, which I think would be a win.

95

is this used?

97

and this?

107

is this unused? this seems like it could be a natural part of this class...

clangd/tool/ClangdMain.cpp
103 ↗(On Diff #145385)

why this change?

unittests/clangd/HeadersTests.cpp
97

Is there any way we can avoid creating another copy of this code?

ioeric updated this revision to Diff 146045.May 9 2018, 6:09 PM
ioeric marked 15 inline comments as done.
  • Merged with origin/master
  • Address review comments.
  • Revert unintended change.
ioeric added a comment.May 9 2018, 6:10 PM

I'm concerned about the scope of this patch - it does too many things and touches too many files for me to feel comfortable that I understand it well enough to review.
Is it possible to split it up? (You mention 6 distinct things in the description).

Sorry about the big change! And thanks for the early feedback on headers library!

I think there are a few things going on here:

  1. Removing the existing way of include insertion (additional command)
  2. Populating #include insertion in code completion workflow.
  3. Refactoring #include path calculation to make 2 work
  4. Move some helpers (e.g. replacementToEdit) to public header.
  5. Share InclusionLocation between preamble code and header insertion code.

I was trying to keep 1 and 2 in the same patch so that we don't regress features, but it's probably fine if no one is actually using it... I'm happy to split that out if having them in the same patch makes review hard.

I think 2 and 3 could stay in the same patch as it would be hard to see where the design in 3 came from without 2. But if you got the idea, I guess they could still be split.

4 and 5 should be independent enough to be 2 separate patches. I thought the changes were small and could be included in this patch. I'll split them as well now that you mention.

clangd/Headers.h
1

Refactored code according to your suggestions. PTAL

here we provide all the information needed to compute the edits (style, code...) but don't actually do so

Sorry... forgot to delete some leftover after an earlier revision.

28

Thanks! Inclusion sounds better.

Apart from header insertion and testing, this is also shared with the preamble code.

69

I think there are three pretty independent parts of include insertion:

  1. URI/Verbatim to HeaderFile conversion (which lives in HeaderInsertion in CodeComplete.cpp right now).
  2. Calculate include paths based on existing inclusions and HeaderSearch.
  3. Calculate include insertion edits using tooling::HeaderIncludes.

Initially, I grouped all these in one class (something like HeaderInsertion) which returns an edit given the URIs in the symbol info, but it turned out to be hard to test. For example, among all 3 components, 2 was the most interesting piece to test, while an integration test is probably enough for 1 and 3, but we would need to create URIs (due to 1) and retrieve include name from edits (due to 3) in order to test 2. Since each individual piece seemed independent enough, I decided to keep them separated. I also kept URI logic out of the header library so that it could potentially be shared with other features that are not index-based include insertion, or be moved out of clangd as a tooling library.

In the new revision, I refactored the code according to your suggestions and got rid of this class.

72

Good idea!

107

Thanks for the catches! Missed these after iterating from an earlier version.,,

clangd/tool/ClangdMain.cpp
103 ↗(On Diff #145385)

Oops, this was not intended. I increased the limit for profiling. Reverted...

unittests/clangd/HeadersTests.cpp
97

This was moved here. Headers library no longer needs compiler instance. I'm not sure if there is an easier way to test HeaderSearch and PPCallbacks without a compiler instance...

ioeric updated this revision to Diff 146046.May 9 2018, 6:14 PM
  • Minor cleanup
sammccall added inline comments.May 14 2018, 6:35 AM
clangd/CodeComplete.cpp
247

Do you think it would make sense to move this class to Headers.h? This would reduce the non-completion related code in this large file.

261

If we wanted to avoid URI dependencies in Headers.h but move this class there, the Declaring/Inserted headers could be HeaderFile (possibly invalid). toHeaderFile would stay here.

This might be a neater separation of concerns anyway.

317

This strikes me as overly defensive. We should never have an include header but no declaration location, and if the declaration header is invalid then the include inserter should take care of that, not this code (I think?)

700

PreambleInclusions?

969

this callback is a bit confusing, particularly sequencing/lifetimes.
semaCodeComplete is local, could we simplify it by coupling a bit, passing an IncludeInserter* ("will be populated by the preprocessor") and moving this code (and the preamble-includes handling) inside semaCodeComplete?

This would be a bit more natural if we had IncludeInsertion::addExisting(Insertion) instead of IncludeInsertion::setExisting(vector<Insertion>), I think.

1130

nit: /*Inclusions=*/

clangd/CodeComplete.h
73

should this be PreambleInclusions, or is it broader than that?

clangd/Headers.h
69

OK, SGTM

unittests/clangd/HeadersTests.cpp
97

Moved from where?

You could consider adding inclusions to TestTU (sorry it's in D46524 which I thought had already landed, but should today)

ioeric updated this revision to Diff 146675.May 14 2018, 1:44 PM
ioeric marked 7 inline comments as done.
  • Addressed review comments.
  • Merged with origin/master
sammccall accepted this revision.May 15 2018, 4:52 AM

Nice, ship it!

clangd/CodeComplete.cpp
317

is this comment still relevant here?

791

nit: FormatStyle

802

nit: includes is a pointer, capture by value?

961

This leaks. reset (or = nullptr)

This revision is now accepted and ready to land.May 15 2018, 4:52 AM
ioeric updated this revision to Diff 146834.May 15 2018, 8:18 AM
ioeric marked 4 inline comments as done.
  • Addressed review comments.
ioeric updated this revision to Diff 146838.May 15 2018, 8:25 AM
ioeric updated this revision to Diff 146839.May 15 2018, 8:25 AM
  • Rebase...
ioeric updated this revision to Diff 146843.May 15 2018, 8:31 AM
  • Merged with origin/master
This revision was automatically updated to reflect the committed changes.