This is an archive of the discontinued LLVM Phabricator instance.

[clangd][ObjC] Improve support for class properties
ClosedPublic

Authored by dgoldman on Apr 6 2021, 10:34 AM.

Details

Summary

Class properties are always implicit short-hands for the getter/setter
class methods.

We need to explicitly visit the interface decl UIColor in UIColor.blueColor,
otherwise we instead show the method decl even while hovering over
UIColor in the expression.

Diff Detail

Event Timeline

dgoldman created this revision.Apr 6 2021, 10:34 AM
dgoldman requested review of this revision.Apr 6 2021, 10:34 AM
Herald added a project: Restricted Project. · View Herald TranscriptApr 6 2021, 10:34 AM
dgoldman updated this revision to Diff 335582.Apr 6 2021, 10:37 AM
  • Add FIXMEs
dgoldman added inline comments.Apr 6 2021, 10:38 AM
clang-tools-extra/clangd/FindTarget.cpp
309–313

Is there a good way to handle this case where the expression can refer to multiple decls?

sammccall added inline comments.Apr 23 2021, 3:53 PM
clang-tools-extra/clangd/FindTarget.cpp
309–313

TL;DR: yes, fix the AST :-)

The design assumption is that an AST node (specifically: the tokens owned by exactly that AST node and not a descendant of it) refers to one thing. I don't see an easy way to hack around this.

Expressions like this are supposed to be split into multiple AST nodes. But ObjC seems to be missing AST nodes in a bunch of places (Protocol lists is another).

e.g. in C++ equivalent DeclRefExpr UIColor::blackColor there'd be both a NestedNameSpecifier for UIColor:: and a TagTypeLoc for UIColor. And objc [Test foo] has an ObjCInterfaceTypeLoc for Test.


I'm not sure this is the right place for this comment, the problem isn't what VisitObjCPropertyRefExpr is doing, the issue is that the caller is passing the wrong kind of node to findTarget() because there's no right one.

769

comment here:
// There's no contained TypeLoc node for the receiver type.

clang-tools-extra/clangd/unittests/FindTargetTests.cpp
1056–1057

As in the other patch, we should keep these large unrelated reformattings out of substantive patches.

dgoldman added inline comments.Apr 23 2021, 4:31 PM
clang-tools-extra/clangd/FindTarget.cpp
309–313

That seems a bit invasive - is it really "fixing" the AST - is there anything wrong with the current AST design or rather any notable improvements by adding more nodes to the AST beside this one use case here?

It seems like the design could be adapted if we had a SourceLocation hint here (from the caller) to disambiguate which one we mean, but I'm guessing not all of the callers/users of this would have one?

dgoldman updated this revision to Diff 340840.Apr 27 2021, 7:27 AM

Rebase on top of main

dgoldman updated this revision to Diff 340885.Apr 27 2021, 9:38 AM
dgoldman marked 2 inline comments as done.

Fixes for review

sammccall accepted this revision.Apr 28 2021, 3:16 AM
sammccall added inline comments.
clang-tools-extra/clangd/FindTarget.cpp
309–313

That seems a bit invasive

I'm not sure it actually requires any changes to AST classes, just to RecursiveASTVisitor to wrap the getClassReceiverType() & getReceiverLocation() into n ObjCInterfaceTypeLoc (which is a value object) and visit it.

is it really "fixing" the AST

It's inconsistent with the design of the rest of the AST.
There are very few other cases where AST nodes have this kind of compound meaning rather than being to split into sub-nodes.
(In fact ObjC protocol lists are the only example I can think of. I suspect this dates back to early clang days, maybe before the patterns became established)
And similarly, there are few/no places where types are referenced that don't have a TypeLoc node traversed by RecursiveASTVisitor.

is there anything wrong with the current AST design or rather any notable improvements by adding more nodes to the AST beside this one use case here?

I guess the use case here is "precisely communicating a selection in an IDE".
Expand-selection features and show-ast-structure features don't work in clangd for a similar reason.

Outside clangd I'm less familiar of course! Matchers, clang-tidy checks and refactorings spring to mind.
For instance, if you want to write a tool to rename/split an ObjC class, then something like typeLoc(loc(asString("FooClass"))) would match all usages... except this one, so your tool would have a bug.

This revision is now accepted and ready to land.Apr 28 2021, 3:16 AM
dgoldman marked 2 inline comments as done.Apr 28 2021, 6:57 AM
dgoldman added inline comments.
clang-tools-extra/clangd/FindTarget.cpp
309–313

I'm not sure it actually requires any changes to AST classes, just to RecursiveASTVisitor to wrap the getClassReceiverType() & getReceiverLocation() into n ObjCInterfaceTypeLoc (which is a value object) and visit it.

Thanks, I'll look into that in a follow up - I'd imagine it could affect lots of other things but I'm not sure.

Outside clangd I'm less familiar of course! Matchers, clang-tidy checks and refactorings spring to mind.
For instance, if you want to write a tool to rename/split an ObjC class, then something like typeLoc(loc(asString("FooClass"))) would match all usages... except this one, so your tool would have a bug.

Interesting, I wonder how Xcode works with this (e.g. for refactorings), I'll ask around to see if anyone has suggestions/further context here.

This revision was automatically updated to reflect the committed changes.
dgoldman marked an inline comment as done.