This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Handle unresolved scope specifier when fixing includes.
ClosedPublic

Authored by ioeric on Feb 13 2019, 8:00 AM.

Details

Summary

In the following examples, "clangd" is unresolved, and the fixer will try to fix
include for clang::clangd; however, clang::clangd::X is usually intended. So
when handling a qualifier that is unresolved, we change the unresolved name and
scopes so that the fixer will fix "clang::clangd::X" in the following example.

  namespace clang {
  	clangd::X
	~~~~~~
  }
  // or
  clang::clangd::X
         ~~~~~~

Event Timeline

ioeric created this revision.Feb 13 2019, 8:00 AM
Herald added a project: Restricted Project. · View Herald TranscriptFeb 13 2019, 8:00 AM
ioeric updated this revision to Diff 186674.Feb 13 2019, 8:02 AM
  • Remove unintended change.
ioeric edited the summary of this revision. (Show Details)Feb 13 2019, 8:02 AM
Harbormaster completed remote builds in B28103: Diff 186674.
sammccall added inline comments.Feb 18 2019, 2:30 AM
clangd/IncludeFixer.cpp
320–321

We can be more precise about this now I think: IIUC this is the resolved specified scope.
in two senses: it's the part of what was typed that was resolved, and it's in its resolved form not its typed form (think namespace clang { clangd::x } --> clang::clangd::)

321

nit: I don't think this is an example, it's the only case right?

Consider calling this UnresolvedSpecifiedScope

322

nit: qualier -> qualifier
accissible -> accessible

324

No idea when this can be invalid, but we could just return here?

325

I'm a bit concerned about how this mixes extraction of scopes from the source code/AST (which is now *really* complicated) with building the query and assembling the correction.

Can we reasonably extract the former to a helper function? Not sure exactly what the signature would be, but it would be helpful to find out.

The other thing is I think this has a lot in common with the scope-wrangling code in CodeComplete, and could *maybe* be unified a bit once isolated.

334

hmm, won't this heuristic have false positives?

// indexed-header.h
namespace a { int X; }

// main-file.cc
namespace b = a;
namespace c { int Y = b::x; }

I worry spelling is going to be "b::" here, while SpecifiedNS is going to be "a::".

372

identifiers

377

this only depends on the params right?
This could be static or even moved out of the class.

ioeric updated this revision to Diff 187222.Feb 18 2019, 4:39 AM
ioeric marked 9 inline comments as done.
  • address review comments
ioeric added inline comments.Feb 18 2019, 4:39 AM
clangd/IncludeFixer.cpp
334

Thanks for pointing this out! I completely missed the namespace alias case. Fixed and added a test.

sammccall accepted this revision.Feb 18 2019, 10:29 AM

Thanks! The layering is *much* clearer now.
I can still suggest a couple of tweaks, but they're pretty much cosmetic.

clangd/IncludeFixer.cpp
190

you're showing a range here, it should be a point though?

191

this isn't wrong per se (conservative, bails out e.g. on unicode)
But is it much harder to call Lexer::findNextToken twice and expect a raw identifier and ::?

231

Unrsolved -> Unresolved

emphasis might be clearer as UnresolvedIsSpecifier - there's always an unresolved entity, the boolean is indicating that it's a specifier

256

I don't think this vlog is useful as-is (quite far down the stack with no context)
Did you intend to remove it?

322

Following up on our offline discussion :-)
I think that since extractSpecifiedScopes can want to modify the name, we should just expand that function's signature/responsibility to always determine the name.

So we'd pass the const DeclarationNameInfo& to extractSpecifiedScopes, and it would return a struct {optional<string> ResolvedScope; optional<string> UnresolvedScope; string Name}.
Maybe need to call them CheapUnresolvedName/extractUnresolvedNameCheaply or similar.
But I think the code change is small.

This revision is now accepted and ready to land.Feb 18 2019, 10:29 AM

Hi Eric, I have just couple details.

clangd/IncludeFixer.cpp
188

qualfied -> qualified

193

It seems to me that calling Lexer would be better indeed.

216

Maybe move the comment about work done eagerly to the function?

251

Does this work with anonymous namespaces?

263

I'd personally prefer to add parentheses here to have the if/else if/else consistent. Up to you though.

271

Is the term qualifier applicable here? (Honest question.)

It seems like C++ grammar uses specifier (same as you in IsUnrsolvedSpecifier )
http://www.nongnu.org/hcb/#nested-name-specifier

unittests/clangd/DiagnosticsTests.cpp
452

If (see above) we decide qualifier should be replaced by specifier or smth else please replace here as well, otherwise ignore this.

ioeric updated this revision to Diff 187343.Feb 19 2019, 3:57 AM
ioeric marked 16 inline comments as done.
  • address review comment
clangd/IncludeFixer.cpp
191

Good idea. Lexer is a better option.

251

I'm not sure... how do you use an anonymous namespace as a scope specifier?

256

Indeed. Thanks for the catch!

271

You've raised a good point. We've been using specifier and qualifier interchangeably in the project. But specifier does seem to be a more appropriate name to use. I've fixed uses in this file. Uses in other files probably need a separate cleanup.

322

Sounds good. Thanks!

ioeric updated this revision to Diff 187359.Feb 19 2019, 6:30 AM
  • minor cleanup
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptFeb 19 2019, 6:31 AM