[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-16 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

Sorry, that was a bad example as it's not actually valid. Here's a slightly 
modified one:

  template 
  class a {};
  
  constexpr int b = 2;
  constexpr int c = 3;
  constexpr int d = 4;
  
  a e;

The parser knows the first `<` opens a template-param-list because the name 
before it, `a`, resolves to a template-name, and that the second `<` is a 
comparison operator because the name before //that//, `b`, does not.

But a native client-side matcher might incorrectly pick the second `<` as the 
opening angle-bracket to match the `>`.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-16 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

In D139926#4056478 , @kadircet wrote:

> This will only make sure we have a distinction between `<<` and `>>` used as 
> operators vs `<`/`>`

Note that `<<` and `>>` are not the only (or even the primary, in my mind) 
issue: there is an ambiguity between `<`/`>` as template argument list 
delimiters vs. comparison operators.

For example:

  template 
  class a {};
  
  constexpr int b = 2;
  constexpr int c = 3;
  
  ac> e;

Here, if the cursor is next to the `<`, a naive client-side angle-bracket 
matcher might highlight the first `>`, when the correct one to highlight would 
be the second one.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-16 Thread Christian Kandeler via Phabricator via cfe-commits
ckandeler added a comment.

In D139926#4056585 , @kadircet wrote:

> Especially as this comes as two different `HighlightingKind`s and they're 
> likely to get colored differently, and having your matching brackets in 
> different colors is quite annoying.

We can easily check the actual character at the given position in the client, 
so I could just merge the two highlighting kinds.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-16 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added a comment.

> Note that we use this information to *animate* the matching tokens, i.e. when 
> the cursor is on one of them, both it and its counterpart get a special 
> highlighting. That's why it's so important that the language server 
> guarantees they always come in pairs.

Oh I see the argument here (somehow missed comment, probably because i had a 
stale window lying around), this totally makes sense. but I am still feeling 
uneasy due to implementation complexity (it's embarrassing but dealing with 
`>>` is quite problematic, still, with little value :/) + the UX we'll have in 
other editors by default.
Especially as this comes as two different `HighlightingKind`s and they're 
likely to get colored differently, and having your matching brackets in 
different colors is quite annoying.

I feel like editors can still have a quite good behaviour with existing 
operator highlights, as one can build an extra layer on top to provide 
"matching bracket" support, and whenever the data is broken (e.g. non-matching 
brackets) just keep using the results from last "successful" run.




Comment at: clang-tools-extra/clangd/SemanticHighlighting.cpp:408
+  Position End = Begin;
+  ++End.character;
+  addToken(*LRange, HighlightingKind::AngleBracketOpen);

there can be weird cases like (same goes for -1 below):
```foo>\
>```

can you add tests to make sure we're handling these properly (or not producing 
braces for them if it complicates the logic too much, i don't think there'll be 
many cases where they pop-up).



Comment at: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp:930
+  $Class[[B]] $LocalVariable_def[[b]];
+  int $LocalVariable_def[[i]] = 
static_cast$AngleBracketOpen[[<]]int$AngleBracketClose[[>]](3.5);
+  void *$LocalVariable_def[[p]] = 
reinterpret_cast$AngleBracketOpen[[<]]void *$AngleBracketClose[[>]](0);

could you also add tests for `>>` and `>>>` to make sure they're handled 
correctly


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-16 Thread Kadir Cetinkaya via Phabricator via cfe-commits
kadircet added a comment.

Sorry for missing this one, apparently I've already started writing an answer 
but got context switching and forgot about it.

> This is needed for clients that would like to visualize matching
> opening and closing angle brackets, which can be valuable in non-trivial
> template declarations or instantiations.

