DeclBase.cpp revision 1e68ecc4fcce12f683c4fd38acfd1a004001b04f
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/DeclContextInternals.h" 17#include "clang/AST/DeclCXX.h" 18#include "clang/AST/DeclFriend.h" 19#include "clang/AST/DeclObjC.h" 20#include "clang/AST/DeclTemplate.h" 21#include "clang/AST/DependentDiagnostic.h" 22#include "clang/AST/ExternalASTSource.h" 23#include "clang/AST/ASTContext.h" 24#include "clang/AST/Type.h" 25#include "clang/AST/Stmt.h" 26#include "clang/AST/StmtCXX.h" 27#include "clang/AST/ASTMutationListener.h" 28#include "clang/Basic/TargetInfo.h" 29#include "llvm/ADT/DenseMap.h" 30#include "llvm/Support/raw_ostream.h" 31#include <algorithm> 32using namespace clang; 33 34//===----------------------------------------------------------------------===// 35// Statistics 36//===----------------------------------------------------------------------===// 37 38#define DECL(DERIVED, BASE) static int n##DERIVED##s = 0; 39#define ABSTRACT_DECL(DECL) 40#include "clang/AST/DeclNodes.inc" 41 42static bool StatSwitch = false; 43 44void *Decl::AllocateDeserializedDecl(const ASTContext &Context, 45 unsigned ID, 46 unsigned Size) { 47 return Context.Allocate(Size); 48} 49 50const char *Decl::getDeclKindName() const { 51 switch (DeclKind) { 52 default: llvm_unreachable("Declaration not in DeclNodes.inc!"); 53#define DECL(DERIVED, BASE) case DERIVED: return #DERIVED; 54#define ABSTRACT_DECL(DECL) 55#include "clang/AST/DeclNodes.inc" 56 } 57} 58 59void Decl::setInvalidDecl(bool Invalid) { 60 InvalidDecl = Invalid; 61 if (Invalid) { 62 // Defensive maneuver for ill-formed code: we're likely not to make it to 63 // a point where we set the access specifier, so default it to "public" 64 // to avoid triggering asserts elsewhere in the front end. 65 setAccess(AS_public); 66 } 67} 68 69const char *DeclContext::getDeclKindName() const { 70 switch (DeclKind) { 71 default: llvm_unreachable("Declaration context not in DeclNodes.inc!"); 72#define DECL(DERIVED, BASE) case Decl::DERIVED: return #DERIVED; 73#define ABSTRACT_DECL(DECL) 74#include "clang/AST/DeclNodes.inc" 75 } 76} 77 78bool Decl::CollectingStats(bool Enable) { 79 if (Enable) StatSwitch = true; 80 return StatSwitch; 81} 82 83void Decl::PrintStats() { 84 llvm::errs() << "\n*** Decl Stats:\n"; 85 86 int totalDecls = 0; 87#define DECL(DERIVED, BASE) totalDecls += n##DERIVED##s; 88#define ABSTRACT_DECL(DECL) 89#include "clang/AST/DeclNodes.inc" 90 llvm::errs() << " " << totalDecls << " decls total.\n"; 91 92 int totalBytes = 0; 93#define DECL(DERIVED, BASE) \ 94 if (n##DERIVED##s > 0) { \ 95 totalBytes += (int)(n##DERIVED##s * sizeof(DERIVED##Decl)); \ 96 llvm::errs() << " " << n##DERIVED##s << " " #DERIVED " decls, " \ 97 << sizeof(DERIVED##Decl) << " each (" \ 98 << n##DERIVED##s * sizeof(DERIVED##Decl) \ 99 << " bytes)\n"; \ 100 } 101#define ABSTRACT_DECL(DECL) 102#include "clang/AST/DeclNodes.inc" 103 104 llvm::errs() << "Total bytes = " << totalBytes << "\n"; 105} 106 107void Decl::add(Kind k) { 108 switch (k) { 109 default: llvm_unreachable("Declaration not in DeclNodes.inc!"); 110#define DECL(DERIVED, BASE) case DERIVED: ++n##DERIVED##s; break; 111#define ABSTRACT_DECL(DECL) 112#include "clang/AST/DeclNodes.inc" 113 } 114} 115 116bool Decl::isTemplateParameterPack() const { 117 if (const TemplateTypeParmDecl *TTP = dyn_cast<TemplateTypeParmDecl>(this)) 118 return TTP->isParameterPack(); 119 if (const NonTypeTemplateParmDecl *NTTP 120 = dyn_cast<NonTypeTemplateParmDecl>(this)) 121 return NTTP->isParameterPack(); 122 if (const TemplateTemplateParmDecl *TTP 123 = dyn_cast<TemplateTemplateParmDecl>(this)) 124 return TTP->isParameterPack(); 125 return false; 126} 127 128bool Decl::isParameterPack() const { 129 if (const ParmVarDecl *Parm = dyn_cast<ParmVarDecl>(this)) 130 return Parm->isParameterPack(); 131 132 return isTemplateParameterPack(); 133} 134 135bool Decl::isFunctionOrFunctionTemplate() const { 136 if (const UsingShadowDecl *UD = dyn_cast<UsingShadowDecl>(this)) 137 return UD->getTargetDecl()->isFunctionOrFunctionTemplate(); 138 139 return isa<FunctionDecl>(this) || isa<FunctionTemplateDecl>(this); 140} 141 142bool Decl::isTemplateDecl() const { 143 return isa<TemplateDecl>(this); 144} 145 146const DeclContext *Decl::getParentFunctionOrMethod() const { 147 for (const DeclContext *DC = getDeclContext(); 148 DC && !DC->isTranslationUnit() && !DC->isNamespace(); 149 DC = DC->getParent()) 150 if (DC->isFunctionOrMethod()) 151 return DC; 152 153 return 0; 154} 155 156 157//===----------------------------------------------------------------------===// 158// PrettyStackTraceDecl Implementation 159//===----------------------------------------------------------------------===// 160 161void PrettyStackTraceDecl::print(raw_ostream &OS) const { 162 SourceLocation TheLoc = Loc; 163 if (TheLoc.isInvalid() && TheDecl) 164 TheLoc = TheDecl->getLocation(); 165 166 if (TheLoc.isValid()) { 167 TheLoc.print(OS, SM); 168 OS << ": "; 169 } 170 171 OS << Message; 172 173 if (const NamedDecl *DN = dyn_cast_or_null<NamedDecl>(TheDecl)) 174 OS << " '" << DN->getQualifiedNameAsString() << '\''; 175 OS << '\n'; 176} 177 178//===----------------------------------------------------------------------===// 179// Decl Implementation 180//===----------------------------------------------------------------------===// 181 182// Out-of-line virtual method providing a home for Decl. 183Decl::~Decl() { } 184 185void Decl::setDeclContext(DeclContext *DC) { 186 DeclCtx = DC; 187} 188 189void Decl::setLexicalDeclContext(DeclContext *DC) { 190 if (DC == getLexicalDeclContext()) 191 return; 192 193 if (isInSemaDC()) { 194 MultipleDC *MDC = new (getASTContext()) MultipleDC(); 195 MDC->SemanticDC = getDeclContext(); 196 MDC->LexicalDC = DC; 197 DeclCtx = MDC; 198 } else { 199 getMultipleDC()->LexicalDC = DC; 200 } 201} 202 203bool Decl::isInAnonymousNamespace() const { 204 const DeclContext *DC = getDeclContext(); 205 do { 206 if (const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(DC)) 207 if (ND->isAnonymousNamespace()) 208 return true; 209 } while ((DC = DC->getParent())); 210 211 return false; 212} 213 214TranslationUnitDecl *Decl::getTranslationUnitDecl() { 215 if (TranslationUnitDecl *TUD = dyn_cast<TranslationUnitDecl>(this)) 216 return TUD; 217 218 DeclContext *DC = getDeclContext(); 219 assert(DC && "This decl is not contained in a translation unit!"); 220 221 while (!DC->isTranslationUnit()) { 222 DC = DC->getParent(); 223 assert(DC && "This decl is not contained in a translation unit!"); 224 } 225 226 return cast<TranslationUnitDecl>(DC); 227} 228 229ASTContext &Decl::getASTContext() const { 230 return getTranslationUnitDecl()->getASTContext(); 231} 232 233ASTMutationListener *Decl::getASTMutationListener() const { 234 return getASTContext().getASTMutationListener(); 235} 236 237bool Decl::isUsed(bool CheckUsedAttr) const { 238 if (Used) 239 return true; 240 241 // Check for used attribute. 242 if (CheckUsedAttr && hasAttr<UsedAttr>()) 243 return true; 244 245 // Check redeclarations for used attribute. 246 for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) { 247 if ((CheckUsedAttr && I->hasAttr<UsedAttr>()) || I->Used) 248 return true; 249 } 250 251 return false; 252} 253 254bool Decl::isReferenced() const { 255 if (Referenced) 256 return true; 257 258 // Check redeclarations. 259 for (redecl_iterator I = redecls_begin(), E = redecls_end(); I != E; ++I) 260 if (I->Referenced) 261 return true; 262 263 return false; 264} 265 266/// \brief Determine the availability of the given declaration based on 267/// the target platform. 268/// 269/// When it returns an availability result other than \c AR_Available, 270/// if the \p Message parameter is non-NULL, it will be set to a 271/// string describing why the entity is unavailable. 272/// 273/// FIXME: Make these strings localizable, since they end up in 274/// diagnostics. 275static AvailabilityResult CheckAvailability(ASTContext &Context, 276 const AvailabilityAttr *A, 277 std::string *Message) { 278 StringRef TargetPlatform = Context.getTargetInfo().getPlatformName(); 279 StringRef PrettyPlatformName 280 = AvailabilityAttr::getPrettyPlatformName(TargetPlatform); 281 if (PrettyPlatformName.empty()) 282 PrettyPlatformName = TargetPlatform; 283 284 VersionTuple TargetMinVersion = Context.getTargetInfo().getPlatformMinVersion(); 285 if (TargetMinVersion.empty()) 286 return AR_Available; 287 288 // Match the platform name. 289 if (A->getPlatform()->getName() != TargetPlatform) 290 return AR_Available; 291 292 std::string HintMessage; 293 if (!A->getMessage().empty()) { 294 HintMessage = " - "; 295 HintMessage += A->getMessage(); 296 } 297 298 // Make sure that this declaration has not been marked 'unavailable'. 299 if (A->getUnavailable()) { 300 if (Message) { 301 Message->clear(); 302 llvm::raw_string_ostream Out(*Message); 303 Out << "not available on " << PrettyPlatformName 304 << HintMessage; 305 } 306 307 return AR_Unavailable; 308 } 309 310 // Make sure that this declaration has already been introduced. 311 if (!A->getIntroduced().empty() && 312 TargetMinVersion < A->getIntroduced()) { 313 if (Message) { 314 Message->clear(); 315 llvm::raw_string_ostream Out(*Message); 316 Out << "introduced in " << PrettyPlatformName << ' ' 317 << A->getIntroduced() << HintMessage; 318 } 319 320 return AR_NotYetIntroduced; 321 } 322 323 // Make sure that this declaration hasn't been obsoleted. 324 if (!A->getObsoleted().empty() && TargetMinVersion >= A->getObsoleted()) { 325 if (Message) { 326 Message->clear(); 327 llvm::raw_string_ostream Out(*Message); 328 Out << "obsoleted in " << PrettyPlatformName << ' ' 329 << A->getObsoleted() << HintMessage; 330 } 331 332 return AR_Unavailable; 333 } 334 335 // Make sure that this declaration hasn't been deprecated. 336 if (!A->getDeprecated().empty() && TargetMinVersion >= A->getDeprecated()) { 337 if (Message) { 338 Message->clear(); 339 llvm::raw_string_ostream Out(*Message); 340 Out << "first deprecated in " << PrettyPlatformName << ' ' 341 << A->getDeprecated() << HintMessage; 342 } 343 344 return AR_Deprecated; 345 } 346 347 return AR_Available; 348} 349 350AvailabilityResult Decl::getAvailability(std::string *Message) const { 351 AvailabilityResult Result = AR_Available; 352 std::string ResultMessage; 353 354 for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { 355 if (DeprecatedAttr *Deprecated = dyn_cast<DeprecatedAttr>(*A)) { 356 if (Result >= AR_Deprecated) 357 continue; 358 359 if (Message) 360 ResultMessage = Deprecated->getMessage(); 361 362 Result = AR_Deprecated; 363 continue; 364 } 365 366 if (UnavailableAttr *Unavailable = dyn_cast<UnavailableAttr>(*A)) { 367 if (Message) 368 *Message = Unavailable->getMessage(); 369 return AR_Unavailable; 370 } 371 372 if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { 373 AvailabilityResult AR = CheckAvailability(getASTContext(), Availability, 374 Message); 375 376 if (AR == AR_Unavailable) 377 return AR_Unavailable; 378 379 if (AR > Result) { 380 Result = AR; 381 if (Message) 382 ResultMessage.swap(*Message); 383 } 384 continue; 385 } 386 } 387 388 if (Message) 389 Message->swap(ResultMessage); 390 return Result; 391} 392 393bool Decl::canBeWeakImported(bool &IsDefinition) const { 394 IsDefinition = false; 395 if (const VarDecl *Var = dyn_cast<VarDecl>(this)) { 396 if (!Var->hasExternalStorage() || Var->getInit()) { 397 IsDefinition = true; 398 return false; 399 } 400 } else if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { 401 if (FD->hasBody()) { 402 IsDefinition = true; 403 return false; 404 } 405 } else if (isa<ObjCPropertyDecl>(this) || isa<ObjCMethodDecl>(this)) 406 return false; 407 else if (!(getASTContext().getLangOptions().ObjCNonFragileABI && 408 isa<ObjCInterfaceDecl>(this))) 409 return false; 410 411 return true; 412} 413 414bool Decl::isWeakImported() const { 415 bool IsDefinition; 416 if (!canBeWeakImported(IsDefinition)) 417 return false; 418 419 for (attr_iterator A = attr_begin(), AEnd = attr_end(); A != AEnd; ++A) { 420 if (isa<WeakImportAttr>(*A)) 421 return true; 422 423 if (AvailabilityAttr *Availability = dyn_cast<AvailabilityAttr>(*A)) { 424 if (CheckAvailability(getASTContext(), Availability, 0) 425 == AR_NotYetIntroduced) 426 return true; 427 } 428 } 429 430 return false; 431} 432 433unsigned Decl::getIdentifierNamespaceForKind(Kind DeclKind) { 434 switch (DeclKind) { 435 case Function: 436 case CXXMethod: 437 case CXXConstructor: 438 case CXXDestructor: 439 case CXXConversion: 440 case EnumConstant: 441 case Var: 442 case ImplicitParam: 443 case ParmVar: 444 case NonTypeTemplateParm: 445 case ObjCMethod: 446 case ObjCProperty: 447 return IDNS_Ordinary; 448 case Label: 449 return IDNS_Label; 450 case IndirectField: 451 return IDNS_Ordinary | IDNS_Member; 452 453 case ObjCCompatibleAlias: 454 case ObjCInterface: 455 return IDNS_Ordinary | IDNS_Type; 456 457 case Typedef: 458 case TypeAlias: 459 case TypeAliasTemplate: 460 case UnresolvedUsingTypename: 461 case TemplateTypeParm: 462 return IDNS_Ordinary | IDNS_Type; 463 464 case UsingShadow: 465 return 0; // we'll actually overwrite this later 466 467 case UnresolvedUsingValue: 468 return IDNS_Ordinary | IDNS_Using; 469 470 case Using: 471 return IDNS_Using; 472 473 case ObjCProtocol: 474 return IDNS_ObjCProtocol; 475 476 case Field: 477 case ObjCAtDefsField: 478 case ObjCIvar: 479 return IDNS_Member; 480 481 case Record: 482 case CXXRecord: 483 case Enum: 484 return IDNS_Tag | IDNS_Type; 485 486 case Namespace: 487 case NamespaceAlias: 488 return IDNS_Namespace; 489 490 case FunctionTemplate: 491 return IDNS_Ordinary; 492 493 case ClassTemplate: 494 case TemplateTemplateParm: 495 return IDNS_Ordinary | IDNS_Tag | IDNS_Type; 496 497 // Never have names. 498 case Friend: 499 case FriendTemplate: 500 case AccessSpec: 501 case LinkageSpec: 502 case FileScopeAsm: 503 case StaticAssert: 504 case ObjCPropertyImpl: 505 case Block: 506 case TranslationUnit: 507 508 case UsingDirective: 509 case ClassTemplateSpecialization: 510 case ClassTemplatePartialSpecialization: 511 case ClassScopeFunctionSpecialization: 512 case ObjCImplementation: 513 case ObjCCategory: 514 case ObjCCategoryImpl: 515 case Import: 516 // Never looked up by name. 517 return 0; 518 } 519 520 return 0; 521} 522 523void Decl::setAttrs(const AttrVec &attrs) { 524 assert(!HasAttrs && "Decl already contains attrs."); 525 526 AttrVec &AttrBlank = getASTContext().getDeclAttrs(this); 527 assert(AttrBlank.empty() && "HasAttrs was wrong?"); 528 529 AttrBlank = attrs; 530 HasAttrs = true; 531} 532 533void Decl::dropAttrs() { 534 if (!HasAttrs) return; 535 536 HasAttrs = false; 537 getASTContext().eraseDeclAttrs(this); 538} 539 540const AttrVec &Decl::getAttrs() const { 541 assert(HasAttrs && "No attrs to get!"); 542 return getASTContext().getDeclAttrs(this); 543} 544 545void Decl::swapAttrs(Decl *RHS) { 546 bool HasLHSAttr = this->HasAttrs; 547 bool HasRHSAttr = RHS->HasAttrs; 548 549 // Usually, neither decl has attrs, nothing to do. 550 if (!HasLHSAttr && !HasRHSAttr) return; 551 552 // If 'this' has no attrs, swap the other way. 553 if (!HasLHSAttr) 554 return RHS->swapAttrs(this); 555 556 ASTContext &Context = getASTContext(); 557 558 // Handle the case when both decls have attrs. 559 if (HasRHSAttr) { 560 std::swap(Context.getDeclAttrs(this), Context.getDeclAttrs(RHS)); 561 return; 562 } 563 564 // Otherwise, LHS has an attr and RHS doesn't. 565 Context.getDeclAttrs(RHS) = Context.getDeclAttrs(this); 566 Context.eraseDeclAttrs(this); 567 this->HasAttrs = false; 568 RHS->HasAttrs = true; 569} 570 571Decl *Decl::castFromDeclContext (const DeclContext *D) { 572 Decl::Kind DK = D->getDeclKind(); 573 switch(DK) { 574#define DECL(NAME, BASE) 575#define DECL_CONTEXT(NAME) \ 576 case Decl::NAME: \ 577 return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); 578#define DECL_CONTEXT_BASE(NAME) 579#include "clang/AST/DeclNodes.inc" 580 default: 581#define DECL(NAME, BASE) 582#define DECL_CONTEXT_BASE(NAME) \ 583 if (DK >= first##NAME && DK <= last##NAME) \ 584 return static_cast<NAME##Decl*>(const_cast<DeclContext*>(D)); 585#include "clang/AST/DeclNodes.inc" 586 llvm_unreachable("a decl that inherits DeclContext isn't handled"); 587 } 588} 589 590DeclContext *Decl::castToDeclContext(const Decl *D) { 591 Decl::Kind DK = D->getKind(); 592 switch(DK) { 593#define DECL(NAME, BASE) 594#define DECL_CONTEXT(NAME) \ 595 case Decl::NAME: \ 596 return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); 597#define DECL_CONTEXT_BASE(NAME) 598#include "clang/AST/DeclNodes.inc" 599 default: 600#define DECL(NAME, BASE) 601#define DECL_CONTEXT_BASE(NAME) \ 602 if (DK >= first##NAME && DK <= last##NAME) \ 603 return static_cast<NAME##Decl*>(const_cast<Decl*>(D)); 604#include "clang/AST/DeclNodes.inc" 605 llvm_unreachable("a decl that inherits DeclContext isn't handled"); 606 } 607} 608 609SourceLocation Decl::getBodyRBrace() const { 610 // Special handling of FunctionDecl to avoid de-serializing the body from PCH. 611 // FunctionDecl stores EndRangeLoc for this purpose. 612 if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(this)) { 613 const FunctionDecl *Definition; 614 if (FD->hasBody(Definition)) 615 return Definition->getSourceRange().getEnd(); 616 return SourceLocation(); 617 } 618 619 if (Stmt *Body = getBody()) 620 return Body->getSourceRange().getEnd(); 621 622 return SourceLocation(); 623} 624 625void Decl::CheckAccessDeclContext() const { 626#ifndef NDEBUG 627 // Suppress this check if any of the following hold: 628 // 1. this is the translation unit (and thus has no parent) 629 // 2. this is a template parameter (and thus doesn't belong to its context) 630 // 3. this is a non-type template parameter 631 // 4. the context is not a record 632 // 5. it's invalid 633 // 6. it's a C++0x static_assert. 634 if (isa<TranslationUnitDecl>(this) || 635 isa<TemplateTypeParmDecl>(this) || 636 isa<NonTypeTemplateParmDecl>(this) || 637 !isa<CXXRecordDecl>(getDeclContext()) || 638 isInvalidDecl() || 639 isa<StaticAssertDecl>(this) || 640 // FIXME: a ParmVarDecl can have ClassTemplateSpecialization 641 // as DeclContext (?). 642 isa<ParmVarDecl>(this) || 643 // FIXME: a ClassTemplateSpecialization or CXXRecordDecl can have 644 // AS_none as access specifier. 645 isa<CXXRecordDecl>(this) || 646 isa<ClassScopeFunctionSpecializationDecl>(this)) 647 return; 648 649 assert(Access != AS_none && 650 "Access specifier is AS_none inside a record decl"); 651#endif 652} 653 654DeclContext *Decl::getNonClosureContext() { 655 return getDeclContext()->getNonClosureAncestor(); 656} 657 658DeclContext *DeclContext::getNonClosureAncestor() { 659 DeclContext *DC = this; 660 661 // This is basically "while (DC->isClosure()) DC = DC->getParent();" 662 // except that it's significantly more efficient to cast to a known 663 // decl type and call getDeclContext() than to call getParent(). 664 while (isa<BlockDecl>(DC)) 665 DC = cast<BlockDecl>(DC)->getDeclContext(); 666 667 assert(!DC->isClosure()); 668 return DC; 669} 670 671//===----------------------------------------------------------------------===// 672// DeclContext Implementation 673//===----------------------------------------------------------------------===// 674 675bool DeclContext::classof(const Decl *D) { 676 switch (D->getKind()) { 677#define DECL(NAME, BASE) 678#define DECL_CONTEXT(NAME) case Decl::NAME: 679#define DECL_CONTEXT_BASE(NAME) 680#include "clang/AST/DeclNodes.inc" 681 return true; 682 default: 683#define DECL(NAME, BASE) 684#define DECL_CONTEXT_BASE(NAME) \ 685 if (D->getKind() >= Decl::first##NAME && \ 686 D->getKind() <= Decl::last##NAME) \ 687 return true; 688#include "clang/AST/DeclNodes.inc" 689 return false; 690 } 691} 692 693DeclContext::~DeclContext() { } 694 695/// \brief Find the parent context of this context that will be 696/// used for unqualified name lookup. 697/// 698/// Generally, the parent lookup context is the semantic context. However, for 699/// a friend function the parent lookup context is the lexical context, which 700/// is the class in which the friend is declared. 701DeclContext *DeclContext::getLookupParent() { 702 // FIXME: Find a better way to identify friends 703 if (isa<FunctionDecl>(this)) 704 if (getParent()->getRedeclContext()->isFileContext() && 705 getLexicalParent()->getRedeclContext()->isRecord()) 706 return getLexicalParent(); 707 708 return getParent(); 709} 710 711bool DeclContext::isInlineNamespace() const { 712 return isNamespace() && 713 cast<NamespaceDecl>(this)->isInline(); 714} 715 716bool DeclContext::isDependentContext() const { 717 if (isFileContext()) 718 return false; 719 720 if (isa<ClassTemplatePartialSpecializationDecl>(this)) 721 return true; 722 723 if (const CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) 724 if (Record->getDescribedClassTemplate()) 725 return true; 726 727 if (const FunctionDecl *Function = dyn_cast<FunctionDecl>(this)) { 728 if (Function->getDescribedFunctionTemplate()) 729 return true; 730 731 // Friend function declarations are dependent if their *lexical* 732 // context is dependent. 733 if (cast<Decl>(this)->getFriendObjectKind()) 734 return getLexicalParent()->isDependentContext(); 735 } 736 737 return getParent() && getParent()->isDependentContext(); 738} 739 740bool DeclContext::isTransparentContext() const { 741 if (DeclKind == Decl::Enum) 742 return !cast<EnumDecl>(this)->isScoped(); 743 else if (DeclKind == Decl::LinkageSpec) 744 return true; 745 746 return false; 747} 748 749bool DeclContext::isExternCContext() const { 750 const DeclContext *DC = this; 751 while (DC->DeclKind != Decl::TranslationUnit) { 752 if (DC->DeclKind == Decl::LinkageSpec) 753 return cast<LinkageSpecDecl>(DC)->getLanguage() 754 == LinkageSpecDecl::lang_c; 755 DC = DC->getParent(); 756 } 757 return false; 758} 759 760bool DeclContext::Encloses(const DeclContext *DC) const { 761 if (getPrimaryContext() != this) 762 return getPrimaryContext()->Encloses(DC); 763 764 for (; DC; DC = DC->getParent()) 765 if (DC->getPrimaryContext() == this) 766 return true; 767 return false; 768} 769 770DeclContext *DeclContext::getPrimaryContext() { 771 switch (DeclKind) { 772 case Decl::TranslationUnit: 773 case Decl::LinkageSpec: 774 case Decl::Block: 775 // There is only one DeclContext for these entities. 776 return this; 777 778 case Decl::Namespace: 779 // The original namespace is our primary context. 780 return static_cast<NamespaceDecl*>(this)->getOriginalNamespace(); 781 782 case Decl::ObjCMethod: 783 return this; 784 785 case Decl::ObjCInterface: 786 if (ObjCInterfaceDecl *Def = cast<ObjCInterfaceDecl>(this)->getDefinition()) 787 return Def; 788 789 return this; 790 791 case Decl::ObjCProtocol: 792 if (ObjCProtocolDecl *Def = cast<ObjCProtocolDecl>(this)->getDefinition()) 793 return Def; 794 795 return this; 796 797 case Decl::ObjCCategory: 798 return this; 799 800 case Decl::ObjCImplementation: 801 case Decl::ObjCCategoryImpl: 802 return this; 803 804 default: 805 if (DeclKind >= Decl::firstTag && DeclKind <= Decl::lastTag) { 806 // If this is a tag type that has a definition or is currently 807 // being defined, that definition is our primary context. 808 TagDecl *Tag = cast<TagDecl>(this); 809 assert(isa<TagType>(Tag->TypeForDecl) || 810 isa<InjectedClassNameType>(Tag->TypeForDecl)); 811 812 if (TagDecl *Def = Tag->getDefinition()) 813 return Def; 814 815 if (!isa<InjectedClassNameType>(Tag->TypeForDecl)) { 816 const TagType *TagTy = cast<TagType>(Tag->TypeForDecl); 817 if (TagTy->isBeingDefined()) 818 // FIXME: is it necessarily being defined in the decl 819 // that owns the type? 820 return TagTy->getDecl(); 821 } 822 823 return Tag; 824 } 825 826 assert(DeclKind >= Decl::firstFunction && DeclKind <= Decl::lastFunction && 827 "Unknown DeclContext kind"); 828 return this; 829 } 830} 831 832DeclContext *DeclContext::getNextContext() { 833 switch (DeclKind) { 834 case Decl::Namespace: 835 // Return the next namespace 836 return static_cast<NamespaceDecl*>(this)->getNextNamespace(); 837 838 default: 839 return 0; 840 } 841} 842 843std::pair<Decl *, Decl *> 844DeclContext::BuildDeclChain(const SmallVectorImpl<Decl*> &Decls, 845 bool FieldsAlreadyLoaded) { 846 // Build up a chain of declarations via the Decl::NextDeclInContext field. 847 Decl *FirstNewDecl = 0; 848 Decl *PrevDecl = 0; 849 for (unsigned I = 0, N = Decls.size(); I != N; ++I) { 850 if (FieldsAlreadyLoaded && isa<FieldDecl>(Decls[I])) 851 continue; 852 853 Decl *D = Decls[I]; 854 if (PrevDecl) 855 PrevDecl->NextDeclInContext = D; 856 else 857 FirstNewDecl = D; 858 859 PrevDecl = D; 860 } 861 862 return std::make_pair(FirstNewDecl, PrevDecl); 863} 864 865/// \brief Load the declarations within this lexical storage from an 866/// external source. 867void 868DeclContext::LoadLexicalDeclsFromExternalStorage() const { 869 ExternalASTSource *Source = getParentASTContext().getExternalSource(); 870 assert(hasExternalLexicalStorage() && Source && "No external storage?"); 871 872 // Notify that we have a DeclContext that is initializing. 873 ExternalASTSource::Deserializing ADeclContext(Source); 874 875 // Load the external declarations, if any. 876 SmallVector<Decl*, 64> Decls; 877 ExternalLexicalStorage = false; 878 switch (Source->FindExternalLexicalDecls(this, Decls)) { 879 case ELR_Success: 880 break; 881 882 case ELR_Failure: 883 case ELR_AlreadyLoaded: 884 return; 885 } 886 887 if (Decls.empty()) 888 return; 889 890 // We may have already loaded just the fields of this record, in which case 891 // we need to ignore them. 892 bool FieldsAlreadyLoaded = false; 893 if (const RecordDecl *RD = dyn_cast<RecordDecl>(this)) 894 FieldsAlreadyLoaded = RD->LoadedFieldsFromExternalStorage; 895 896 // Splice the newly-read declarations into the beginning of the list 897 // of declarations. 898 Decl *ExternalFirst, *ExternalLast; 899 llvm::tie(ExternalFirst, ExternalLast) = BuildDeclChain(Decls, 900 FieldsAlreadyLoaded); 901 ExternalLast->NextDeclInContext = FirstDecl; 902 FirstDecl = ExternalFirst; 903 if (!LastDecl) 904 LastDecl = ExternalLast; 905} 906 907DeclContext::lookup_result 908ExternalASTSource::SetNoExternalVisibleDeclsForName(const DeclContext *DC, 909 DeclarationName Name) { 910 ASTContext &Context = DC->getParentASTContext(); 911 StoredDeclsMap *Map; 912 if (!(Map = DC->LookupPtr)) 913 Map = DC->CreateStoredDeclsMap(Context); 914 915 StoredDeclsList &List = (*Map)[Name]; 916 assert(List.isNull()); 917 (void) List; 918 919 return DeclContext::lookup_result(); 920} 921 922DeclContext::lookup_result 923ExternalASTSource::SetExternalVisibleDeclsForName(const DeclContext *DC, 924 DeclarationName Name, 925 ArrayRef<NamedDecl*> Decls) { 926 ASTContext &Context = DC->getParentASTContext();; 927 928 StoredDeclsMap *Map; 929 if (!(Map = DC->LookupPtr)) 930 Map = DC->CreateStoredDeclsMap(Context); 931 932 StoredDeclsList &List = (*Map)[Name]; 933 for (ArrayRef<NamedDecl*>::iterator 934 I = Decls.begin(), E = Decls.end(); I != E; ++I) { 935 if (List.isNull()) 936 List.setOnlyValue(*I); 937 else 938 List.AddSubsequentDecl(*I); 939 } 940 941 return List.getLookupResult(); 942} 943 944DeclContext::decl_iterator DeclContext::noload_decls_begin() const { 945 return decl_iterator(FirstDecl); 946} 947 948DeclContext::decl_iterator DeclContext::noload_decls_end() const { 949 return decl_iterator(); 950} 951 952DeclContext::decl_iterator DeclContext::decls_begin() const { 953 if (hasExternalLexicalStorage()) 954 LoadLexicalDeclsFromExternalStorage(); 955 956 return decl_iterator(FirstDecl); 957} 958 959DeclContext::decl_iterator DeclContext::decls_end() const { 960 if (hasExternalLexicalStorage()) 961 LoadLexicalDeclsFromExternalStorage(); 962 963 return decl_iterator(); 964} 965 966bool DeclContext::decls_empty() const { 967 if (hasExternalLexicalStorage()) 968 LoadLexicalDeclsFromExternalStorage(); 969 970 return !FirstDecl; 971} 972 973void DeclContext::removeDecl(Decl *D) { 974 assert(D->getLexicalDeclContext() == this && 975 "decl being removed from non-lexical context"); 976 assert((D->NextDeclInContext || D == LastDecl) && 977 "decl is not in decls list"); 978 979 // Remove D from the decl chain. This is O(n) but hopefully rare. 980 if (D == FirstDecl) { 981 if (D == LastDecl) 982 FirstDecl = LastDecl = 0; 983 else 984 FirstDecl = D->NextDeclInContext; 985 } else { 986 for (Decl *I = FirstDecl; true; I = I->NextDeclInContext) { 987 assert(I && "decl not found in linked list"); 988 if (I->NextDeclInContext == D) { 989 I->NextDeclInContext = D->NextDeclInContext; 990 if (D == LastDecl) LastDecl = I; 991 break; 992 } 993 } 994 } 995 996 // Mark that D is no longer in the decl chain. 997 D->NextDeclInContext = 0; 998 999 // Remove D from the lookup table if necessary. 1000 if (isa<NamedDecl>(D)) { 1001 NamedDecl *ND = cast<NamedDecl>(D); 1002 1003 // Remove only decls that have a name 1004 if (!ND->getDeclName()) return; 1005 1006 StoredDeclsMap *Map = getPrimaryContext()->LookupPtr; 1007 if (!Map) return; 1008 1009 StoredDeclsMap::iterator Pos = Map->find(ND->getDeclName()); 1010 assert(Pos != Map->end() && "no lookup entry for decl"); 1011 if (Pos->second.getAsVector() || Pos->second.getAsDecl() == ND) 1012 Pos->second.remove(ND); 1013 } 1014} 1015 1016void DeclContext::addHiddenDecl(Decl *D) { 1017 assert(D->getLexicalDeclContext() == this && 1018 "Decl inserted into wrong lexical context"); 1019 assert(!D->getNextDeclInContext() && D != LastDecl && 1020 "Decl already inserted into a DeclContext"); 1021 1022 if (FirstDecl) { 1023 LastDecl->NextDeclInContext = D; 1024 LastDecl = D; 1025 } else { 1026 FirstDecl = LastDecl = D; 1027 } 1028 1029 // Notify a C++ record declaration that we've added a member, so it can 1030 // update it's class-specific state. 1031 if (CXXRecordDecl *Record = dyn_cast<CXXRecordDecl>(this)) 1032 Record->addedMember(D); 1033 1034 // If this is a newly-created (not de-serialized) import declaration, wire 1035 // it in to the list of local import declarations. 1036 if (!D->isFromASTFile()) { 1037 if (ImportDecl *Import = dyn_cast<ImportDecl>(D)) 1038 D->getASTContext().addedLocalImportDecl(Import); 1039 } 1040} 1041 1042void DeclContext::addDecl(Decl *D) { 1043 addHiddenDecl(D); 1044 1045 if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) 1046 ND->getDeclContext()->makeDeclVisibleInContext(ND); 1047} 1048 1049void DeclContext::addDeclInternal(Decl *D) { 1050 addHiddenDecl(D); 1051 1052 if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) 1053 ND->getDeclContext()->makeDeclVisibleInContextInternal(ND); 1054} 1055 1056/// buildLookup - Build the lookup data structure with all of the 1057/// declarations in DCtx (and any other contexts linked to it or 1058/// transparent contexts nested within it). 1059void DeclContext::buildLookup(DeclContext *DCtx) { 1060 for (; DCtx; DCtx = DCtx->getNextContext()) { 1061 for (decl_iterator D = DCtx->decls_begin(), 1062 DEnd = DCtx->decls_end(); 1063 D != DEnd; ++D) { 1064 // Insert this declaration into the lookup structure, but only 1065 // if it's semantically in its decl context. During non-lazy 1066 // lookup building, this is implicitly enforced by addDecl. 1067 if (NamedDecl *ND = dyn_cast<NamedDecl>(*D)) 1068 if (D->getDeclContext() == DCtx) 1069 makeDeclVisibleInContextImpl(ND, false); 1070 1071 // If this declaration is itself a transparent declaration context or 1072 // inline namespace, add its members (recursively). 1073 if (DeclContext *InnerCtx = dyn_cast<DeclContext>(*D)) 1074 if (InnerCtx->isTransparentContext() || InnerCtx->isInlineNamespace()) 1075 buildLookup(InnerCtx->getPrimaryContext()); 1076 } 1077 } 1078} 1079 1080DeclContext::lookup_result 1081DeclContext::lookup(DeclarationName Name) { 1082 DeclContext *PrimaryContext = getPrimaryContext(); 1083 if (PrimaryContext != this) 1084 return PrimaryContext->lookup(Name); 1085 1086 if (hasExternalVisibleStorage()) { 1087 // Check to see if we've already cached the lookup results. 1088 if (LookupPtr) { 1089 StoredDeclsMap::iterator I = LookupPtr->find(Name); 1090 if (I != LookupPtr->end()) 1091 return I->second.getLookupResult(); 1092 } 1093 1094 ExternalASTSource *Source = getParentASTContext().getExternalSource(); 1095 return Source->FindExternalVisibleDeclsByName(this, Name); 1096 } 1097 1098 /// If there is no lookup data structure, build one now by walking 1099 /// all of the linked DeclContexts (in declaration order!) and 1100 /// inserting their values. 1101 if (!LookupPtr) { 1102 buildLookup(this); 1103 1104 if (!LookupPtr) 1105 return lookup_result(lookup_iterator(0), lookup_iterator(0)); 1106 } 1107 1108 StoredDeclsMap::iterator Pos = LookupPtr->find(Name); 1109 if (Pos == LookupPtr->end()) 1110 return lookup_result(lookup_iterator(0), lookup_iterator(0)); 1111 return Pos->second.getLookupResult(); 1112} 1113 1114DeclContext::lookup_const_result 1115DeclContext::lookup(DeclarationName Name) const { 1116 return const_cast<DeclContext*>(this)->lookup(Name); 1117} 1118 1119void DeclContext::localUncachedLookup(DeclarationName Name, 1120 llvm::SmallVectorImpl<NamedDecl *> &Results) { 1121 Results.clear(); 1122 1123 // If there's no external storage, just perform a normal lookup and copy 1124 // the results. 1125 if (!hasExternalVisibleStorage() && !hasExternalLexicalStorage()) { 1126 lookup_result LookupResults = lookup(Name); 1127 Results.insert(Results.end(), LookupResults.first, LookupResults.second); 1128 return; 1129 } 1130 1131 // If we have a lookup table, check there first. Maybe we'll get lucky. 1132 if (LookupPtr) { 1133 StoredDeclsMap::iterator Pos = LookupPtr->find(Name); 1134 if (Pos != LookupPtr->end()) { 1135 Results.insert(Results.end(), 1136 Pos->second.getLookupResult().first, 1137 Pos->second.getLookupResult().second); 1138 return; 1139 } 1140 } 1141 1142 // Slow case: grovel through the declarations in our chain looking for 1143 // matches. 1144 for (Decl *D = FirstDecl; D; D = D->getNextDeclInContext()) { 1145 if (NamedDecl *ND = dyn_cast<NamedDecl>(D)) 1146 if (ND->getDeclName() == Name) 1147 Results.push_back(ND); 1148 } 1149} 1150 1151DeclContext *DeclContext::getRedeclContext() { 1152 DeclContext *Ctx = this; 1153 // Skip through transparent contexts. 1154 while (Ctx->isTransparentContext()) 1155 Ctx = Ctx->getParent(); 1156 return Ctx; 1157} 1158 1159DeclContext *DeclContext::getEnclosingNamespaceContext() { 1160 DeclContext *Ctx = this; 1161 // Skip through non-namespace, non-translation-unit contexts. 1162 while (!Ctx->isFileContext()) 1163 Ctx = Ctx->getParent(); 1164 return Ctx->getPrimaryContext(); 1165} 1166 1167bool DeclContext::InEnclosingNamespaceSetOf(const DeclContext *O) const { 1168 // For non-file contexts, this is equivalent to Equals. 1169 if (!isFileContext()) 1170 return O->Equals(this); 1171 1172 do { 1173 if (O->Equals(this)) 1174 return true; 1175 1176 const NamespaceDecl *NS = dyn_cast<NamespaceDecl>(O); 1177 if (!NS || !NS->isInline()) 1178 break; 1179 O = NS->getParent(); 1180 } while (O); 1181 1182 return false; 1183} 1184 1185void DeclContext::makeDeclVisibleInContext(NamedDecl *D, bool Recoverable) 1186{ 1187 makeDeclVisibleInContextWithFlags(D, false, Recoverable); 1188} 1189 1190void DeclContext::makeDeclVisibleInContextInternal(NamedDecl *D, bool Recoverable) 1191{ 1192 makeDeclVisibleInContextWithFlags(D, true, Recoverable); 1193} 1194 1195void DeclContext::makeDeclVisibleInContextWithFlags(NamedDecl *D, bool Internal, bool Recoverable) { 1196 // FIXME: This feels like a hack. Should DeclarationName support 1197 // template-ids, or is there a better way to keep specializations 1198 // from being visible? 1199 if (isa<ClassTemplateSpecializationDecl>(D) || D->isTemplateParameter()) 1200 return; 1201 if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) 1202 if (FD->isFunctionTemplateSpecialization()) 1203 return; 1204 1205 DeclContext *PrimaryContext = getPrimaryContext(); 1206 if (PrimaryContext != this) { 1207 PrimaryContext->makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); 1208 return; 1209 } 1210 1211 // If we already have a lookup data structure, perform the insertion 1212 // into it. If we haven't deserialized externally stored decls, deserialize 1213 // them so we can add the decl. Otherwise, be lazy and don't build that 1214 // structure until someone asks for it. 1215 if (LookupPtr || !Recoverable || hasExternalVisibleStorage()) 1216 makeDeclVisibleInContextImpl(D, Internal); 1217 1218 // If we are a transparent context or inline namespace, insert into our 1219 // parent context, too. This operation is recursive. 1220 if (isTransparentContext() || isInlineNamespace()) 1221 getParent()->makeDeclVisibleInContextWithFlags(D, Internal, Recoverable); 1222 1223 Decl *DCAsDecl = cast<Decl>(this); 1224 // Notify that a decl was made visible unless it's a Tag being defined. 1225 if (!(isa<TagDecl>(DCAsDecl) && cast<TagDecl>(DCAsDecl)->isBeingDefined())) 1226 if (ASTMutationListener *L = DCAsDecl->getASTMutationListener()) 1227 L->AddedVisibleDecl(this, D); 1228} 1229 1230void DeclContext::makeDeclVisibleInContextImpl(NamedDecl *D, bool Internal) { 1231 // Skip unnamed declarations. 1232 if (!D->getDeclName()) 1233 return; 1234 1235 // Skip entities that can't be found by name lookup into a particular 1236 // context. 1237 if ((D->getIdentifierNamespace() == 0 && !isa<UsingDirectiveDecl>(D)) || 1238 D->isTemplateParameter()) 1239 return; 1240 1241 ASTContext *C = 0; 1242 if (!LookupPtr) { 1243 C = &getParentASTContext(); 1244 CreateStoredDeclsMap(*C); 1245 } 1246 1247 // If there is an external AST source, load any declarations it knows about 1248 // with this declaration's name. 1249 // If the lookup table contains an entry about this name it means that we 1250 // have already checked the external source. 1251 if (!Internal) 1252 if (ExternalASTSource *Source = getParentASTContext().getExternalSource()) 1253 if (hasExternalVisibleStorage() && 1254 LookupPtr->find(D->getDeclName()) == LookupPtr->end()) 1255 Source->FindExternalVisibleDeclsByName(this, D->getDeclName()); 1256 1257 // Insert this declaration into the map. 1258 StoredDeclsList &DeclNameEntries = (*LookupPtr)[D->getDeclName()]; 1259 if (DeclNameEntries.isNull()) { 1260 DeclNameEntries.setOnlyValue(D); 1261 return; 1262 } 1263 1264 // If it is possible that this is a redeclaration, check to see if there is 1265 // already a decl for which declarationReplaces returns true. If there is 1266 // one, just replace it and return. 1267 if (DeclNameEntries.HandleRedeclaration(D)) 1268 return; 1269 1270 // Put this declaration into the appropriate slot. 1271 DeclNameEntries.AddSubsequentDecl(D); 1272} 1273 1274/// Returns iterator range [First, Last) of UsingDirectiveDecls stored within 1275/// this context. 1276DeclContext::udir_iterator_range 1277DeclContext::getUsingDirectives() const { 1278 lookup_const_result Result = lookup(UsingDirectiveDecl::getName()); 1279 return udir_iterator_range(reinterpret_cast<udir_iterator>(Result.first), 1280 reinterpret_cast<udir_iterator>(Result.second)); 1281} 1282 1283//===----------------------------------------------------------------------===// 1284// Creation and Destruction of StoredDeclsMaps. // 1285//===----------------------------------------------------------------------===// 1286 1287StoredDeclsMap *DeclContext::CreateStoredDeclsMap(ASTContext &C) const { 1288 assert(!LookupPtr && "context already has a decls map"); 1289 assert(getPrimaryContext() == this && 1290 "creating decls map on non-primary context"); 1291 1292 StoredDeclsMap *M; 1293 bool Dependent = isDependentContext(); 1294 if (Dependent) 1295 M = new DependentStoredDeclsMap(); 1296 else 1297 M = new StoredDeclsMap(); 1298 M->Previous = C.LastSDM; 1299 C.LastSDM = llvm::PointerIntPair<StoredDeclsMap*,1>(M, Dependent); 1300 LookupPtr = M; 1301 return M; 1302} 1303 1304void ASTContext::ReleaseDeclContextMaps() { 1305 // It's okay to delete DependentStoredDeclsMaps via a StoredDeclsMap 1306 // pointer because the subclass doesn't add anything that needs to 1307 // be deleted. 1308 StoredDeclsMap::DestroyAll(LastSDM.getPointer(), LastSDM.getInt()); 1309} 1310 1311void StoredDeclsMap::DestroyAll(StoredDeclsMap *Map, bool Dependent) { 1312 while (Map) { 1313 // Advance the iteration before we invalidate memory. 1314 llvm::PointerIntPair<StoredDeclsMap*,1> Next = Map->Previous; 1315 1316 if (Dependent) 1317 delete static_cast<DependentStoredDeclsMap*>(Map); 1318 else 1319 delete Map; 1320 1321 Map = Next.getPointer(); 1322 Dependent = Next.getInt(); 1323 } 1324} 1325 1326DependentDiagnostic *DependentDiagnostic::Create(ASTContext &C, 1327 DeclContext *Parent, 1328 const PartialDiagnostic &PDiag) { 1329 assert(Parent->isDependentContext() 1330 && "cannot iterate dependent diagnostics of non-dependent context"); 1331 Parent = Parent->getPrimaryContext(); 1332 if (!Parent->LookupPtr) 1333 Parent->CreateStoredDeclsMap(C); 1334 1335 DependentStoredDeclsMap *Map 1336 = static_cast<DependentStoredDeclsMap*>(Parent->LookupPtr); 1337 1338 // Allocate the copy of the PartialDiagnostic via the ASTContext's 1339 // BumpPtrAllocator, rather than the ASTContext itself. 1340 PartialDiagnostic::Storage *DiagStorage = 0; 1341 if (PDiag.hasStorage()) 1342 DiagStorage = new (C) PartialDiagnostic::Storage; 1343 1344 DependentDiagnostic *DD = new (C) DependentDiagnostic(PDiag, DiagStorage); 1345 1346 // TODO: Maybe we shouldn't reverse the order during insertion. 1347 DD->NextDiagnostic = Map->FirstDiagnostic; 1348 Map->FirstDiagnostic = DD; 1349 1350 return DD; 1351} 1352