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>
@@ -54,10 +55,15 @@ struct LookupInfo {
5455 name = dm->getMember ();
5556 kind = LookupKind::CXXMethodName;
5657 explicitArgs = dm->template_arguments ();
58+ } else if (const auto *um =
59+ llvm::dyn_cast<clang::UnresolvedMemberExpr>(expr)) {
60+ name = um->getMemberName ();
61+ kind = LookupKind::CXXMethodName;
62+ explicitArgs = um->template_arguments ();
5763 } else if (const auto *dref =
5864 llvm::dyn_cast<clang::DependentScopeDeclRefExpr>(expr)) {
5965 clang::DeclarationName dname = dref->getDeclName ();
60- if (name .getNameKind () ==
66+ if (dname .getNameKind () ==
6167 clang::DeclarationName::NameKind::CXXConstructorName) {
6268 name = dname;
6369 kind = LookupKind::CXXConstructorName;
@@ -255,7 +261,8 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
255261 return spec;
256262 }
257263
258- if (result == clang::TemplateDeductionResult::SubstitutionFailure) {
264+ if (result == clang::TemplateDeductionResult::SubstitutionFailure ||
265+ result == clang::TemplateDeductionResult::ConstraintsNotSatisfied) {
259266 if (const auto *deduced = info.takeCanonical ()) {
260267 clang::TemplateArgumentListInfo targsInfo;
261268 for (const auto &arg : deduced->asArray ()) {
@@ -287,7 +294,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
287294 return ns;
288295 }
289296
290- clang::RecordDecl *createRecordDecl (llvm::StringRef name) {
297+ clang::RecordDecl *
298+ createRecordDecl (llvm::StringRef name,
299+ clang::QualType base = clang::QualType()) {
291300 bool owned = true ;
292301 bool dependent = false ;
293302 clang::CXXScopeSpec scope;
@@ -300,11 +309,135 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
300309 clang::TypeResult (), false , false , clang::OffsetOfKind::Outside);
301310 assert (decl.isUsable () && " Record decl creation failed" );
302311 auto *rdecl = decl.getAs <clang::RecordDecl>();
312+
303313 rdecl->startDefinition ();
314+ if (!base.isNull ()) {
315+ clang::CXXBaseSpecifier baseSpec (
316+ clang::SourceRange (loc_, loc_), false , true , clang::AS_public,
317+ sema_->Context .getTrivialTypeSourceInfo (base, loc_),
318+ /* EllipsisLoc=*/ clang::SourceLocation ());
319+ const clang::CXXBaseSpecifier *bases[] = {&baseSpec};
320+ llvm::cast<clang::CXXRecordDecl>(rdecl)->setBases (bases, 1 );
321+ }
304322 rdecl->completeDefinition ();
305323 return rdecl;
306324 }
307325
326+ static clang::QualType getNTTPType (const clang::TemplateArgument &arg) {
327+ switch (arg.getKind ()) {
328+ case clang::TemplateArgument::Integral:
329+ return arg.getIntegralType ();
330+ case clang::TemplateArgument::Declaration:
331+ return arg.getParamTypeForDecl ();
332+ case clang::TemplateArgument::NullPtr:
333+ return arg.getNullPtrType ();
334+ case clang::TemplateArgument::StructuralValue:
335+ return arg.getStructuralValueType ();
336+ default :
337+ return clang::QualType ();
338+ }
339+ }
340+
341+ clang::QualType createMirrorType (llvm::StringRef name, clang::QualType hint) {
342+ clang::ASTContext &ctx = sema_->Context ;
343+ forceCompleteDefinition (hint);
344+
345+ const auto *hdecl = hint->getAsCXXRecordDecl ();
346+ assert (hdecl && " Failed resolving hint record declaration" );
347+ assert (hdecl->isCompleteDefinition () && " Incomplete hint" );
348+
349+ const auto *hspec =
350+ llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
351+ if (!hspec) {
352+ // if it is not a template specialization inheriting from it suffices
353+ clang::RecordDecl *rdecl = createRecordDecl (name, hint);
354+ return ctx.getTagType (clang::ElaboratedTypeKeyword::None,
355+ rdecl->getQualifier (), rdecl, false );
356+ }
357+
358+ auto *pattern = clang::CXXRecordDecl::Create (
359+ ctx, clang::TagTypeKind::Struct, sema_->CurContext , loc_, loc_,
360+ &ctx.Idents .get (name));
361+
362+ auto *htdecl = hspec->getSpecializedTemplate ();
363+ auto *mirror = clang::ClassTemplateDecl::Create (
364+ ctx, sema_->CurContext , loc_,
365+ clang::DeclarationName (&ctx.Idents .get (name)),
366+ htdecl->getTemplateParameters (), pattern);
367+ pattern->setDescribedClassTemplate (mirror);
368+
369+ clang::TemplateArgumentListInfo bargs (loc_, loc_);
370+ for (const clang::TemplateArgument &arg :
371+ htdecl->getTemplateParameters ()->getInjectedTemplateArgs (ctx)) {
372+ bargs.addArgument (
373+ sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
374+ }
375+ clang::QualType base_t = sema_->CheckTemplateIdType (
376+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (htdecl), loc_,
377+ bargs, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
378+ assert (!base_t .isNull () && " Failed building mirror base" );
379+
380+ pattern->startDefinition ();
381+ clang::CXXBaseSpecifier base (clang::SourceRange (loc_, loc_), false , true ,
382+ clang::AS_public,
383+ ctx.getTrivialTypeSourceInfo (base_t , loc_),
384+ /* EllipsisLoc=*/ clang::SourceLocation ());
385+ const clang::CXXBaseSpecifier *bases[] = {&base};
386+ pattern->setBases (bases, 1 );
387+ pattern->completeDefinition ();
388+ sema_->CurContext ->addDecl (mirror);
389+
390+ clang::TemplateArgumentListInfo args (loc_, loc_);
391+ for (const clang::TemplateArgument &arg :
392+ hspec->getTemplateArgs ().asArray ()) {
393+ args.addArgument (
394+ sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
395+ }
396+
397+ clang::QualType spec = sema_->CheckTemplateIdType (
398+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (mirror), loc_,
399+ args, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
400+ assert (!spec.isNull () && spec->getAsCXXRecordDecl ());
401+
402+ // required to print Tn instead of Tn<arg1, arg2, ...>
403+ clang::NamespaceDecl *ns = createNamespaceDecl ();
404+ auto *alias =
405+ clang::TypeAliasDecl::Create (ctx, ns, loc_, loc_, &ctx.Idents .get (name),
406+ ctx.getTrivialTypeSourceInfo (spec, loc_));
407+ ns->addDecl (alias);
408+
409+ clang::QualType alias_t = ctx.getTypedefType (
410+ clang::ElaboratedTypeKeyword::None, std::nullopt , alias);
411+ spec->getAsCXXRecordDecl ()->addAttr (
412+ clang::PreferredNameAttr::CreateImplicit (
413+ ctx, ctx.getTrivialTypeSourceInfo (alias_t , loc_)));
414+
415+ return ctx.getCanonicalType (spec);
416+ }
417+
418+ clang::QualType
419+ getDefaultArg (clang::TemplateDecl *decl,
420+ const clang::TemplateTypeParmDecl *parm,
421+ llvm::ArrayRef<clang::TemplateArgument> currentArgs) {
422+ clang::QualType type = parm->getDefaultArgument ().getArgument ().getAsType ();
423+ if (!type->isDependentType ()) {
424+ return type;
425+ }
426+
427+ clang::Sema::InstantiatingTemplate Inst (*sema_, loc_, decl);
428+ assert (!Inst.isInvalid () && " Invalid instantiation context" );
429+
430+ clang::MultiLevelTemplateArgumentList mtal;
431+ mtal.setKind (clang::TemplateSubstitutionKind::Rewrite);
432+ mtal.addOuterTemplateArguments (currentArgs);
433+
434+ clang::TypeSourceInfo *tsi =
435+ sema_->SubstType (sema_->Context .getTrivialTypeSourceInfo (type), mtal,
436+ loc_, clang::DeclarationName ());
437+ assert (tsi && " Template argument type instantiation failed" );
438+ return tsi->getType ();
439+ }
440+
308441 clang::VarDecl *createVarDecl (clang::QualType type, llvm::StringRef name,
309442 clang::StorageClass sclass = clang::SC_None) {
310443 clang::ASTContext &ctx = sema_->Context ;
@@ -349,11 +482,19 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
349482 createTemplateArguments (clang::TemplateDecl *decl,
350483 llvm::SmallVectorImpl<clang::TemplateArgument> &out) {
351484 for (clang::NamedDecl *param : *decl->getTemplateParameters ()) {
352- if (llvm::isa<clang::TemplateTypeParmDecl>(param)) {
353- clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
354- clang::QualType type =
355- sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
356- rdecl->getQualifier (), rdecl, false );
485+ if (const auto *ttp =
486+ llvm::dyn_cast<clang::TemplateTypeParmDecl>(param)) {
487+ clang::QualType type;
488+ if (ttp->hasDefaultArgument ()) {
489+ clang::QualType hint = getDefaultArg (decl, ttp, out);
490+ assert (!hint.isNull () && " Failed retrieving type hint" );
491+ type = createMirrorType (param->getName (), hint);
492+ } else {
493+ clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
494+ type = sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
495+ rdecl->getQualifier (), rdecl, false );
496+ }
497+ assert (!type.isNull () && " Template type argument creation failed" );
357498 out.emplace_back (type);
358499 } else if (const auto *nttp =
359500 llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(param)) {
@@ -499,6 +640,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
499640 clang::NamespaceDecl *ns = createNamespaceDecl ();
500641 clang::Sema::ContextRAII savedContext (*sema_, ns);
501642 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
643+ assert (rule && " Rule instantiation failed" );
502644 llvm::ArrayRef<clang::ParmVarDecl *> parms = rule->parameters ();
503645 auto csk = lookup.name .getNameKind () ==
504646 clang::DeclarationName::NameKind::CXXOperatorName
@@ -605,6 +747,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
605747 clang::NamespaceDecl *ns = createNamespaceDecl ();
606748 clang::Sema::ContextRAII savedContext (*sema_, ns);
607749 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
750+ assert (rule && " Rule instantiation failed" );
608751 clang::CXXRecordDecl *rdecl =
609752 resolveCXXRecordDecl (rule->getParamDecl (0 )->getType ());
610753 assert (rdecl && " Failed fetching record decl" );
@@ -622,6 +765,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
622765 clang::NamespaceDecl *ns = createNamespaceDecl ();
623766 clang::Sema::ContextRAII savedContext (*sema_, ns);
624767 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
768+ assert (rule && " Rule instantiation failed" );
625769
626770 clang::Expr *obj = createOpaqueValueExpr (
627771 rule->getParamDecl (0 )->getType ().getNonReferenceType ());
0 commit comments