This is an archive of the discontinued LLVM Phabricator instance.

[clangd] Added highlighting for class and enum types
ClosedPublic

Authored by jvikstrom on Jul 5 2019, 10:54 AM.

Diff Detail

Repository
rL LLVM

Event Timeline

jvikstrom created this revision.Jul 5 2019, 10:54 AM
Herald added a project: Restricted Project. · View Herald TranscriptJul 5 2019, 10:54 AM
hokein added inline comments.Jul 8 2019, 1:22 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
68 ↗(On Diff #208208)

We are only interested in TagDecl, maybe use the VisitTagLoc callback, so that you can get rid of the filtering code above.

72 ↗(On Diff #208208)

nit: auto => const auto *, we usually spell out the pointer type explicitly.

73 ↗(On Diff #208208)

Here is the case:

class Foo {
   ~Foo
 // ^~~ we get a TypeLoc whose TagDecl is a cxxRecordDecl.
}

not sure this is expected in clang AST, but it is unreasonable in highlighting context -- ideally, we want to highlight ~Foo as a destructor (we may encounter a tricky case, like ~ /*comment*/ Foo(), but I assume this is rarce, should be fine), @sammccall, @ilya-biryukov, thoughts?

99 ↗(On Diff #208208)

nit: clang-format

214 ↗(On Diff #208208)

entity.name.type.class.cpp?

clang-tools-extra/clangd/SemanticHighlighting.h
29 ↗(On Diff #208208)

Type is general, can match different types, I think we want distinguish different types (class, enum, etc).

Since this patch is highlighting class, I think the name should be Class?

jvikstrom updated this revision to Diff 208354.EditedJul 8 2019, 3:34 AM
jvikstrom marked an inline comment as done.

Type -> Class
Also added more tests.

jvikstrom marked 4 inline comments as done.Jul 8 2019, 3:35 AM
jvikstrom added inline comments.
clang-tools-extra/clangd/SemanticHighlighting.cpp
68 ↗(On Diff #208208)

With just VisitTagLoc it does not catch this case:

namespace abc {
  template<typename T>
  struct $Type[[A]] {};
}
abc::$Type[[A]]<int> $Variable[[AA]];

I guess I could add a bunch of `Visit*TypeLoc``` methods but I can't seem to find the correct Visit method for the case above...

sammccall added inline comments.Jul 8 2019, 4:18 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
61 ↗(On Diff #208354)

should you highlight DependentNameTypeLoc::getNameLoc()? (As some generic "type" rather than "class" as we can't resolve the name) Or is the unqualified name highlighted by traversing some other node?

62 ↗(On Diff #208354)

Nit: consider splitting this || into two statements so you can comment each.

The comments should ideally say what drives the actual behavior in this situation, e.g. "For elaborated types, the underlying type will be highlighted when visiting the inner typeloc"

70 ↗(On Diff #208354)

The patch description says "non-builtin types".

It's fine to just handle tag types (struct class enum union) in this patch, but there are other cases you may want to handle later (e.g. typedefs/using).

Random thought for the future: you could highlight auto differently based on the actual underlying type (e.g. class vs enum vs pointer...)

73 ↗(On Diff #208354)

This code is doing something really weird: you've seen a mention of a class, now you're checking to see if the destructor's declaration encloses the mention so you can not highlight it.

First, I'm not convinced highlighting it is bad or worth any complexity to avoid, happy to discuss further.

Second, this will get a bunch of cases wrong:

  • a call to the destructor (a->~Foo()) will still be highligthed
  • the out-of-line definition of the destructor (Foo::~Foo() { ... }) will still be highlighted
  • a (separate) mention of the class name within the body of the destructor (defined inline) will not be highlighted
100 ↗(On Diff #208354)

consider implementing enum in this patch too: it's a TagDecl so you've already done almost all the work, just need to add another if here

68 ↗(On Diff #208208)

Your logic seems sound to me, but please add a comment like "This covers classes, class templates, etc"

99 ↗(On Diff #208208)

RecordDecl, unless you're trying to distinguish C++ from C for some reason

jvikstrom updated this revision to Diff 208412.Jul 8 2019, 7:40 AM
jvikstrom marked 5 inline comments as done.

Addressed comments.

jvikstrom added inline comments.Jul 8 2019, 7:52 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
73 ↗(On Diff #208208)

Do we want to highlight the entire "~Foo" or only the ~"Foo" for destructors?

jvikstrom updated this revision to Diff 208416.Jul 8 2019, 7:54 AM

Clang formatted.

hokein added inline comments.Jul 8 2019, 8:08 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
73 ↗(On Diff #208208)

based on our discussion, we'd just highlight ~"Foo" as a class type for now.

jvikstrom marked 3 inline comments as done.Jul 8 2019, 9:18 AM
hokein added a comment.Jul 9 2019, 1:59 AM

could you please also update the patch description? "non-builtin" types are not precise, this patch only highlights the class and enum types.

clang-tools-extra/clangd/SemanticHighlighting.cpp
71 ↗(On Diff #208416)

nit: you could simplify the code like

if (const auto* D = TL.getXXX)
  addToken(D->getLocation(), D);
return true;
81 ↗(On Diff #208416)

nit: move this around if (isa<RecordDecl>(D)) { since they are related to Class, and we should have a comment describing the highlighting behavior of class, constructor, and destructor.

clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
87 ↗(On Diff #208416)

could we split the enum case into a separate testcase?

Thinking it further, we may want to highlight the enumerator as well.

101 ↗(On Diff #208416)

this test case can be merged into the above case (we could add constructor/destructor to class B there)

sammccall added inline comments.Jul 9 2019, 2:24 AM
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
87 ↗(On Diff #208416)

(please don't add enum value highlighting in this patch, though)

jvikstrom updated this revision to Diff 208621.Jul 9 2019, 2:59 AM
jvikstrom marked 5 inline comments as done.

Addressed comments.

jvikstrom updated this revision to Diff 208622.Jul 9 2019, 3:00 AM

Changed commit message.

Harbormaster completed remote builds in B34575: Diff 208622.
jvikstrom retitled this revision from [clangd] Added highlighting for non-builtin types to [clangd] Added highlighting for class and enum types.Jul 9 2019, 3:00 AM
jvikstrom edited the summary of this revision. (Show Details)
jvikstrom added inline comments.Jul 9 2019, 3:04 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
81 ↗(On Diff #208416)

I don't really know what you mean with this comment after the move RecordDecl around (or rather where to put the comment and what to put in it)
I wrote a comment but don't know if that's really helpful

hokein added inline comments.Jul 9 2019, 3:49 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
38 ↗(On Diff #208622)

I don't understand this comment -- when visiting the constructor AST, we get a TagTypeLoc, and its underlying Decl is a CXXConstructorDecl

73 ↗(On Diff #208622)

From the comment of getTypePtr():

This function requires that the type not be NULL. If the type might be NULL, use the (slightly less efficient) \c getTypePtrOrNull().`

I think we should use getTypePtrOrNull if you want to check the type ptr is null.

if (const auto* Type = TL.getTypePtrOrNull()) 
  if (if (const auto* D = Type.getTagDecl())
    addToken(D->getLocation(), D);
81 ↗(On Diff #208416)

I don't really know what you mean with this comment after the move RecordDecl around (or rather where to put the comment and what to put in it)

sorry for the confusion, I meant we group "class" cases together just as what your code does now (there are going to be many of kinds, it would be clear if we break them into group and sort them).

I wrote a comment but don't know if that's really helpful

The comment should comment something not obvious but important in the code, so here we don't have a if (isa<CXXDestructorDecl>(D))) case to handle the destructor, but the code does highlight destructors -- for destructors, we get a TagTypeLoc whose underlying decl is CXXRecordDecl in VisitTypeLoc), I think it deserves a comment here.

clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
57 ↗(On Diff #208622)

just realize this case, this seems weird to me, we are highlighting a keyword struct as a class type.

jvikstrom updated this revision to Diff 208670.Jul 9 2019, 6:51 AM
jvikstrom marked 4 inline comments as done.

No longer highlighting anonymous structs as types.

jvikstrom added inline comments.Jul 9 2019, 6:52 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
38 ↗(On Diff #208622)

So the Constructor TypeLoc does not have a TagTypeDecl and is not a TagTypeLoc. When we get the TypePtr of the constructor it's a "FunctionProtoType" and there is no way to distinguish it from other functions. Therefore we need to get the constructor decls as NamedDecls..

The comment was written badly though. This version should be better now I hope.

jvikstrom updated this revision to Diff 208671.Jul 9 2019, 6:55 AM

Changed comment in addToken.

jvikstrom marked an inline comment as done.Jul 9 2019, 6:55 AM
Harbormaster completed remote builds in B34591: Diff 208671.
hokein added inline comments.Jul 9 2019, 7:37 AM
clang-tools-extra/clangd/SemanticHighlighting.cpp
52 ↗(On Diff #208671)

if you move this to addToken (and change function parameter type to NamedDecl), then you don't need the check on Line 79.

73 ↗(On Diff #208671)

nit: remove the debug dump.

77 ↗(On Diff #208671)

Again, you can save one cost of TL.getTypePtr().

if (const auto* TypePtr = TL.getTypePtr())
  if (const auto* TD = TypePtr->getAsTagDecl())
87 ↗(On Diff #208671)

how about?

We highlight class decls, constructor decls and destructor decls as `Class` type. The destructor decls are handled in `VisitTypeLoc` (we will visit a TypeLoc where the underlying Type is a CXXRecordDecl).
38 ↗(On Diff #208622)

ah, I see, that make senses, thanks for the explanation.

jvikstrom updated this revision to Diff 208708.Jul 9 2019, 8:58 AM
jvikstrom marked 4 inline comments as done.

Addressed comments.

(Thanks for addressing my comments earlier. I don't have more concerns, but haven't been following the last revisions in detail so will leave approval to Haojian)

nridge added a subscriber: nridge.Jul 9 2019, 5:04 PM

@jvikstrom out of curiosity, are you testing these patches against a client-side implementation of semantic highlighting? If so, which one?

@jvikstrom out of curiosity, are you testing these patches against a client-side implementation of semantic highlighting? If so, which one?

Yes, I am testing against Theia. Just modified the Theia c++ language client to include the semantic highlighting service.

hokein accepted this revision.Jul 10 2019, 1:20 AM

thanks, looks good.

clang-tools-extra/clangd/SemanticHighlighting.cpp
83 ↗(On Diff #208708)

this comment doesn't belong to the if statement below, should move to Line 87.

This revision is now accepted and ready to land.Jul 10 2019, 1:20 AM

are you testing these patches against a client-side implementation of semantic highlighting? If so, which one?

Looks like Theia is the only LSP client supporting the semantic highlighting proposal, we use it to verify the behavior.

And we also have a hidden tweak (run clangd with -hidden-feature) to annotate all the highlighting tokens, we use it to verify whether the token is being highlighted in a correct TextMate scope (it is triggered via the codeAction in VSCode).

This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptJul 10 2019, 1:43 AM