#include namespace clice { bool isDefinition(const clang::Decl* decl) { if(auto VD = llvm::dyn_cast(decl)) { return VD->isThisDeclarationADefinition(); } if(auto FD = llvm::dyn_cast(decl)) { return FD->isThisDeclarationADefinition(); } if(auto TD = llvm::dyn_cast(decl)) { return TD->isThisDeclarationADefinition(); } if(llvm::isa(decl)) { return true; } return false; } const static clang::CXXRecordDecl* getDeclContextForTemplateInstationPattern(const clang::Decl* D) { if(const auto* CTSD = dyn_cast(D->getDeclContext())) { return CTSD->getTemplateInstantiationPattern(); } if(const auto* RD = dyn_cast(D->getDeclContext())) { return RD->getInstantiatedFromMemberClass(); } return nullptr; } const clang::NamedDecl* instantiatedFrom(const clang::NamedDecl* decl) { if(auto CTSD = llvm::dyn_cast(decl)) { /// If the decl is an full specialization, return itself. auto kind = CTSD->getTemplateSpecializationKind(); if(kind == clang::TSK_Undeclared || kind == clang::TSK_ExplicitSpecialization) { return CTSD; } auto CRD = CTSD->getTemplateInstantiationPattern(); assert(CRD && "Unexpected template instantiation pattern"); /// Primary template. if(auto CTD = CRD->getDescribedClassTemplate()) { return CTD; } /// Partial specialization. return CRD; } if(auto FD = llvm::dyn_cast(decl)) { /// If the decl is an full specialization, return itself. if(FD->getTemplateSpecializationKind() == clang::TSK_ExplicitSpecialization) { return FD; } return FD->getTemplateInstantiationPattern(); } if(auto VD = llvm::dyn_cast(decl)) { /// If the decl is an full specialization, return itself. if(VD->getTemplateSpecializationKind() == clang::TSK_ExplicitSpecialization) { return VD; } return VD->getTemplateInstantiationPattern(); } if(auto CRD = llvm::dyn_cast(decl)) { if(auto CTD = CRD->getDescribedClassTemplate()) { return CTD; } return CRD->getInstantiatedFromMemberClass(); } /// For `FieldDecl` and `TypedefNameDecl`, clang will not store their instantiation information /// in the AST. So we need to look up the original decl manually. if(llvm::isa(decl)) { /// FIXME: figure out the context. if(auto context = getDeclContextForTemplateInstationPattern(decl)) { for(auto member: context->lookup(decl->getDeclName())) { if(member->isImplicit()) { continue; } if(member->getKind() == decl->getKind()) { return member; } } } } if(auto ED = llvm::dyn_cast(decl)) { return ED->getInstantiatedFromMemberEnum(); } if(auto ECD = llvm::dyn_cast(decl)) { auto ED = llvm::cast(ECD->getDeclContext()); if(auto context = ED->getInstantiatedFromMemberEnum()) { for(auto member: context->lookup(ECD->getDeclName())) { return member; } } } return nullptr; } clang::QualType typeForDecl(const clang::NamedDecl* decl) { if(auto VD = llvm::dyn_cast(decl)) { return VD->getType(); } if(auto FD = llvm::dyn_cast(decl)) { return FD->getType(); } if(auto ECD = llvm::dyn_cast(decl)) { return ECD->getType(); } if(auto BD = llvm::dyn_cast(decl)) { return BD->getType(); } if(auto TD = llvm::dyn_cast(decl)) { return TD->getUnderlyingType(); } if(auto CCD = llvm::dyn_cast(decl)) { return CCD->getThisType(); } if(auto CDD = llvm::dyn_cast(decl)) { return CDD->getThisType(); } return clang::QualType(); } const clang::NamedDecl* declForType(clang::QualType type) { if(type.isNull()) { return nullptr; } if(auto RT = llvm::dyn_cast(type)) { return RT->getDecl(); } if(auto TT = llvm::dyn_cast(type)) { return TT->getDecl(); } /// FIXME: if(auto TST = llvm::dyn_cast(type)) { auto decl = TST->getTemplateName().getAsTemplateDecl(); if(type->isDependentType()) { return decl; } /// For a template specialization type, the template name is possibly a `ClassTemplateDecl` /// `TypeAliasTemplateDecl` or `TemplateTemplateParmDecl` and `BuiltinTemplateDecl`. if(llvm::isa(decl)) { return decl; } return instantiatedFrom(TST->getAsCXXRecordDecl()); } return nullptr; } void dumpInclude(clang::SourceManager& srcMgr, clang::SourceLocation loc) { auto file = srcMgr.getFileID(loc); for(auto includeLoc = srcMgr.getIncludeLoc(file); includeLoc.isValid(); includeLoc = srcMgr.getIncludeLoc(file)) { includeLoc.dump(srcMgr); file = srcMgr.getFileID(includeLoc); } } } // namespace clice