@@ -344,43 +344,61 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
344344 }
345345 }
346346
347- clang::QualType createMirrorType (llvm::StringRef name, clang::QualType hint) {
348- clang::ASTContext &ctx = sema_->Context ;
349- forceCompleteDefinition (hint);
347+ clang::QualType
348+ getTemplateIdType (clang::ClassTemplateDecl *decl,
349+ llvm::ArrayRef<clang::TemplateArgument> args) {
350+ clang::TemplateArgumentListInfo info (loc_, loc_);
351+ for (const clang::TemplateArgument &arg : args) {
352+ info.addArgument (
353+ sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
354+ }
355+ return sema_->CheckTemplateIdType (clang::ElaboratedTypeKeyword::None,
356+ clang::TemplateName (decl), loc_, info,
357+ sema_->getCurScope (),
358+ /* ForNestedNameSpecifier=*/ false );
359+ }
350360
351- const auto *hdecl = hint->getAsCXXRecordDecl ();
352- assert (hdecl && " Failed resolving hint record declaration" );
353- assert (hdecl->isCompleteDefinition () && " Incomplete hint" );
361+ using MirrorMap = llvm::SmallDenseMap<const clang::ClassTemplateDecl *,
362+ clang::ClassTemplateDecl *>;
354363
355- const auto *hspec =
356- llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
357- if (!hspec) {
358- // if it is not a template specialization inheriting from it suffices
359- clang::RecordDecl *rdecl = createRecordDecl (name, hint);
360- return ctx.getTagType (clang::ElaboratedTypeKeyword::None,
361- rdecl->getQualifier (), rdecl, false );
364+ clang::TypeSourceInfo *findMatch (MirrorMap &substs, clang::QualType type) {
365+ const auto *tst = type->getAs <clang::TemplateSpecializationType>();
366+ if (!tst) {
367+ return nullptr ;
368+ }
369+
370+ const auto *tdecl = llvm::dyn_cast_or_null<clang::ClassTemplateDecl>(
371+ tst->getTemplateName ().getAsTemplateDecl ());
372+ if (!tdecl) {
373+ return nullptr ;
374+ }
375+
376+ if (auto it = substs.find (tdecl->getCanonicalDecl ()); it != substs.end ()) {
377+ auto match = getTemplateIdType (it->second , tst->template_arguments ());
378+ assert (!match.isNull ());
379+ return sema_->Context .getTrivialTypeSourceInfo (match, loc_);
362380 }
381+ return nullptr ;
382+ }
363383
384+ clang::ClassTemplateDecl *
385+ createInheritingTemplate (llvm::StringRef name, clang::ClassTemplateDecl *decl,
386+ MirrorMap &substs) {
387+ clang::ASTContext &ctx = sema_->Context ;
364388 auto *pattern = clang::CXXRecordDecl::Create (
365389 ctx, clang::TagTypeKind::Struct, sema_->CurContext , loc_, loc_,
366390 &ctx.Idents .get (name));
367391
368- auto *htdecl = hspec->getSpecializedTemplate ();
369392 auto *mirror = clang::ClassTemplateDecl::Create (
370393 ctx, sema_->CurContext , loc_,
371394 clang::DeclarationName (&ctx.Idents .get (name)),
372- htdecl ->getTemplateParameters (), pattern);
395+ decl ->getTemplateParameters (), pattern);
373396 pattern->setDescribedClassTemplate (mirror);
397+ mirror->setAccess (clang::AS_public);
398+ substs.try_emplace (decl->getCanonicalDecl (), mirror);
374399
375- clang::TemplateArgumentListInfo bargs (loc_, loc_);
376- for (const clang::TemplateArgument &arg :
377- htdecl->getTemplateParameters ()->getInjectedTemplateArgs (ctx)) {
378- bargs.addArgument (
379- sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
380- }
381- clang::QualType base_t = sema_->CheckTemplateIdType (
382- clang::ElaboratedTypeKeyword::None, clang::TemplateName (htdecl), loc_,
383- bargs, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
400+ clang::QualType base_t = getTemplateIdType (
401+ decl, decl->getTemplateParameters ()->getInjectedTemplateArgs (ctx));
384402 assert (!base_t .isNull () && " Failed building mirror base" );
385403
386404 pattern->startDefinition ();
@@ -390,19 +408,49 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
390408 /* EllipsisLoc=*/ clang::SourceLocation ());
391409 const clang::CXXBaseSpecifier *bases[] = {&base};
392410 pattern->setBases (bases, 1 );
411+
412+ for (auto *member : decl->getTemplatedDecl ()->decls ()) {
413+ if (const auto *td = llvm::dyn_cast<clang::TypedefNameDecl>(member)) {
414+ if (auto *replacement = findMatch (substs, td->getUnderlyingType ())) {
415+ auto *copy = clang::TypedefDecl::Create (
416+ ctx, pattern, loc_, loc_, td->getIdentifier (), replacement);
417+ copy->setAccess (clang::AS_public);
418+ pattern->addDecl (copy);
419+ }
420+ } else if (auto *tdecl =
421+ llvm::dyn_cast<clang::ClassTemplateDecl>(member)) {
422+ clang::Sema::ContextRAII savedContext (*sema_, pattern);
423+ createInheritingTemplate (tdecl->getName (), tdecl, substs);
424+ }
425+ }
426+
393427 pattern->completeDefinition ();
394428 sema_->CurContext ->addDecl (mirror);
429+ return mirror;
430+ }
395431
396- clang::TemplateArgumentListInfo args (loc_, loc_);
397- for (const clang::TemplateArgument &arg :
398- hspec->getTemplateArgs ().asArray ()) {
399- args.addArgument (
400- sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
432+ clang::QualType createMirrorType (llvm::StringRef name, clang::QualType hint) {
433+ clang::ASTContext &ctx = sema_->Context ;
434+ forceCompleteDefinition (hint);
435+
436+ const auto *hdecl = hint->getAsCXXRecordDecl ();
437+ assert (hdecl && " Failed resolving hint record declaration" );
438+ assert (hdecl->isCompleteDefinition () && " Incomplete hint" );
439+
440+ const auto *hspec =
441+ llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
442+ if (!hspec) {
443+ // if it is not a template specialization inheriting from it suffices
444+ clang::RecordDecl *rdecl = createRecordDecl (name, hint);
445+ return ctx.getTagType (clang::ElaboratedTypeKeyword::None,
446+ rdecl->getQualifier (), rdecl, false );
401447 }
402448
403- clang::QualType spec = sema_->CheckTemplateIdType (
404- clang::ElaboratedTypeKeyword::None, clang::TemplateName (mirror), loc_,
405- args, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
449+ MirrorMap substs;
450+ auto *mirror =
451+ createInheritingTemplate (name, hspec->getSpecializedTemplate (), substs);
452+ clang::QualType spec =
453+ getTemplateIdType (mirror, hspec->getTemplateArgs ().asArray ());
406454 assert (!spec.isNull () && spec->getAsCXXRecordDecl ());
407455
408456 // required to print Tn instead of Tn<arg1, arg2, ...>
0 commit comments