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 ()) {
@@ -292,7 +299,9 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
292299 return ns;
293300 }
294301
295- clang::RecordDecl *createRecordDecl (llvm::StringRef name) {
302+ clang::RecordDecl *
303+ createRecordDecl (llvm::StringRef name,
304+ clang::QualType base = clang::QualType()) {
296305 bool owned = true ;
297306 bool dependent = false ;
298307 clang::CXXScopeSpec scope;
@@ -305,11 +314,135 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
305314 clang::TypeResult (), false , false , clang::OffsetOfKind::Outside);
306315 assert (decl.isUsable () && " Record decl creation failed" );
307316 auto *rdecl = decl.getAs <clang::RecordDecl>();
317+
308318 rdecl->startDefinition ();
319+ if (!base.isNull ()) {
320+ clang::CXXBaseSpecifier baseSpec (
321+ clang::SourceRange (loc_, loc_), false , true , clang::AS_public,
322+ sema_->Context .getTrivialTypeSourceInfo (base, loc_),
323+ /* EllipsisLoc=*/ clang::SourceLocation ());
324+ const clang::CXXBaseSpecifier *bases[] = {&baseSpec};
325+ llvm::cast<clang::CXXRecordDecl>(rdecl)->setBases (bases, 1 );
326+ }
309327 rdecl->completeDefinition ();
310328 return rdecl;
311329 }
312330
331+ static clang::QualType getNTTPType (const clang::TemplateArgument &arg) {
332+ switch (arg.getKind ()) {
333+ case clang::TemplateArgument::Integral:
334+ return arg.getIntegralType ();
335+ case clang::TemplateArgument::Declaration:
336+ return arg.getParamTypeForDecl ();
337+ case clang::TemplateArgument::NullPtr:
338+ return arg.getNullPtrType ();
339+ case clang::TemplateArgument::StructuralValue:
340+ return arg.getStructuralValueType ();
341+ default :
342+ return clang::QualType ();
343+ }
344+ }
345+
346+ clang::QualType createMirrorType (llvm::StringRef name, clang::QualType hint) {
347+ clang::ASTContext &ctx = sema_->Context ;
348+ forceCompleteDefinition (hint);
349+
350+ const auto *hdecl = hint->getAsCXXRecordDecl ();
351+ assert (hdecl && " Failed resolving hint record declaration" );
352+ assert (hdecl->isCompleteDefinition () && " Incomplete hint" );
353+
354+ const auto *hspec =
355+ llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(hdecl);
356+ if (!hspec) {
357+ // if it is not a template specialization inheriting from it suffices
358+ clang::RecordDecl *rdecl = createRecordDecl (name, hint);
359+ return ctx.getTagType (clang::ElaboratedTypeKeyword::None,
360+ rdecl->getQualifier (), rdecl, false );
361+ }
362+
363+ auto *pattern = clang::CXXRecordDecl::Create (
364+ ctx, clang::TagTypeKind::Struct, sema_->CurContext , loc_, loc_,
365+ &ctx.Idents .get (name));
366+
367+ auto *htdecl = hspec->getSpecializedTemplate ();
368+ auto *mirror = clang::ClassTemplateDecl::Create (
369+ ctx, sema_->CurContext , loc_,
370+ clang::DeclarationName (&ctx.Idents .get (name)),
371+ htdecl->getTemplateParameters (), pattern);
372+ pattern->setDescribedClassTemplate (mirror);
373+
374+ clang::TemplateArgumentListInfo bargs (loc_, loc_);
375+ for (const clang::TemplateArgument &arg :
376+ htdecl->getTemplateParameters ()->getInjectedTemplateArgs (ctx)) {
377+ bargs.addArgument (
378+ sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
379+ }
380+ clang::QualType base_t = sema_->CheckTemplateIdType (
381+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (htdecl), loc_,
382+ bargs, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
383+ assert (!base_t .isNull () && " Failed building mirror base" );
384+
385+ pattern->startDefinition ();
386+ clang::CXXBaseSpecifier base (clang::SourceRange (loc_, loc_), false , true ,
387+ clang::AS_public,
388+ ctx.getTrivialTypeSourceInfo (base_t , loc_),
389+ /* EllipsisLoc=*/ clang::SourceLocation ());
390+ const clang::CXXBaseSpecifier *bases[] = {&base};
391+ pattern->setBases (bases, 1 );
392+ pattern->completeDefinition ();
393+ sema_->CurContext ->addDecl (mirror);
394+
395+ clang::TemplateArgumentListInfo args (loc_, loc_);
396+ for (const clang::TemplateArgument &arg :
397+ hspec->getTemplateArgs ().asArray ()) {
398+ args.addArgument (
399+ sema_->getTrivialTemplateArgumentLoc (arg, getNTTPType (arg), loc_));
400+ }
401+
402+ clang::QualType spec = sema_->CheckTemplateIdType (
403+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (mirror), loc_,
404+ args, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
405+ assert (!spec.isNull () && spec->getAsCXXRecordDecl ());
406+
407+ // required to print Tn instead of Tn<arg1, arg2, ...>
408+ clang::NamespaceDecl *ns = createNamespaceDecl ();
409+ auto *alias =
410+ clang::TypeAliasDecl::Create (ctx, ns, loc_, loc_, &ctx.Idents .get (name),
411+ ctx.getTrivialTypeSourceInfo (spec, loc_));
412+ ns->addDecl (alias);
413+
414+ clang::QualType alias_t = ctx.getTypedefType (
415+ clang::ElaboratedTypeKeyword::None, std::nullopt , alias);
416+ spec->getAsCXXRecordDecl ()->addAttr (
417+ clang::PreferredNameAttr::CreateImplicit (
418+ ctx, ctx.getTrivialTypeSourceInfo (alias_t , loc_)));
419+
420+ return ctx.getCanonicalType (spec);
421+ }
422+
423+ clang::QualType
424+ getDefaultArg (clang::TemplateDecl *decl,
425+ const clang::TemplateTypeParmDecl *parm,
426+ llvm::ArrayRef<clang::TemplateArgument> currentArgs) {
427+ clang::QualType type = parm->getDefaultArgument ().getArgument ().getAsType ();
428+ if (!type->isDependentType ()) {
429+ return type;
430+ }
431+
432+ clang::Sema::InstantiatingTemplate Inst (*sema_, loc_, decl);
433+ assert (!Inst.isInvalid () && " Invalid instantiation context" );
434+
435+ clang::MultiLevelTemplateArgumentList mtal;
436+ mtal.setKind (clang::TemplateSubstitutionKind::Rewrite);
437+ mtal.addOuterTemplateArguments (currentArgs);
438+
439+ clang::TypeSourceInfo *tsi =
440+ sema_->SubstType (sema_->Context .getTrivialTypeSourceInfo (type), mtal,
441+ loc_, clang::DeclarationName ());
442+ assert (tsi && " Template argument type instantiation failed" );
443+ return tsi->getType ();
444+ }
445+
313446 clang::VarDecl *createVarDecl (clang::QualType type, llvm::StringRef name,
314447 clang::StorageClass sclass = clang::SC_None) {
315448 clang::ASTContext &ctx = sema_->Context ;
@@ -354,11 +487,19 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
354487 createTemplateArguments (clang::TemplateDecl *decl,
355488 llvm::SmallVectorImpl<clang::TemplateArgument> &out) {
356489 for (clang::NamedDecl *param : *decl->getTemplateParameters ()) {
357- if (llvm::isa<clang::TemplateTypeParmDecl>(param)) {
358- clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
359- clang::QualType type =
360- sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
361- rdecl->getQualifier (), rdecl, false );
490+ if (const auto *ttp =
491+ llvm::dyn_cast<clang::TemplateTypeParmDecl>(param)) {
492+ clang::QualType type;
493+ if (ttp->hasDefaultArgument ()) {
494+ clang::QualType hint = getDefaultArg (decl, ttp, out);
495+ assert (!hint.isNull () && " Failed retrieving type hint" );
496+ type = createMirrorType (param->getName (), hint);
497+ } else {
498+ clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
499+ type = sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
500+ rdecl->getQualifier (), rdecl, false );
501+ }
502+ assert (!type.isNull () && " Template type argument creation failed" );
362503 out.emplace_back (type);
363504 } else if (const auto *nttp =
364505 llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(param)) {
@@ -504,6 +645,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
504645 clang::NamespaceDecl *ns = createNamespaceDecl ();
505646 clang::Sema::ContextRAII savedContext (*sema_, ns);
506647 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
648+ assert (rule && " Rule instantiation failed" );
507649 llvm::ArrayRef<clang::ParmVarDecl *> parms = rule->parameters ();
508650 auto csk = lookup.name .getNameKind () ==
509651 clang::DeclarationName::NameKind::CXXOperatorName
@@ -610,6 +752,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
610752 clang::NamespaceDecl *ns = createNamespaceDecl ();
611753 clang::Sema::ContextRAII savedContext (*sema_, ns);
612754 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
755+ assert (rule && " Rule instantiation failed" );
613756 clang::CXXRecordDecl *rdecl =
614757 resolveCXXRecordDecl (rule->getParamDecl (0 )->getType ());
615758 assert (rdecl && " Failed fetching record decl" );
@@ -627,6 +770,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
627770 clang::NamespaceDecl *ns = createNamespaceDecl ();
628771 clang::Sema::ContextRAII savedContext (*sema_, ns);
629772 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
773+ assert (rule && " Rule instantiation failed" );
630774
631775 clang::Expr *obj = createOpaqueValueExpr (
632776 rule->getParamDecl (0 )->getType ().getNonReferenceType ());
0 commit comments