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::Class;
34       Info.Lang = SymbolLanguage::CXX;
35       break;
36     case TTK_Interface:
37       Info.Kind = SymbolKind::Protocol;
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::Import:
57       Info.Kind = SymbolKind::Module;
58       break;
59     case Decl::Typedef:
60       Info.Kind = SymbolKind::TypeAlias; break; // Lang = C
61     case Decl::Function:
62       Info.Kind = SymbolKind::Function;
63       break;
64     case Decl::ParmVar:
65       Info.Kind = SymbolKind::Variable;
66       break;
67     case Decl::Var:
68       Info.Kind = SymbolKind::Variable;
69       if (isa<CXXRecordDecl>(D->getDeclContext())) {
70         Info.Kind = SymbolKind::StaticProperty;
71         Info.Lang = SymbolLanguage::CXX;
72       }
73       break;
74     case Decl::Field:
75       Info.Kind = SymbolKind::Field;
76       if (const CXXRecordDecl *
77             CXXRec = dyn_cast<CXXRecordDecl>(D->getDeclContext())) {
78         if (!CXXRec->isCLike())
79           Info.Lang = SymbolLanguage::CXX;
80       }
81       break;
82     case Decl::EnumConstant:
83       Info.Kind = SymbolKind::EnumConstant; break;
84     case Decl::ObjCInterface:
85     case Decl::ObjCImplementation:
86       Info.Kind = SymbolKind::Class;
87       Info.Lang = SymbolLanguage::ObjC;
88       break;
89     case Decl::ObjCProtocol:
90       Info.Kind = SymbolKind::Protocol;
91       Info.Lang = SymbolLanguage::ObjC;
92       break;
93     case Decl::ObjCCategory:
94     case Decl::ObjCCategoryImpl:
95       Info.Kind = SymbolKind::Extension;
96       Info.Lang = SymbolLanguage::ObjC;
97       break;
98     case Decl::ObjCMethod:
99       if (cast<ObjCMethodDecl>(D)->isInstanceMethod())
100         Info.Kind = SymbolKind::InstanceMethod;
101       else
102         Info.Kind = SymbolKind::ClassMethod;
103       Info.Lang = SymbolLanguage::ObjC;
104       break;
105     case Decl::ObjCProperty:
106       Info.Kind = SymbolKind::InstanceProperty;
107       Info.Lang = SymbolLanguage::ObjC;
108       break;
109     case Decl::ObjCIvar:
110       Info.Kind = SymbolKind::Field;
111       Info.Lang = SymbolLanguage::ObjC;
112       break;
113     case Decl::Namespace:
114       Info.Kind = SymbolKind::Namespace;
115       Info.Lang = SymbolLanguage::CXX;
116       break;
117     case Decl::NamespaceAlias:
118       Info.Kind = SymbolKind::NamespaceAlias;
119       Info.Lang = SymbolLanguage::CXX;
120       break;
121     case Decl::CXXConstructor:
122       Info.Kind = SymbolKind::Constructor;
123       Info.Lang = SymbolLanguage::CXX;
124       break;
125     case Decl::CXXDestructor:
126       Info.Kind = SymbolKind::Destructor;
127       Info.Lang = SymbolLanguage::CXX;
128       break;
129     case Decl::CXXConversion:
130       Info.Kind = SymbolKind::ConversionFunction;
131       Info.Lang = SymbolLanguage::CXX;
132       break;
133     case Decl::CXXMethod: {
134       const CXXMethodDecl *MD = cast<CXXMethodDecl>(D);
135       if (MD->isStatic())
136         Info.Kind = SymbolKind::StaticMethod;
137       else
138         Info.Kind = SymbolKind::InstanceMethod;
139       Info.Lang = SymbolLanguage::CXX;
140       break;
141     }
142     case Decl::ClassTemplate:
143       Info.Kind = SymbolKind::Class;
144       Info.TemplateKind = SymbolCXXTemplateKind::Template;
145       Info.Lang = SymbolLanguage::CXX;
146       break;
147     case Decl::FunctionTemplate:
148       Info.Kind = SymbolKind::Function;
149       Info.TemplateKind = SymbolCXXTemplateKind::Template;
150       Info.Lang = SymbolLanguage::CXX;
151       if (const CXXMethodDecl *MD = dyn_cast_or_null<CXXMethodDecl>(
152                            cast<FunctionTemplateDecl>(D)->getTemplatedDecl())) {
153         if (isa<CXXConstructorDecl>(MD))
154           Info.Kind = SymbolKind::Constructor;
155         else if (isa<CXXDestructorDecl>(MD))
156           Info.Kind = SymbolKind::Destructor;
157         else if (isa<CXXConversionDecl>(MD))
158           Info.Kind = SymbolKind::ConversionFunction;
159         else {
160           if (MD->isStatic())
161             Info.Kind = SymbolKind::StaticMethod;
162           else
163             Info.Kind = SymbolKind::InstanceMethod;
164         }
165       }
166       break;
167     case Decl::TypeAliasTemplate:
168       Info.Kind = SymbolKind::TypeAlias;
169       Info.Lang = SymbolLanguage::CXX;
170       Info.TemplateKind = SymbolCXXTemplateKind::Template;
171       break;
172     case Decl::TypeAlias:
173       Info.Kind = SymbolKind::TypeAlias;
174       Info.Lang = SymbolLanguage::CXX;
175       break;
176     default:
177       break;
178     }
179   }
180 
181   if (Info.Kind == SymbolKind::Unknown)
182     return Info;
183 
184   if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
185     if (FD->getTemplatedKind() ==
186           FunctionDecl::TK_FunctionTemplateSpecialization)
187       Info.TemplateKind = SymbolCXXTemplateKind::TemplateSpecialization;
188   }
189 
190   if (Info.TemplateKind != SymbolCXXTemplateKind::NonTemplate)
191     Info.Lang = SymbolLanguage::CXX;
192 
193   return Info;
194 }
195 
196 void index::applyForEachSymbolRole(SymbolRoleSet Roles,
197                                    llvm::function_ref<void(SymbolRole)> Fn) {
198 #define APPLY_FOR_ROLE(Role) \
199   if (Roles & (unsigned)SymbolRole::Role) \
200     Fn(SymbolRole::Role)
201 
202   APPLY_FOR_ROLE(Declaration);
203   APPLY_FOR_ROLE(Definition);
204   APPLY_FOR_ROLE(Reference);
205   APPLY_FOR_ROLE(Read);
206   APPLY_FOR_ROLE(Write);
207   APPLY_FOR_ROLE(Call);
208   APPLY_FOR_ROLE(Dynamic);
209   APPLY_FOR_ROLE(AddressOf);
210   APPLY_FOR_ROLE(Implicit);
211   APPLY_FOR_ROLE(RelationChildOf);
212   APPLY_FOR_ROLE(RelationBaseOf);
213   APPLY_FOR_ROLE(RelationOverrideOf);
214   APPLY_FOR_ROLE(RelationReceivedBy);
215   APPLY_FOR_ROLE(RelationCalledBy);
216 
217 #undef APPLY_FOR_ROLE
218 }
219 
220 void index::printSymbolRoles(SymbolRoleSet Roles, raw_ostream &OS) {
221   bool VisitedOnce = false;
222   applyForEachSymbolRole(Roles, [&](SymbolRole Role) {
223     if (VisitedOnce)
224       OS << ',';
225     else
226       VisitedOnce = true;
227     switch (Role) {
228     case SymbolRole::Declaration: OS << "Decl"; break;
229     case SymbolRole::Definition: OS << "Def"; break;
230     case SymbolRole::Reference: OS << "Ref"; break;
231     case SymbolRole::Read: OS << "Read"; break;
232     case SymbolRole::Write: OS << "Writ"; break;
233     case SymbolRole::Call: OS << "Call"; break;
234     case SymbolRole::Dynamic: OS << "Dyn"; break;
235     case SymbolRole::AddressOf: OS << "Addr"; break;
236     case SymbolRole::Implicit: OS << "Impl"; break;
237     case SymbolRole::RelationChildOf: OS << "RelChild"; break;
238     case SymbolRole::RelationBaseOf: OS << "RelBase"; break;
239     case SymbolRole::RelationOverrideOf: OS << "RelOver"; break;
240     case SymbolRole::RelationReceivedBy: OS << "RelRec"; break;
241     case SymbolRole::RelationCalledBy: OS << "RelCall"; break;
242     }
243   });
244 }
245 
246 bool index::printSymbolName(const Decl *D, const LangOptions &LO,
247                             raw_ostream &OS) {
248   if (auto *ND = dyn_cast<NamedDecl>(D)) {
249     PrintingPolicy Policy(LO);
250     // Forward references can have different template argument names. Suppress
251     // the template argument names in constructors to make their name more
252     // stable.
253     Policy.SuppressTemplateArgsInCXXConstructors = true;
254     DeclarationName DeclName = ND->getDeclName();
255     if (DeclName.isEmpty())
256       return true;
257     DeclName.print(OS, Policy);
258     return false;
259   } else {
260     return true;
261   }
262 }
263 
264 StringRef index::getSymbolKindString(SymbolKind K) {
265   switch (K) {
266   case SymbolKind::Unknown: return "<unknown>";
267   case SymbolKind::Module: return "module";
268   case SymbolKind::Namespace: return "namespace";
269   case SymbolKind::NamespaceAlias: return "namespace-alias";
270   case SymbolKind::Macro: return "macro";
271   case SymbolKind::Enum: return "enum";
272   case SymbolKind::Struct: return "struct";
273   case SymbolKind::Class: return "class";
274   case SymbolKind::Protocol: return "protocol";
275   case SymbolKind::Extension: return "extension";
276   case SymbolKind::Union: return "union";
277   case SymbolKind::TypeAlias: return "type-alias";
278   case SymbolKind::Function: return "function";
279   case SymbolKind::Variable: return "variable";
280   case SymbolKind::Field: return "field";
281   case SymbolKind::EnumConstant: return "enumerator";
282   case SymbolKind::InstanceMethod: return "instance-method";
283   case SymbolKind::ClassMethod: return "class-method";
284   case SymbolKind::StaticMethod: return "static-method";
285   case SymbolKind::InstanceProperty: return "instance-property";
286   case SymbolKind::ClassProperty: return "class-property";
287   case SymbolKind::StaticProperty: return "static-property";
288   case SymbolKind::Constructor: return "constructor";
289   case SymbolKind::Destructor: return "destructor";
290   case SymbolKind::ConversionFunction: return "coversion-func";
291   }
292   llvm_unreachable("invalid symbol kind");
293 }
294 
295 StringRef index::getTemplateKindStr(SymbolCXXTemplateKind TK) {
296   switch (TK) {
297   case SymbolCXXTemplateKind::NonTemplate: return "NT";
298   case SymbolCXXTemplateKind::Template : return "T";
299   case SymbolCXXTemplateKind::TemplatePartialSpecialization : return "TPS";
300   case SymbolCXXTemplateKind::TemplateSpecialization: return "TS";
301   }
302   llvm_unreachable("invalid template kind");
303 }
304 
305 StringRef index::getSymbolLanguageString(SymbolLanguage K) {
306   switch (K) {
307   case SymbolLanguage::C: return "C";
308   case SymbolLanguage::ObjC: return "ObjC";
309   case SymbolLanguage::CXX: return "C++";
310   }
311   llvm_unreachable("invalid symbol language kind");
312 }
313