22// Distributed under the MIT license that can be found in the LICENSE file.
33
44#include < clang/AST/ASTContext.h>
5+ #include < clang/AST/Attr.h>
56#include < clang/AST/Decl.h>
67#include < clang/AST/Expr.h>
78#include < clang/AST/PrettyPrinter.h>
@@ -58,10 +59,15 @@ struct LookupInfo {
5859 name = dm->getMember ();
5960 kind = LookupKind::CXXMethodName;
6061 explicitArgs = dm->template_arguments ();
62+ } else if (const auto *um =
63+ llvm::dyn_cast<clang::UnresolvedMemberExpr>(expr)) {
64+ name = um->getMemberName ();
65+ kind = LookupKind::CXXMethodName;
66+ explicitArgs = um->template_arguments ();
6167 } else if (const auto *dref =
6268 llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(expr)) {
6369 clang::DeclarationName dname = dref->getDeclName ();
64- if (name .getNameKind () ==
70+ if (dname .getNameKind () ==
6571 clang::DeclarationName::NameKind::CXXConstructorName) {
6672 name = dname;
6773 kind = LookupKind::CXXConstructorName;
@@ -260,7 +266,8 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
260266 return spec;
261267 }
262268
263- if (result == clang::TemplateDeductionResult::SubstitutionFailure) {
269+ if (result == clang::TemplateDeductionResult::SubstitutionFailure ||
270+ result == clang::TemplateDeductionResult::ConstraintsNotSatisfied) {
264271 if (const auto *deduced = info.takeCanonical ()) {
265272 clang::TemplateArgumentListInfo targsInfo;
266273 for (const auto &arg : deduced->asArray ()) {
@@ -293,7 +300,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
293300 return ns;
294301 }
295302
296- clang::RecordDecl *createRecordDecl (llvm::StringRef name) {
303+ clang::RecordDecl *
304+ createRecordDecl (llvm::StringRef name,
305+ clang::QualType base = clang::QualType()) {
297306 bool owned = true ;
298307 bool dependent = false ;
299308 clang::CXXScopeSpec scope;
@@ -306,11 +315,183 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
306315 clang::TypeResult (), false , false , clang::OffsetOfKind::Outside);
307316 assert (decl.isUsable () && " Record decl creation failed" );
308317 auto *rdecl = decl.getAs <clang::RecordDecl>();
318+
309319 rdecl->startDefinition ();
320+ if (!base.isNull ()) {
321+ clang::CXXBaseSpecifier baseSpec (
322+ clang::SourceRange (loc_, loc_), false , true , clang::AS_public,
323+ sema_->Context .getTrivialTypeSourceInfo (base, loc_),
324+ /* EllipsisLoc=*/ clang::SourceLocation ());
325+ const clang::CXXBaseSpecifier *bases[] = {&baseSpec};
326+ llvm::cast<clang::CXXRecordDecl>(rdecl)->setBases (bases, 1 );
327+ }
310328 rdecl->completeDefinition ();
311329 return rdecl;
312330 }
313331
332+ static clang::QualType getNTTPType (const clang::TemplateArgument &arg) {
333+ switch (arg.getKind ()) {
334+ case clang::TemplateArgument::Integral:
335+ return arg.getIntegralType ();
336+ case clang::TemplateArgument::Declaration:
337+ return arg.getParamTypeForDecl ();
338+ case clang::TemplateArgument::NullPtr:
339+ return arg.getNullPtrType ();
340+ case clang::TemplateArgument::StructuralValue:
341+ return arg.getStructuralValueType ();
342+ default :
343+ return clang::QualType ();
344+ }
345+ }
346+
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+ }
360+
361+ using MirrorMap = llvm::SmallDenseMap<const clang::ClassTemplateDecl *,
362+ clang::ClassTemplateDecl *>;
363+
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_);
380+ }
381+ return nullptr ;
382+ }
383+
384+ clang::ClassTemplateDecl *
385+ createInheritingTemplate (llvm::StringRef name, clang::ClassTemplateDecl *decl,
386+ MirrorMap &substs) {
387+ clang::ASTContext &ctx = sema_->Context ;
388+ auto *pattern = clang::CXXRecordDecl::Create (
389+ ctx, clang::TagTypeKind::Struct, sema_->CurContext , loc_, loc_,
390+ &ctx.Idents .get (name));
391+
392+ auto *mirror = clang::ClassTemplateDecl::Create (
393+ ctx, sema_->CurContext , loc_,
394+ clang::DeclarationName (&ctx.Idents .get (name)),
395+ decl->getTemplateParameters (), pattern);
396+ pattern->setDescribedClassTemplate (mirror);
397+ mirror->setAccess (clang::AS_public);
398+ substs.try_emplace (decl->getCanonicalDecl (), mirror);
399+
400+ clang::QualType base_t = getTemplateIdType (
401+ decl, decl->getTemplateParameters ()->getInjectedTemplateArgs (ctx));
402+ assert (!base_t .isNull () && " Failed building mirror base" );
403+
404+ pattern->startDefinition ();
405+ clang::CXXBaseSpecifier base (clang::SourceRange (loc_, loc_), false , true ,
406+ clang::AS_public,
407+ ctx.getTrivialTypeSourceInfo (base_t , loc_),
408+ /* EllipsisLoc=*/ clang::SourceLocation ());
409+ const clang::CXXBaseSpecifier *bases[] = {&base};
410+ 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+
427+ pattern->completeDefinition ();
428+ sema_->CurContext ->addDecl (mirror);
429+ return mirror;
430+ }
431+
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 );
447+ }
448+
449+ MirrorMap substs;
450+ auto *mirror =
451+ createInheritingTemplate (name, hspec->getSpecializedTemplate (), substs);
452+ clang::QualType spec =
453+ getTemplateIdType (mirror, hspec->getTemplateArgs ().asArray ());
454+ assert (!spec.isNull () && spec->getAsCXXRecordDecl ());
455+
456+ // required to print Tn instead of Tn<arg1, arg2, ...>
457+ clang::NamespaceDecl *ns = createNamespaceDecl ();
458+ auto *alias =
459+ clang::TypeAliasDecl::Create (ctx, ns, loc_, loc_, &ctx.Idents .get (name),
460+ ctx.getTrivialTypeSourceInfo (spec, loc_));
461+ ns->addDecl (alias);
462+
463+ clang::QualType alias_t = ctx.getTypedefType (
464+ clang::ElaboratedTypeKeyword::None, std::nullopt , alias);
465+ spec->getAsCXXRecordDecl ()->addAttr (
466+ clang::PreferredNameAttr::CreateImplicit (
467+ ctx, ctx.getTrivialTypeSourceInfo (alias_t , loc_)));
468+
469+ return ctx.getCanonicalType (spec);
470+ }
471+
472+ clang::QualType
473+ getDefaultArg (clang::TemplateDecl *decl,
474+ const clang::TemplateTypeParmDecl *parm,
475+ llvm::ArrayRef<clang::TemplateArgument> currentArgs) {
476+ clang::QualType type = parm->getDefaultArgument ().getArgument ().getAsType ();
477+ if (!type->isDependentType ()) {
478+ return type;
479+ }
480+
481+ clang::Sema::InstantiatingTemplate Inst (*sema_, loc_, decl);
482+ assert (!Inst.isInvalid () && " Invalid instantiation context" );
483+
484+ clang::MultiLevelTemplateArgumentList mtal;
485+ mtal.setKind (clang::TemplateSubstitutionKind::Rewrite);
486+ mtal.addOuterTemplateArguments (currentArgs);
487+
488+ clang::TypeSourceInfo *tsi =
489+ sema_->SubstType (sema_->Context .getTrivialTypeSourceInfo (type), mtal,
490+ loc_, clang::DeclarationName ());
491+ assert (tsi && " Template argument type instantiation failed" );
492+ return tsi->getType ();
493+ }
494+
314495 clang::VarDecl *createVarDecl (clang::QualType type, llvm::StringRef name,
315496 clang::StorageClass sclass = clang::SC_None) {
316497 clang::ASTContext &ctx = sema_->Context ;
@@ -355,11 +536,19 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
355536 createTemplateArguments (clang::TemplateDecl *decl,
356537 llvm::SmallVectorImpl<clang::TemplateArgument> &out) {
357538 for (clang::NamedDecl *param : *decl->getTemplateParameters ()) {
358- if (llvm::isa<clang::TemplateTypeParmDecl>(param)) {
359- clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
360- clang::QualType type =
361- sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
362- rdecl->getQualifier (), rdecl, false );
539+ if (const auto *ttp =
540+ llvm::dyn_cast<clang::TemplateTypeParmDecl>(param)) {
541+ clang::QualType type;
542+ if (ttp->hasDefaultArgument ()) {
543+ clang::QualType hint = getDefaultArg (decl, ttp, out);
544+ assert (!hint.isNull () && " Failed retrieving type hint" );
545+ type = createMirrorType (param->getName (), hint);
546+ } else {
547+ clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
548+ type = sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
549+ rdecl->getQualifier (), rdecl, false );
550+ }
551+ assert (!type.isNull () && " Template type argument creation failed" );
363552 out.emplace_back (type);
364553 } else if (const auto *nttp =
365554 llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(param)) {
@@ -505,6 +694,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
505694 clang::NamespaceDecl *ns = createNamespaceDecl ();
506695 clang::Sema::ContextRAII savedContext (*sema_, ns);
507696 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
697+ assert (rule && " Rule instantiation failed" );
508698 llvm::ArrayRef<clang::ParmVarDecl *> parms = rule->parameters ();
509699 auto csk = lookup.name .getNameKind () ==
510700 clang::DeclarationName::NameKind::CXXOperatorName
@@ -611,6 +801,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
611801 clang::NamespaceDecl *ns = createNamespaceDecl ();
612802 clang::Sema::ContextRAII savedContext (*sema_, ns);
613803 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
804+ assert (rule && " Rule instantiation failed" );
614805 clang::CXXRecordDecl *rdecl =
615806 resolveCXXRecordDecl (rule->getParamDecl (0 )->getType ());
616807 assert (rdecl && " Failed fetching record decl" );
@@ -628,6 +819,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
628819 clang::NamespaceDecl *ns = createNamespaceDecl ();
629820 clang::Sema::ContextRAII savedContext (*sema_, ns);
630821 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
822+ assert (rule && " Rule instantiation failed" );
631823
632824 clang::Expr *obj = createOpaqueValueExpr (
633825 rule->getParamDecl (0 )->getType ().getNonReferenceType ());
0 commit comments