Added highlighting for class and enum types using VisitTypeLoc. Ignoring namespace qualifiers as for now.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
- Build Status
Buildable 34574 Build 34573: arc lint + arc unit
Event Timeline
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
75 | We are only interested in TagDecl, maybe use the VisitTagLoc callback, so that you can get rid of the filtering code above. | |
79 | nit: auto => const auto *, we usually spell out the pointer type explicitly. | |
80 | 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? | |
104 | nit: clang-format | |
215 | entity.name.type.class.cpp? | |
clang-tools-extra/clangd/SemanticHighlighting.h | ||
29 | 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? |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
75 | 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... |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
67 | 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? | |
68 | 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" | |
75 | Your logic seems sound to me, but please add a comment like "This covers classes, class templates, etc" | |
76 | 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...) | |
79 | 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:
| |
104 | RecordDecl, unless you're trying to distinguish C++ from C for some reason | |
104 | 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 |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
80 | Do we want to highlight the entire "~Foo" or only the ~"Foo" for destructors? |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
80 | based on our discussion, we'd just highlight ~"Foo" as a class type for now. |
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 | ||
---|---|---|
73 | nit: you could simplify the code like if (const auto* D = TL.getXXX) addToken(D->getLocation(), D); return true; | |
83 | 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 | ||
89 | could we split the enum case into a separate testcase? Thinking it further, we may want to highlight the enumerator as well. | |
103 | this test case can be merged into the above case (we could add constructor/destructor to class B there) |
clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp | ||
---|---|---|
89 | (please don't add enum value highlighting in this patch, though) |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
83 | 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) |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
38–45 | I don't understand this comment -- when visiting the constructor AST, we get a TagTypeLoc, and its underlying Decl is a CXXConstructorDecl | |
73 | From the comment of getTypePtr():
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); | |
83 |
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).
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 | just realize this case, this seems weird to me, we are highlighting a keyword struct as a class type. |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
38–45 | 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. |
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
38–45 | ah, I see, that make senses, thanks for the explanation. | |
49 | if you move this to addToken (and change function parameter type to NamedDecl), then you don't need the check on Line 79. | |
70 | nit: remove the debug dump. | |
74 | Again, you can save one cost of TL.getTypePtr(). if (const auto* TypePtr = TL.getTypePtr()) if (const auto* TD = TypePtr->getAsTagDecl()) | |
83 | 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). |
(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)
@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.
thanks, looks good.
clang-tools-extra/clangd/SemanticHighlighting.cpp | ||
---|---|---|
85 | this comment doesn't belong to the if statement below, should move to Line 87. |
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).
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?