I am not sure how the clients will make use of this information to visualize 
"matching" angle brackets. all the opening and closing brackets are likely to 
be visualized in the same way (respectively), no?
This will only make sure we have a distinction between `<<` and `>>` used as 
operators vs `<`/`>` and the rest of the work to highlight matching braces 
needs to be specially done by the editor.
Since we've the distinction of "operator" now as @nridge pointed out, I would 
rather want editors to use that information to skip brackets that have the 
operator highlighting.
I am not sure what concrete cases you've (it would help if you could provide 
some examples) for the incomplete code argument, because it goes both ways, 
i.e. I don't think the false positives you get in operators vs template 
argument lists won't be any different (e.g. foo x, where `foo` is not 
defined won't have right highlighting).


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-09 Thread Christian Kandeler via Phabricator via cfe-commits
ckandeler added a comment.

In D139926#4033152 , @nridge wrote:

> In D139926#4032473 , @ckandeler 
> wrote:
>
>> In D139926#4030782 , @nridge wrote:
>>
>>> It's true that there is an ambiguity between `<` and `>` as operators, vs. 
>>> template arg/param list delimiters, but, at least in terms of user 
>>> understanding of code, my sense is that the highlighting of the 
>>> **preceding** token should be sufficient to disambiguate -- i.e. it would 
>>> be some sort of type name in the template case, vs. a variable / literal / 
>>> punctuation ending an expression in the operator case.
>>
>> We used to do this sort of heuristic in our old libclang-based 
>> implementation, and it turned out to be rather messy, with a surprising 
>> amount of exceptions having to be added.
>
> To clarify, I'm not suggesting that any client-side logic use this heuristic, 
> only that it's probably good enough for a human reader to disambiguate 
> without needing to assign angle brackets and comparison operators different 
> colors.

Note that we use this information to *animate* the matching tokens, i.e. when 
the cursor is on one of them, both it and its counterpart get a special 
highlighting. That's why it's so important that the language server guarantees 
they always come in pairs.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-07 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

In D139926#4032473 , @ckandeler wrote:

> In D139926#4030782 , @nridge wrote:
>
>> It's true that there is an ambiguity between `<` and `>` as operators, vs. 
>> template arg/param list delimiters, but, at least in terms of user 
>> understanding of code, my sense is that the highlighting of the 
>> **preceding** token should be sufficient to disambiguate -- i.e. it would be 
>> some sort of type name in the template case, vs. a variable / literal / 
>> punctuation ending an expression in the operator case.
>
> We used to do this sort of heuristic in our old libclang-based 
> implementation, and it turned out to be rather messy, with a surprising 
> amount of exceptions having to be added.

To clarify, I'm not suggesting that any client-side logic use this heuristic, 
only that it's probably good enough for a human reader to disambiguate without 
needing to assign angle brackets and comparison operators different colors.

