// A using declaration in the removed namespace could cause // name conflict, e.g., // namespace NS1 { // void foo(void) {} // } // namespace NS2 { // using NS1::foo; // void bar() { ... foo(); ... } // } // void foo() {...} // void func() {... foo(); ...} // if we remove NS2, then foo() in func() will become ambiguous. // In this case, we need to replace the first invocation of foo() // with NS1::foo() void RemoveNamespace::handleOneUsingShadowDecl(const UsingShadowDecl *UD, const DeclContext *ParentCtx) { const NamedDecl *ND = UD->getTargetDecl(); if (!hasNameConflict(ND, ParentCtx)) return; std::string NewName; const UsingDecl *D = UD->getUsingDecl(); NestedNameSpecifierLoc QualifierLoc = D->getQualifierLoc(); NestedNameSpecifier *NNS = QualifierLoc.getNestedNameSpecifier(); // QualifierLoc could be ::foo, whose PrefixLoc is invalid, e.g., // void foo(); // namespace NS2 { // using ::foo; // void bar () { foo(); } // } if (NNS->getKind() != NestedNameSpecifier::Global) { // NestedNameSpecifierLoc PrefixLoc = QualifierLoc.getPrefix(); RewriteHelper->getQualifierAsString(QualifierLoc, NewName); } if ( const TemplateDecl *TD = dyn_cast<TemplateDecl>(ND) ) { ND = TD->getTemplatedDecl(); } // NewName += "::"; const FunctionDecl *FD = dyn_cast<FunctionDecl>(ND); if (FD && FD->isOverloadedOperator()) { const char *Op = clang::getOperatorSpelling(FD->getOverloadedOperator()); std::string OpStr(Op); NewName += ("operator::" + OpStr); } else { const IdentifierInfo *IdInfo = ND->getIdentifier(); TransAssert(IdInfo && "Invalid IdentifierInfo!"); NewName += IdInfo->getName(); } UsingNamedDeclToNewName[ND] = NewName; // the tied UsingDecl becomes useless, and hence it's removable UselessUsingDecls.insert(D); }
bool Sema::ShouldEnterDeclaratorScope(Scope *S, const CXXScopeSpec &SS) { assert(SS.isSet() && "Parser passed invalid CXXScopeSpec."); // Don't enter a declarator context when the current context is an Objective-C // declaration. if (isa<ObjCContainerDecl>(CurContext) || isa<ObjCMethodDecl>(CurContext)) return false; NestedNameSpecifier *Qualifier = SS.getScopeRep(); // There are only two places a well-formed program may qualify a // declarator: first, when defining a namespace or class member // out-of-line, and second, when naming an explicitly-qualified // friend function. The latter case is governed by // C++03 [basic.lookup.unqual]p10: // In a friend declaration naming a member function, a name used // in the function declarator and not part of a template-argument // in a template-id is first looked up in the scope of the member // function's class. If it is not found, or if the name is part of // a template-argument in a template-id, the look up is as // described for unqualified names in the definition of the class // granting friendship. // i.e. we don't push a scope unless it's a class member. switch (Qualifier->getKind()) { case NestedNameSpecifier::Global: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: // These are always namespace scopes. We never want to enter a // namespace scope from anything but a file context. return CurContext->getRedeclContext()->isFileContext(); case NestedNameSpecifier::Identifier: case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: case NestedNameSpecifier::Super: // These are never namespace scopes. return true; } llvm_unreachable("Invalid NestedNameSpecifier::Kind!"); }
void NestedNameSpecifierLocBuilder::MakeTrivial(ASTContext &Context, NestedNameSpecifier *Qualifier, SourceRange R) { Representation = Qualifier; // Construct bogus (but well-formed) source information for the // nested-name-specifier. BufferSize = 0; SmallVector<NestedNameSpecifier *, 4> Stack; for (NestedNameSpecifier *NNS = Qualifier; NNS; NNS = NNS->getPrefix()) Stack.push_back(NNS); while (!Stack.empty()) { NestedNameSpecifier *NNS = Stack.back(); Stack.pop_back(); switch (NNS->getKind()) { case NestedNameSpecifier::Identifier: case NestedNameSpecifier::Namespace: case NestedNameSpecifier::NamespaceAlias: SaveSourceLocation(R.getBegin(), Buffer, BufferSize, BufferCapacity); break; case NestedNameSpecifier::TypeSpec: case NestedNameSpecifier::TypeSpecWithTemplate: { TypeSourceInfo *TSInfo = Context.getTrivialTypeSourceInfo(QualType(NNS->getAsType(), 0), R.getBegin()); SavePointer(TSInfo->getTypeLoc().getOpaqueData(), Buffer, BufferSize, BufferCapacity); break; } case NestedNameSpecifier::Global: break; } // Save the location of the '::'. SaveSourceLocation(Stack.empty()? R.getEnd() : R.getBegin(), Buffer, BufferSize, BufferCapacity); } }
/// \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; }
/// 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!"); }
// 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; }
bool RemoveNamespace::isGlobalNamespace(NestedNameSpecifierLoc Loc) { NestedNameSpecifier *NNS = Loc.getNestedNameSpecifier(); return (NNS->getKind() == NestedNameSpecifier::Global); }