xref: /llvm-project/clang/tools/libclang/CIndexCXX.cpp (revision 1682deed0fd02c6aca98154e8e9cf6c573ff6d45)
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