blob: 4f43c50d141a8ccef909ee7c019f2c4b44fc79e3 [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"
Ted Kremenek87763822010-01-12 02:07:58 +000017#include "llvm/ADT/SmallString.h"
Benjamin Kramer9895c6a2010-01-12 11:32:40 +000018#include "llvm/Support/raw_ostream.h"
Ted Kremenek1b6869a2010-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 Kremenek31723832010-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 Kremenek1b6869a2010-01-05 22:06:45 +000042}
43
Ted Kremenek31723832010-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 Kramer9895c6a2010-01-12 11:32:40 +000065
Ted Kremenekc50277f2010-01-12 23:33:42 +000066//===----------------------------------------------------------------------===//
67// USR generation.
68//===----------------------------------------------------------------------===//
69
70namespace {
Ted Kremenek2fee4e62010-01-14 01:50:21 +000071class USRGenerator : public DeclVisitor<USRGenerator> {
72 llvm::raw_ostream &Out;
Ted Kremenek3adca6d2010-01-18 22:02:49 +000073 bool IgnoreResults;
Ted Kremenek2fee4e62010-01-14 01:50:21 +000074public:
Ted Kremenek3adca6d2010-01-18 22:02:49 +000075 USRGenerator(llvm::raw_ostream &out) : Out(out), IgnoreResults(false) {}
76
77 bool ignoreResults() const { return IgnoreResults; }
Ted Kremenek2fee4e62010-01-14 01:50:21 +000078
79 void VisitBlockDecl(BlockDecl *D);
80 void VisitDeclContext(DeclContext *D);
Ted Kremenek3adca6d2010-01-18 22:02:49 +000081 void VisitFieldDecl(FieldDecl *D);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000082 void VisitFunctionDecl(FunctionDecl *D);
83 void VisitNamedDecl(NamedDecl *D);
84 void VisitNamespaceDecl(NamespaceDecl *D);
85 void VisitObjCContainerDecl(ObjCContainerDecl *CD);
86 void VisitObjCMethodDecl(ObjCMethodDecl *MD);
87 void VisitObjCPropertyDecl(ObjCPropertyDecl *D);
Ted Kremenekb82b3be2010-01-18 22:42:20 +000088 void VisitTagDecl(TagDecl *D);
Ted Kremenek2fee4e62010-01-14 01:50:21 +000089 void VisitTypedefDecl(TypedefDecl *D);
90};
Ted Kremenekc50277f2010-01-12 23:33:42 +000091} // end anonymous namespace
92
Ted Kremenek2fee4e62010-01-14 01:50:21 +000093void USRGenerator::VisitBlockDecl(BlockDecl *D) {
94 VisitDeclContext(D->getDeclContext());
95 // FIXME: Better support for anonymous blocks.
96 Out << "@B^anon";
97}
98
99void USRGenerator::VisitDeclContext(DeclContext *DC) {
100 if (NamedDecl *D = dyn_cast<NamedDecl>(DC))
101 Visit(D);
102}
103
Ted Kremenek3adca6d2010-01-18 22:02:49 +0000104void USRGenerator::VisitFieldDecl(FieldDecl *D) {
105 const std::string &s = D->getNameAsString();
106 if (s.empty()) {
107 // Bit fields can be anonymous.
108 IgnoreResults = true;
109 return;
110 }
111 VisitDeclContext(D->getDeclContext());
112 Out << "@^FI^" << s;
113}
114
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000115void USRGenerator::VisitFunctionDecl(FunctionDecl *D) {
116 VisitDeclContext(D->getDeclContext());
117 Out << "@F^" << D->getNameAsString();
118}
Ted Kremenekc50277f2010-01-12 23:33:42 +0000119
120void USRGenerator::VisitNamedDecl(NamedDecl *D) {
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000121 VisitDeclContext(D->getDeclContext());
Ted Kremenekc50277f2010-01-12 23:33:42 +0000122 const std::string &s = D->getNameAsString();
123 assert(!s.empty());
Ted Kremenek2fee4e62010-01-14 01:50:21 +0000124 Out << "@^" << s;
125}
126
127void USRGenerator::VisitNamespaceDecl(NamespaceDecl *D) {
128 VisitDeclContext(D->getDeclContext());
129 Out << "@N^" << D->getNameAsString();
Ted Kremenekc50277f2010-01-12 23:33:42 +0000130}
131
Ted Kremenekc50277f2010-01-12 23:33:42 +0000132void USRGenerator::VisitObjCMethodDecl(ObjCMethodDecl *D) {
133 Visit(cast<Decl>(D->getDeclContext()));
134 Out << (D->isInstanceMethod() ? "(im)" : "(cm)");
135 Out << DeclarationName(D->getSelector()).getAsString();
136}
137
138void USRGenerator::VisitObjCContainerDecl(ObjCContainerDecl *D) {
139 switch (D->getKind()) {
140 default:
141 assert(false && "Invalid ObjC container.");
142 case Decl::ObjCInterface:
143 case Decl::ObjCImplementation:
144 Out << "objc(cs)" << D->getName();
145 break;
146 case Decl::ObjCCategory: {
147 ObjCCategoryDecl *CD = cast<ObjCCategoryDecl>(D);
148 Out << "objc(cy)" << CD->getClassInterface()->getName()
Ted Kremeneke381c992010-01-18 23:25:32 +0000149 << '^' << CD->getName();
Ted Kremenekc50277f2010-01-12 23:33:42 +0000150 break;
151 }
152 case Decl::ObjCCategoryImpl: {
153 ObjCCategoryImplDecl *CD = cast<ObjCCategoryImplDecl>(D);
154 Out << "objc(cy)" << CD->getClassInterface()->getName()
Ted Kremeneke381c992010-01-18 23:25:32 +0000155 << '^' << CD->getName();
Ted Kremenekc50277f2010-01-12 23:33:42 +0000156 break;
157 }
158 case Decl::ObjCProtocol:
159 Out << "objc(pl)" << cast<ObjCProtocolDecl>(D)->getName();
160 break;
161 }
162}
163
164void USRGenerator::VisitObjCPropertyDecl(ObjCPropertyDecl *D) {
165 Visit(cast<Decl>(D->getDeclContext()));
166 Out << "(py)" << D->getName();
167}
168
Ted Kremenekb82b3be2010-01-18 22:42:20 +0000169void USRGenerator::VisitTagDecl(TagDecl *D) {
170 VisitDeclContext(D->getDeclContext());
171 switch (D->getTagKind()) {
172 case TagDecl::TK_struct: Out << "@S^"; break;
173 case TagDecl::TK_class: Out << "@C^"; break;
174 case TagDecl::TK_union: Out << "@U^"; break;
175 case TagDecl::TK_enum: Out << "@E^"; break;
176 }
177
Ted Kremenekc5b48b32010-01-15 23:34:31 +0000178 // FIXME: Better support for anonymous structures and enums.
179 const std::string &s = D->getNameAsString();
180 if (s.empty()) {
181 if (TypedefDecl *TD = D->getTypedefForAnonDecl())
182 Out << "^anontd^" << TD->getNameAsString();
183 else
184 Out << "^anon";
185 }
186 else
187 Out << s;
188}
189
Ted Kremenekc50277f2010-01-12 23:33:42 +0000190void USRGenerator::VisitTypedefDecl(TypedefDecl *D) {
191 DeclContext *DC = D->getDeclContext();
192 if (NamedDecl *DCN = dyn_cast<NamedDecl>(DC))
193 Visit(DCN);
194 Out << "typedef@" << D->getName();
195}
196
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000197// FIXME: This is a skeleton implementation. It will be overhauled.
198static CXString ConstructUSR(Decl *D) {
199 llvm::SmallString<1024> StrBuf;
200 {
201 llvm::raw_svector_ostream Out(StrBuf);
202 USRGenerator UG(Out);
203 UG.Visit(static_cast<Decl*>(D));
Ted Kremenek3adca6d2010-01-18 22:02:49 +0000204 if (UG.ignoreResults())
205 return CIndexer::createCXString(NULL);
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000206 }
207
208 if (StrBuf.empty())
209 return CIndexer::createCXString(NULL);
210
211 // Return a copy of the string that must be disposed by the caller.
212 return CIndexer::createCXString(StrBuf.c_str(), true);
213}
214
215
Benjamin Kramer9895c6a2010-01-12 11:32:40 +0000216extern "C" {
217
Ted Kremenek31723832010-01-11 23:56:39 +0000218/// clang_getDeclaration() maps from a CXEntity to the matching CXDecl (if any)
219/// in a specified translation unit.
220CXDecl clang_getDeclaration(CXEntity CE, CXTranslationUnit TU) {
221 return (CXDecl) GetEntity(CE).getDecl(GetASTContext(TU));
222}
223
224
225CXEntity clang_getEntityFromDecl(CXIndex CIdx, CXDecl CE) {
226 if (Decl *D = (Decl *) CE)
227 return MakeEntity(CIdx, Entity::get(D, GetProgram(CIdx)));
228 return NullCXEntity();
229}
Ted Kremenek87763822010-01-12 02:07:58 +0000230
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000231CXString clang_getCursorUSR(CXCursor C) {
232 if (Decl *D = cxcursor::getCursorDecl(C))
Ted Kremeneke381c992010-01-18 23:25:32 +0000233 return ConstructUSR(D);
Ted Kremenekcf84aa42010-01-18 20:23:29 +0000234
235 return CIndexer::createCXString(NULL);
236}
Ted Kremenek1b6869a2010-01-05 22:06:45 +0000237
Ted Kremenek1b6869a2010-01-05 22:06:45 +0000238} // end extern "C"