>>> This is needed for clients that would like to visualize matching opening 
>>> and closing angle brackets, which can be valuable in non-trivial template 
>>> declarations or instantiations.
>>
>> For this use case, could an editor make use of the recently added operator 
>> tokens (https://reviews.llvm.org/D136594) instead, inferring that a `<` 
>> token which does not have an `operator` semantic token is a template 
>> delimiter?
>
> I have a suspicion that this will lead to false positives for invalid code.

Ah, interesting. I guess in the case of invalid code (no/malformed AST) you 
wouldn't get AngleBracket tokens either, so this gives you a three-way signal 
(Operator vs. AngleBracket vs. no semantic token) that's richer than just the 
two-way signal of Operator vs. no Operator.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-06 Thread Christian Kandeler via Phabricator via cfe-commits
ckandeler added a comment.

In D139926#4030782 , @nridge wrote:

> It's true that there is an ambiguity between `<` and `>` as operators, vs. 
> template arg/param list delimiters, but, at least in terms of user 
> understanding of code, my sense is that the highlighting of the **preceding** 
> token should be sufficient to disambiguate -- i.e. it would be some sort of 
> type name in the template case, vs. a variable / literal / punctuation ending 
> an expression in the operator case.

We used to do this sort of heuristic in our old libclang-based implementation, 
and it turned out to be rather messy, with a surprising amount of exceptions 
having to be added.

>> This is needed for clients that would like to visualize matching opening and 
>> closing angle brackets, which can be valuable in non-trivial template 
>> declarations or instantiations.
>
> For this use case, could an editor make use of the recently added operator 
> tokens (https://reviews.llvm.org/D136594) instead, inferring that a `<` token 
> which does not have an `operator` semantic token is a template delimiter?

I have a suspicion that this will lead to false positives for invalid code.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2023-01-06 Thread Nathan Ridge via Phabricator via cfe-commits
nridge added a comment.

I'm happy to review the implementation, but I would first appreciate some 
guidance from @sammccall or @kadircet about whether we should add these 
semantic token kinds in the first place.

They would be a non-standard extension to the LSP token kinds, so I think the 
use case for them should be fairly compelling.

It's true that there is an ambiguity between `<` and `>` as operators, vs. 
template arg/param list delimiters, but, at least in terms of user 
understanding of code, my sense is that the highlighting of the **preceding** 
token should be sufficient to disambiguate -- i.e. it would be some sort of 
type name in the template case, vs. a variable / literal / punctuation ending 
an expression in the operator case.

> This is needed for clients that would like to visualize matching opening and 
> closing angle brackets, which can be valuable in non-trivial template 
> declarations or instantiations.

For this use case, could an editor make use of the recently added operator 
tokens (https://reviews.llvm.org/D136594) instead, inferring that a `<` token 
which does not have an `operator` semantic token is a template delimiter?


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

___
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2022-12-13 Thread Christian Kandeler via Phabricator via cfe-commits
ckandeler updated this revision to Diff 482422.
ckandeler added a comment.

Rebased.


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D139926/new/

https://reviews.llvm.org/D139926

Files:
  clang-tools-extra/clangd/SemanticHighlighting.cpp
  clang-tools-extra/clangd/SemanticHighlighting.h
  clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
===
--- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -130,17 +130,17 @@
 )cpp",
   R"cpp(
   namespace $Namespace_decl[[abc]] {
-template
+template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
 struct $Class_def[[A]] {
   $TemplateParameter[[T]] $Field_decl[[t]];
 };
   }
-  template
-  struct $Class_def[[C]] : $Namespace[[abc]]::$Class[[A]]<$TemplateParameter[[T]]> {
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
+  struct $Class_def[[C]] : $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]$TemplateParameter[[T]]$AngleBracketClose[[>]] {
 typename $TemplateParameter[[T]]::$Type_dependentName[[A]]* $Field_decl[[D]];
   };
-  $Namespace[[abc]]::$Class[[A]] $Variable_def[[AA]];
-  typedef $Namespace[[abc]]::$Class[[A]] $Class_decl[[AAA]];
+  $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]int$AngleBracketClose[[>]] $Variable_def[[AA]];
+  typedef $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]int$AngleBracketClose[[>]] $Class_decl[[AAA]];
   struct $Class_def[[B]] {
 $Class_decl_constrDestr[[B]]();
 ~$Class_decl_constrDestr[[B]]();
@@ -243,36 +243,36 @@
   typedef float $Primitive_decl[[F]];
 )cpp",
   R"cpp(
-  template
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]], typename = void$AngleBracketClose[[>]]
   class $Class_def[[A]] {
 $TemplateParameter[[T]] $Field_decl[[AA]];
 $TemplateParameter[[T]] $Method_decl[[foo]]();
   };
-  template
+  template$AngleBracketOpen[[<]]class $TemplateParameter_def[[TT]]$AngleBracketClose[[>]]
   class $Class_def[[B]] {
-$Class[[A]]<$TemplateParameter[[TT]]> $Field_decl[[AA]];
+$Class[[A]]$AngleBracketOpen[[<]]$TemplateParameter[[TT]]$AngleBracketClose[[>]] $Field_decl[[AA]];
   };
