================ @@ -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:
I think I was making sure if the D is actually *not* a specialization of a template - otherwise, we probably end up printing the whole template arguments together here. (I have a vague memory, so I could be wrong. I'll be back with an example.) 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