196 lines
5.8 KiB
C++
196 lines
5.8 KiB
C++
#include <Compiler/Utility.h>
|
|
|
|
namespace clice {
|
|
|
|
bool isDefinition(const clang::Decl* decl) {
|
|
if(auto VD = llvm::dyn_cast<clang::VarDecl>(decl)) {
|
|
return VD->isThisDeclarationADefinition();
|
|
}
|
|
|
|
if(auto FD = llvm::dyn_cast<clang::FunctionDecl>(decl)) {
|
|
return FD->isThisDeclarationADefinition();
|
|
}
|
|
|
|
if(auto TD = llvm::dyn_cast<clang::TagDecl>(decl)) {
|
|
return TD->isThisDeclarationADefinition();
|
|
}
|
|
|
|
if(llvm::isa<clang::FieldDecl,
|
|
clang::EnumConstantDecl,
|
|
clang::TypedefNameDecl,
|
|
clang::ConceptDecl>(decl)) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
const static clang::CXXRecordDecl* getDeclContextForTemplateInstationPattern(const clang::Decl* D) {
|
|
if(const auto* CTSD = dyn_cast<clang::ClassTemplateSpecializationDecl>(D->getDeclContext())) {
|
|
return CTSD->getTemplateInstantiationPattern();
|
|
}
|
|
|
|
if(const auto* RD = dyn_cast<clang::CXXRecordDecl>(D->getDeclContext())) {
|
|
return RD->getInstantiatedFromMemberClass();
|
|
}
|
|
|
|
return nullptr;
|
|
}
|
|
|
|
const clang::NamedDecl* instantiatedFrom(const clang::NamedDecl* decl) {
|
|
if(auto CTSD = llvm::dyn_cast<clang::ClassTemplateSpecializationDecl>(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<clang::FunctionDecl>(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<clang::VarDecl>(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<clang::CXXRecordDecl>(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<clang::FieldDecl, clang::TypedefNameDecl>(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<clang::EnumDecl>(decl)) {
|
|
return ED->getInstantiatedFromMemberEnum();
|
|
}
|
|
|
|
if(auto ECD = llvm::dyn_cast<clang::EnumConstantDecl>(decl)) {
|
|
auto ED = llvm::cast<clang::EnumDecl>(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<clang::VarDecl>(decl)) {
|
|
return VD->getType();
|
|
}
|
|
|
|
if(auto FD = llvm::dyn_cast<clang::FieldDecl>(decl)) {
|
|
return FD->getType();
|
|
}
|
|
|
|
if(auto ECD = llvm::dyn_cast<clang::EnumConstantDecl>(decl)) {
|
|
return ECD->getType();
|
|
}
|
|
|
|
if(auto BD = llvm::dyn_cast<clang::BindingDecl>(decl)) {
|
|
return BD->getType();
|
|
}
|
|
|
|
if(auto TD = llvm::dyn_cast<clang::TypedefNameDecl>(decl)) {
|
|
return TD->getUnderlyingType();
|
|
}
|
|
|
|
if(auto CCD = llvm::dyn_cast<clang::CXXConstructorDecl>(decl)) {
|
|
return CCD->getThisType();
|
|
}
|
|
|
|
if(auto CDD = llvm::dyn_cast<clang::CXXDestructorDecl>(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<clang::TagType>(type)) {
|
|
return RT->getDecl();
|
|
}
|
|
|
|
if(auto TT = llvm::dyn_cast<clang::TypedefType>(type)) {
|
|
return TT->getDecl();
|
|
}
|
|
|
|
/// FIXME:
|
|
if(auto TST = llvm::dyn_cast<clang::TemplateSpecializationType>(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<clang::TemplateTemplateParmDecl,
|
|
clang::TypeAliasTemplateDecl,
|
|
clang::BuiltinTemplateDecl>(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
|