-  template
+  template$AngleBracketOpen[[<]]class $TemplateParameter_def[[TT]], class $TemplateParameter_def[[GG]]$AngleBracketClose[[>]]
   class $Class_def[[BB]] {};
   template
   class $Class_def[[BB]]<$TemplateParameter[[T]], int> {};
   template
   class $Class_def[[BB]]<$TemplateParameter[[T]], $TemplateParameter[[T]]*> {};
 
-  template class $TemplateParameter_def[[T]], class $TemplateParameter_def[[C]]>
-  $TemplateParameter[[T]]<$TemplateParameter[[C]]> $Function_decl[[f]]();
+  template$AngleBracketOpen[[<]]template$AngleBracketOpen[[<]]class$AngleBracketClose[[>]] class $TemplateParameter_def[[T]], class $TemplateParameter_def[[C]]$AngleBracketClose[[>]]
+  $TemplateParameter[[T]]$AngleBracketOpen[[<]]$TemplateParameter[[C]]$AngleBracketClose[[>]] $Function_decl[[f]]();
 
-  template
+  template$AngleBracketOpen[[<]]typename$AngleBracketClose[[>]]
   class $Class_def[[Foo]] {};
 
-  template
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
   void $Function_decl[[foo]]($TemplateParameter[[T]] ...);
 )cpp",
   R"cpp(
-  template 
+  template $AngleBracketOpen[[<]]class $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
   struct $Class_def[[Tmpl]] {$TemplateParameter[[T]] $Field_decl[[x]] = 0;};
-  extern template struct $Class_def[[Tmpl]];
-  template struct $Class_def[[Tmpl]];
+  extern template struct $Class_def[[Tmpl]]$AngleBracketOpen[[<]]float$AngleBracketClose[[>]];
+  template struct $Class_def[[Tmpl]]$AngleBracketOpen[[<]]double$AngleBracketClose[[>]];
 )cpp",
   // This test is to guard against highlightings disappearing when using
   // conversion operators as their behaviour in the clang AST differ from
@@ -335,17 +335,17 @@
 )cpp",
   R"cpp(
   class $Class_def[[G]] {};
-  template<$Class[[G]] *$TemplateParameter_def_readonly[[U]]>
+  template$AngleBracketOpen[[<]]$Class[[G]] *$TemplateParameter_def_readonly[[U]]$AngleBracketClose[[>]]
   class $Class_def[[GP]] {};
-  template<$Class[[G]] &$TemplateParameter_def_readonly[[U]]>
+  template$AngleBracketOpen[[<]]$Class[[G]] &$TemplateParameter_def_readonly[[U]]$AngleBracketClose[[>]]
   class $Class_def[[GR]] {};
-  template
+  template$AngleBracketOpen[[<]]int 

[PATCH] D139926: [clangd] Add semantic tokens for angle brackets

2022-12-13 Thread Christian Kandeler via Phabricator via cfe-commits
ckandeler created this revision.
ckandeler added a reviewer: sammccall.
Herald added subscribers: kadircet, arphaman.
Herald added a project: All.
ckandeler requested review of this revision.
Herald added subscribers: cfe-commits, MaskRay, ilya-biryukov.
Herald added a project: clang-tools-extra.

This is needed for clients that would like to visualize matching
opening and closing angle brackets, which can be valuable in non-trivial
template declarations or instantiations.
It is not possible to do this with simple lexing, as the tokens
could also refer to operators.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D139926

Files:
  clang-tools-extra/clangd/SemanticHighlighting.cpp
  clang-tools-extra/clangd/SemanticHighlighting.h
  clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp

Index: clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
===
--- clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
+++ clang-tools-extra/clangd/unittests/SemanticHighlightingTests.cpp
@@ -130,17 +130,17 @@
 )cpp",
   R"cpp(
   namespace $Namespace_decl[[abc]] {
-template
+template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
 struct $Class_def[[A]] {
   $TemplateParameter[[T]] $Field_decl[[t]];
 };
   }
