[clang-tools-extra] [clangd] Support go-to-definition on type hints. The core part (PR #86629)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Mon Jul 8 02:06:21 PDT 2024
================
@@ -372,6 +374,292 @@ maybeDropCxxExplicitObjectParameters(ArrayRef<const ParmVarDecl *> Params) {
return Params;
}
+class TypeInlayHintLabelPartBuilder
+ : public TypeVisitor<TypeInlayHintLabelPartBuilder> {
+ QualType CurrentType;
+ NestedNameSpecifier *CurrentNestedNameSpecifier;
+ ASTContext &Context;
+ StringRef MainFilePath;
+ const PrintingPolicy &PP;
+ SourceManager &SM;
+ std::vector<InlayHintLabelPart> &LabelChunks;
+
+ struct CurrentTypeRAII {
+ TypeInlayHintLabelPartBuilder &Builder;
+ QualType PreviousType;
+ NestedNameSpecifier *PreviousNestedNameSpecifier;
+ CurrentTypeRAII(TypeInlayHintLabelPartBuilder &Builder, QualType New,
+ NestedNameSpecifier *NNS = nullptr)
+ : Builder(Builder), PreviousType(Builder.CurrentType),
+ PreviousNestedNameSpecifier(Builder.CurrentNestedNameSpecifier) {
+ Builder.CurrentType = New;
+ if (NNS)
+ Builder.CurrentNestedNameSpecifier = NNS;
+ }
+ ~CurrentTypeRAII() {
+ Builder.CurrentType = PreviousType;
+ Builder.CurrentNestedNameSpecifier = PreviousNestedNameSpecifier;
+ }
+ };
+
+ void addLabel(llvm::function_ref<void(llvm::raw_ostream &)> NamePrinter,
+ llvm::function_ref<SourceLocation()> SourceLocationGetter) {
+ std::string Label;
+ llvm::raw_string_ostream OS(Label);
+ NamePrinter(OS);
+ auto &Name = LabelChunks.emplace_back();
+ Name.value = std::move(Label);
+ Name.location = makeLocation(Context, SourceLocationGetter(), MainFilePath);
+ }
+
+ void addLabel(std::string Label) {
+ if (LabelChunks.empty()) {
+ LabelChunks.emplace_back(std::move(Label));
+ return;
+ }
+ auto &Back = LabelChunks.back();
+ if (Back.location) {
+ LabelChunks.emplace_back(std::move(Label));
+ return;
+ }
+ // Let's combine the "unclickable" pieces together.
+ Back.value += std::move(Label);
+ }
+
+ void printTemplateArgumentList(llvm::ArrayRef<TemplateArgument> Args) {
+ unsigned Size = Args.size();
+ for (unsigned I = 0; I < Size; ++I) {
+ auto &TA = Args[I];
+ if (PP.SuppressDefaultTemplateArgs && TA.getIsDefaulted())
+ continue;
+ if (I)
+ addLabel(", ");
+ printTemplateArgument(TA);
+ }
+ }
+
+ void printTemplateArgument(const TemplateArgument &TA) {
+ switch (TA.getKind()) {
+ case TemplateArgument::Pack:
+ return printTemplateArgumentList(TA.pack_elements());
+ case TemplateArgument::Type: {
+ CurrentTypeRAII Guard(*this, TA.getAsType());
+ return Visit(TA.getAsType().getTypePtr());
+ }
+ // TODO: Add support for NTTP arguments.
+ case TemplateArgument::Expression:
+ case TemplateArgument::StructuralValue:
+ case TemplateArgument::Null:
+ case TemplateArgument::Declaration:
+ case TemplateArgument::NullPtr:
+ case TemplateArgument::Integral:
+ case TemplateArgument::Template:
+ case TemplateArgument::TemplateExpansion:
+ break;
+ }
+ std::string Label;
+ llvm::raw_string_ostream OS(Label);
+ TA.print(PP, OS, /*IncludeType=*/true);
+ addLabel(std::move(Label));
+ }
+
+ void handleTemplateSpecialization(
+ TemplateName TN, llvm::ArrayRef<TemplateArgument> Args,
+ SourceLocation TemplateNameLocation = SourceLocation()) {
+ SourceLocation Location;
+ TemplateDecl *TD = nullptr;
+ auto PrintType = TemplateName::Qualified::AsWritten;
+ switch (TN.getKind()) {
+ case TemplateName::Template:
+ TD = TN.getAsTemplateDecl();
+ Location = nameLocation(*TD, SM);
+ break;
+ case TemplateName::QualifiedTemplate:
+ if (NestedNameSpecifier *NNS =
+ TN.getAsQualifiedTemplateName()->getQualifier();
+ NNS == CurrentNestedNameSpecifier) {
+ // We have handled the NNS in VisitElaboratedType(). Avoid printing it
+ // twice.
+ TN = TN.getAsQualifiedTemplateName()->getUnderlyingTemplate();
+ PrintType = TemplateName::Qualified::None;
+ }
+ break;
+ case TemplateName::OverloadedTemplate:
+ case TemplateName::AssumedTemplate:
+ case TemplateName::DependentTemplate:
+ case TemplateName::SubstTemplateTemplateParm:
+ case TemplateName::SubstTemplateTemplateParmPack:
+ case TemplateName::UsingTemplate:
+ break;
+ }
+
+ addLabel([&](llvm::raw_ostream &OS) { TN.print(OS, PP, PrintType); },
+ [&] {
+ if (TemplateNameLocation.isValid())
+ return TemplateNameLocation;
+ return Location;
+ });
+
+ addLabel("<");
+ printTemplateArgumentList(Args);
+ addLabel(">");
+ }
+
+ void maybeAddQualifiers() {
+ auto Quals = CurrentType.split().Quals;
+ if (!Quals.empty()) {
+ addLabel(Quals.getAsString());
+ addLabel(" ");
+ }
+ }
+
+ // When printing a reference, the referenced type might also be a reference.
+ // If so, we want to skip that before printing the inner type.
+ static QualType skipTopLevelReferences(QualType T) {
+ if (auto *Ref = T->getAs<ReferenceType>())
+ return skipTopLevelReferences(Ref->getPointeeTypeAsWritten());
+ return T;
+ }
+
+public:
+ TypeInlayHintLabelPartBuilder(QualType Current, ASTContext &Context,
+ StringRef MainFilePath,
+ const PrintingPolicy &PP,
+ llvm::StringRef Prefix,
+ std::vector<InlayHintLabelPart> &LabelChunks)
+ : CurrentType(Current), CurrentNestedNameSpecifier(nullptr),
+ Context(Context), MainFilePath(MainFilePath), PP(PP),
+ SM(Context.getSourceManager()), LabelChunks(LabelChunks) {
+ LabelChunks.reserve(16);
+ if (!Prefix.empty())
+ addLabel(Prefix.str());
+ }
+
+ void VisitType(const Type *) { addLabel(CurrentType.getAsString(PP)); }
+
+ void VisitTagType(const TagType *TT) {
+ auto *D = TT->getDecl();
+ if (auto *Specialization = dyn_cast<ClassTemplateSpecializationDecl>(D))
+ return handleTemplateSpecialization(
+ TemplateName(Specialization->getSpecializedTemplate()),
+ Specialization->getTemplateArgs().asArray());
+ if (auto *RD = dyn_cast<CXXRecordDecl>(D);
+ RD && !RD->getTemplateInstantiationPattern())
----------------
zyn0217 wrote:
Yeah, for example, given
```cpp
template <typename, typename = int>
struct A {};
A<float> bar[1];
auto [value] = bar;
```
where the type AST of `value` looks like:
```cpp
RecordType 0x7fd8dc0fac00 'A<float>'
`-ClassTemplateSpecialization 0x7fd8dc0faaf0 'A'
```
so we might have cases where the class template specialization is modeled as a `RecordType` rather than a `TemplateSpecializationType`.
https://github.com/llvm/llvm-project/pull/86629
More information about the cfe-commits
mailing list