================ @@ -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) { + maybeAddQualifiers(); + SourceLocation Location; + if (auto *Specialization = + dyn_cast_if_present<ClassTemplateSpecializationDecl>( + TST->desugar().getCanonicalType()->getAsCXXRecordDecl())) + Location = nameLocation(*Specialization, SM); + return handleTemplateSpecialization(TST->getTemplateName(), + TST->template_arguments(), Location); + } + + void VisitSubstTemplateTypeParmType(const SubstTemplateTypeParmType *ST) { + maybeAddQualifiers(); + CurrentTypeRAII Guard(*this, ST->getReplacementType()); + return Visit(ST->getReplacementType().getTypePtr()); + } +}; + +unsigned lengthOfInlayHintLabelPart(llvm::ArrayRef<InlayHintLabelPart> Labels) { ---------------- HighCommander4 wrote:
I would suggest calling it "lengthOfInlayHintLabel" (or otherwise "lengthOfInlayHintLabelPart**s**") https://github.com/llvm/llvm-project/pull/86629 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits