[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
Sun Jul 7 08:47:49 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())
+ return addLabel(
+ [&](llvm::raw_ostream &OS) { return RD->printName(OS, PP); },
+ [&] { return nameLocation(*RD, SM); });
+ return VisitType(TT);
+ }
+
+ void VisitEnumType(const EnumType *ET) {
+ return addLabel(
+ [&](llvm::raw_ostream &OS) { return ET->getDecl()->printName(OS, PP); },
+ [&] { return nameLocation(*ET->getDecl(), SM); });
+ }
+
+ void VisitAutoType(const AutoType *AT) {
+ if (!AT->isDeduced() || AT->getDeducedType()->isDecltypeType())
+ return;
+ maybeAddQualifiers();
+ CurrentTypeRAII Guard(*this, AT->getDeducedType());
+ return Visit(AT->getDeducedType().getTypePtr());
+ }
+
+ void VisitElaboratedType(const ElaboratedType *ET) {
+ maybeAddQualifiers();
+ if (auto *NNS = ET->getQualifier()) {
+ switch (NNS->getKind()) {
+ case NestedNameSpecifier::Identifier:
+ case NestedNameSpecifier::Namespace:
+ case NestedNameSpecifier::NamespaceAlias:
+ case NestedNameSpecifier::Global:
+ case NestedNameSpecifier::Super: {
+ std::string Label;
+ llvm::raw_string_ostream OS(Label);
+ NNS->print(OS, PP);
+ addLabel(std::move(Label));
+ } break;
+ case NestedNameSpecifier::TypeSpec:
+ case NestedNameSpecifier::TypeSpecWithTemplate:
+ CurrentTypeRAII Guard(
+ *this,
+ QualType(
+ NNS->getAsType(),
+ /*Quals=*/0) // Do we need cv-qualifiers on type specifiers?
+ );
+ Visit(NNS->getAsType());
+ addLabel("::");
+ break;
+ }
+ }
+ CurrentTypeRAII Guard(*this, ET->getNamedType(), ET->getQualifier());
+ return Visit(ET->getNamedType().getTypePtr());
+ }
+
+ void VisitReferenceType(const ReferenceType *RT) {
+ maybeAddQualifiers();
+ QualType Next = skipTopLevelReferences(RT->getPointeeTypeAsWritten());
+ CurrentTypeRAII Guard(*this, Next);
+ Visit(Next.getTypePtr());
+ if (Next->getPointeeType().isNull())
+ addLabel(" ");
+ if (RT->isLValueReferenceType())
+ addLabel("&");
+ if (RT->isRValueReferenceType())
+ addLabel("&&");
+ }
+
+ void VisitPointerType(const PointerType *PT) {
+ QualType Next = PT->getPointeeType();
+ std::optional<CurrentTypeRAII> Guard(std::in_place, *this, Next);
+ Visit(Next.getTypePtr());
+ if (Next->getPointeeType().isNull())
+ addLabel(" ");
+ addLabel("*");
+ Guard.reset();
+ maybeAddQualifiers();
+ }
+
+ void VisitUsingType(const UsingType *UT) {
+ addLabel([&](llvm::raw_ostream &OS) { UT->getFoundDecl()->printName(OS); },
+ [&] {
+ BaseUsingDecl *Introducer = UT->getFoundDecl()->getIntroducer();
+ if (auto *UD = dyn_cast<UsingDecl>(Introducer))
+ return nameLocation(*UD, SM);
+ return nameLocation(*Introducer, SM);
+ });
+ }
+
+ void VisitTypedefType(const TypedefType *TT) {
+ addLabel([&](llvm::raw_ostream &OS) { TT->getDecl()->printName(OS); },
+ [&] { return nameLocation(*TT->getDecl(), SM); });
+ }
+
+ void VisitTemplateSpecializationType(const TemplateSpecializationType *TST) {
----------------
zyn0217 wrote:
Hmm, looks like the handling in VisitTagType() has turned into dead codes in the past commits. I'll remove anyway.
https://github.com/llvm/llvm-project/pull/86629
More information about the cfe-commits
mailing list