1 //===--- IndexSymbol.cpp - Types and functions for indexing symbols -------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/Index/IndexSymbol.h"
11 #include "clang/AST/DeclCXX.h"
12 #include "clang/AST/DeclObjC.h"
13 #include "clang/AST/DeclTemplate.h"
14 #include "clang/AST/PrettyPrinter.h"
15 
16 using namespace clang;
17 using namespace clang::index;
18 
19 SymbolInfo index::getSymbolInfo(const Decl *D) {
20   assert(D);
21   SymbolInfo Info;
22   Info.Kind = SymbolKind::Unknown;
23   Info.TemplateKind = SymbolCXXTemplateKind::NonTemplate;
24   Info.Lang = SymbolLanguage::C;
25 
26   if (const TagDecl *TD = dyn_cast<TagDecl>(D)) {
27     switch (TD->getTagKind()) {
28     case TTK_Struct:
29       Info.Kind = SymbolKind::Struct; break;
30     case TTK_Union:
31       Info.Kind = SymbolKind::Union; break;
32     case TTK_Class:
33       Info.Kind = SymbolKind::CXXClass;
34       Info.Lang = SymbolLanguage::CXX;
35       break;
36     case TTK_Interface:
37       Info.Kind = SymbolKind::CXXInterface;
38       Info.Lang = SymbolLanguage::CXX;
39       break;
40     case TTK_Enum:
41       Info.Kind = SymbolKind::Enum; break;
42     }
43 
44     if (const CXXRecordDecl *CXXRec = dyn_cast<CXXRecordDecl>(D))
45       if (!CXXRec->isCLike())
46         Info.Lang = SymbolLanguage::CXX;
47 
48     if (isa<ClassTemplatePartialSpecializationDecl>(D)) {
49       Info.TemplateKind = SymbolCXXTemplateKind::TemplatePartialSpecialization;
50     } else if (isa<ClassTemplateSpecializationDecl>(D)) {
51       Info.TemplateKind = SymbolCXXTemplateKind::TemplateSpecialization;
52     }
53 
54   } else {
55     switch (D->getKind()) {
56     case Decl::Typedef:
57       Info.Kind = SymbolKind::Typedef; break;
58     case Decl::Function:
59       Info.Kind = SymbolKind::Function;
60       break;
61     case Decl::ParmVar:
62       Info.Kind = SymbolKind::Variable;
63       break;
64     case Decl::Var:
65       Info.Kind = SymbolKind::Variable;
66       if (isa<CXXRecordDecl>(D->getDeclContext())) {
67         Info.Kind = SymbolKind::CXXStaticVariable;
68         Info.Lang = SymbolLanguage::CXX;
69       }
70       break;
71     case Decl::Field:
72       Info.Kind = SymbolKind::Field;
73       if (const CXXRecordDecl *
74             CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
75         if (!CXXRec->isCLike())
76           Info.Lang = SymbolLanguage::CXX;
77       }
78       break;
79     case Decl::EnumConstant:
80       Info.Kind = SymbolKind::EnumConstant; break;
81     case Decl::ObjCInterface:
82     case Decl::ObjCImplementation:
83       Info.Kind = SymbolKind::ObjCClass;
84       Info.Lang = SymbolLanguage::ObjC;
85       break;
86     case Decl::ObjCProtocol:
87       Info.Kind = SymbolKind::ObjCProtocol;
88       Info.Lang = SymbolLanguage::ObjC;
89       break;
90     case Decl::ObjCCategory:
91     case Decl::ObjCCategoryImpl:
92       Info.Kind = SymbolKind::ObjCCategory;
93       Info.Lang = SymbolLanguage::ObjC;
94       break;
95     case Decl::ObjCMethod:
96       if (cast<ObjCMethodDecl>(D)->isInstanceMethod())
97         Info.Kind = SymbolKind::ObjCInstanceMethod;
98       else
99         Info.Kind = SymbolKind::ObjCClassMethod;
100       Info.Lang = SymbolLanguage::ObjC;
101       break;
102     case Decl::ObjCProperty:
103       Info.Kind = SymbolKind::ObjCProperty;
104       Info.Lang = SymbolLanguage::ObjC;
105       break;
106     case Decl::ObjCIvar:
107       Info.Kind = SymbolKind::ObjCIvar;
108       Info.Lang = SymbolLanguage::ObjC;
109       break;
110     case Decl::Namespace:
111       Info.Kind = SymbolKind::CXXNamespace;
112       Info.Lang = SymbolLanguage::CXX;
113       break;
114     case Decl::NamespaceAlias:
115       Info.Kind = SymbolKind::CXXNamespaceAlias;
116       Info.Lang = SymbolLanguage::CXX;
117       break;
118     case Decl::CXXConstructor:
119       Info.Kind = SymbolKind::CXXConstructor;
120       Info.Lang = SymbolLanguage::CXX;
121       break;
122     case Decl::CXXDestructor:
123       Info.Kind = SymbolKind::CXXDestructor;
124       Info.Lang = SymbolLanguage::CXX;
125       break;
126     case Decl::CXXConversion:
127       Info.Kind = SymbolKind::CXXConversionFunction;
128       Info.Lang = SymbolLanguage::CXX;
129       break;
130     case Decl::CXXMethod: {
131       const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
132       if (MD->isStatic())
133         Info.Kind = SymbolKind::CXXStaticMethod;
134       else
135         Info.Kind = SymbolKind::CXXInstanceMethod;
136       Info.Lang = SymbolLanguage::CXX;
137       break;
138     }
139     case Decl::ClassTemplate:
140       Info.Kind = SymbolKind::CXXClass;
141       Info.TemplateKind = SymbolCXXTemplateKind::Template;
142       break;
143     case Decl::FunctionTemplate:
144       Info.Kind = SymbolKind::Function;
145       Info.TemplateKind = SymbolCXXTemplateKind::Template;
146       if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
147                            cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
148         if (isa<CXXConstructorDecl>(MD))
149           Info.Kind = SymbolKind::CXXConstructor;
150         else if (isa<CXXDestructorDecl>(MD))
151           Info.Kind = SymbolKind::CXXDestructor;
152         else if (isa<CXXConversionDecl>(MD))
153           Info.Kind = SymbolKind::CXXConversionFunction;
154         else {
155           if (MD->isStatic())
156             Info.Kind = SymbolKind::CXXStaticMethod;
157           else
158             Info.Kind = SymbolKind::CXXInstanceMethod;
159         }
160       }
161       break;
162     case Decl::TypeAliasTemplate:
163       Info.Kind = SymbolKind::CXXTypeAlias;
164       Info.TemplateKind = SymbolCXXTemplateKind::Template;
165       break;
166     case Decl::TypeAlias:
167       Info.Kind = SymbolKind::CXXTypeAlias;
168       Info.Lang = SymbolLanguage::CXX;
169       break;
170     default:
171       break;
172     }
173   }
174 
175   if (Info.Kind == SymbolKind::Unknown)
176     return Info;
177 
178   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
179     if (FD->getTemplatedKind() ==
180           FunctionDecl::TK_FunctionTemplateSpecialization)
181       Info.TemplateKind = SymbolCXXTemplateKind::TemplateSpecialization;
182   }
183 
184   if (Info.TemplateKind != SymbolCXXTemplateKind::NonTemplate)
185     Info.Lang = SymbolLanguage::CXX;
186 
187   return Info;
188 }
189 
190 void index::applyForEachSymbolRole(SymbolRoleSet Roles,
191                                    llvm::function_ref<void(SymbolRole)> Fn) {
192 #define APPLY_FOR_ROLE(Role) \
193   if (Roles & (unsigned)SymbolRole::Role) \
194     Fn(SymbolRole::Role)
195 
196   APPLY_FOR_ROLE(Declaration);
197   APPLY_FOR_ROLE(Definition);
198   APPLY_FOR_ROLE(Reference);
199   APPLY_FOR_ROLE(Read);
200   APPLY_FOR_ROLE(Write);
201   APPLY_FOR_ROLE(Call);
202   APPLY_FOR_ROLE(Dynamic);
203   APPLY_FOR_ROLE(AddressOf);
204   APPLY_FOR_ROLE(Implicit);
205   APPLY_FOR_ROLE(RelationChildOf);
206   APPLY_FOR_ROLE(RelationBaseOf);
207   APPLY_FOR_ROLE(RelationOverrideOf);
208   APPLY_FOR_ROLE(RelationReceivedBy);
209 
210 #undef APPLY_FOR_ROLE
211 }
212 
213 void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
214   bool VisitedOnce = false;
215   applyForEachSymbolRole(Roles, [&](SymbolRole Role) {
216     if (VisitedOnce)
217       OS << '/';
218     else
219       VisitedOnce = true;
220     switch (Role) {
221     case SymbolRole::Declaration: OS << "Decl"; break;
222     case SymbolRole::Definition: OS << "Def"; break;
223     case SymbolRole::Reference: OS << "Ref"; break;
224     case SymbolRole::Read: OS << "Read"; break;
225     case SymbolRole::Write: OS << "Writ"; break;
226     case SymbolRole::Call: OS << "Call"; break;
227     case SymbolRole::Dynamic: OS << "Dyn"; break;
228     case SymbolRole::AddressOf: OS << "Addr"; break;
229     case SymbolRole::Implicit: OS << "Impl"; break;
230     case SymbolRole::RelationChildOf: OS << "RelChild"; break;
231     case SymbolRole::RelationBaseOf: OS << "RelBase"; break;
232     case SymbolRole::RelationOverrideOf: OS << "RelOver"; break;
233     case SymbolRole::RelationReceivedBy: OS << "RelRec"; break;
234     }
235   });
236 }
237 
238 bool index::printSymbolName(const Decl *D, const LangOptions &LO,
239                             raw_ostream &OS) {
240   if (auto *ND = dyn_cast<NamedDecl>(D)) {
241     PrintingPolicy Policy(LO);
242     // Forward references can have different template argument names. Suppress
243     // the template argument names in constructors to make their name more
244     // stable.
245     Policy.SuppressTemplateArgsInCXXConstructors = true;
246     DeclarationName DeclName = ND->getDeclName();
247     if (DeclName.isEmpty())
248       return true;
249     DeclName.print(OS, Policy);
250     return false;
251   } else {
252     return true;
253   }
254 }
255 
256 StringRef index::getSymbolKindString(SymbolKind K) {
257   switch (K) {
258   case SymbolKind::Unknown: return "<unknown>";
259   case SymbolKind::Module: return "module";
260   case SymbolKind::Macro: return "macro";
261   case SymbolKind::Enum: return "enum";
262   case SymbolKind::Struct: return "struct";
263   case SymbolKind::Union: return "union";
264   case SymbolKind::Typedef: return "typedef";
265   case SymbolKind::Function: return "function";
266   case SymbolKind::Variable: return "variable";
267   case SymbolKind::Field: return "field";
268   case SymbolKind::EnumConstant: return "enumerator";
269   case SymbolKind::ObjCClass: return "objc-class";
270   case SymbolKind::ObjCProtocol: return "objc-protocol";
271   case SymbolKind::ObjCCategory: return "objc-category";
272   case SymbolKind::ObjCInstanceMethod: return "objc-instance-method";
273   case SymbolKind::ObjCClassMethod: return "objc-class-method";
274   case SymbolKind::ObjCProperty: return "objc-property";
275   case SymbolKind::ObjCIvar: return "objc-ivar";
276   case SymbolKind::CXXClass: return "c++-class";
277   case SymbolKind::CXXNamespace: return "namespace";
278   case SymbolKind::CXXNamespaceAlias: return "namespace-alias";
279   case SymbolKind::CXXStaticVariable: return "c++-static-var";
280   case SymbolKind::CXXStaticMethod: return "c++-static-method";
281   case SymbolKind::CXXInstanceMethod: return "c++-instance-method";
282   case SymbolKind::CXXConstructor: return "constructor";
283   case SymbolKind::CXXDestructor: return "destructor";
284   case SymbolKind::CXXConversionFunction: return "coversion-func";
285   case SymbolKind::CXXTypeAlias: return "type-alias";
286   case SymbolKind::CXXInterface: return "c++-__interface";
287   }
288   llvm_unreachable("invalid symbol kind");
289 }
290 
291 StringRef index::getTemplateKindStr(SymbolCXXTemplateKind TK) {
292   switch (TK) {
293   case SymbolCXXTemplateKind::NonTemplate: return "NT";
294   case SymbolCXXTemplateKind::Template : return "T";
295   case SymbolCXXTemplateKind::TemplatePartialSpecialization : return "TPS";
296   case SymbolCXXTemplateKind::TemplateSpecialization: return "TS";
297   }
298   llvm_unreachable("invalid template kind");
299 }
300 
301 StringRef index::getSymbolLanguageString(SymbolLanguage K) {
302   switch (K) {
303   case SymbolLanguage::C: return "C";
304   case SymbolLanguage::ObjC: return "ObjC";
305   case SymbolLanguage::CXX: return "C++";
306   }
307   llvm_unreachable("invalid symbol language kind");
308 }
309