templateSpecializationTypeLoc ASTMatcher does not work as shown in documentation example

The documentation for templateSpecializationTypeLoc (in https://clang.llvm.org/docs/LibASTMatchersReference.html) gives the following example for its usage:

Given
template <typename T> class C {};
C<char> var;
varDecl(hasTypeLoc(templateSpecializationTypeLoc(typeLoc())))
matches C<char> var.

However, testing this via clang-query seems to show that this is not the case: https://godbolt.org/z/69Md3fsoM. I am looking for a way to match only the shared_ptr part of std::shared_ptr<int>, and this seems to be the matcher that would help narrow it down. Is this a known issue, and if so, is there a workaround?

Upon closer inspection, it seems that the reason this is not matched correctly is because C<char> is parsed as an ElaboratedTypeLoc instead of a TemplateSpecializationTypeLoc. Thus varDecl(hasTypeLoc(elaboratedTypeLoc(typeLoc()))) generates a match for the example shown for the templateSpecializationTypeLoc ASTMatcher. However, this means that the more specific API given by TemplateSpecializationTypeLoc is inaccessible when matching in that way.

Good catch.
The example in the reference seems unnecessarily complex (and erroneous as you pointed out).
It would probably make the most sense for it to be similar to the example provided for templateSpecializationType as they have the same behavior but with templateSpecializationTypeLoc matching the SourceLocation.

To my knowledge, a matcher that returns a class template without the template list does not exist, and I don’t think it would be trivial to implement one. I could be wrong though.

If you are simply interested in retrieving the SourceLocation for the shared_ptr part (without namespace and template list) then it would probably be easier to implement using a RangeSelector. See RangeSelector.h/.cpp for such examples.

Let me know if you need more pointers on how these work as the lack of documentation can be a bit overwhelming at first.