blob: 2c38047fef313dadf74675e6a6f6b05926e82007 [file] [log] [blame]
Ted Kremenek1b6869a2010-01-05 22:06:45 +00001//===- CIndexUSR.cpp - Clang-C Source Indexing Library --------------------===//
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// This file implements the generation and use of USRs from CXEntities.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CIndexer.h"
Ted Kremenekcf84aa42010-01-18 20:23:29 +000015#include "CXCursor.h"
Benjamin Kramer9895c6a2010-01-12 11:32:40 +000016#include "clang/AST/DeclVisitor.h"
Benjamin Kramerb846deb2010-04-12 19:45:50 +000017#include "clang/Lex/PreprocessingRecord.h"
Ted Kremenek87763822010-01-12 02:07:58 +000018#include "llvm/ADT/SmallString.h"
Benjamin Kramer9895c6a2010-01-12 11:32:40 +000019#include "llvm/Support/raw_ostream.h"
Benjamin Kramerb846deb2010-04-12 19:45:50 +000020using namespace clang;
Ted Kremenekee4db4f2010-02-17 00:41:08 +000021using namespace clang::cxstring;
22
Ted Kremenekc50277f2010-01-12 23:33:42 +000023//===----------------------------------------------------------------------===//
24// USR generation.
25//===----------------------------------------------------------------------===//
26
27namespace {
Ted Kremenek2fee4e62010-01-14 01:50:21 +000028class USRGenerator : public DeclVisitor<USRGenerator> {
29 llvm::raw_ostream &Out;
Ted Kremenek3adca6d2010-01-18 22:02:49 +000030 bool IgnoreResults;
Ted Kremenek1865cfe2010-04-15 21:04:25 +000031 ASTUnit *AU;
Ted Kremenek2fee4e62010-01-14 01:50:21 +000032public:
Ted Kremenek1865cfe2010-04-15 21:04:25 +000033 USRGenerator(ASTUnit *au, llvm::raw_ostream &out)
34 : Out(out), IgnoreResults(false), AU(au) {}
Ted Kremenek896b70f2010-03-13 02:50:34 +000035
Ted Kremenek3adca6d2010-01-18 22:02:49 +000036 bool ignoreResults() const { return IgnoreResults; }
Ted Kremenek896b70f2010-03-13 02:50:34 +000037
38 // Visitation methods from generating USRs from AST elements.
Ted Kremenek2fee4e62010-01-14 01:50:21 +000039 void VisitBlockDecl(BlockDecl *D);
40 void VisitDeclContext(DeclContext *D);
Ted Kremenek3adca6d2010-01-18 22:02:49 +000041 void VisitFieldDecl(FieldDecl *D);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000042 void VisitFunctionDecl(FunctionDecl *D);
43 void VisitNamedDecl(NamedDecl *D);
44 void VisitNamespaceDecl(NamespaceDecl *D);
Ted Kremenek896b70f2010-03-13 02:50:34 +000045 void VisitObjCContainerDecl(ObjCContainerDecl *CD);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000046 void VisitObjCMethodDecl(ObjCMethodDecl *MD);
47 void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
Ted Kremenekb82b3be2010-01-18 22:42:20 +000048 void VisitTagDecl(TagDecl *D);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000049 void VisitTypedefDecl(TypedefDecl *D);
Ted Kremenek896b70f2010-03-13 02:50:34 +000050
Ted Kremenek896b70f2010-03-13 02:50:34 +000051 /// String generation methods used both by the visitation methods
52 /// and from other clients that want to directly generate USRs. These
53 /// methods do not construct complete USRs (which incorporate the parents
54 /// of an AST element), but only the fragments concerning the AST element
55 /// itself.
56
57 /// Generate a USR fragment for a named declaration. This does
58 /// not include the USR component for the parent.
59 void GenNamedDecl(llvm::StringRef name);
60
61 /// Generate a USR for an Objective-C class.
62 void GenObjCClass(llvm::StringRef cls);
63 /// Generate a USR for an Objective-C class category.
64 void GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat);
65 /// Generate a USR fragment for an Objective-C instance variable. The
66 /// complete USR can be created by concatenating the USR for the
67 /// encompassing class with this USR fragment.
68 void GenObjCIvar(llvm::StringRef ivar);
69 /// Generate a USR fragment for an Objective-C method.
70 void GenObjCMethod(llvm::StringRef sel, bool isInstanceMethod);
71 /// Generate a USR fragment for an Objective-C property.
72 void GenObjCProperty(llvm::StringRef prop);
73 /// Generate a USR for an Objective-C protocol.
74 void GenObjCProtocol(llvm::StringRef prot);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000075};
Ted Kremenek896b70f2010-03-13 02:50:34 +000076
77class StringUSRGenerator {
78private:
79 llvm::SmallString<1024> StrBuf;
80 llvm::raw_svector_ostream Out;
81 USRGenerator UG;
82public:
Ted Kremenek1865cfe2010-04-15 21:04:25 +000083 StringUSRGenerator(const CXCursor *C = 0)
84 : Out(StrBuf), UG(C ? cxcursor::getCursorASTUnit(*C) : 0, Out) {
Ted Kremenek0c0fb412010-03-25 02:00:36 +000085 // Add the USR space prefix.
Ted Kremenek1865cfe2010-04-15 21:04:25 +000086 Out << "c:";
Ted Kremenek0c0fb412010-03-25 02:00:36 +000087 }
Ted Kremenek896b70f2010-03-13 02:50:34 +000088
89 llvm::StringRef str() {
90 return Out.str();
91 }
92
93 USRGenerator* operator->() { return &UG; }
94
95 template <typename T>
96 llvm::raw_svector_ostream &operator<<(const T &x) {
97 Out << x;
98 return Out;
99 }
100};
101
Ted Kremenekc50277f2010-01-12 23:33:42 +0000102} // end anonymous namespace
103
Ted Kremenek896b70f2010-03-13 02:50:34 +0000104//===----------------------------------------------------------------------===//
105// Generating USRs from ASTS.
106//===----------------------------------------------------------------------===//
107
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000108void USRGenerator::VisitBlockDecl(BlockDecl *D) {
109 VisitDeclContext(D->getDeclContext());
110 // FIXME: Better support for anonymous blocks.
111 Out << "@B^anon";
112}
113
114void USRGenerator::VisitDeclContext(DeclContext *DC) {
115 if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
116 Visit(D);
117}
118
Ted Kremenek3adca6d2010-01-18 22:02:49 +0000119void USRGenerator::VisitFieldDecl(FieldDecl *D) {
120 const std::string &s = D->getNameAsString();
121 if (s.empty()) {
122 // Bit fields can be anonymous.
123 IgnoreResults = true;
124 return;
125 }
126 VisitDeclContext(D->getDeclContext());
127 Out << "@^FI^" << s;
128}
129
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000130void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
131 VisitDeclContext(D->getDeclContext());
132 Out << "@F^" << D->getNameAsString();
133}
Ted Kremenekc50277f2010-01-12 23:33:42 +0000134
135void USRGenerator::VisitNamedDecl(NamedDecl *D) {
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000136 VisitDeclContext(D->getDeclContext());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000137 const std::string &s = D->getNameAsString();
Ted Kremenek896b70f2010-03-13 02:50:34 +0000138 // assert(!s.empty());
139 GenNamedDecl(s);
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000140}
141
142void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
143 VisitDeclContext(D->getDeclContext());
144 Out << "@N^" << D->getNameAsString();
Ted Kremenekc50277f2010-01-12 23:33:42 +0000145}
146
Ted Kremenekc50277f2010-01-12 23:33:42 +0000147void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
148 Visit(cast<Decl>(D->getDeclContext()));
Ted Kremenek896b70f2010-03-13 02:50:34 +0000149 GenObjCMethod(DeclarationName(D->getSelector()).getAsString(),
150 D->isInstanceMethod());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000151}
152
153void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
154 switch (D->getKind()) {
155 default:
156 assert(false && "Invalid ObjC container.");
157 case Decl::ObjCInterface:
158 case Decl::ObjCImplementation:
Ted Kremenek896b70f2010-03-13 02:50:34 +0000159 GenObjCClass(D->getName());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000160 break;
161 case Decl::ObjCCategory: {
162 ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
Ted Kremenekebfa3392010-03-19 20:39:03 +0000163 ObjCInterfaceDecl *ID = CD->getClassInterface();
164 if (!ID) {
165 // Handle invalid code where the @interface might not
166 // have been specified.
167 // FIXME: We should be able to generate this USR even if the
168 // @interface isn't available.
169 IgnoreResults = true;
170 return;
171 }
172 GenObjCCategory(ID->getName(), CD->getName());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000173 break;
174 }
175 case Decl::ObjCCategoryImpl: {
176 ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
Ted Kremenekebfa3392010-03-19 20:39:03 +0000177 ObjCInterfaceDecl *ID = CD->getClassInterface();
178 if (!ID) {
179 // Handle invalid code where the @interface might not
180 // have been specified.
181 // FIXME: We should be able to generate this USR even if the
182 // @interface isn't available.
183 IgnoreResults = true;
184 return;
185 }
186 GenObjCCategory(ID->getName(), CD->getName());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000187 break;
188 }
189 case Decl::ObjCProtocol:
Ted Kremenek896b70f2010-03-13 02:50:34 +0000190 GenObjCProtocol(cast<ObjCProtocolDecl>(D)->getName());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000191 break;
192 }
193}
194
195void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
196 Visit(cast<Decl>(D->getDeclContext()));
Ted Kremenek896b70f2010-03-13 02:50:34 +0000197 GenObjCProperty(D->getName());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000198}
199
Ted Kremenekb82b3be2010-01-18 22:42:20 +0000200void USRGenerator::VisitTagDecl(TagDecl *D) {
201 VisitDeclContext(D->getDeclContext());
202 switch (D->getTagKind()) {
203 case TagDecl::TK_struct: Out << "@S^"; break;
204 case TagDecl::TK_class: Out << "@C^"; break;
205 case TagDecl::TK_union: Out << "@U^"; break;
206 case TagDecl::TK_enum: Out << "@E^"; break;
207 }
Ted Kremenek896b70f2010-03-13 02:50:34 +0000208
Ted Kremenekc5b48b32010-01-15 23:34:31 +0000209 // FIXME: Better support for anonymous structures and enums.
210 const std::string &s = D->getNameAsString();
211 if (s.empty()) {
212 if (TypedefDecl *TD = D->getTypedefForAnonDecl())
Ted Kremenek896b70f2010-03-13 02:50:34 +0000213 Out << "^anontd^" << TD->getNameAsString();
Ted Kremenekc5b48b32010-01-15 23:34:31 +0000214 else
215 Out << "^anon";
216 }
217 else
218 Out << s;
219}
220
Ted Kremenekc50277f2010-01-12 23:33:42 +0000221void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
222 DeclContext *DC = D->getDeclContext();
223 if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
Ted Kremenek896b70f2010-03-13 02:50:34 +0000224 Visit(DCN);
Ted Kremenekc50277f2010-01-12 23:33:42 +0000225 Out << "typedef@" << D->getName();
226}
227
Ted Kremenek896b70f2010-03-13 02:50:34 +0000228//===----------------------------------------------------------------------===//
229// General purpose USR generation methods.
230//===----------------------------------------------------------------------===//
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000231
Ted Kremenek896b70f2010-03-13 02:50:34 +0000232void USRGenerator::GenNamedDecl(llvm::StringRef name) {
233 Out << "@^" << name;
234}
235
236void USRGenerator::GenObjCClass(llvm::StringRef cls) {
237 Out << "objc(cs)" << cls;
238}
239
240void USRGenerator::GenObjCCategory(llvm::StringRef cls, llvm::StringRef cat) {
241 Out << "objc(cy)" << cls << '^' << cat;
242}
243
244void USRGenerator::GenObjCIvar(llvm::StringRef ivar) {
245 GenNamedDecl(ivar);
246}
247
248void USRGenerator::GenObjCMethod(llvm::StringRef meth, bool isInstanceMethod) {
249 Out << (isInstanceMethod ? "(im)" : "(cm)") << meth;
250}
251
252void USRGenerator::GenObjCProperty(llvm::StringRef prop) {
253 Out << "(py)" << prop;
254}
255
256void USRGenerator::GenObjCProtocol(llvm::StringRef prot) {
257 Out << "objc(pl)" << prot;
258}
259
260//===----------------------------------------------------------------------===//
261// API hooks.
262//===----------------------------------------------------------------------===//
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000263
Benjamin Kramercfb51b62010-04-08 15:54:07 +0000264static inline llvm::StringRef extractUSRSuffix(llvm::StringRef s) {
265 return s.startswith("c:") ? s.substr(2) : "";
266}
267
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000268static CXString getDeclCursorUSR(const CXCursor &C) {
Ted Kremenek896b70f2010-03-13 02:50:34 +0000269 Decl *D = cxcursor::getCursorDecl(C);
270 if (!D)
271 return createCXString(NULL);
272
Ted Kremenek1865cfe2010-04-15 21:04:25 +0000273 // Check if the cursor has 'NoLinkage'.
274 if (const NamedDecl *ND = dyn_cast_or_null<NamedDecl>(D))
275 switch (ND->getLinkage()) {
276 case ExternalLinkage:
277 // Generate USRs for all entities with external linkage.
278 break;
279 case NoLinkage:
280 // We allow enums, typedefs, and structs that have no linkage to
281 // have USRs that are anchored to the file they were defined in
282 // (e.g., the header). This is a little gross, but in principal
283 // enums/anonymous structs/etc. defined in a common header file
284 // are referred to across multiple translation units.
285 if (isa<TagDecl>(ND))
286 break;
287 // Fall-through.
288 case InternalLinkage:
289 case UniqueExternalLinkage:
290 return createCXString("");
291 }
292
293 StringUSRGenerator SUG(&C);
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000294 SUG->Visit(D);
Ted Kremenek896b70f2010-03-13 02:50:34 +0000295
Ted Kremenek0c0fb412010-03-25 02:00:36 +0000296 if (SUG->ignoreResults())
Ted Kremenekebfa3392010-03-19 20:39:03 +0000297 return createCXString("");
Ted Kremenek896b70f2010-03-13 02:50:34 +0000298
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000299 // Return a copy of the string that must be disposed by the caller.
Ted Kremenek896b70f2010-03-13 02:50:34 +0000300 return createCXString(SUG.str(), true);
301}
302
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000303extern "C" {
304
305CXString clang_getCursorUSR(CXCursor C) {
Ted Kremenekfa8231d2010-04-11 22:20:34 +0000306 const CXCursorKind &K = clang_getCursorKind(C);
307
308 if (clang_isDeclaration(K))
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000309 return getDeclCursorUSR(C);
Ted Kremenekfa8231d2010-04-11 22:20:34 +0000310
311 if (K == CXCursor_MacroDefinition) {
Ted Kremenek1865cfe2010-04-15 21:04:25 +0000312 StringUSRGenerator SUG(&C);
Ted Kremenekfa8231d2010-04-11 22:20:34 +0000313 SUG << "macro@"
314 << cxcursor::getCursorMacroDefinition(C)->getName()->getNameStart();
315 return createCXString(SUG.str(), true);
316 }
317
Ted Kremenekc3ef91d2010-04-11 22:20:26 +0000318 return createCXString("");
319}
320
Ted Kremenek896b70f2010-03-13 02:50:34 +0000321CXString clang_constructUSR_ObjCIvar(const char *name, CXString classUSR) {
322 StringUSRGenerator SUG;
Ted Kremenek0c0fb412010-03-25 02:00:36 +0000323 SUG << extractUSRSuffix(clang_getCString(classUSR));
Ted Kremenek896b70f2010-03-13 02:50:34 +0000324 SUG->GenObjCIvar(name);
325 return createCXString(SUG.str(), true);
326}
327
328CXString clang_constructUSR_ObjCMethod(const char *name,
329 unsigned isInstanceMethod,
330 CXString classUSR) {
331 StringUSRGenerator SUG;
Ted Kremenek0c0fb412010-03-25 02:00:36 +0000332 SUG << extractUSRSuffix(clang_getCString(classUSR));
Ted Kremenek896b70f2010-03-13 02:50:34 +0000333 SUG->GenObjCMethod(name, isInstanceMethod);
334 return createCXString(SUG.str(), true);
335}
336
337CXString clang_constructUSR_ObjCClass(const char *name) {
338 StringUSRGenerator SUG;
339 SUG->GenObjCClass(name);
340 return createCXString(SUG.str(), true);
341}
342
343CXString clang_constructUSR_ObjCProtocol(const char *name) {
344 StringUSRGenerator SUG;
345 SUG->GenObjCProtocol(name);
346 return createCXString(SUG.str(), true);
347}
348
Ted Kremenek66ccaec2010-03-15 17:38:58 +0000349CXString clang_constructUSR_ObjCCategory(const char *class_name,
Ted Kremenek0c0fb412010-03-25 02:00:36 +0000350 const char *category_name) {
Ted Kremenek896b70f2010-03-13 02:50:34 +0000351 StringUSRGenerator SUG;
352 SUG->GenObjCCategory(class_name, category_name);
353 return createCXString(SUG.str(), true);
354}
355
356CXString clang_constructUSR_ObjCProperty(const char *property,
357 CXString classUSR) {
358 StringUSRGenerator SUG;
Ted Kremenek0c0fb412010-03-25 02:00:36 +0000359 SUG << extractUSRSuffix(clang_getCString(classUSR));
Ted Kremenek896b70f2010-03-13 02:50:34 +0000360 SUG->GenObjCProperty(property);
361 return createCXString(SUG.str(), true);
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000362}
Ted Kremenek1b6869a2010-01-05 22:06:45 +0000363
Ted Kremenek1b6869a2010-01-05 22:06:45 +0000364} // end extern "C"