DeclBase.cpp revision 67762a35dca6202d2272db02d0b8740728e3aa8f
1//===--- DeclBase.cpp - Declaration AST Node Implementation ---------------===// 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 Decl and DeclContext classes. 11// 12//===----------------------------------------------------------------------===// 13 14#include "clang/AST/DeclBase.h" 15#include "clang/AST/Decl.h" 16#include "clang/AST/DeclCXX.h" 17#include "clang/AST/DeclObjC.h" 18#include "clang/AST/DeclTemplate.h" 19#include "clang/AST/ASTContext.h" 20#include "clang/AST/Type.h" 21#include "llvm/ADT/DenseMap.h" 22#include <algorithm> 23#include <functional> 24#include <vector> 25using namespace clang; 26 27//===----------------------------------------------------------------------===// 28// Statistics 29//===----------------------------------------------------------------------===// 30 31#define DECL(Derived, Base) static int n##Derived##s = 0; 32#include "clang/AST/DeclNodes.def" 33 34static bool StatSwitch = false; 35 36// This keeps track of all decl attributes. Since so few decls have attrs, we 37// keep them in a hash map instead of wasting space in the Decl class. 38typedef llvm::DenseMap<const Decl*, Attr*> DeclAttrMapTy; 39 40static DeclAttrMapTy *DeclAttrs = 0; 41 42const char *Decl::getDeclKindName() const { 43 switch (DeclKind) { 44 default: assert(0 && "Declaration not in DeclNodes.def!"); 45#define DECL(Derived, Base) case Derived: return #Derived; 46#include "clang/AST/DeclNodes.def" 47 } 48} 49 50const char *DeclContext::getDeclKindName() const { 51 switch (DeclKind) { 52 default: assert(0 && "Declaration context not in DeclNodes.def!"); 53#define DECL(Derived, Base) case Decl::Derived: return #Derived; 54#include "clang/AST/DeclNodes.def" 55 } 56} 57 58bool Decl::CollectingStats(bool Enable) { 59 if (Enable) 60 StatSwitch = true; 61 return StatSwitch; 62} 63 64void Decl::PrintStats() { 65 fprintf(stderr, "*** Decl Stats:\n"); 66 67 int totalDecls = 0; 68#define DECL(Derived, Base) totalDecls += n##Derived##s; 69#include "clang/AST/DeclNodes.def" 70 fprintf(stderr, " %d decls total.\n", totalDecls); 71 72 int totalBytes = 0; 73#define DECL(Derived, Base) \ 74 if (n##Derived##s > 0) { \ 75 totalBytes += (int)(n##Derived##s * sizeof(Derived##Decl)); \ 76 fprintf(stderr, " %d " #Derived " decls, %d each (%d bytes)\n", \ 77 n##Derived##s, (int)sizeof(Derived##Decl), \ 78 (int)(n##Derived##s * sizeof(Derived##Decl))); \ 79 } 80#include "clang/AST/DeclNodes.def" 81 82 fprintf(stderr, "Total bytes = %d\n", totalBytes); 83} 84 85void Decl::addDeclKind(Kind k) { 86 switch (k) { 87 default: assert(0 && "Declaration not in DeclNodes.def!"); 88#define DECL(Derived, Base) case Derived: ++n##Derived##s; break; 89#include "clang/AST/DeclNodes.def" 90 } 91} 92 93//===----------------------------------------------------------------------===// 94// Decl Implementation 95//===----------------------------------------------------------------------===// 96 97void Decl::setDeclContext(DeclContext *DC) { 98 if (isOutOfSemaDC()) 99 delete getMultipleDC(); 100 101 DeclCtx = reinterpret_cast<uintptr_t>(DC); 102} 103 104void Decl::setLexicalDeclContext(DeclContext *DC) { 105 if (DC == getLexicalDeclContext()) 106 return; 107 108 if (isInSemaDC()) { 109 MultipleDC *MDC = new MultipleDC(); 110 MDC->SemanticDC = getDeclContext(); 111 MDC->LexicalDC = DC; 112 DeclCtx = reinterpret_cast<uintptr_t>(MDC) | 0x1; 113 } else { 114 getMultipleDC()->LexicalDC = DC; 115 } 116} 117 118// Out-of-line virtual method providing a home for Decl. 119Decl::~Decl() { 120 if (isOutOfSemaDC()) 121 delete getMultipleDC(); 122 123 if (!HasAttrs) 124 return; 125 126 DeclAttrMapTy::iterator it = DeclAttrs->find(this); 127 assert(it != DeclAttrs->end() && "No attrs found but HasAttrs is true!"); 128 129 // release attributes. 130 delete it->second; 131 invalidateAttrs(); 132} 133 134void Decl::addAttr(Attr *NewAttr) { 135 if (!DeclAttrs) 136 DeclAttrs = new DeclAttrMapTy(); 137 138 Attr *&ExistingAttr = (*DeclAttrs)[this]; 139 140 NewAttr->setNext(ExistingAttr); 141 ExistingAttr = NewAttr; 142 143 HasAttrs = true; 144} 145 146void Decl::invalidateAttrs() { 147 if (!HasAttrs) return; 148 149 HasAttrs = false; 150 (*DeclAttrs)[this] = 0; 151 DeclAttrs->erase(this); 152 153 if (DeclAttrs->empty()) { 154 delete DeclAttrs; 155 DeclAttrs = 0; 156 } 157} 158 159const Attr *Decl::getAttrs() const { 160 if (!HasAttrs) 161 return 0; 162 163 return (*DeclAttrs)[this]; 164} 165 166void Decl::swapAttrs(Decl *RHS) { 167 bool HasLHSAttr = this->HasAttrs; 168 bool HasRHSAttr = RHS->HasAttrs; 169 170 // Usually, neither decl has attrs, nothing to do. 171 if (!HasLHSAttr && !HasRHSAttr) return; 172 173 // If 'this' has no attrs, swap the other way. 174 if (!HasLHSAttr) 175 return RHS->swapAttrs(this); 176 177 // Handle the case when both decls have attrs. 178 if (HasRHSAttr) { 179 std::swap((*DeclAttrs)[this], (*DeclAttrs)[RHS]); 180 return; 181 } 182 183 // Otherwise, LHS has an attr and RHS doesn't. 184 (*DeclAttrs)[RHS] = (*DeclAttrs)[this]; 185 (*DeclAttrs).erase(this); 186 this->HasAttrs = false; 187 RHS->HasAttrs = true; 188} 189 190 191void Decl::Destroy(ASTContext& C) { 192#if 0 193 // FIXME: Once ownership is fully understood, we can enable this code 194 if (DeclContext *DC = dyn_cast<DeclContext>(this)) 195 DC->decls_begin()->Destroy(C); 196 197 // Observe the unrolled recursion. By setting N->NextDeclInScope = 0x0 198 // within the loop, only the Destroy method for the first Decl 199 // will deallocate all of the Decls in a chain. 200 201 Decl* N = NextDeclInScope; 202 203 while (N) { 204 Decl* Tmp = N->NextDeclInScope; 205 N->NextDeclInScope = 0; 206 N->Destroy(C); 207 N = Tmp; 208 } 209 210 this->~Decl(); 211 C.Deallocate((void *)this); 212#endif 213} 214 215Decl *Decl::castFromDeclContext (const DeclContext *D) { 216 Decl::Kind DK = D->getDeclKind(); 217 switch(DK) { 218#define DECL_CONTEXT(Name) \ 219 case Decl::Name: \ 220 return static_cast<Name##Decl*>(const_cast<DeclContext*>(D)); 221#define DECL_CONTEXT_BASE(Name) 222#include "clang/AST/DeclNodes.def" 223 default: 224#define DECL_CONTEXT_BASE(Name) \ 225 if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \ 226 return static_cast<Name##Decl*>(const_cast<DeclContext*>(D)); 227#include "clang/AST/DeclNodes.def" 228 assert(false && "a decl that inherits DeclContext isn't handled"); 229 return 0; 230 } 231} 232 233DeclContext *Decl::castToDeclContext(const Decl *D) { 234 Decl::Kind DK = D->getKind(); 235 switch(DK) { 236#define DECL_CONTEXT(Name) \ 237 case Decl::Name: \ 238 return static_cast<Name##Decl*>(const_cast<Decl*>(D)); 239#define DECL_CONTEXT_BASE(Name) 240#include "clang/AST/DeclNodes.def" 241 default: 242#define DECL_CONTEXT_BASE(Name) \ 243 if (DK >= Decl::Name##First && DK <= Decl::Name##Last) \ 244 return static_cast<Name##Decl*>(const_cast<Decl*>(D)); 245#include "clang/AST/DeclNodes.def" 246 assert(false && "a decl that inherits DeclContext isn't handled"); 247 return 0; 248 } 249} 250 251//===----------------------------------------------------------------------===// 252// DeclContext Implementation 253//===----------------------------------------------------------------------===// 254 255bool DeclContext::classof(const Decl *D) { 256 switch (D->getKind()) { 257#define DECL_CONTEXT(Name) case Decl::Name: 258#define DECL_CONTEXT_BASE(Name) 259#include "clang/AST/DeclNodes.def" 260 return true; 261 default: 262#define DECL_CONTEXT_BASE(Name) \ 263 if (D->getKind() >= Decl::Name##First && \ 264 D->getKind() <= Decl::Name##Last) \ 265 return true; 266#include "clang/AST/DeclNodes.def" 267 return false; 268 } 269} 270 271/// StoredDeclsList - This is an array of decls optimized a common case of only 272/// containing one entry. 273struct StoredDeclsList { 274 /// Data - If the integer is 0, then the pointer is a NamedDecl*. If the 275 /// integer is 1, then it is a VectorTy; 276 llvm::PointerIntPair<void*, 1, bool> Data; 277 278 /// VectorTy - When in vector form, this is what the Data pointer points to. 279 typedef llvm::SmallVector<NamedDecl*, 4> VectorTy; 280public: 281 StoredDeclsList() {} 282 StoredDeclsList(const StoredDeclsList &RHS) : Data(RHS.Data) { 283 if (isVector()) 284 Data.setPointer(new VectorTy(getVector())); 285 } 286 287 ~StoredDeclsList() { 288 // If this is a vector-form, free the vector. 289 if (isVector()) 290 delete &getVector(); 291 } 292 293 bool isVector() const { return Data.getInt() != 0; } 294 bool isInline() const { return Data.getInt() == 0; } 295 bool isNull() const { return Data.getPointer() == 0; } 296 297 void setOnlyValue(NamedDecl *ND) { 298 assert(isInline() && "Not inline"); 299 Data.setPointer(ND); 300 } 301 302 /// getLookupResult - Return an array of all the decls that this list 303 /// represents. 304 DeclContext::lookup_result getLookupResult() { 305 // If we have a single inline unit, return it. 306 if (isInline()) { 307 assert(!isNull() && "Empty list isn't allowed"); 308 309 // Data is a raw pointer to a NamedDecl*, return it. 310 void *Ptr = &Data; 311 return DeclContext::lookup_result((NamedDecl**)Ptr, (NamedDecl**)Ptr+1); 312 } 313 314 // Otherwise, we have a range result. 315 VectorTy &V = getVector(); 316 return DeclContext::lookup_result(&V[0], &V[0]+V.size()); 317 } 318 319 /// HandleRedeclaration - If this is a redeclaration of an existing decl, 320 /// replace the old one with D and return true. Otherwise return false. 321 bool HandleRedeclaration(NamedDecl *D) { 322 // Most decls only have one entry in their list, special case it. 323 if (isInline()) { 324 if (!D->declarationReplaces(getInlineValue())) 325 return false; 326 setOnlyValue(D); 327 return true; 328 } 329 330 // Determine if this declaration is actually a redeclaration. 331 VectorTy &Vec = getVector(); 332 VectorTy::iterator RDI 333 = std::find_if(Vec.begin(), Vec.end(), 334 std::bind1st(std::mem_fun(&NamedDecl::declarationReplaces), 335 D)); 336 if (RDI == Vec.end()) 337 return false; 338 *RDI = D; 339 return true; 340 } 341 342 /// AddSubsequentDecl - This is called on the second and later decl when it is 343 /// not a redeclaration to merge it into the appropriate place in our list. 344 /// 345 void AddSubsequentDecl(NamedDecl *D) { 346 // If this is the second decl added to the list, convert this to vector 347 // form. 348 if (isInline()) { 349 NamedDecl *OldD = getInlineValue(); 350 Data.setInt(1); 351 VectorTy *VT = new VectorTy(); 352 VT->push_back(OldD); 353 Data.setPointer(VT); 354 } 355 356 VectorTy &Vec = getVector(); 357 if (isa<UsingDirectiveDecl>(D) || 358 D->getIdentifierNamespace() == Decl::IDNS_Tag) 359 Vec.push_back(D); 360 else if (Vec.back()->getIdentifierNamespace() == Decl::IDNS_Tag) { 361 NamedDecl *TagD = Vec.back(); 362 Vec.back() = D; 363 Vec.push_back(TagD); 364 } else 365 Vec.push_back(D); 366 } 367 368 369private: 370 VectorTy &getVector() const { 371 assert(isVector() && "Not in vector form"); 372 return *static_cast<VectorTy*>(Data.getPointer()); 373 } 374 375 NamedDecl *getInlineValue() const { 376 assert(isInline() && "Not in inline form"); 377 return (NamedDecl*)Data.getPointer(); 378 } 379}; 380 381 382 383typedef llvm::DenseMap<DeclarationName, StoredDeclsList> StoredDeclsMap; 384 385DeclContext::~DeclContext() { 386 unsigned Size = LookupPtr.getInt(); 387 if (Size == LookupIsMap) 388 delete static_cast<StoredDeclsMap*>(LookupPtr.getPointer()); 389 else 390 delete [] static_cast<NamedDecl**>(LookupPtr.getPointer()); 391} 392 393void DeclContext::DestroyDecls(ASTContext &C) { 394 for (decl_iterator D = decls_begin(); D != decls_end(); ) 395 (*D++)->Destroy(C); 396} 397 398bool DeclContext::isTransparentContext() const { 399 if (DeclKind == Decl::Enum) 400 return true; // FIXME: Check for C++0x scoped enums 401 else if (DeclKind == Decl::LinkageSpec) 402 return true; 403 else if (DeclKind == Decl::Record || DeclKind == Decl::CXXRecord) 404 return cast<RecordDecl>(this)->isAnonymousStructOrUnion(); 405 else if (DeclKind == Decl::Namespace) 406 return false; // FIXME: Check for C++0x inline namespaces 407 408 return false; 409} 410 411DeclContext *DeclContext::getPrimaryContext() { 412 switch (DeclKind) { 413 case Decl::TranslationUnit: 414 case Decl::LinkageSpec: 415 case Decl::Block: 416 // There is only one DeclContext for these entities. 417 return this; 418 419 case Decl::Namespace: 420 // The original namespace is our primary context. 421 return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); 422 423 case Decl::ObjCMethod: 424 return this; 425 426 case Decl::ObjCInterface: 427 case Decl::ObjCProtocol: 428 case Decl::ObjCCategory: 429 // FIXME: Can Objective-C interfaces be forward-declared? 430 return this; 431 432 case Decl::ObjCImplementation: 433 case Decl::ObjCCategoryImpl: 434 return this; 435 436 default: 437 if (DeclKind >= Decl::TagFirst && DeclKind <= Decl::TagLast) { 438 // If this is a tag type that has a definition or is currently 439 // being defined, that definition is our primary context. 440 if (TagType *TagT 441 = cast_or_null<TagType>(cast<TagDecl>(this)->TypeForDecl)) 442 if (TagT->isBeingDefined() || 443 (TagT->getDecl() && TagT->getDecl()->isDefinition())) 444 return TagT->getDecl(); 445 return this; 446 } 447 448 assert(DeclKind >= Decl::FunctionFirst && DeclKind <= Decl::FunctionLast && 449 "Unknown DeclContext kind"); 450 return this; 451 } 452} 453 454DeclContext *DeclContext::getNextContext() { 455 switch (DeclKind) { 456 case Decl::Namespace: 457 // Return the next namespace 458 return static_cast<NamespaceDecl*>(this)->getNextNamespace(); 459 460 default: 461 return 0; 462 } 463} 464 465void DeclContext::addDecl(Decl *D) { 466 assert(D->getLexicalDeclContext() == this && 467 "Decl inserted into wrong lexical context"); 468 assert(!D->NextDeclInScope && D != LastDecl && 469 "Decl already inserted into a DeclContext"); 470 471 if (FirstDecl) { 472 LastDecl->NextDeclInScope = D; 473 LastDecl = D; 474 } else { 475 FirstDecl = LastDecl = D; 476 } 477 478 if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) 479 ND->getDeclContext()->makeDeclVisibleInContext(ND); 480} 481 482/// buildLookup - Build the lookup data structure with all of the 483/// declarations in DCtx (and any other contexts linked to it or 484/// transparent contexts nested within it). 485void DeclContext::buildLookup(DeclContext *DCtx) { 486 for (; DCtx; DCtx = DCtx->getNextContext()) { 487 for (decl_iterator D = DCtx->decls_begin(), DEnd = DCtx->decls_end(); 488 D != DEnd; ++D) { 489 // Insert this declaration into the lookup structure 490 if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) 491 makeDeclVisibleInContextImpl(ND); 492 493 // If this declaration is itself a transparent declaration context, 494 // add its members (recursively). 495 if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) 496 if (InnerCtx->isTransparentContext()) 497 buildLookup(InnerCtx->getPrimaryContext()); 498 } 499 } 500} 501 502DeclContext::lookup_result 503DeclContext::lookup(DeclarationName Name) { 504 DeclContext *PrimaryContext = getPrimaryContext(); 505 if (PrimaryContext != this) 506 return PrimaryContext->lookup(Name); 507 508 /// If there is no lookup data structure, build one now by walking 509 /// all of the linked DeclContexts (in declaration order!) and 510 /// inserting their values. 511 if (LookupPtr.getPointer() == 0) 512 buildLookup(this); 513 514 if (isLookupMap()) { 515 StoredDeclsMap *Map = static_cast<StoredDeclsMap*>(LookupPtr.getPointer()); 516 StoredDeclsMap::iterator Pos = Map->find(Name); 517 if (Pos == Map->end()) 518 return lookup_result(0, 0); 519 return Pos->second.getLookupResult(); 520 } 521 522 // We have a small array. Look into it. 523 unsigned Size = LookupPtr.getInt(); 524 NamedDecl **Array = static_cast<NamedDecl**>(LookupPtr.getPointer()); 525 for (unsigned Idx = 0; Idx != Size; ++Idx) 526 if (Array[Idx]->getDeclName() == Name) { 527 unsigned Last = Idx + 1; 528 while (Last != Size && Array[Last]->getDeclName() == Name) 529 ++Last; 530 return lookup_result(&Array[Idx], &Array[Last]); 531 } 532 533 return lookup_result(0, 0); 534} 535 536DeclContext::lookup_const_result 537DeclContext::lookup(DeclarationName Name) const { 538 return const_cast<DeclContext*>(this)->lookup(Name); 539} 540 541const DeclContext *DeclContext::getLookupContext() const { 542 const DeclContext *Ctx = this; 543 // Skip through transparent contexts. 544 while (Ctx->isTransparentContext()) 545 Ctx = Ctx->getParent(); 546 return Ctx; 547} 548 549void DeclContext::makeDeclVisibleInContext(NamedDecl *D) { 550 // FIXME: This feels like a hack. Should DeclarationName support 551 // template-ids, or is there a better way to keep specializations 552 // from being visible? 553 if (isa<ClassTemplateSpecializationDecl>(D)) 554 return; 555 556 DeclContext *PrimaryContext = getPrimaryContext(); 557 if (PrimaryContext != this) { 558 PrimaryContext->makeDeclVisibleInContext(D); 559 return; 560 } 561 562 // If we already have a lookup data structure, perform the insertion 563 // into it. Otherwise, be lazy and don't build that structure until 564 // someone asks for it. 565 if (LookupPtr.getPointer()) 566 makeDeclVisibleInContextImpl(D); 567 568 // If we are a transparent context, insert into our parent context, 569 // too. This operation is recursive. 570 if (isTransparentContext()) 571 getParent()->makeDeclVisibleInContext(D); 572} 573 574void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D) { 575 // Skip unnamed declarations. 576 if (!D->getDeclName()) 577 return; 578 579 // FIXME: This feels like a hack. Should DeclarationName support 580 // template-ids, or is there a better way to keep specializations 581 // from being visible? 582 if (isa<ClassTemplateSpecializationDecl>(D)) 583 return; 584 585 bool MayBeRedeclaration = true; 586 587 if (!isLookupMap()) { 588 unsigned Size = LookupPtr.getInt(); 589 590 // The lookup data is stored as an array. Search through the array 591 // to find the insertion location. 592 NamedDecl **Array; 593 if (Size == 0) { 594 Array = new NamedDecl*[LookupIsMap - 1]; 595 LookupPtr.setPointer(Array); 596 } else { 597 Array = static_cast<NamedDecl **>(LookupPtr.getPointer()); 598 } 599 600 // We always keep declarations of the same name next to each other 601 // in the array, so that it is easy to return multiple results 602 // from lookup(). 603 unsigned FirstMatch; 604 for (FirstMatch = 0; FirstMatch != Size; ++FirstMatch) 605 if (Array[FirstMatch]->getDeclName() == D->getDeclName()) 606 break; 607 608 unsigned InsertPos = FirstMatch; 609 if (FirstMatch != Size) { 610 // We found another declaration with the same name. First 611 // determine whether this is a redeclaration of an existing 612 // declaration in this scope, in which case we will replace the 613 // existing declaration. 614 unsigned LastMatch = FirstMatch; 615 for (; LastMatch != Size; ++LastMatch) { 616 if (Array[LastMatch]->getDeclName() != D->getDeclName()) 617 break; 618 619 if (D->declarationReplaces(Array[LastMatch])) { 620 // D is a redeclaration of an existing element in the 621 // array. Replace that element with D. 622 Array[LastMatch] = D; 623 return; 624 } 625 } 626 627 // [FirstMatch, LastMatch) contains the set of declarations that 628 // have the same name as this declaration. Determine where the 629 // declaration D will be inserted into this range. 630 if (D->getKind() == Decl::UsingDirective || 631 D->getIdentifierNamespace() == Decl::IDNS_Tag) 632 InsertPos = LastMatch; 633 else if (Array[LastMatch-1]->getIdentifierNamespace() == Decl::IDNS_Tag) 634 InsertPos = LastMatch - 1; 635 else 636 InsertPos = LastMatch; 637 } 638 639 if (Size < LookupIsMap - 1) { 640 // The new declaration will fit in the array. Insert the new 641 // declaration at the position Match in the array. 642 for (unsigned Idx = Size; Idx > InsertPos; --Idx) 643 Array[Idx] = Array[Idx-1]; 644 645 Array[InsertPos] = D; 646 LookupPtr.setInt(Size + 1); 647 return; 648 } 649 650 // We've reached capacity in this array. Create a map and copy in 651 // all of the declarations that were stored in the array. 652 StoredDeclsMap *Map = new StoredDeclsMap(16); 653 LookupPtr.setPointer(Map); 654 LookupPtr.setInt(LookupIsMap); 655 for (unsigned Idx = 0; Idx != LookupIsMap - 1; ++Idx) 656 makeDeclVisibleInContextImpl(Array[Idx]); 657 delete [] Array; 658 659 // Fall through to perform insertion into the map. 660 MayBeRedeclaration = false; 661 } 662 663 // Insert this declaration into the map. 664 StoredDeclsMap &Map = *static_cast<StoredDeclsMap*>(LookupPtr.getPointer()); 665 StoredDeclsList &DeclNameEntries = Map[D->getDeclName()]; 666 if (DeclNameEntries.isNull()) { 667 DeclNameEntries.setOnlyValue(D); 668 return; 669 } 670 671 // If it is possible that this is a redeclaration, check to see if there is 672 // already a decl for which declarationReplaces returns true. If there is 673 // one, just replace it and return. 674 if (MayBeRedeclaration && DeclNameEntries.HandleRedeclaration(D)) 675 return; 676 677 // Put this declaration into the appropriate slot. 678 DeclNameEntries.AddSubsequentDecl(D); 679} 680 681/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within 682/// this context. 683DeclContext::udir_iterator_range DeclContext::getUsingDirectives() const { 684 lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); 685 return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), 686 reinterpret_cast<udir_iterator>(Result.second)); 687} 688 689