1 //===- CIndexCXX.cpp - Clang-C Source Indexing Library --------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements the libclang support for C++ cursors. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "CIndexer.h" 14 #include "CXCursor.h" 15 #include "CXType.h" 16 #include "clang/AST/DeclCXX.h" 17 #include "clang/AST/DeclTemplate.h" 18 19 using namespace clang; 20 using namespace clang::cxcursor; 21 22 unsigned clang_isVirtualBase(CXCursor C) { 23 if (C.kind != CXCursor_CXXBaseSpecifier) 24 return 0; 25 26 const CXXBaseSpecifier *B = getCursorCXXBaseSpecifier(C); 27 return B->isVirtual(); 28 } 29 30 unsigned clang_visitCXXBaseClasses(CXType PT, CXFieldVisitor visitor, 31 CXClientData client_data) { 32 CXCursor PC = clang_getTypeDeclaration(PT); 33 if (clang_isInvalid(PC.kind)) 34 return false; 35 const CXXRecordDecl *RD = 36 dyn_cast_if_present<CXXRecordDecl>(cxcursor::getCursorDecl(PC)); 37 if (!RD || RD->isInvalidDecl()) 38 return false; 39 RD = RD->getDefinition(); 40 if (!RD || RD->isInvalidDecl()) 41 return false; 42 43 for (auto &Base : RD->bases()) { 44 // Callback to the client. 45 switch ( 46 visitor(cxcursor::MakeCursorCXXBaseSpecifier(&Base, getCursorTU(PC)), 47 client_data)) { 48 case CXVisit_Break: 49 return true; 50 case CXVisit_Continue: 51 break; 52 } 53 } 54 return true; 55 } 56 57 enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) { 58 AccessSpecifier spec = AS_none; 59 60 if (C.kind == CXCursor_CXXAccessSpecifier || clang_isDeclaration(C.kind)) 61 spec = getCursorDecl(C)->getAccess(); 62 else if (C.kind == CXCursor_CXXBaseSpecifier) 63 spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier(); 64 else 65 return CX_CXXInvalidAccessSpecifier; 66 67 switch (spec) { 68 case AS_public: return CX_CXXPublic; 69 case AS_protected: return CX_CXXProtected; 70 case AS_private: return CX_CXXPrivate; 71 case AS_none: return CX_CXXInvalidAccessSpecifier; 72 } 73 74 llvm_unreachable("Invalid AccessSpecifier!"); 75 } 76 77 enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) { 78 using namespace clang::cxcursor; 79 80 switch (C.kind) { 81 case CXCursor_ClassTemplate: 82 case CXCursor_FunctionTemplate: 83 if (const TemplateDecl *Template 84 = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C))) 85 return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind; 86 break; 87 88 case CXCursor_ClassTemplatePartialSpecialization: 89 if (const ClassTemplateSpecializationDecl *PartialSpec 90 = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( 91 getCursorDecl(C))) { 92 switch (PartialSpec->getTagKind()) { 93 case TagTypeKind::Interface: 94 case TagTypeKind::Struct: 95 return CXCursor_StructDecl; 96 case TagTypeKind::Class: 97 return CXCursor_ClassDecl; 98 case TagTypeKind::Union: 99 return CXCursor_UnionDecl; 100 case TagTypeKind::Enum: 101 return CXCursor_NoDeclFound; 102 } 103 } 104 break; 105 106 default: 107 break; 108 } 109 110 return CXCursor_NoDeclFound; 111 } 112 113 CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { 114 if (!clang_isDeclaration(C.kind)) 115 return clang_getNullCursor(); 116 117 const Decl *D = getCursorDecl(C); 118 if (!D) 119 return clang_getNullCursor(); 120 121 Decl *Template = nullptr; 122 if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) { 123 if (const ClassTemplatePartialSpecializationDecl *PartialSpec 124 = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord)) 125 Template = PartialSpec->getSpecializedTemplate(); 126 else if (const ClassTemplateSpecializationDecl *ClassSpec 127 = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) { 128 llvm::PointerUnion<ClassTemplateDecl *, 129 ClassTemplatePartialSpecializationDecl *> Result 130 = ClassSpec->getSpecializedTemplateOrPartial(); 131 if (isa<ClassTemplateDecl *>(Result)) 132 Template = cast<ClassTemplateDecl *>(Result); 133 else 134 Template = cast<ClassTemplatePartialSpecializationDecl *>(Result); 135 136 } else 137 Template = CXXRecord->getInstantiatedFromMemberClass(); 138 } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) { 139 Template = Function->getPrimaryTemplate(); 140 if (!Template) 141 Template = Function->getInstantiatedFromMemberFunction(); 142 } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) { 143 if (Var->isStaticDataMember()) 144 Template = Var->getInstantiatedFromStaticDataMember(); 145 } else if (const RedeclarableTemplateDecl *Tmpl 146 = dyn_cast<RedeclarableTemplateDecl>(D)) 147 Template = Tmpl->getInstantiatedFromMemberTemplate(); 148 149 if (!Template) 150 return clang_getNullCursor(); 151 152 return MakeCXCursor(Template, getCursorTU(C)); 153 } 154