1//===- CIndexHigh.cpp - Higher level API functions ------------------------===// 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 "IndexingContext.h" 11#include "clang/AST/DeclVisitor.h" 12 13using namespace clang; 14using namespace cxindex; 15 16namespace { 17 18class IndexingDeclVisitor : public ConstDeclVisitor<IndexingDeclVisitor, bool> { 19 IndexingContext &IndexCtx; 20 21public: 22 explicit IndexingDeclVisitor(IndexingContext &indexCtx) 23 : IndexCtx(indexCtx) { } 24 25 /// \brief Returns true if the given method has been defined explicitly by the 26 /// user. 27 static bool hasUserDefined(const ObjCMethodDecl *D, 28 const ObjCImplDecl *Container) { 29 const ObjCMethodDecl *MD = Container->getMethod(D->getSelector(), 30 D->isInstanceMethod()); 31 return MD && !MD->isImplicit() && MD->isThisDeclarationADefinition(); 32 } 33 34 void handleDeclarator(const DeclaratorDecl *D, const NamedDecl *Parent = 0) { 35 if (!Parent) Parent = D; 36 37 if (!IndexCtx.shouldIndexFunctionLocalSymbols()) { 38 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), Parent); 39 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), Parent); 40 } else { 41 if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(D)) { 42 IndexCtx.handleVar(Parm); 43 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { 44 for (FunctionDecl::param_const_iterator PI = FD->param_begin(), 45 PE = FD->param_end(); 46 PI != PE; ++PI) { 47 IndexCtx.handleVar(*PI); 48 } 49 } 50 } 51 } 52 53 void handleObjCMethod(const ObjCMethodDecl *D) { 54 IndexCtx.handleObjCMethod(D); 55 if (D->isImplicit()) 56 return; 57 58 IndexCtx.indexTypeSourceInfo(D->getResultTypeSourceInfo(), D); 59 for (ObjCMethodDecl::param_const_iterator I = D->param_begin(), 60 E = D->param_end(); 61 I != E; ++I) 62 handleDeclarator(*I, D); 63 64 if (D->isThisDeclarationADefinition()) { 65 const Stmt *Body = D->getBody(); 66 if (Body) { 67 IndexCtx.indexBody(Body, D, D); 68 } 69 } 70 } 71 72 bool VisitFunctionDecl(const FunctionDecl *D) { 73 IndexCtx.handleFunction(D); 74 handleDeclarator(D); 75 76 if (const CXXConstructorDecl *Ctor = dyn_cast<CXXConstructorDecl>(D)) { 77 // Constructor initializers. 78 for (CXXConstructorDecl::init_const_iterator I = Ctor->init_begin(), 79 E = Ctor->init_end(); 80 I != E; ++I) { 81 CXXCtorInitializer *Init = *I; 82 if (Init->isWritten()) { 83 IndexCtx.indexTypeSourceInfo(Init->getTypeSourceInfo(), D); 84 if (const FieldDecl *Member = Init->getAnyMember()) 85 IndexCtx.handleReference(Member, Init->getMemberLocation(), D, D); 86 IndexCtx.indexBody(Init->getInit(), D, D); 87 } 88 } 89 } 90 91 if (D->isThisDeclarationADefinition()) { 92 const Stmt *Body = D->getBody(); 93 if (Body) { 94 IndexCtx.indexBody(Body, D, D); 95 } 96 } 97 return true; 98 } 99 100 bool VisitVarDecl(const VarDecl *D) { 101 IndexCtx.handleVar(D); 102 handleDeclarator(D); 103 IndexCtx.indexBody(D->getInit(), D); 104 return true; 105 } 106 107 bool VisitFieldDecl(const FieldDecl *D) { 108 IndexCtx.handleField(D); 109 handleDeclarator(D); 110 if (D->isBitField()) 111 IndexCtx.indexBody(D->getBitWidth(), D); 112 else if (D->hasInClassInitializer()) 113 IndexCtx.indexBody(D->getInClassInitializer(), D); 114 return true; 115 } 116 117 bool VisitMSPropertyDecl(const MSPropertyDecl *D) { 118 handleDeclarator(D); 119 return true; 120 } 121 122 bool VisitEnumConstantDecl(const EnumConstantDecl *D) { 123 IndexCtx.handleEnumerator(D); 124 IndexCtx.indexBody(D->getInitExpr(), D); 125 return true; 126 } 127 128 bool VisitTypedefNameDecl(const TypedefNameDecl *D) { 129 IndexCtx.handleTypedefName(D); 130 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 131 return true; 132 } 133 134 bool VisitTagDecl(const TagDecl *D) { 135 // Non-free standing tags are handled in indexTypeSourceInfo. 136 if (D->isFreeStanding()) 137 IndexCtx.indexTagDecl(D); 138 return true; 139 } 140 141 bool VisitObjCInterfaceDecl(const ObjCInterfaceDecl *D) { 142 IndexCtx.handleObjCInterface(D); 143 144 if (D->isThisDeclarationADefinition()) { 145 IndexCtx.indexTUDeclsInObjCContainer(); 146 IndexCtx.indexDeclContext(D); 147 } 148 return true; 149 } 150 151 bool VisitObjCProtocolDecl(const ObjCProtocolDecl *D) { 152 IndexCtx.handleObjCProtocol(D); 153 154 if (D->isThisDeclarationADefinition()) { 155 IndexCtx.indexTUDeclsInObjCContainer(); 156 IndexCtx.indexDeclContext(D); 157 } 158 return true; 159 } 160 161 bool VisitObjCImplementationDecl(const ObjCImplementationDecl *D) { 162 const ObjCInterfaceDecl *Class = D->getClassInterface(); 163 if (!Class) 164 return true; 165 166 if (Class->isImplicitInterfaceDecl()) 167 IndexCtx.handleObjCInterface(Class); 168 169 IndexCtx.handleObjCImplementation(D); 170 171 IndexCtx.indexTUDeclsInObjCContainer(); 172 173 // Index the ivars first to make sure the synthesized ivars are indexed 174 // before indexing the methods that can reference them. 175 for (ObjCImplementationDecl::ivar_iterator 176 IvarI = D->ivar_begin(), 177 IvarE = D->ivar_end(); IvarI != IvarE; ++IvarI) { 178 IndexCtx.indexDecl(*IvarI); 179 } 180 for (DeclContext::decl_iterator 181 I = D->decls_begin(), E = D->decls_end(); I != E; ++I) { 182 if (!isa<ObjCIvarDecl>(*I)) 183 IndexCtx.indexDecl(*I); 184 } 185 186 return true; 187 } 188 189 bool VisitObjCCategoryDecl(const ObjCCategoryDecl *D) { 190 IndexCtx.handleObjCCategory(D); 191 192 IndexCtx.indexTUDeclsInObjCContainer(); 193 IndexCtx.indexDeclContext(D); 194 return true; 195 } 196 197 bool VisitObjCCategoryImplDecl(const ObjCCategoryImplDecl *D) { 198 const ObjCCategoryDecl *Cat = D->getCategoryDecl(); 199 if (!Cat) 200 return true; 201 202 IndexCtx.handleObjCCategoryImpl(D); 203 204 IndexCtx.indexTUDeclsInObjCContainer(); 205 IndexCtx.indexDeclContext(D); 206 return true; 207 } 208 209 bool VisitObjCMethodDecl(const ObjCMethodDecl *D) { 210 // Methods associated with a property, even user-declared ones, are 211 // handled when we handle the property. 212 if (D->isPropertyAccessor()) 213 return true; 214 215 handleObjCMethod(D); 216 return true; 217 } 218 219 bool VisitObjCPropertyDecl(const ObjCPropertyDecl *D) { 220 if (ObjCMethodDecl *MD = D->getGetterMethodDecl()) 221 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 222 handleObjCMethod(MD); 223 if (ObjCMethodDecl *MD = D->getSetterMethodDecl()) 224 if (MD->getLexicalDeclContext() == D->getLexicalDeclContext()) 225 handleObjCMethod(MD); 226 IndexCtx.handleObjCProperty(D); 227 IndexCtx.indexTypeSourceInfo(D->getTypeSourceInfo(), D); 228 return true; 229 } 230 231 bool VisitObjCPropertyImplDecl(const ObjCPropertyImplDecl *D) { 232 ObjCPropertyDecl *PD = D->getPropertyDecl(); 233 IndexCtx.handleSynthesizedObjCProperty(D); 234 235 if (D->getPropertyImplementation() == ObjCPropertyImplDecl::Dynamic) 236 return true; 237 assert(D->getPropertyImplementation() == ObjCPropertyImplDecl::Synthesize); 238 239 if (ObjCIvarDecl *IvarD = D->getPropertyIvarDecl()) { 240 if (!IvarD->getSynthesize()) 241 IndexCtx.handleReference(IvarD, D->getPropertyIvarDeclLoc(), 0, 242 D->getDeclContext()); 243 } 244 245 if (ObjCMethodDecl *MD = PD->getGetterMethodDecl()) { 246 if (MD->isPropertyAccessor() && 247 !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext()))) 248 IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(), 249 D->getLexicalDeclContext()); 250 } 251 if (ObjCMethodDecl *MD = PD->getSetterMethodDecl()) { 252 if (MD->isPropertyAccessor() && 253 !hasUserDefined(MD, cast<ObjCImplDecl>(D->getDeclContext()))) 254 IndexCtx.handleSynthesizedObjCMethod(MD, D->getLocation(), 255 D->getLexicalDeclContext()); 256 } 257 return true; 258 } 259 260 bool VisitNamespaceDecl(const NamespaceDecl *D) { 261 IndexCtx.handleNamespace(D); 262 IndexCtx.indexDeclContext(D); 263 return true; 264 } 265 266 bool VisitUsingDecl(const UsingDecl *D) { 267 // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR, 268 // we should do better. 269 270 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); 271 for (UsingDecl::shadow_iterator 272 I = D->shadow_begin(), E = D->shadow_end(); I != E; ++I) { 273 IndexCtx.handleReference((*I)->getUnderlyingDecl(), D->getLocation(), 274 D, D->getLexicalDeclContext()); 275 } 276 return true; 277 } 278 279 bool VisitUsingDirectiveDecl(const UsingDirectiveDecl *D) { 280 // FIXME: Parent for the following is CXIdxEntity_Unexposed with no USR, 281 // we should do better. 282 283 IndexCtx.indexNestedNameSpecifierLoc(D->getQualifierLoc(), D); 284 IndexCtx.handleReference(D->getNominatedNamespaceAsWritten(), 285 D->getLocation(), D, D->getLexicalDeclContext()); 286 return true; 287 } 288 289 bool VisitClassTemplateDecl(const ClassTemplateDecl *D) { 290 IndexCtx.handleClassTemplate(D); 291 if (D->isThisDeclarationADefinition()) 292 IndexCtx.indexDeclContext(D->getTemplatedDecl()); 293 return true; 294 } 295 296 bool VisitClassTemplateSpecializationDecl(const 297 ClassTemplateSpecializationDecl *D) { 298 // FIXME: Notify subsequent callbacks if info comes from implicit 299 // instantiation. 300 if (D->isThisDeclarationADefinition() && 301 (IndexCtx.shouldIndexImplicitTemplateInsts() || 302 !IndexCtx.isTemplateImplicitInstantiation(D))) 303 IndexCtx.indexTagDecl(D); 304 return true; 305 } 306 307 bool VisitFunctionTemplateDecl(const FunctionTemplateDecl *D) { 308 IndexCtx.handleFunctionTemplate(D); 309 FunctionDecl *FD = D->getTemplatedDecl(); 310 handleDeclarator(FD, D); 311 if (FD->isThisDeclarationADefinition()) { 312 const Stmt *Body = FD->getBody(); 313 if (Body) { 314 IndexCtx.indexBody(Body, D, FD); 315 } 316 } 317 return true; 318 } 319 320 bool VisitTypeAliasTemplateDecl(const TypeAliasTemplateDecl *D) { 321 IndexCtx.handleTypeAliasTemplate(D); 322 IndexCtx.indexTypeSourceInfo(D->getTemplatedDecl()->getTypeSourceInfo(), D); 323 return true; 324 } 325 326 bool VisitImportDecl(const ImportDecl *D) { 327 IndexCtx.importedModule(D); 328 return true; 329 } 330}; 331 332} // anonymous namespace 333 334void IndexingContext::indexDecl(const Decl *D) { 335 if (D->isImplicit() && shouldIgnoreIfImplicit(D)) 336 return; 337 338 bool Handled = IndexingDeclVisitor(*this).Visit(D); 339 if (!Handled && isa<DeclContext>(D)) 340 indexDeclContext(cast<DeclContext>(D)); 341} 342 343void IndexingContext::indexDeclContext(const DeclContext *DC) { 344 for (DeclContext::decl_iterator 345 I = DC->decls_begin(), E = DC->decls_end(); I != E; ++I) { 346 indexDecl(*I); 347 } 348} 349 350void IndexingContext::indexTopLevelDecl(const Decl *D) { 351 if (isNotFromSourceFile(D->getLocation())) 352 return; 353 354 if (isa<ObjCMethodDecl>(D)) 355 return; // Wait for the objc container. 356 357 indexDecl(D); 358} 359 360void IndexingContext::indexDeclGroupRef(DeclGroupRef DG) { 361 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) 362 indexTopLevelDecl(*I); 363} 364 365void IndexingContext::indexTUDeclsInObjCContainer() { 366 while (!TUDeclsInObjCContainer.empty()) { 367 DeclGroupRef DG = TUDeclsInObjCContainer.front(); 368 TUDeclsInObjCContainer.pop_front(); 369 indexDeclGroupRef(DG); 370 } 371} 372