/// Compute the DeclContext that is associated with the given /// scope specifier. /// /// \param SS the C++ scope specifier as it appears in the source /// /// \param EnteringContext when true, we will be entering the context of /// this scope specifier, so we can retrieve the declaration context of a /// class template or class template partial specialization even if it is /// not the current instantiation. /// /// \returns the declaration context represented by the scope specifier @p SS, /// or NULL if the declaration context cannot be computed (e.g., because it is /// dependent and not the current instantiation). DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext) { if (!SS.isSet() || SS.isInvalid()) return nullptr; NestedNameSpecifier *NNS = SS.getScopeRep(); if (NNS->isDependent()) { // If this nested-name-specifier refers to the current // instantiation, return its DeclContext. if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) return Record; if (EnteringContext) { const Type *NNSType = NNS->getAsType(); if (!NNSType) { return nullptr; } // Look through type alias templates, per C++0x [temp.dep.type]p1. NNSType = Context.getCanonicalType(NNSType); if (const TemplateSpecializationType *SpecType = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. if (ClassTemplateDecl *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>( SpecType->getTemplateName().getAsTemplateDecl())) { QualType ContextType = Context.getCanonicalType(QualType(SpecType, 0)); // If the type of the nested name specifier is the same as the // injected class name of the named class template, we're entering // into that class template definition. QualType Injected = ClassTemplate->getInjectedClassNameSpecialization(); if (Context.hasSameType(Injected, ContextType)) return ClassTemplate->getTemplatedDecl(); // If the type of the nested name specifier is the same as the // type of one of the class template's class template partial // specializations, we're entering into the definition of that // class template partial specialization. if (ClassTemplatePartialSpecializationDecl *PartialSpec = ClassTemplate->findPartialSpecialization(ContextType)) { // A declaration of the partial specialization must be visible. // We can always recover here, because this only happens when we're // entering the context, and that can't happen in a SFINAE context. assert(!isSFINAEContext() && "partial specialization scope specifier in SFINAE context?"); if (!hasVisibleDeclaration(PartialSpec)) diagnoseMissingImport(SS.getLastQualifierNameLoc(), PartialSpec, MissingImportKind::PartialSpecialization, /*Recover*/true); return PartialSpec; } } } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. return RecordT->getDecl(); } } return nullptr; } switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: llvm_unreachable("Dependent nested-name-specifier has no DeclContext"); case NestedNameSpecifier::Namespace: return NNS->getAsNamespace(); case NestedNameSpecifier::NamespaceAlias: return NNS->getAsNamespaceAlias()->getNamespace(); case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { const TagType *Tag = NNS->getAsType()->getAs<TagType>(); assert(Tag && "Non-tag type in nested-name-specifier"); return Tag->getDecl(); } case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); case NestedNameSpecifier::Super: return NNS->getAsRecordDecl(); } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); }
/// \brief Compute the DeclContext that is associated with the given /// scope specifier. /// /// \param SS the C++ scope specifier as it appears in the source /// /// \param EnteringContext when true, we will be entering the context of /// this scope specifier, so we can retrieve the declaration context of a /// class template or class template partial specialization even if it is /// not the current instantiation. /// /// \returns the declaration context represented by the scope specifier @p SS, /// or NULL if the declaration context cannot be computed (e.g., because it is /// dependent and not the current instantiation). DeclContext *Sema::computeDeclContext(const CXXScopeSpec &SS, bool EnteringContext) { if (!SS.isSet() || SS.isInvalid()) return 0; NestedNameSpecifier *NNS = static_cast<NestedNameSpecifier *>(SS.getScopeRep()); if (NNS->isDependent()) { // If this nested-name-specifier refers to the current // instantiation, return its DeclContext. if (CXXRecordDecl *Record = getCurrentInstantiationOf(NNS)) return Record; if (EnteringContext) { const Type *NNSType = NNS->getAsType(); if (!NNSType) { return 0; } // Look through type alias templates, per C++0x [temp.dep.type]p1. NNSType = Context.getCanonicalType(NNSType); if (const TemplateSpecializationType *SpecType = NNSType->getAs<TemplateSpecializationType>()) { // We are entering the context of the nested name specifier, so try to // match the nested name specifier to either a primary class template // or a class template partial specialization. if (ClassTemplateDecl *ClassTemplate = dyn_cast_or_null<ClassTemplateDecl>( SpecType->getTemplateName().getAsTemplateDecl())) { QualType ContextType = Context.getCanonicalType(QualType(SpecType, 0)); // If the type of the nested name specifier is the same as the // injected class name of the named class template, we're entering // into that class template definition. QualType Injected = ClassTemplate->getInjectedClassNameSpecialization(); if (Context.hasSameType(Injected, ContextType)) return ClassTemplate->getTemplatedDecl(); // If the type of the nested name specifier is the same as the // type of one of the class template's class template partial // specializations, we're entering into the definition of that // class template partial specialization. if (ClassTemplatePartialSpecializationDecl *PartialSpec = ClassTemplate->findPartialSpecialization(ContextType)) return PartialSpec; } } else if (const RecordType *RecordT = NNSType->getAs<RecordType>()) { // The nested name specifier refers to a member of a class template. return RecordT->getDecl(); } } return 0; } switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: llvm_unreachable("Dependent nested-name-specifier has no DeclContext"); case NestedNameSpecifier::Namespace: return NNS->getAsNamespace(); case NestedNameSpecifier::NamespaceAlias: return NNS->getAsNamespaceAlias()->getNamespace(); case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { const TagType *Tag = NNS->getAsType()->getAs<TagType>(); assert(Tag && "Non-tag type in nested-name-specifier"); return Tag->getDecl(); } break; case NestedNameSpecifier::Global: return Context.getTranslationUnitDecl(); } // Required to silence a GCC warning. return 0; }
// It handles two cases: // * remove the specifier if it refers to TheNamespaceDecl // * replace the specifier with a new name if the corresponding namespace // has a name conflicts, e.g., // namespace NS1 { } // namespace NS2 { // namespace NS1 { // void foo() {} // } // namespace NS3 { // using NS1::foo; // void bar() { foo(); } // } // } // If we remove NS2, then the inner namespace NS1 conflicts with // the global NS1, but "using NS1::foo" refers to the conflicting NS1. bool RemoveNamespaceRewriteVisitor::TraverseNestedNameSpecifierLoc( NestedNameSpecifierLoc QualifierLoc) { SkipRewriteName = false; // Reset the flag if (SkipTraverseNestedNameSpecifier) { SkipTraverseNestedNameSpecifier = false; return true; } if (!QualifierLoc || QualifierLoc.getBeginLoc().isInvalid()) return true; SmallVector<NestedNameSpecifierLoc, 8> QualifierLocs; for (; QualifierLoc; QualifierLoc = QualifierLoc.getPrefix()) QualifierLocs.push_back(QualifierLoc); while (!QualifierLocs.empty()) { NestedNameSpecifierLoc Loc = QualifierLocs.pop_back_val(); NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier(); NestedNameSpecifier::SpecifierKind Kind = NNS->getKind(); const NamespaceDecl *ND = NULL; switch (Kind) { case NestedNameSpecifier::Namespace: { ND = NNS->getAsNamespace()->getCanonicalDecl(); break; } case NestedNameSpecifier::NamespaceAlias: { const NamespaceAliasDecl *NAD = NNS->getAsNamespaceAlias(); if (!NAD->getQualifier()) ND = NAD->getNamespace()->getCanonicalDecl(); break; } case NestedNameSpecifier::TypeSpec: // Fall-through case NestedNameSpecifier::TypeSpecWithTemplate: TraverseTypeLoc(Loc.getTypeLoc()); break; default: break; } if (!ND) continue; if (ND == ConsumerInstance->TheNamespaceDecl) { ConsumerInstance->RewriteHelper->removeSpecifier(Loc); continue; } std::string SpecifierName; if (Loc.getBeginLoc().isInvalid()) continue; ConsumerInstance->RewriteHelper->getSpecifierAsString(Loc, SpecifierName); std::string NDName = ND->getNameAsString(); std::string Name = ""; ConsumerInstance->getNewName(ND, Name); // Skip it if this specifier is the same as ND's name. // Note that the above case could only happen for UsingNamedDecls if (ConsumerInstance->isForUsingNamedDecls && (SpecifierName == NDName)) { // It could happen for example: // namespace NS1 { } // namespace NS2 { // using namespace NS1; // void bar() { NS1::foo(); } // } // If we remove NS2, then the guard below avoids renaming // NS1::foo to NS1::foo::foo. if (Name.empty()) { SkipRewriteName = true; return true; } // another case to handle: // namespace NS1 { // namespace NS2 { // void foo() {} // } // } // namespace NS3 { // using namespace NS1; // void bar() { NS2::foo(); } // } // If we remove NS3, we do need to rename NS2::foo as NS1::NS2::foo if (!ConsumerInstance->isSuffix(Name, SpecifierName)) { SkipRewriteName = true; return true; } } if (!Name.empty()) { ConsumerInstance->RewriteHelper->replaceSpecifier(Loc, Name); SkipRewriteName = true; return true; } } return true; }