-  template
-  struct $Class_def[[C]] : $Namespace[[abc]]::$Class[[A]]<$TemplateParameter[[T]]> {
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
+  struct $Class_def[[C]] : $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]$TemplateParameter[[T]]$AngleBracketClose[[>]] {
 typename $TemplateParameter[[T]]::$Type_dependentName[[A]]* $Field_decl[[D]];
   };
-  $Namespace[[abc]]::$Class[[A]] $Variable_def[[AA]];
-  typedef $Namespace[[abc]]::$Class[[A]] $Class_decl[[AAA]];
+  $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]int$AngleBracketClose[[>]] $Variable_def[[AA]];
+  typedef $Namespace[[abc]]::$Class[[A]]$AngleBracketOpen[[<]]int$AngleBracketClose[[>]] $Class_decl[[AAA]];
   struct $Class_def[[B]] {
 $Class_decl_constrDestr[[B]]();
 ~$Class_decl_constrDestr[[B]]();
@@ -243,36 +243,36 @@
   typedef float $Primitive_decl[[F]];
 )cpp",
   R"cpp(
-  template
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]], typename = void$AngleBracketClose[[>]]
   class $Class_def[[A]] {
 $TemplateParameter[[T]] $Field_decl[[AA]];
 $TemplateParameter[[T]] $Method_decl[[foo]]();
   };
-  template
+  template$AngleBracketOpen[[<]]class $TemplateParameter_def[[TT]]$AngleBracketClose[[>]]
   class $Class_def[[B]] {
-$Class[[A]]<$TemplateParameter[[TT]]> $Field_decl[[AA]];
+$Class[[A]]$AngleBracketOpen[[<]]$TemplateParameter[[TT]]$AngleBracketClose[[>]] $Field_decl[[AA]];
   };
-  template
+  template$AngleBracketOpen[[<]]class $TemplateParameter_def[[TT]], class $TemplateParameter_def[[GG]]$AngleBracketClose[[>]]
   class $Class_def[[BB]] {};
   template
   class $Class_def[[BB]]<$TemplateParameter[[T]], int> {};
   template
   class $Class_def[[BB]]<$TemplateParameter[[T]], $TemplateParameter[[T]]*> {};
 
-  template class $TemplateParameter_def[[T]], class $TemplateParameter_def[[C]]>
-  $TemplateParameter[[T]]<$TemplateParameter[[C]]> $Function_decl[[f]]();
+  template$AngleBracketOpen[[<]]template$AngleBracketOpen[[<]]class$AngleBracketClose[[>]] class $TemplateParameter_def[[T]], class $TemplateParameter_def[[C]]$AngleBracketClose[[>]]
+  $TemplateParameter[[T]]$AngleBracketOpen[[<]]$TemplateParameter[[C]]$AngleBracketClose[[>]] $Function_decl[[f]]();
 
-  template
+  template$AngleBracketOpen[[<]]typename$AngleBracketClose[[>]]
   class $Class_def[[Foo]] {};
 
-  template
+  template$AngleBracketOpen[[<]]typename $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
   void $Function_decl[[foo]]($TemplateParameter[[T]] ...);
 )cpp",
   R"cpp(
-  template 
+  template $AngleBracketOpen[[<]]class $TemplateParameter_def[[T]]$AngleBracketClose[[>]]
   struct $Class_def[[Tmpl]] {$TemplateParameter[[T]] $Field_decl[[x]] = 0;};
-  extern template struct $Class_def[[Tmpl]];
-  template struct $Class_def[[Tmpl]];
+  extern template struct $Class_def[[Tmpl]]$AngleBracketOpen[[<]]float$AngleBracketClose[[>]];
+  template struct $Class_def[[Tmpl]]$AngleBracketOpen[[<]]double$AngleBracketClose[[>]];
 )cpp",
   // This test is to guard against highlightings disappearing when using
   // conversion operators as their behaviour in the clang AST differ from
@@ -335,17 +335,17 @@
 )cpp",
   R"cpp(
   class $Class_def[[G]] {};
-  template<$Class[[G]] *$TemplateParameter_def_readonly[[U]]>
+