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(T: PT); |
33 | if (clang_isInvalid(PC.kind)) |
34 | return false; |
35 | const CXXRecordDecl *RD = |
36 | dyn_cast_if_present<CXXRecordDecl>(Val: cxcursor::getCursorDecl(Cursor: 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(B: &Base, TU: getCursorTU(Cursor: 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 | unsigned clang_visitCXXMethods(CXType PT, CXFieldVisitor visitor, |
58 | CXClientData client_data) { |
59 | CXCursor PC = clang_getTypeDeclaration(T: PT); |
60 | if (clang_isInvalid(PC.kind)) |
61 | return false; |
62 | const auto *RD = |
63 | dyn_cast_if_present<CXXRecordDecl>(Val: cxcursor::getCursorDecl(Cursor: 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(Cursor: PC)), client_data)) { |
74 | case CXVisit_Break: |
75 | return true; |
76 | case CXVisit_Continue: |
77 | break; |
78 | } |
79 | } |
80 | return true; |
81 | } |
82 | |
83 | enum 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(Cursor: C)->getAccess(); |
88 | else if (C.kind == CXCursor_CXXBaseSpecifier) |
89 | spec = getCursorCXXBaseSpecifier(C)->getAccessSpecifier(); |
90 | else |
91 | 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 | |
103 | enum 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 *Template |
110 | = dyn_cast_or_null<TemplateDecl>(Val: getCursorDecl(Cursor: C))) |
111 | return MakeCXCursor(Template->getTemplatedDecl(), getCursorTU(Cursor: C)).kind; |
112 | break; |
113 | |
114 | case CXCursor_ClassTemplatePartialSpecialization: |
115 | if (const ClassTemplateSpecializationDecl *PartialSpec |
116 | = dyn_cast_or_null<ClassTemplatePartialSpecializationDecl>( |
117 | Val: getCursorDecl(Cursor: 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 | |
139 | CXCursor clang_getSpecializedCursorTemplate(CXCursor C) { |
140 | if (!clang_isDeclaration(C.kind)) |
141 | return clang_getNullCursor(); |
142 | |
143 | const Decl *D = getCursorDecl(Cursor: C); |
144 | if (!D) |
145 | return clang_getNullCursor(); |
146 | |
147 | Decl *Template = nullptr; |
148 | if (const CXXRecordDecl *CXXRecord = dyn_cast<CXXRecordDecl>(Val: D)) { |
149 | if (const ClassTemplatePartialSpecializationDecl *PartialSpec |
150 | = dyn_cast<ClassTemplatePartialSpecializationDecl>(Val: CXXRecord)) |
151 | Template = PartialSpec->getSpecializedTemplate(); |
152 | else if (const ClassTemplateSpecializationDecl *ClassSpec |
153 | = dyn_cast<ClassTemplateSpecializationDecl>(Val: CXXRecord)) { |
154 | llvm::PointerUnion<ClassTemplateDecl *, |
155 | ClassTemplatePartialSpecializationDecl *> Result |
156 | = ClassSpec->getSpecializedTemplateOrPartial(); |
157 | if (isa<ClassTemplateDecl *>(Val: Result)) |
158 | Template = cast<ClassTemplateDecl *>(Val&: Result); |
159 | else |
160 | Template = cast<ClassTemplatePartialSpecializationDecl *>(Val&: Result); |
161 | |
162 | } else |
163 | Template = CXXRecord->getInstantiatedFromMemberClass(); |
164 | } else if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(Val: D)) { |
165 | Template = Function->getPrimaryTemplate(); |
166 | if (!Template) |
167 | Template = Function->getInstantiatedFromMemberFunction(); |
168 | } else if (const VarDecl *Var = dyn_cast<VarDecl>(Val: D)) { |
169 | if (Var->isStaticDataMember()) |
170 | Template = Var->getInstantiatedFromStaticDataMember(); |
171 | } else if (const RedeclarableTemplateDecl *Tmpl |
172 | = dyn_cast<RedeclarableTemplateDecl>(Val: D)) |
173 | Template = Tmpl->getInstantiatedFromMemberTemplate(); |
174 | |
175 | if (!Template) |
176 | return clang_getNullCursor(); |
177 | |
178 | return MakeCXCursor(D: Template, TU: getCursorTU(Cursor: C)); |
179 | } |
180 | |