clang 20.0.0git
IndexSymbol.cpp
Go to the documentation of this file.
1//===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===//
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
10#include "clang/AST/Attr.h"
11#include "clang/AST/DeclCXX.h"
12#include "clang/AST/DeclObjC.h"
15#include "clang/Lex/MacroInfo.h"
16
17using namespace clang;
18using namespace clang::index;
19
20/// \returns true if \c D is a subclass of 'XCTestCase'.
21static bool isUnitTestCase(const ObjCInterfaceDecl *D) {
22 if (!D)
23 return false;
24 while (const ObjCInterfaceDecl *SuperD = D->getSuperClass()) {
25 if (SuperD->getName() == "XCTestCase")
26 return true;
27 D = SuperD;
28 }
29 return false;
30}
31
32/// \returns true if \c D is in a subclass of 'XCTestCase', returns void, has
33/// no parameters, and its name starts with 'test'.
34static bool isUnitTest(const ObjCMethodDecl *D) {
35 if (!D->parameters().empty())
36 return false;
37 if (!D->getReturnType()->isVoidType())
38 return false;
39 if (!D->getSelector().getNameForSlot(0).starts_with("test"))
40 return false;
41 return isUnitTestCase(D->getClassInterface());
42}
43
44static void checkForIBOutlets(const Decl *D, SymbolPropertySet &PropSet) {
45 if (D->hasAttr<IBOutletAttr>()) {
46 PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated;
47 } else if (D->hasAttr<IBOutletCollectionAttr>()) {
48 PropSet |= (SymbolPropertySet)SymbolProperty::IBAnnotated;
49 PropSet |= (SymbolPropertySet)SymbolProperty::IBOutletCollection;
50 }
51}
52
54 assert(D);
55
56 if (isa<ParmVarDecl>(D))
57 return true;
58
59 if (isa<ObjCTypeParamDecl>(D))
60 return true;
61
62 if (isa<UsingDirectiveDecl>(D))
63 return false;
65 return false;
66
67 if (const NamedDecl *ND = dyn_cast<NamedDecl>(D)) {
68 switch (ND->getFormalLinkage()) {
69 case Linkage::Invalid:
70 llvm_unreachable("Linkage hasn't been computed!");
71 case Linkage::None:
72 case Linkage::Internal:
73 return true;
74 case Linkage::VisibleNone:
75 case Linkage::UniqueExternal:
76 llvm_unreachable("Not a sema linkage");
77 case Linkage::Module:
78 case Linkage::External:
79 return false;
80 }
81 }
82
83 return true;
84}
85
87 assert(D);
88 SymbolInfo Info;
89 Info.Kind = SymbolKind::Unknown;
90 Info.SubKind = SymbolSubKind::None;
92 Info.Lang = SymbolLanguage::C;
93
95 Info.Properties |= (SymbolPropertySet)SymbolProperty::Local;
96 }
97 if (isa<ObjCProtocolDecl>(D->getDeclContext())) {
98 Info.Properties |= (SymbolPropertySet)SymbolProperty::ProtocolInterface;
99 }
100
101 if (auto *VT = dyn_cast<VarTemplateDecl>(D)) {
102 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
103 Info.Lang = SymbolLanguage::CXX;
104 // All other fields are filled from the templated decl.
105 D = VT->getTemplatedDecl();
106 }
107
108 if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
109 switch (TD->getTagKind()) {
110 case TagTypeKind::Struct:
111 Info.Kind = SymbolKind::Struct; break;
112 case TagTypeKind::Union:
113 Info.Kind = SymbolKind::Union; break;
114 case TagTypeKind::Class:
115 Info.Kind = SymbolKind::Class;
116 Info.Lang = SymbolLanguage::CXX;
117 break;
118 case TagTypeKind::Interface:
119 Info.Kind = SymbolKind::Protocol;
120 Info.Lang = SymbolLanguage::CXX;
121 break;
122 case TagTypeKind::Enum:
123 Info.Kind = SymbolKind::Enum; break;
124 }
125
126 if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D)) {
127 if (!CXXRec->isCLike()) {
128 Info.Lang = SymbolLanguage::CXX;
129 if (CXXRec->getDescribedClassTemplate()) {
130 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
131 }
132 }
133 }
134
135 if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
136 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
137 Info.Properties |=
138 (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;
139 } else if (isa<ClassTemplateSpecializationDecl>(D)) {
140 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
141 Info.Properties |=
142 (SymbolPropertySet)SymbolProperty::TemplateSpecialization;
143 }
144
145 } else if (auto *VD = dyn_cast<VarDecl>(D)) {
146 Info.Kind = SymbolKind::Variable;
147 if (isa<ParmVarDecl>(D)) {
148 Info.Kind = SymbolKind::Parameter;
149 } else if (isa<CXXRecordDecl>(D->getDeclContext())) {
150 Info.Kind = SymbolKind::StaticProperty;
151 Info.Lang = SymbolLanguage::CXX;
152 }
153
154 if (isa<VarTemplatePartialSpecializationDecl>(D)) {
155 Info.Lang = SymbolLanguage::CXX;
156 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
157 Info.Properties |=
158 (SymbolPropertySet)SymbolProperty::TemplatePartialSpecialization;
159 } else if (isa<VarTemplateSpecializationDecl>(D)) {
160 Info.Lang = SymbolLanguage::CXX;
161 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
162 Info.Properties |=
163 (SymbolPropertySet)SymbolProperty::TemplateSpecialization;
164 } else if (VD->getDescribedVarTemplate()) {
165 Info.Lang = SymbolLanguage::CXX;
166 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
167 }
168
169 } else {
170 switch (D->getKind()) {
171 case Decl::Import:
172 Info.Kind = SymbolKind::Module;
173 break;
174 case Decl::Typedef:
175 Info.Kind = SymbolKind::TypeAlias; break; // Lang = C
176 case Decl::Function:
177 Info.Kind = SymbolKind::Function;
178 break;
179 case Decl::Field:
180 case Decl::IndirectField:
181 Info.Kind = SymbolKind::Field;
182 if (const CXXRecordDecl *
183 CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
184 if (!CXXRec->isCLike())
185 Info.Lang = SymbolLanguage::CXX;
186 }
187 break;
188 case Decl::EnumConstant:
189 Info.Kind = SymbolKind::EnumConstant; break;
190 case Decl::ObjCInterface:
191 case Decl::ObjCImplementation: {
192 Info.Kind = SymbolKind::Class;
193 Info.Lang = SymbolLanguage::ObjC;
194 const ObjCInterfaceDecl *ClsD = dyn_cast<ObjCInterfaceDecl>(D);
195 if (!ClsD)
196 ClsD = cast<ObjCImplementationDecl>(D)->getClassInterface();
197 if (isUnitTestCase(ClsD))
198 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
199 break;
200 }
201 case Decl::ObjCProtocol:
202 Info.Kind = SymbolKind::Protocol;
203 Info.Lang = SymbolLanguage::ObjC;
204 break;
205 case Decl::ObjCCategory:
206 case Decl::ObjCCategoryImpl: {
207 Info.Kind = SymbolKind::Extension;
208 Info.Lang = SymbolLanguage::ObjC;
209 const ObjCInterfaceDecl *ClsD = nullptr;
210 if (auto *CatD = dyn_cast<ObjCCategoryDecl>(D))
211 ClsD = CatD->getClassInterface();
212 else
213 ClsD = cast<ObjCCategoryImplDecl>(D)->getClassInterface();
214 if (isUnitTestCase(ClsD))
215 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
216 break;
217 }
218 case Decl::ObjCMethod: {
219 const ObjCMethodDecl *MD = cast<ObjCMethodDecl>(D);
220 Info.Kind = MD->isInstanceMethod() ? SymbolKind::InstanceMethod : SymbolKind::ClassMethod;
221 if (MD->isPropertyAccessor()) {
222 if (MD->param_size())
223 Info.SubKind = SymbolSubKind::AccessorSetter;
224 else
225 Info.SubKind = SymbolSubKind::AccessorGetter;
226 }
227 Info.Lang = SymbolLanguage::ObjC;
228 if (isUnitTest(MD))
229 Info.Properties |= (SymbolPropertySet)SymbolProperty::UnitTest;
230 if (D->hasAttr<IBActionAttr>())
231 Info.Properties |= (SymbolPropertySet)SymbolProperty::IBAnnotated;
232 break;
233 }
234 case Decl::ObjCProperty:
235 Info.Kind = SymbolKind::InstanceProperty;
236 Info.Lang = SymbolLanguage::ObjC;
238 if (auto *Annot = D->getAttr<AnnotateAttr>()) {
239 if (Annot->getAnnotation() == "gk_inspectable")
240 Info.Properties |= (SymbolPropertySet)SymbolProperty::GKInspectable;
241 }
242 break;
243 case Decl::ObjCIvar:
244 Info.Kind = SymbolKind::Field;
245 Info.Lang = SymbolLanguage::ObjC;
247 break;
248 case Decl::Namespace:
249 Info.Kind = SymbolKind::Namespace;
250 Info.Lang = SymbolLanguage::CXX;
251 break;
252 case Decl::NamespaceAlias:
253 Info.Kind = SymbolKind::NamespaceAlias;
254 Info.Lang = SymbolLanguage::CXX;
255 break;
256 case Decl::CXXConstructor: {
257 Info.Kind = SymbolKind::Constructor;
258 Info.Lang = SymbolLanguage::CXX;
259 auto *CD = cast<CXXConstructorDecl>(D);
260 if (CD->isCopyConstructor())
261 Info.SubKind = SymbolSubKind::CXXCopyConstructor;
262 else if (CD->isMoveConstructor())
263 Info.SubKind = SymbolSubKind::CXXMoveConstructor;
264 break;
265 }
266 case Decl::CXXDestructor:
267 Info.Kind = SymbolKind::Destructor;
268 Info.Lang = SymbolLanguage::CXX;
269 break;
270 case Decl::CXXConversion:
271 Info.Kind = SymbolKind::ConversionFunction;
272 Info.Lang = SymbolLanguage::CXX;
273 break;
274 case Decl::CXXMethod: {
275 const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
276 if (MD->isStatic())
277 Info.Kind = SymbolKind::StaticMethod;
278 else
279 Info.Kind = SymbolKind::InstanceMethod;
280 Info.Lang = SymbolLanguage::CXX;
281 break;
282 }
283 case Decl::ClassTemplate:
284 Info.Kind = SymbolKind::Class;
285 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
286 Info.Lang = SymbolLanguage::CXX;
287 break;
288 case Decl::FunctionTemplate:
289 Info.Kind = SymbolKind::Function;
290 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
291 Info.Lang = SymbolLanguage::CXX;
292 if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
293 cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
294 if (isa<CXXConstructorDecl>(MD))
295 Info.Kind = SymbolKind::Constructor;
296 else if (isa<CXXDestructorDecl>(MD))
297 Info.Kind = SymbolKind::Destructor;
298 else if (isa<CXXConversionDecl>(MD))
299 Info.Kind = SymbolKind::ConversionFunction;
300 else {
301 if (MD->isStatic())
302 Info.Kind = SymbolKind::StaticMethod;
303 else
304 Info.Kind = SymbolKind::InstanceMethod;
305 }
306 }
307 break;
308 case Decl::TypeAliasTemplate:
309 Info.Kind = SymbolKind::TypeAlias;
310 Info.Lang = SymbolLanguage::CXX;
311 Info.Properties |= (SymbolPropertySet)SymbolProperty::Generic;
312 break;
313 case Decl::TypeAlias:
314 Info.Kind = SymbolKind::TypeAlias;
315 Info.Lang = SymbolLanguage::CXX;
316 break;
317 case Decl::UnresolvedUsingTypename:
318 Info.