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,135 @@ 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 createMirrorType (llvm::StringRef name, clang::QualType hint) {
348+ clang::ASTContext &ctx = sema_->Context ;
349+ forceCompleteDefinition (hint);
350+
351+ const auto *hdecl = hint->getAsCXXRecordDecl ();
352+ assert (hdecl && " Failed resolving hint record declaration" );
353+ assert (hdecl->isCompleteDefinition () && " Incomplete hint" );
354+
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 );
362+ }
363+
364+ auto *pattern = clang::CXXRecordDecl::Create (
365+ ctx, clang::TagTypeKind::Struct, sema_->CurContext , loc_, loc_,
366+ &ctx.Idents .get (name));
367+
368+ auto *htdecl = hspec->getSpecializedTemplate ();
369+ auto *mirror = clang::ClassTemplateDecl::Create (
370+ ctx, sema_->CurContext , loc_,
371+ clang::DeclarationName (&ctx.Idents .get (name)),
372+ htdecl->getTemplateParameters (), pattern);
373+ pattern->setDescribedClassTemplate (mirror);
374+
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 );
384+ assert (!base_t .isNull () && " Failed building mirror base" );
385+
386+ pattern->startDefinition ();
387+ clang::CXXBaseSpecifier base (clang::SourceRange (loc_, loc_), false , true ,
388+ clang::AS_public,
389+ ctx.getTrivialTypeSourceInfo (base_t , loc_),
390+ /* EllipsisLoc=*/ clang::SourceLocation ());
391+ const clang::CXXBaseSpecifier *bases[] = {&base};
392+ pattern->setBases (bases, 1 );
393+ pattern->completeDefinition ();
394+ sema_->CurContext ->addDecl (mirror);
395+
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_));
401+ }
402+
403+ clang::QualType spec = sema_->CheckTemplateIdType (
404+ clang::ElaboratedTypeKeyword::None, clang::TemplateName (mirror), loc_,
405+ args, sema_->getCurScope (), /* ForNestedNameSpecifier=*/ false );
406+ assert (!spec.isNull () && spec->getAsCXXRecordDecl ());
407+
408+ // required to print Tn instead of Tn<arg1, arg2, ...>
409+ clang::NamespaceDecl *ns = createNamespaceDecl ();
410+ auto *alias =
411+ clang::TypeAliasDecl::Create (ctx, ns, loc_, loc_, &ctx.Idents .get (name),
412+ ctx.getTrivialTypeSourceInfo (spec, loc_));
413+ ns->addDecl (alias);
414+
415+ clang::QualType alias_t = ctx.getTypedefType (
416+ clang::ElaboratedTypeKeyword::None, std::nullopt , alias);
417+ spec->getAsCXXRecordDecl ()->addAttr (
418+ clang::PreferredNameAttr::CreateImplicit (
419+ ctx, ctx.getTrivialTypeSourceInfo (alias_t , loc_)));
420+
421+ return ctx.getCanonicalType (spec);
422+ }
423+
424+ clang::QualType
425+ getDefaultArg (clang::TemplateDecl *decl,
426+ const clang::TemplateTypeParmDecl *parm,
427+ llvm::ArrayRef<clang::TemplateArgument> currentArgs) {
428+ clang::QualType type = parm->getDefaultArgument ().getArgument ().getAsType ();
429+ if (!type->isDependentType ()) {
430+ return type;
431+ }
432+
433+ clang::Sema::InstantiatingTemplate Inst (*sema_, loc_, decl);
434+ assert (!Inst.isInvalid () && " Invalid instantiation context" );
435+
436+ clang::MultiLevelTemplateArgumentList mtal;
437+ mtal.setKind (clang::TemplateSubstitutionKind::Rewrite);
438+ mtal.addOuterTemplateArguments (currentArgs);
439+
440+ clang::TypeSourceInfo *tsi =
441+ sema_->SubstType (sema_->Context .getTrivialTypeSourceInfo (type), mtal,
442+ loc_, clang::DeclarationName ());
443+ assert (tsi && " Template argument type instantiation failed" );
444+ return tsi->getType ();
445+ }
446+
314447 clang::VarDecl *createVarDecl (clang::QualType type, llvm::StringRef name,
315448 clang::StorageClass sclass = clang::SC_None) {
316449 clang::ASTContext &ctx = sema_->Context ;
@@ -355,11 +488,19 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
355488 createTemplateArguments (clang::TemplateDecl *decl,
356489 llvm::SmallVectorImpl<clang::TemplateArgument> &out) {
357490 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 );
491+ if (const auto *ttp =
492+ llvm::dyn_cast<clang::TemplateTypeParmDecl>(param)) {
493+ clang::QualType type;
494+ if (ttp->hasDefaultArgument ()) {
495+ clang::QualType hint = getDefaultArg (decl, ttp, out);
496+ assert (!hint.isNull () && " Failed retrieving type hint" );
497+ type = createMirrorType (param->getName (), hint);
498+ } else {
499+ clang::RecordDecl *rdecl = createRecordDecl (param->getName ());
500+ type = sema_->Context .getTagType (clang::ElaboratedTypeKeyword::None,
501+ rdecl->getQualifier (), rdecl, false );
502+ }
503+ assert (!type.isNull () && " Template type argument creation failed" );
363504 out.emplace_back (type);
364505 } else if (const auto *nttp =
365506 llvm::dyn_cast<clang::NonTypeTemplateParmDecl>(param)) {
@@ -505,6 +646,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
505646 clang::NamespaceDecl *ns = createNamespaceDecl ();
506647 clang::Sema::ContextRAII savedContext (*sema_, ns);
507648 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
649+ assert (rule && " Rule instantiation failed" );
508650 llvm::ArrayRef<clang::ParmVarDecl *> parms = rule->parameters ();
509651 auto csk = lookup.name .getNameKind () ==
510652 clang::DeclarationName::NameKind::CXXOperatorName
@@ -611,6 +753,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
611753 clang::NamespaceDecl *ns = createNamespaceDecl ();
612754 clang::Sema::ContextRAII savedContext (*sema_, ns);
613755 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
756+ assert (rule && " Rule instantiation failed" );
614757 clang::CXXRecordDecl *rdecl =
615758 resolveCXXRecordDecl (rule->getParamDecl (0 )->getType ());
616759 assert (rdecl && " Failed fetching record decl" );
@@ -628,6 +771,7 @@ class Callback : public clang::ast_matchers::MatchFinder::MatchCallback {
628771 clang::NamespaceDecl *ns = createNamespaceDecl ();
629772 clang::Sema::ContextRAII savedContext (*sema_, ns);
630773 clang::FunctionDecl *rule = instantiateRuleDecl (decl);
774+ assert (rule && " Rule instantiation failed" );
631775
632776 clang::Expr *obj = createOpaqueValueExpr (
633777 rule->getParamDecl (0 )->getType ().getNonReferenceType ());
0 commit comments