180 lines · cpp
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-exception6//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 19using namespace clang;20using namespace clang::cxcursor;21 22unsigned 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 30unsigned 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 57unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor,58 CXClientData client_data) {59 CXCursor PC = clang_getTypeDeclaration(PT);60 if (clang_isInvalid(PC.kind))61 return false;62 const auto *RD =63 dyn_cast_if_present<CXXRecordDecl>(cxcursor::getCursorDecl(PC));64 if (!RD || RD->isInvalidDecl())65 return false;66 RD = RD->getDefinition();67 if (!RD || RD->isInvalidDecl())68 return false;69 70 for (const auto *Method : RD->methods()) {71 // Callback to the client.72 switch (73 visitor(cxcursor::MakeCXCursor(Method, getCursorTU(PC)), client_data)) {74 case CXVisit_Break:75 return true;76 case CXVisit_Continue:77 break;78 }79 }80 return true;81}82 83enum CX_CXXAccessSpecifier clang_getCXXAccessSpecifier(CXCursor C) {84 AccessSpecifier spec = AS_none;85 86 if (C.kind == CXCursor_CXXAccessSpecifier || clang_isDeclaration(C.kind))87 spec = getCursorDecl(C)->getAccess();88 else if (C.kind == CXCursor_CXXBaseSpecifier)89 spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier();90 else91 return CX_CXXInvalidAccessSpecifier;92 93 switch (spec) {94 case AS_public: return CX_CXXPublic;95 case AS_protected: return CX_CXXProtected;96 case AS_private: return CX_CXXPrivate;97 case AS_none: return CX_CXXInvalidAccessSpecifier;98 }99 100 llvm_unreachable("Invalid AccessSpecifier!");101}102 103enum CXCursorKind clang_getTemplateCursorKind(CXCursor C) {104 using namespace clang::cxcursor;105 106 switch (C.kind) {107 case CXCursor_ClassTemplate: 108 case CXCursor_FunctionTemplate:109 if (const TemplateDecl *Template110 = dyn_cast_or_null<TemplateDecl>(getCursorDecl(C)))111 return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(C)).kind;112 break;113 114 case CXCursor_ClassTemplatePartialSpecialization:115 if (const ClassTemplateSpecializationDecl *PartialSpec116 = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>(117 getCursorDecl(C))) {118 switch (PartialSpec->getTagKind()) {119 case TagTypeKind::Interface:120 case TagTypeKind::Struct:121 return CXCursor_StructDecl;122 case TagTypeKind::Class:123 return CXCursor_ClassDecl;124 case TagTypeKind::Union:125 return CXCursor_UnionDecl;126 case TagTypeKind::Enum:127 return CXCursor_NoDeclFound;128 }129 }130 break;131 132 default:133 break;134 }135 136 return CXCursor_NoDeclFound;137}138 139CXCursor clang_getSpecializedCursorTemplate(CXCursor C) {140 if (!clang_isDeclaration(C.kind))141 return clang_getNullCursor();142 143 const Decl *D = getCursorDecl(C);144 if (!D)145 return clang_getNullCursor();146 147 Decl *Template = nullptr;148 if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(D)) {149 if (const ClassTemplatePartialSpecializationDecl *PartialSpec150 = dyn_cast<ClassTemplatePartialSpecializationDecl>(CXXRecord))151 Template = PartialSpec->getSpecializedTemplate();152 else if (const ClassTemplateSpecializationDecl *ClassSpec 153 = dyn_cast<ClassTemplateSpecializationDecl>(CXXRecord)) {154 llvm::PointerUnion<ClassTemplateDecl *,155 ClassTemplatePartialSpecializationDecl *> Result156 = ClassSpec->getSpecializedTemplateOrPartial();157 if (isa<ClassTemplateDecl *>(Result))158 Template = cast<ClassTemplateDecl *>(Result);159 else160 Template = cast<ClassTemplatePartialSpecializationDecl *>(Result);161 162 } else 163 Template = CXXRecord->getInstantiatedFromMemberClass();164 } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(D)) {165 Template = Function->getPrimaryTemplate();166 if (!Template)167 Template = Function->getInstantiatedFromMemberFunction();168 } else if (const VarDecl *Var = dyn_cast<VarDecl>(D)) {169 if (Var->isStaticDataMember())170 Template = Var->getInstantiatedFromStaticDataMember();171 } else if (const RedeclarableTemplateDecl *Tmpl172 = dyn_cast<RedeclarableTemplateDecl>(D))173 Template = Tmpl->getInstantiatedFromMemberTemplate();174 175 if (!Template)176 return clang_getNullCursor();177 178 return MakeCXCursor(Template, getCursorTU(C));179}180