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
208

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

211

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::)

212

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

Consider calling this UnresolvedSpecifiedScope

213

nit: qualier -> qualifier
accissible -> accessible

216

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.

235

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::".

315

identifiers

320

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
235

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
189

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

190

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 ::?

230

Unrsolved -> Unresolved

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

249

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.

255

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

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
187

qualfied -> qualified

192

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

215

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

250

Does this work with anonymous namespaces?

262

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

270

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
190

Good idea. Lexer is a better option.

249

Sounds good. Thanks!

250

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

255

Indeed. Thanks for the catch!

270

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.

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