blob: bd88ab44b83aef643153d798094ef064b549b67a [file] [log] [blame]
Ted Kremenek9cd9f6d2010-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 Kremenek473c7a72010-01-18 20:23:29 +000015#include "CXCursor.h"
Benjamin Kramer59617be2010-01-12 11:32:40 +000016#include "clang/AST/DeclVisitor.h"
Ted Kremenek5631d2d2010-01-12 02:07:58 +000017#include "llvm/ADT/SmallString.h"
Benjamin Kramer59617be2010-01-12 11:32:40 +000018#include "llvm/Support/raw_ostream.h"
Ted Kremenek9cd9f6d2010-01-05 22:06:45 +000019
20// Some notes on CXEntity:
21//
22// - Since the 'ordinary' namespace includes functions, data, typedefs,
23// ObjC interfaces, thecurrent algorithm is a bit naive (resulting in one
24// entity for 2 different types). For example:
25//
26// module1.m: @interface Foo @end Foo *x;
27// module2.m: void Foo(int);
28//
29// - Since the unique name spans translation units, static data/functions
30// within a CXTranslationUnit are *not* currently represented by entities.
31// As a result, there will be no entity for the following:
32//
33// module.m: static void Foo() { }
34//
Ted Kremeneke5f86be2010-01-11 23:56:39 +000035
36static inline Entity GetEntity(const CXEntity &E) {
37 return Entity::getFromOpaquePtr(E.data);
38}
39
40static inline ASTUnit *GetTranslationUnit(CXTranslationUnit TU) {
41 return (ASTUnit*) TU;
Ted Kremenek9cd9f6d2010-01-05 22:06:45 +000042}
43
Ted Kremeneke5f86be2010-01-11 23:56:39 +000044static inline ASTContext &GetASTContext(CXTranslationUnit TU) {
45 return GetTranslationUnit(TU)->getASTContext();
46}
47
48static inline CXEntity NullCXEntity() {
49 CXEntity CE;
50 CE.index = NULL;
51 CE.data = NULL;
52 return CE;
53}
54
55static inline CXEntity MakeEntity(CXIndex CIdx, const Entity &E) {
56 CXEntity CE;
57 CE.index = CIdx;
58 CE.data = E.getAsOpaquePtr();
59 return CE;
60}
61
62static inline Program &GetProgram(CXIndex CIdx) {
63 return ((CIndexer*) CIdx)->getProgram();
64}
Benjamin Kramer59617be2010-01-12 11:32:40 +000065
Ted Kremenekcb674f92010-01-12 23:33:42 +000066//===----------------------------------------------------------------------===//
67// USR generation.
68//===----------------------------------------------------------------------===//
69
70namespace {
Ted Kremeneke1b55252010-01-14 01:50:21 +000071class USRGenerator : public DeclVisitor<USRGenerator> {
72 llvm::raw_ostream &Out;
Ted Kremeneka6980af2010-01-18 22:02:49 +000073 bool IgnoreResults;
Ted Kremeneke1b55252010-01-14 01:50:21 +000074public:
Ted Kremeneka6980af2010-01-18 22:02:49 +000075 USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {}
76
77 bool ignoreResults() const { return IgnoreResults; }
Ted Kremeneke1b55252010-01-14 01:50:21 +000078
79 void VisitBlockDecl(BlockDecl *D);
80 void VisitDeclContext(DeclContext *D);
Ted Kremenek8433d1d2010-01-15 20:04:31 +000081 void VisitEnumDecl(EnumDecl *D);
Ted Kremeneka6980af2010-01-18 22:02:49 +000082 void VisitFieldDecl(FieldDecl *D);
Ted Kremeneke1b55252010-01-14 01:50:21 +000083 void VisitFunctionDecl(FunctionDecl *D);
84 void VisitNamedDecl(NamedDecl *D);
85 void VisitNamespaceDecl(NamespaceDecl *D);
86 void VisitObjCContainerDecl(ObjCContainerDecl *CD);
87 void VisitObjCMethodDecl(ObjCMethodDecl *MD);
88 void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
89 void VisitRecordDecl(RecordDecl *D);
Ted Kremenek6b1d5502010-01-15 23:34:31 +000090 void VisitTagDeclCommon(TagDecl *D);
Ted Kremeneke1b55252010-01-14 01:50:21 +000091 void VisitTypedefDecl(TypedefDecl *D);
92};
Ted Kremenekcb674f92010-01-12 23:33:42 +000093} // end anonymous namespace
94
Ted Kremeneke1b55252010-01-14 01:50:21 +000095void USRGenerator::VisitBlockDecl(BlockDecl *D) {
96 VisitDeclContext(D->getDeclContext());
97 // FIXME: Better support for anonymous blocks.
98 Out << "@B^anon";
99}
100
101void USRGenerator::VisitDeclContext(DeclContext *DC) {
102 if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
103 Visit(D);
104}
105
Ted Kremenek8433d1d2010-01-15 20:04:31 +0000106void USRGenerator::VisitEnumDecl(EnumDecl *D) {
107 VisitDeclContext(D->getDeclContext());
108 Out << "@E^";
Ted Kremenek6b1d5502010-01-15 23:34:31 +0000109 VisitTagDeclCommon(D);
Ted Kremenek8433d1d2010-01-15 20:04:31 +0000110}
111
Ted Kremeneka6980af2010-01-18 22:02:49 +0000112void USRGenerator::VisitFieldDecl(FieldDecl *D) {
113 const std::string &s = D->getNameAsString();
114 if (s.empty()) {
115 // Bit fields can be anonymous.
116 IgnoreResults = true;
117 return;
118 }
119 VisitDeclContext(D->getDeclContext());
120 Out << "@^FI^" << s;
121}
122
Ted Kremeneke1b55252010-01-14 01:50:21 +0000123void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
124 VisitDeclContext(D->getDeclContext());
125 Out << "@F^" << D->getNameAsString();
126}
Ted Kremenekcb674f92010-01-12 23:33:42 +0000127
128void USRGenerator::VisitNamedDecl(NamedDecl *D) {
Ted Kremeneke1b55252010-01-14 01:50:21 +0000129 VisitDeclContext(D->getDeclContext());
Ted Kremenekcb674f92010-01-12 23:33:42 +0000130 const std::string &s = D->getNameAsString();
131 assert(!s.empty());
Ted Kremeneke1b55252010-01-14 01:50:21 +0000132 Out << "@^" << s;
133}
134
135void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
136 VisitDeclContext(D->getDeclContext());
137 Out << "@N^" << D->getNameAsString();
Ted Kremenekcb674f92010-01-12 23:33:42 +0000138}
139
140void USRGenerator::VisitRecordDecl(RecordDecl *D) {
Ted Kremeneke1b55252010-01-14 01:50:21 +0000141 VisitDeclContext(D->getDeclContext());
142 Out << "@S^";
Ted Kremenek6b1d5502010-01-15 23:34:31 +0000143 VisitTagDeclCommon(D);
Ted Kremenekcb674f92010-01-12 23:33:42 +0000144}
145
146void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
147 Visit(cast<Decl>(D->getDeclContext()));
148 Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
149 Out << DeclarationName(D->getSelector()).getAsString();
150}
151
152void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
153 switch (D->getKind()) {
154 default:
155 assert(false && "Invalid ObjC container.");
156 case Decl::ObjCInterface:
157 case Decl::ObjCImplementation:
158 Out << "objc(cs)" << D->getName();
159 break;
160 case Decl::ObjCCategory: {
161 ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
162 Out << "objc(cy)" << CD->getClassInterface()->getName()
163 << '_' << CD->getName();
164 break;
165 }
166 case Decl::ObjCCategoryImpl: {
167 ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
168 Out << "objc(cy)" << CD->getClassInterface()->getName()
169 << '_' << CD->getName();
170 break;
171 }
172 case Decl::ObjCProtocol:
173 Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName();
174 break;
175 }
176}
177
178void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
179 Visit(cast<Decl>(D->getDeclContext()));
180 Out << "(py)" << D->getName();
181}
182
Ted Kremenek6b1d5502010-01-15 23:34:31 +0000183void USRGenerator::VisitTagDeclCommon(TagDecl *D) {
184 // FIXME: Better support for anonymous structures and enums.
185 const std::string &s = D->getNameAsString();
186 if (s.empty()) {
187 if (TypedefDecl *TD = D->getTypedefForAnonDecl())
188 Out << "^anontd^" << TD->getNameAsString();
189 else
190 Out << "^anon";
191 }
192 else
193 Out << s;
194}
195
Ted Kremenekcb674f92010-01-12 23:33:42 +0000196void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
197 DeclContext *DC = D->getDeclContext();
198 if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
199 Visit(DCN);
200 Out << "typedef@" << D->getName();
201}
202
Ted Kremenek473c7a72010-01-18 20:23:29 +0000203// FIXME: This is a skeleton implementation. It will be overhauled.
204static CXString ConstructUSR(Decl *D) {
205 llvm::SmallString<1024> StrBuf;
206 {
207 llvm::raw_svector_ostream Out(StrBuf);
208 USRGenerator UG(Out);
209 UG.Visit(static_cast<Decl*>(D));
Ted Kremeneka6980af2010-01-18 22:02:49 +0000210 if (UG.ignoreResults())
211 return CIndexer::createCXString(NULL);
Ted Kremenek473c7a72010-01-18 20:23:29 +0000212 }
213
214 if (StrBuf.empty())
215 return CIndexer::createCXString(NULL);
216
217 // Return a copy of the string that must be disposed by the caller.
218 return CIndexer::createCXString(StrBuf.c_str(), true);
219}
220
221
Benjamin Kramer59617be2010-01-12 11:32:40 +0000222extern "C" {
223
Ted Kremeneke5f86be2010-01-11 23:56:39 +0000224/// clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any)
225/// in a specified translation unit.
226CXDecl clang_getDeclaration(CXEntity CE, CXTranslationUnit TU) {
227 return (CXDecl) GetEntity(CE).getDecl(GetASTContext(TU));
228}
229
230
231CXEntity clang_getEntityFromDecl(CXIndex CIdx, CXDecl CE) {
232 if (Decl *D = (Decl *) CE)
233 return MakeEntity(CIdx, Entity::get(D, GetProgram(CIdx)));
234 return NullCXEntity();
235}
Ted Kremenek5631d2d2010-01-12 02:07:58 +0000236
Ted Kremenek473c7a72010-01-18 20:23:29 +0000237CXString clang_getCursorUSR(CXCursor C) {
238 if (Decl *D = cxcursor::getCursorDecl(C))
239 return ConstructUSR(D);
240
241
242 return CIndexer::createCXString(NULL);
243}
Ted Kremenek9cd9f6d2010-01-05 22:06:45 +0000244
Ted Kremenek9cd9f6d2010-01-05 22:06:45 +0000245} // end extern "C"