xref: /llvm-project/clang-tools-extra/clang-change-namespace/ChangeNamespace.cpp (revision d2a96d170a4faa0a6c42fe5f23c073891d6118b8)
15f5a7458SNico Weber //===-- ChangeNamespace.cpp - Change namespace implementation -------------===//
25f5a7458SNico Weber //
35f5a7458SNico Weber // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f5a7458SNico Weber // See https://llvm.org/LICENSE.txt for license information.
55f5a7458SNico Weber // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f5a7458SNico Weber //
75f5a7458SNico Weber //===----------------------------------------------------------------------===//
85f5a7458SNico Weber #include "ChangeNamespace.h"
95f5a7458SNico Weber #include "clang/AST/ASTContext.h"
105f5a7458SNico Weber #include "clang/Format/Format.h"
115f5a7458SNico Weber #include "clang/Lex/Lexer.h"
125f5a7458SNico Weber #include "llvm/Support/Casting.h"
135f5a7458SNico Weber #include "llvm/Support/ErrorHandling.h"
145f5a7458SNico Weber 
155f5a7458SNico Weber using namespace clang::ast_matchers;
165f5a7458SNico Weber 
175f5a7458SNico Weber namespace clang {
185f5a7458SNico Weber namespace change_namespace {
195f5a7458SNico Weber 
205f5a7458SNico Weber namespace {
215f5a7458SNico Weber 
226a3b10e2SNathan James inline std::string joinNamespaces(ArrayRef<StringRef> Namespaces) {
236a3b10e2SNathan James   return llvm::join(Namespaces, "::");
245f5a7458SNico Weber }
255f5a7458SNico Weber 
265f5a7458SNico Weber // Given "a::b::c", returns {"a", "b", "c"}.
275f5a7458SNico Weber llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
285f5a7458SNico Weber   llvm::SmallVector<llvm::StringRef, 4> Splitted;
295f5a7458SNico Weber   Name.split(Splitted, "::", /*MaxSplit=*/-1,
305f5a7458SNico Weber              /*KeepEmpty=*/false);
315f5a7458SNico Weber   return Splitted;
325f5a7458SNico Weber }
335f5a7458SNico Weber 
345f5a7458SNico Weber SourceLocation startLocationForType(TypeLoc TLoc) {
355f5a7458SNico Weber   // For elaborated types (e.g. `struct a::A`) we want the portion after the
365f5a7458SNico Weber   // `struct` but including the namespace qualifier, `a::`.
375f5a7458SNico Weber   if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
385f5a7458SNico Weber     NestedNameSpecifierLoc NestedNameSpecifier =
395f5a7458SNico Weber         TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
405f5a7458SNico Weber     if (NestedNameSpecifier.getNestedNameSpecifier())
415f5a7458SNico Weber       return NestedNameSpecifier.getBeginLoc();
425f5a7458SNico Weber     TLoc = TLoc.getNextTypeLoc();
435f5a7458SNico Weber   }
445f5a7458SNico Weber   return TLoc.getBeginLoc();
455f5a7458SNico Weber }
465f5a7458SNico Weber 
475f5a7458SNico Weber SourceLocation endLocationForType(TypeLoc TLoc) {
485f5a7458SNico Weber   // Dig past any namespace or keyword qualifications.
495f5a7458SNico Weber   while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
505f5a7458SNico Weber          TLoc.getTypeLocClass() == TypeLoc::Qualified)
515f5a7458SNico Weber     TLoc = TLoc.getNextTypeLoc();
525f5a7458SNico Weber 
535f5a7458SNico Weber   // The location for template specializations (e.g. Foo<int>) includes the
545f5a7458SNico Weber   // templated types in its location range.  We want to restrict this to just
555f5a7458SNico Weber   // before the `<` character.
565f5a7458SNico Weber   if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
575f5a7458SNico Weber     return TLoc.castAs<TemplateSpecializationTypeLoc>()
585f5a7458SNico Weber         .getLAngleLoc()
595f5a7458SNico Weber         .getLocWithOffset(-1);
605f5a7458SNico Weber   return TLoc.getEndLoc();
615f5a7458SNico Weber }
625f5a7458SNico Weber 
635f5a7458SNico Weber // Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
645f5a7458SNico Weber // If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
655f5a7458SNico Weber // is empty, nullptr is returned.
665f5a7458SNico Weber // For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
675f5a7458SNico Weber // the NamespaceDecl of namespace "a" will be returned.
685f5a7458SNico Weber const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
695f5a7458SNico Weber                                        llvm::StringRef PartialNsName) {
705f5a7458SNico Weber   if (!InnerNs || PartialNsName.empty())
715f5a7458SNico Weber     return nullptr;
725f5a7458SNico Weber   const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
735f5a7458SNico Weber   const auto *CurrentNs = InnerNs;
745f5a7458SNico Weber   auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
755f5a7458SNico Weber   while (!PartialNsNameSplitted.empty()) {
765f5a7458SNico Weber     // Get the inner-most namespace in CurrentContext.
775f5a7458SNico Weber     while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
785f5a7458SNico Weber       CurrentContext = CurrentContext->getParent();
795f5a7458SNico Weber     if (!CurrentContext)
805f5a7458SNico Weber       return nullptr;
815f5a7458SNico Weber     CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
825f5a7458SNico Weber     if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
835f5a7458SNico Weber       return nullptr;
845f5a7458SNico Weber     PartialNsNameSplitted.pop_back();
855f5a7458SNico Weber     CurrentContext = CurrentContext->getParent();
865f5a7458SNico Weber   }
875f5a7458SNico Weber   return CurrentNs;
885f5a7458SNico Weber }
895f5a7458SNico Weber 
905f5a7458SNico Weber static std::unique_ptr<Lexer>
915f5a7458SNico Weber getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
925f5a7458SNico Weber                         const LangOptions &LangOpts) {
935f5a7458SNico Weber   if (Loc.isMacroID() &&
945f5a7458SNico Weber       !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
955f5a7458SNico Weber     return nullptr;
965f5a7458SNico Weber   // Break down the source location.
975f5a7458SNico Weber   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
985f5a7458SNico Weber   // Try to load the file buffer.
995f5a7458SNico Weber   bool InvalidTemp = false;
1005f5a7458SNico Weber   llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
1015f5a7458SNico Weber   if (InvalidTemp)
1025f5a7458SNico Weber     return nullptr;
1035f5a7458SNico Weber 
1045f5a7458SNico Weber   const char *TokBegin = File.data() + LocInfo.second;
1055f5a7458SNico Weber   // Lex from the start of the given location.
1061c705d9cSJonas Devlieghere   return std::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
1075f5a7458SNico Weber                                   LangOpts, File.begin(), TokBegin, File.end());
1085f5a7458SNico Weber }
1095f5a7458SNico Weber 
1105f5a7458SNico Weber // FIXME: get rid of this helper function if this is supported in clang-refactor
1115f5a7458SNico Weber // library.
1125f5a7458SNico Weber static SourceLocation getStartOfNextLine(SourceLocation Loc,
1135f5a7458SNico Weber                                          const SourceManager &SM,
1145f5a7458SNico Weber                                          const LangOptions &LangOpts) {
1155f5a7458SNico Weber   std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
1165f5a7458SNico Weber   if (!Lex.get())
1175f5a7458SNico Weber     return SourceLocation();
1185f5a7458SNico Weber   llvm::SmallVector<char, 16> Line;
1195f5a7458SNico Weber   // FIXME: this is a bit hacky to get ReadToEndOfLine work.
1205f5a7458SNico Weber   Lex->setParsingPreprocessorDirective(true);
1215f5a7458SNico Weber   Lex->ReadToEndOfLine(&Line);
1225f5a7458SNico Weber   auto End = Loc.getLocWithOffset(Line.size());
1235f5a7458SNico Weber   return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
1245f5a7458SNico Weber              ? End
1255f5a7458SNico Weber              : End.getLocWithOffset(1);
1265f5a7458SNico Weber }
1275f5a7458SNico Weber 
1285f5a7458SNico Weber // Returns `R` with new range that refers to code after `Replaces` being
1295f5a7458SNico Weber // applied.
1305f5a7458SNico Weber tooling::Replacement
1315f5a7458SNico Weber getReplacementInChangedCode(const tooling::Replacements &Replaces,
1325f5a7458SNico Weber                             const tooling::Replacement &R) {
1335f5a7458SNico Weber   unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
1345f5a7458SNico Weber   unsigned NewEnd =
1355f5a7458SNico Weber       Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
1365f5a7458SNico Weber   return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
1375f5a7458SNico Weber                               R.getReplacementText());
1385f5a7458SNico Weber }
1395f5a7458SNico Weber 
1405f5a7458SNico Weber // Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
1415f5a7458SNico Weber // applying all existing Replaces first if there is conflict.
1425f5a7458SNico Weber void addOrMergeReplacement(const tooling::Replacement &R,
1435f5a7458SNico Weber                            tooling::Replacements *Replaces) {
1445f5a7458SNico Weber   auto Err = Replaces->add(R);
1455f5a7458SNico Weber   if (Err) {
1465f5a7458SNico Weber     llvm::consumeError(std::move(Err));
1475f5a7458SNico Weber     auto Replace = getReplacementInChangedCode(*Replaces, R);
1485f5a7458SNico Weber     *Replaces = Replaces->merge(tooling::Replacements(Replace));
1495f5a7458SNico Weber   }
1505f5a7458SNico Weber }
1515f5a7458SNico Weber 
1525f5a7458SNico Weber tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
1535f5a7458SNico Weber                                        llvm::StringRef ReplacementText,
1545f5a7458SNico Weber                                        const SourceManager &SM) {
1555f5a7458SNico Weber   if (!Start.isValid() || !End.isValid()) {
1565f5a7458SNico Weber     llvm::errs() << "start or end location were invalid\n";
1575f5a7458SNico Weber     return tooling::Replacement();
1585f5a7458SNico Weber   }
1595f5a7458SNico Weber   if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
1605f5a7458SNico Weber     llvm::errs()
1615f5a7458SNico Weber         << "start or end location were in different macro expansions\n";
1625f5a7458SNico Weber     return tooling::Replacement();
1635f5a7458SNico Weber   }
1645f5a7458SNico Weber   Start = SM.getSpellingLoc(Start);
1655f5a7458SNico Weber   End = SM.getSpellingLoc(End);
1665f5a7458SNico Weber   if (SM.getFileID(Start) != SM.getFileID(End)) {
1675f5a7458SNico Weber     llvm::errs() << "start or end location were in different files\n";
1685f5a7458SNico Weber     return tooling::Replacement();
1695f5a7458SNico Weber   }
1705f5a7458SNico Weber   return tooling::Replacement(
1715f5a7458SNico Weber       SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
1725f5a7458SNico Weber                                          SM.getSpellingLoc(End)),
1735f5a7458SNico Weber       ReplacementText);
1745f5a7458SNico Weber }
1755f5a7458SNico Weber 
1765f5a7458SNico Weber void addReplacementOrDie(
1775f5a7458SNico Weber     SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
1785f5a7458SNico Weber     const SourceManager &SM,
1795f5a7458SNico Weber     std::map<std::string, tooling::Replacements> *FileToReplacements) {
1805f5a7458SNico Weber   const auto R = createReplacement(Start, End, ReplacementText, SM);
181adcd0268SBenjamin Kramer   auto Err = (*FileToReplacements)[std::string(R.getFilePath())].add(R);
1825f5a7458SNico Weber   if (Err)
1835f5a7458SNico Weber     llvm_unreachable(llvm::toString(std::move(Err)).c_str());
1845f5a7458SNico Weber }
1855f5a7458SNico Weber 
1865f5a7458SNico Weber tooling::Replacement createInsertion(SourceLocation Loc,
1875f5a7458SNico Weber                                      llvm::StringRef InsertText,
1885f5a7458SNico Weber                                      const SourceManager &SM) {
1895f5a7458SNico Weber   if (Loc.isInvalid()) {
1905f5a7458SNico Weber     llvm::errs() << "insert Location is invalid.\n";
1915f5a7458SNico Weber     return tooling::Replacement();
1925f5a7458SNico Weber   }
1935f5a7458SNico Weber   Loc = SM.getSpellingLoc(Loc);
1945f5a7458SNico Weber   return tooling::Replacement(SM, Loc, 0, InsertText);
1955f5a7458SNico Weber }
1965f5a7458SNico Weber 
1975f5a7458SNico Weber // Returns the shortest qualified name for declaration `DeclName` in the
1985f5a7458SNico Weber // namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
1995f5a7458SNico Weber // is "a::c::d", then "b::X" will be returned.
2005f5a7458SNico Weber // Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
2015f5a7458SNico Weber // "::b::X" instead of "b::X" since there will be a name conflict otherwise.
2025f5a7458SNico Weber // \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
2035f5a7458SNico Weber // \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
2045f5a7458SNico Weber //        will have empty name.
2055f5a7458SNico Weber std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
2065f5a7458SNico Weber                                                 llvm::StringRef NsName) {
2075f5a7458SNico Weber   DeclName = DeclName.ltrim(':');
2085f5a7458SNico Weber   NsName = NsName.ltrim(':');
20920f0f15aSKazu Hirata   if (!DeclName.contains(':'))
210adcd0268SBenjamin Kramer     return std::string(DeclName);
2115f5a7458SNico Weber 
2125f5a7458SNico Weber   auto NsNameSplitted = splitSymbolName(NsName);
2135f5a7458SNico Weber   auto DeclNsSplitted = splitSymbolName(DeclName);
2145f5a7458SNico Weber   llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
2155f5a7458SNico Weber   // If the Decl is in global namespace, there is no need to shorten it.
2165f5a7458SNico Weber   if (DeclNsSplitted.empty())
217adcd0268SBenjamin Kramer     return std::string(UnqualifiedDeclName);
2185f5a7458SNico Weber   // If NsName is the global namespace, we can simply use the DeclName sans
2195f5a7458SNico Weber   // leading "::".
2205f5a7458SNico Weber   if (NsNameSplitted.empty())
221adcd0268SBenjamin Kramer     return std::string(DeclName);
2225f5a7458SNico Weber 
2235f5a7458SNico Weber   if (NsNameSplitted.front() != DeclNsSplitted.front()) {
2245f5a7458SNico Weber     // The DeclName must be fully-qualified, but we still need to decide if a
2255f5a7458SNico Weber     // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
2265f5a7458SNico Weber     // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
2275f5a7458SNico Weber     // to avoid conflict.
2285f5a7458SNico Weber     if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
2295f5a7458SNico Weber       return ("::" + DeclName).str();
230adcd0268SBenjamin Kramer     return std::string(DeclName);
2315f5a7458SNico Weber   }
2325f5a7458SNico Weber   // Since there is already an overlap namespace, we know that `DeclName` can be
2335f5a7458SNico Weber   // shortened, so we reduce the longest common prefix.
2345f5a7458SNico Weber   auto DeclI = DeclNsSplitted.begin();
2355f5a7458SNico Weber   auto DeclE = DeclNsSplitted.end();
2365f5a7458SNico Weber   auto NsI = NsNameSplitted.begin();
2375f5a7458SNico Weber   auto NsE = NsNameSplitted.end();
2385f5a7458SNico Weber   for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
2395f5a7458SNico Weber   }
2405f5a7458SNico Weber   return (DeclI == DeclE)
2415f5a7458SNico Weber              ? UnqualifiedDeclName.str()
2425f5a7458SNico Weber              : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
2435f5a7458SNico Weber                    .str();
2445f5a7458SNico Weber }
2455f5a7458SNico Weber 
2465f5a7458SNico Weber std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
2475f5a7458SNico Weber   if (Code.back() != '\n')
2485f5a7458SNico Weber     Code += "\n";
2495f5a7458SNico Weber   auto NsSplitted = splitSymbolName(NestedNs);
2505f5a7458SNico Weber   while (!NsSplitted.empty()) {
2515f5a7458SNico Weber     // FIXME: consider code style for comments.
2525f5a7458SNico Weber     Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
2535f5a7458SNico Weber             "} // namespace " + NsSplitted.back() + "\n")
2545f5a7458SNico Weber                .str();
2555f5a7458SNico Weber     NsSplitted.pop_back();
2565f5a7458SNico Weber   }
2575f5a7458SNico Weber   return Code;
2585f5a7458SNico Weber }
2595f5a7458SNico Weber 
2605f5a7458SNico Weber // Returns true if \p D is a nested DeclContext in \p Context
2615f5a7458SNico Weber bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
2625f5a7458SNico Weber   while (D) {
2635f5a7458SNico Weber     if (D == Context)
2645f5a7458SNico Weber       return true;
2655f5a7458SNico Weber     D = D->getParent();
2665f5a7458SNico Weber   }
2675f5a7458SNico Weber   return false;
2685f5a7458SNico Weber }
2695f5a7458SNico Weber 
2705f5a7458SNico Weber // Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
2715f5a7458SNico Weber bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
2725f5a7458SNico Weber                              const DeclContext *DeclCtx, SourceLocation Loc) {
2735f5a7458SNico Weber   SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
2745f5a7458SNico Weber   Loc = SM.getSpellingLoc(Loc);
2755f5a7458SNico Weber   return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
2765f5a7458SNico Weber          (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
2775f5a7458SNico Weber           isNestedDeclContext(DeclCtx, D->getDeclContext()));
2785f5a7458SNico Weber }
2795f5a7458SNico Weber 
2805f5a7458SNico Weber // Given a qualified symbol name, returns true if the symbol will be
2815f5a7458SNico Weber // incorrectly qualified without leading "::". For example, a symbol
2825f5a7458SNico Weber // "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
2835f5a7458SNico Weber // "util::X" in namespace "na" can potentially conflict with "na::util" (if this
2845f5a7458SNico Weber // exists).
2855f5a7458SNico Weber bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
2865f5a7458SNico Weber                          llvm::StringRef Namespace) {
2875f5a7458SNico Weber   auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
2885f5a7458SNico Weber   assert(!SymbolSplitted.empty());
2895f5a7458SNico Weber   SymbolSplitted.pop_back();  // We are only interested in namespaces.
2905f5a7458SNico Weber 
2915f5a7458SNico Weber   if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
2925f5a7458SNico Weber     auto SymbolTopNs = SymbolSplitted.front();
2935f5a7458SNico Weber     auto NsSplitted = splitSymbolName(Namespace.trim(":"));
2945f5a7458SNico Weber     assert(!NsSplitted.empty());
2955f5a7458SNico Weber 
2965f5a7458SNico Weber     auto LookupDecl = [&AST](const Decl &Scope,
2975f5a7458SNico Weber                              llvm::StringRef Name) -> const NamedDecl * {
2985f5a7458SNico Weber       const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
2995f5a7458SNico Weber       if (!DC)
3005f5a7458SNico Weber         return nullptr;
3015f5a7458SNico Weber       auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
3025f5a7458SNico Weber       if (LookupRes.empty())
3035f5a7458SNico Weber         return nullptr;
3045f5a7458SNico Weber       return LookupRes.front();
3055f5a7458SNico Weber     };
3065f5a7458SNico Weber     // We do not check the outermost namespace since it would not be a
3075f5a7458SNico Weber     // conflict if it equals to the symbol's outermost namespace and the
3085f5a7458SNico Weber     // symbol name would have been shortened.
3095f5a7458SNico Weber     const NamedDecl *Scope =
3105f5a7458SNico Weber         LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
311246bf08dSKazu Hirata     for (const auto &I : llvm::drop_begin(NsSplitted)) {
312246bf08dSKazu Hirata       if (I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
3135f5a7458SNico Weber         return true;
3145f5a7458SNico Weber       // Handles "::util" and "::nx::util" conflicts.
3155f5a7458SNico Weber       if (Scope) {
3165f5a7458SNico Weber         if (LookupDecl(*Scope, SymbolTopNs))
3175f5a7458SNico Weber           return true;
318246bf08dSKazu Hirata         Scope = LookupDecl(*Scope, I);
3195f5a7458SNico Weber       }
3205f5a7458SNico Weber     }
3215f5a7458SNico Weber     if (Scope && LookupDecl(*Scope, SymbolTopNs))
3225f5a7458SNico Weber       return true;
3235f5a7458SNico Weber   }
3245f5a7458SNico Weber   return false;
3255f5a7458SNico Weber }
3265f5a7458SNico Weber 
3275f5a7458SNico Weber bool isTemplateParameter(TypeLoc Type) {
3285f5a7458SNico Weber   while (!Type.isNull()) {
3295f5a7458SNico Weber     if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
3305f5a7458SNico Weber       return true;
3315f5a7458SNico Weber     Type = Type.getNextTypeLoc();
3325f5a7458SNico Weber   }
3335f5a7458SNico Weber   return false;
3345f5a7458SNico Weber }
3355f5a7458SNico Weber 
3365f5a7458SNico Weber } // anonymous namespace
3375f5a7458SNico Weber 
3385f5a7458SNico Weber ChangeNamespaceTool::ChangeNamespaceTool(
3395f5a7458SNico Weber     llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
34025ed42f0SEric Christopher     llvm::ArrayRef<std::string> AllowedSymbolPatterns,
3415f5a7458SNico Weber     std::map<std::string, tooling::Replacements> *FileToReplacements,
3425f5a7458SNico Weber     llvm::StringRef FallbackStyle)
3435f5a7458SNico Weber     : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
3445f5a7458SNico Weber       OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
3455f5a7458SNico Weber       FilePattern(FilePattern), FilePatternRE(FilePattern) {
3465f5a7458SNico Weber   FileToReplacements->clear();
3475f5a7458SNico Weber   auto OldNsSplitted = splitSymbolName(OldNamespace);
3485f5a7458SNico Weber   auto NewNsSplitted = splitSymbolName(NewNamespace);
3495f5a7458SNico Weber   // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
3505f5a7458SNico Weber   while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
3515f5a7458SNico Weber          OldNsSplitted.front() == NewNsSplitted.front()) {
3525f5a7458SNico Weber     OldNsSplitted.erase(OldNsSplitted.begin());
3535f5a7458SNico Weber     NewNsSplitted.erase(NewNsSplitted.begin());
3545f5a7458SNico Weber   }
3555f5a7458SNico Weber   DiffOldNamespace = joinNamespaces(OldNsSplitted);
3565f5a7458SNico Weber   DiffNewNamespace = joinNamespaces(NewNsSplitted);
3575f5a7458SNico Weber 
35825ed42f0SEric Christopher   for (const auto &Pattern : AllowedSymbolPatterns)
35925ed42f0SEric Christopher     AllowedSymbolRegexes.emplace_back(Pattern);
3605f5a7458SNico Weber }
3615f5a7458SNico Weber 
3625f5a7458SNico Weber void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
3635f5a7458SNico Weber   std::string FullOldNs = "::" + OldNamespace;
3645f5a7458SNico Weber   // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
3655f5a7458SNico Weber   // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
3665f5a7458SNico Weber   // be "a::b". Declarations in this namespace will not be visible in the new
3675f5a7458SNico Weber   // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
3685f5a7458SNico Weber   llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
3695f5a7458SNico Weber   llvm::StringRef(DiffOldNamespace)
3705f5a7458SNico Weber       .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
3715f5a7458SNico Weber              /*KeepEmpty=*/false);
3725f5a7458SNico Weber   std::string Prefix = "-";
3735f5a7458SNico Weber   if (!DiffOldNsSplitted.empty())
3745f5a7458SNico Weber     Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
3755f5a7458SNico Weber               DiffOldNsSplitted.front())
3765f5a7458SNico Weber                  .str();
3775f5a7458SNico Weber   auto IsInMovedNs =
3785f5a7458SNico Weber       allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
3795f5a7458SNico Weber             isExpansionInFileMatching(FilePattern));
3805f5a7458SNico Weber   auto IsVisibleInNewNs = anyOf(
3815f5a7458SNico Weber       IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
3825f5a7458SNico Weber   // Match using declarations.
3835f5a7458SNico Weber   Finder->addMatcher(
3845f5a7458SNico Weber       usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
3855f5a7458SNico Weber           .bind("using"),
3865f5a7458SNico Weber       this);
3875f5a7458SNico Weber   // Match using namespace declarations.
3885f5a7458SNico Weber   Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
3895f5a7458SNico Weber                                         IsVisibleInNewNs)
3905f5a7458SNico Weber                          .bind("using_namespace"),
3915f5a7458SNico Weber                      this);
3925f5a7458SNico Weber   // Match namespace alias declarations.
3935f5a7458SNico Weber   Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
3945f5a7458SNico Weber                                         IsVisibleInNewNs)
3955f5a7458SNico Weber                          .bind("namespace_alias"),
3965f5a7458SNico Weber                      this);
3975f5a7458SNico Weber 
3985f5a7458SNico Weber   // Match old namespace blocks.
3995f5a7458SNico Weber   Finder->addMatcher(
4005f5a7458SNico Weber       namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
4015f5a7458SNico Weber           .bind("old_ns"),
4025f5a7458SNico Weber       this);
4035f5a7458SNico Weber 
4045f5a7458SNico Weber   // Match class forward-declarations in the old namespace.
4055f5a7458SNico Weber   // Note that forward-declarations in classes are not matched.
4065f5a7458SNico Weber   Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
4075f5a7458SNico Weber                                    IsInMovedNs, hasParent(namespaceDecl()))
4085f5a7458SNico Weber                          .bind("class_fwd_decl"),
4095f5a7458SNico Weber                      this);
4105f5a7458SNico Weber 
4115f5a7458SNico Weber   // Match template class forward-declarations in the old namespace.
4125f5a7458SNico Weber   Finder->addMatcher(
4135f5a7458SNico Weber       classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
4145f5a7458SNico Weber                         IsInMovedNs, hasParent(namespaceDecl()))
4155f5a7458SNico Weber           .bind("template_class_fwd_decl"),
4165f5a7458SNico Weber       this);
4175f5a7458SNico Weber 
4185f5a7458SNico Weber   // Match references to types that are not defined in the old namespace.
4195f5a7458SNico Weber   // Forward-declarations in the old namespace are also matched since they will
4205f5a7458SNico Weber   // be moved back to the old namespace.
4215f5a7458SNico Weber   auto DeclMatcher = namedDecl(
4225f5a7458SNico Weber       hasAncestor(namespaceDecl()),
4235f5a7458SNico Weber       unless(anyOf(
4245f5a7458SNico Weber           isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
4255f5a7458SNico Weber           hasAncestor(cxxRecordDecl()),
4265f5a7458SNico Weber           allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
4275f5a7458SNico Weber 
4285f5a7458SNico Weber   // Using shadow declarations in classes always refers to base class, which
4295f5a7458SNico Weber   // does not need to be qualified since it can be inferred from inheritance.
4305f5a7458SNico Weber   // Note that this does not match using alias declarations.
4315f5a7458SNico Weber   auto UsingShadowDeclInClass =
4325f5a7458SNico Weber       usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
4335f5a7458SNico Weber 
4345f5a7458SNico Weber   // Match TypeLocs on the declaration. Carefully match only the outermost
4355f5a7458SNico Weber   // TypeLoc and template specialization arguments (which are not outermost)
4365f5a7458SNico Weber   // that are directly linked to types matching `DeclMatcher`. Nested name
4375f5a7458SNico Weber   // specifier locs are handled separately below.
4385f5a7458SNico Weber   Finder->addMatcher(
4395f5a7458SNico Weber       typeLoc(IsInMovedNs,
4405f5a7458SNico Weber               loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
4415f5a7458SNico Weber               unless(anyOf(hasParent(typeLoc(loc(qualType(
4425f5a7458SNico Weber                                hasDeclaration(DeclMatcher),
4435f5a7458SNico Weber                                unless(templateSpecializationType()))))),
4445f5a7458SNico Weber                            hasParent(nestedNameSpecifierLoc()),
445c8f14827SSam McCall                            hasAncestor(decl(isImplicit())),
4465f5a7458SNico Weber                            hasAncestor(UsingShadowDeclInClass),
4475f5a7458SNico Weber                            hasAncestor(functionDecl(isDefaulted())))),
4485f5a7458SNico Weber               hasAncestor(decl().bind("dc")))
4495f5a7458SNico Weber           .bind("type"),
4505f5a7458SNico Weber       this);
4515f5a7458SNico Weber 
4525f5a7458SNico Weber   // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
4535f5a7458SNico Weber   // special case it.
4545f5a7458SNico Weber   // Since using declarations inside classes must have the base class in the
4555f5a7458SNico Weber   // nested name specifier, we leave it to the nested name specifier matcher.
4565f5a7458SNico Weber   Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
4575f5a7458SNico Weber                                unless(UsingShadowDeclInClass))
4585f5a7458SNico Weber                          .bind("using_with_shadow"),
4595f5a7458SNico Weber                      this);
4605f5a7458SNico Weber 
4615f5a7458SNico Weber   // Handle types in nested name specifier. Specifiers that are in a TypeLoc
4625f5a7458SNico Weber   // matched above are not matched, e.g. "A::" in "A::A" is not matched since
4635f5a7458SNico Weber   // "A::A" would have already been fixed.
4645f5a7458SNico Weber   Finder->addMatcher(
4655f5a7458SNico Weber       nestedNameSpecifierLoc(
4665f5a7458SNico Weber           hasAncestor(decl(IsInMovedNs).bind("dc")),
4675f5a7458SNico Weber           loc(nestedNameSpecifier(
4685f5a7458SNico Weber               specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
469c8f14827SSam McCall           unless(anyOf(hasAncestor(decl(isImplicit())),
4705f5a7458SNico Weber                        hasAncestor(UsingShadowDeclInClass),
4715f5a7458SNico Weber                        hasAncestor(functionDecl(isDefaulted())),
4725f5a7458SNico Weber                        hasAncestor(typeLoc(loc(qualType(hasDeclaration(
4735f5a7458SNico Weber                            decl(equalsBoundNode("from_decl"))))))))))
4745f5a7458SNico Weber           .bind("nested_specifier_loc"),
4755f5a7458SNico Weber       this);
4765f5a7458SNico Weber 
4775f5a7458SNico Weber   // Matches base class initializers in constructors. TypeLocs of base class
4785f5a7458SNico Weber   // initializers do not need to be fixed. For example,
4795f5a7458SNico Weber   //    class X : public a::b::Y {
4805f5a7458SNico Weber   //      public:
4815f5a7458SNico Weber   //        X() : Y::Y() {} // Y::Y do not need namespace specifier.
4825f5a7458SNico Weber   //    };
4835f5a7458SNico Weber   Finder->addMatcher(
4845f5a7458SNico Weber       cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
4855f5a7458SNico Weber 
4865f5a7458SNico Weber   // Handle function.
4875f5a7458SNico Weber   // Only handle functions that are defined in a namespace excluding member
4885f5a7458SNico Weber   // function, static methods (qualified by nested specifier), and functions
4895f5a7458SNico Weber   // defined in the global namespace.
4905f5a7458SNico Weber   // Note that the matcher does not exclude calls to out-of-line static method
4915f5a7458SNico Weber   // definitions, so we need to exclude them in the callback handler.
4925f5a7458SNico Weber   auto FuncMatcher =
4935f5a7458SNico Weber       functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
4945f5a7458SNico Weber                                 hasAncestor(namespaceDecl(isAnonymous())),
4955f5a7458SNico Weber                                 hasAncestor(cxxRecordDecl()))),
4965f5a7458SNico Weber                    hasParent(namespaceDecl()));
4975f5a7458SNico Weber   Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
498c8f14827SSam McCall                           unless(hasAncestor(decl(isImplicit()))),
4995f5a7458SNico Weber                           anyOf(callExpr(callee(FuncMatcher)).bind("call"),
5005f5a7458SNico Weber                                 declRefExpr(to(FuncMatcher.bind("func_decl")))
5015f5a7458SNico Weber                                     .bind("func_ref"))),
5025f5a7458SNico Weber                      this);
5035f5a7458SNico Weber 
5045f5a7458SNico Weber   auto GlobalVarMatcher = varDecl(
5055f5a7458SNico Weber       hasGlobalStorage(), hasParent(namespaceDecl()),
5065f5a7458SNico Weber       unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
5075f5a7458SNico Weber   Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
5085f5a7458SNico Weber                                  to(GlobalVarMatcher.bind("var_decl")))
5095f5a7458SNico Weber                          .bind("var_ref"),
5105f5a7458SNico Weber                      this);
5115f5a7458SNico Weber 
5125f5a7458SNico Weber   // Handle unscoped enum constant.
5135f5a7458SNico Weber   auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
5145f5a7458SNico Weber       hasParent(namespaceDecl()),
5155f5a7458SNico Weber       unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
5165f5a7458SNico Weber                    hasAncestor(namespaceDecl(isAnonymous())))))));
5175f5a7458SNico Weber   Finder->addMatcher(
5185f5a7458SNico Weber       declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
5195f5a7458SNico Weber                   to(UnscopedEnumMatcher.bind("enum_const_decl")))
5205f5a7458SNico Weber           .bind("enum_const_ref"),
5215f5a7458SNico Weber       this);
5225f5a7458SNico Weber }
5235f5a7458SNico Weber 
5245f5a7458SNico Weber void ChangeNamespaceTool::run(
5255f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result) {
5265f5a7458SNico Weber   if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
5275f5a7458SNico Weber     UsingDecls.insert(Using);
5285f5a7458SNico Weber   } else if (const auto *UsingNamespace =
5295f5a7458SNico Weber                  Result.Nodes.getNodeAs<UsingDirectiveDecl>(
5305f5a7458SNico Weber                      "using_namespace")) {
5315f5a7458SNico Weber     UsingNamespaceDecls.insert(UsingNamespace);
5325f5a7458SNico Weber   } else if (const auto *NamespaceAlias =
5335f5a7458SNico Weber                  Result.Nodes.getNodeAs<NamespaceAliasDecl>(
5345f5a7458SNico Weber                      "namespace_alias")) {
5355f5a7458SNico Weber     NamespaceAliasDecls.insert(NamespaceAlias);
5365f5a7458SNico Weber   } else if (const auto *NsDecl =
5375f5a7458SNico Weber                  Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
5385f5a7458SNico Weber     moveOldNamespace(Result, NsDecl);
5395f5a7458SNico Weber   } else if (const auto *FwdDecl =
5405f5a7458SNico Weber                  Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
5415f5a7458SNico Weber     moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
5425f5a7458SNico Weber   } else if (const auto *TemplateFwdDecl =
5435f5a7458SNico Weber                  Result.Nodes.getNodeAs<ClassTemplateDecl>(
5445f5a7458SNico Weber                      "template_class_fwd_decl")) {
5455f5a7458SNico Weber     moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
5465f5a7458SNico Weber   } else if (const auto *UsingWithShadow =
5475f5a7458SNico Weber                  Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
5485f5a7458SNico Weber     fixUsingShadowDecl(Result, UsingWithShadow);
5495f5a7458SNico Weber   } else if (const auto *Specifier =
5505f5a7458SNico Weber                  Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
5515f5a7458SNico Weber                      "nested_specifier_loc")) {
5525f5a7458SNico Weber     SourceLocation Start = Specifier->getBeginLoc();
5535f5a7458SNico Weber     SourceLocation End = endLocationForType(Specifier->getTypeLoc());
5545f5a7458SNico Weber     fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
5555f5a7458SNico Weber   } else if (const auto *BaseInitializer =
5565f5a7458SNico Weber                  Result.Nodes.getNodeAs<CXXCtorInitializer>(
5575f5a7458SNico Weber                      "base_initializer")) {
5585f5a7458SNico Weber     BaseCtorInitializerTypeLocs.push_back(
5595f5a7458SNico Weber         BaseInitializer->getTypeSourceInfo()->getTypeLoc());
5605f5a7458SNico Weber   } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
5615f5a7458SNico Weber     // This avoids fixing types with record types as qualifier, which is not
5625f5a7458SNico Weber     // filtered by matchers in some cases, e.g. the type is templated. We should
5635f5a7458SNico Weber     // handle the record type qualifier instead.
5645f5a7458SNico Weber     TypeLoc Loc = *TLoc;
5655f5a7458SNico Weber     while (Loc.getTypeLocClass() == TypeLoc::Qualified)
5665f5a7458SNico Weber       Loc = Loc.getNextTypeLoc();
5675f5a7458SNico Weber     if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
5685f5a7458SNico Weber       NestedNameSpecifierLoc NestedNameSpecifier =
5695f5a7458SNico Weber           Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
57015f3cd6bSMatheus Izvekov       // FIXME: avoid changing injected class names.
57115f3cd6bSMatheus Izvekov       if (auto *NNS = NestedNameSpecifier.getNestedNameSpecifier()) {
57215f3cd6bSMatheus Izvekov         const Type *SpecifierType = NNS->getAsType();
5735f5a7458SNico Weber         if (SpecifierType && SpecifierType->isRecordType())
5745f5a7458SNico Weber           return;
5755f5a7458SNico Weber       }
57615f3cd6bSMatheus Izvekov     }
5775f5a7458SNico Weber     fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
5785f5a7458SNico Weber   } else if (const auto *VarRef =
5795f5a7458SNico Weber                  Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
5805f5a7458SNico Weber     const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
5815f5a7458SNico Weber     assert(Var);
5825f5a7458SNico Weber     if (Var->getCanonicalDecl()->isStaticDataMember())
5835f5a7458SNico Weber       return;
5845f5a7458SNico Weber     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
5855f5a7458SNico Weber     assert(Context && "Empty decl context.");
5865f5a7458SNico Weber     fixDeclRefExpr(Result, Context->getDeclContext(),
5875f5a7458SNico Weber                    llvm::cast<NamedDecl>(Var), VarRef);
5885f5a7458SNico Weber   } else if (const auto *EnumConstRef =
5895f5a7458SNico Weber                  Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
5905f5a7458SNico Weber     // Do not rename the reference if it is already scoped by the EnumDecl name.
5915f5a7458SNico Weber     if (EnumConstRef->hasQualifier() &&
5925f5a7458SNico Weber         EnumConstRef->getQualifier()->getKind() ==
5935f5a7458SNico Weber             NestedNameSpecifier::SpecifierKind::TypeSpec &&
5945f5a7458SNico Weber         EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
5955f5a7458SNico Weber       return;
5965f5a7458SNico Weber     const auto *EnumConstDecl =
5975f5a7458SNico Weber         Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
5985f5a7458SNico Weber     assert(EnumConstDecl);
5995f5a7458SNico Weber     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
6005f5a7458SNico Weber     assert(Context && "Empty decl context.");
6015f5a7458SNico Weber     // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
6025f5a7458SNico Weber     // if it turns out to be an issue.
6035f5a7458SNico Weber     fixDeclRefExpr(Result, Context->getDeclContext(),
6045f5a7458SNico Weber                    llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
6055f5a7458SNico Weber   } else if (const auto *FuncRef =
6065f5a7458SNico Weber                  Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
6075f5a7458SNico Weber     // If this reference has been processed as a function call, we do not
6085f5a7458SNico Weber     // process it again.
609*d2a96d17SKazu Hirata     if (!ProcessedFuncRefs.insert(FuncRef).second)
6105f5a7458SNico Weber       return;
6115f5a7458SNico Weber     const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
6125f5a7458SNico Weber     assert(Func);
6135f5a7458SNico Weber     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
6145f5a7458SNico Weber     assert(Context && "Empty decl context.");
6155f5a7458SNico Weber     fixDeclRefExpr(Result, Context->getDeclContext(),
6165f5a7458SNico Weber                    llvm::cast<NamedDecl>(Func), FuncRef);
6175f5a7458SNico Weber   } else {
6185f5a7458SNico Weber     const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
6195f5a7458SNico Weber     assert(Call != nullptr && "Expecting callback for CallExpr.");
6205f5a7458SNico Weber     const auto *CalleeFuncRef =
6215f5a7458SNico Weber         llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
6225f5a7458SNico Weber     ProcessedFuncRefs.insert(CalleeFuncRef);
6235f5a7458SNico Weber     const FunctionDecl *Func = Call->getDirectCallee();
6245f5a7458SNico Weber     assert(Func != nullptr);
6255f5a7458SNico Weber     // FIXME: ignore overloaded operators. This would miss cases where operators
6265f5a7458SNico Weber     // are called by qualified names (i.e. "ns::operator <"). Ignore such
6275f5a7458SNico Weber     // cases for now.
6285f5a7458SNico Weber     if (Func->isOverloadedOperator())
6295f5a7458SNico Weber       return;
6305f5a7458SNico Weber     // Ignore out-of-line static methods since they will be handled by nested
6315f5a7458SNico Weber     // name specifiers.
6322fd11e0bSThorsten Schütt     if (Func->getCanonicalDecl()->getStorageClass() ==
6332fd11e0bSThorsten Schütt             StorageClass::SC_Static &&
6345f5a7458SNico Weber         Func->isOutOfLine())
6355f5a7458SNico Weber       return;
6365f5a7458SNico Weber     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
6375f5a7458SNico Weber     assert(Context && "Empty decl context.");
6385f5a7458SNico Weber     SourceRange CalleeRange = Call->getCallee()->getSourceRange();
6395f5a7458SNico Weber     replaceQualifiedSymbolInDeclContext(
6405f5a7458SNico Weber         Result, Context->getDeclContext(), CalleeRange.getBegin(),
6415f5a7458SNico Weber         CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
6425f5a7458SNico Weber   }
6435f5a7458SNico Weber }
6445f5a7458SNico Weber 
6455f5a7458SNico Weber static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
6465f5a7458SNico Weber                                                  const SourceManager &SM,
6475f5a7458SNico Weber                                                  const LangOptions &LangOpts) {
6485f5a7458SNico Weber   std::unique_ptr<Lexer> Lex =
6495f5a7458SNico Weber       getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
6505f5a7458SNico Weber   assert(Lex.get() &&
6515f5a7458SNico Weber          "Failed to create lexer from the beginning of namespace.");
6525f5a7458SNico Weber   if (!Lex.get())
6535f5a7458SNico Weber     return SourceLocation();
6545f5a7458SNico Weber   Token Tok;
6555f5a7458SNico Weber   while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
6565f5a7458SNico Weber   }
6575f5a7458SNico Weber   return Tok.isNot(tok::TokenKind::l_brace)
6585f5a7458SNico Weber              ? SourceLocation()
6595f5a7458SNico Weber              : Tok.getEndLoc().getLocWithOffset(1);
6605f5a7458SNico Weber }
6615f5a7458SNico Weber 
6625f5a7458SNico Weber // Stores information about a moved namespace in `MoveNamespaces` and leaves
6635f5a7458SNico Weber // the actual movement to `onEndOfTranslationUnit()`.
6645f5a7458SNico Weber void ChangeNamespaceTool::moveOldNamespace(
6655f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result,
6665f5a7458SNico Weber     const NamespaceDecl *NsDecl) {
6675f5a7458SNico Weber   // If the namespace is empty, do nothing.
6685f5a7458SNico Weber   if (Decl::castToDeclContext(NsDecl)->decls_empty())
6695f5a7458SNico Weber     return;
6705f5a7458SNico Weber 
6715f5a7458SNico Weber   const SourceManager &SM = *Result.SourceManager;
6725f5a7458SNico Weber   // Get the range of the code in the old namespace.
6735f5a7458SNico Weber   SourceLocation Start =
6745f5a7458SNico Weber       getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
6755f5a7458SNico Weber   assert(Start.isValid() && "Can't find l_brace for namespace.");
6765f5a7458SNico Weber   MoveNamespace MoveNs;
6775f5a7458SNico Weber   MoveNs.Offset = SM.getFileOffset(Start);
6785f5a7458SNico Weber   // The range of the moved namespace is from the location just past the left
6795f5a7458SNico Weber   // brace to the location right before the right brace.
6805f5a7458SNico Weber   MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
6815f5a7458SNico Weber 
6825f5a7458SNico Weber   // Insert the new namespace after `DiffOldNamespace`. For example, if
6835f5a7458SNico Weber   // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
6845f5a7458SNico Weber   // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
6855f5a7458SNico Weber   // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
6865f5a7458SNico Weber   // in the above example.
6875f5a7458SNico Weber   // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
6885f5a7458SNico Weber   // namespace will be a nested namespace in the old namespace.
6895f5a7458SNico Weber   const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
6905f5a7458SNico Weber   SourceLocation InsertionLoc = Start;
6915f5a7458SNico Weber   if (OuterNs) {
6925f5a7458SNico Weber     SourceLocation LocAfterNs = getStartOfNextLine(
6935f5a7458SNico Weber         OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
6945f5a7458SNico Weber     assert(LocAfterNs.isValid() &&
6955f5a7458SNico Weber            "Failed to get location after DiffOldNamespace");
6965f5a7458SNico Weber     InsertionLoc = LocAfterNs;
6975f5a7458SNico Weber   }
6985f5a7458SNico Weber   MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
6995f5a7458SNico Weber   MoveNs.FID = SM.getFileID(Start);
7005f5a7458SNico Weber   MoveNs.SourceMgr = Result.SourceManager;
701adcd0268SBenjamin Kramer   MoveNamespaces[std::string(SM.getFilename(Start))].push_back(MoveNs);
7025f5a7458SNico Weber }
7035f5a7458SNico Weber 
7045f5a7458SNico Weber // Removes a class forward declaration from the code in the moved namespace and
7055f5a7458SNico Weber // creates an `InsertForwardDeclaration` to insert the forward declaration back
7065f5a7458SNico Weber // into the old namespace after moving code from the old namespace to the new
7075f5a7458SNico Weber // namespace.
7085f5a7458SNico Weber // For example, changing "a" to "x":
7095f5a7458SNico Weber // Old code:
7105f5a7458SNico Weber //   namespace a {
7115f5a7458SNico Weber //   class FWD;
7125f5a7458SNico Weber //   class A { FWD *fwd; }
7135f5a7458SNico Weber //   }  // a
7145f5a7458SNico Weber // New code:
7155f5a7458SNico Weber //   namespace a {
7165f5a7458SNico Weber //   class FWD;
7175f5a7458SNico Weber //   }  // a
7185f5a7458SNico Weber //   namespace x {
7195f5a7458SNico Weber //   class A { a::FWD *fwd; }
7205f5a7458SNico Weber //   }  // x
7215f5a7458SNico Weber void ChangeNamespaceTool::moveClassForwardDeclaration(
7225f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result,
7235f5a7458SNico Weber     const NamedDecl *FwdDecl) {
7245f5a7458SNico Weber   SourceLocation Start = FwdDecl->getBeginLoc();
7255f5a7458SNico Weber   SourceLocation End = FwdDecl->getEndLoc();
7265f5a7458SNico Weber   const SourceManager &SM = *Result.SourceManager;
7275f5a7458SNico Weber   SourceLocation AfterSemi = Lexer::findLocationAfterToken(
7285f5a7458SNico Weber       End, tok::semi, SM, Result.Context->getLangOpts(),
7295f5a7458SNico Weber       /*SkipTrailingWhitespaceAndNewLine=*/true);
7305f5a7458SNico Weber   if (AfterSemi.isValid())
7315f5a7458SNico Weber     End = AfterSemi.getLocWithOffset(-1);
7325f5a7458SNico Weber   // Delete the forward declaration from the code to be moved.
7335f5a7458SNico Weber   addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
7345f5a7458SNico Weber   llvm::StringRef Code = Lexer::getSourceText(
7355f5a7458SNico Weber       CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
7365f5a7458SNico Weber                                      SM.getSpellingLoc(End)),
7375f5a7458SNico Weber       SM, Result.Context->getLangOpts());
7385f5a7458SNico Weber   // Insert the forward declaration back into the old namespace after moving the
7395f5a7458SNico Weber   // code from old namespace to new namespace.
7405f5a7458SNico Weber   // Insertion information is stored in `InsertFwdDecls` and actual
7415f5a7458SNico Weber   // insertion will be performed in `onEndOfTranslationUnit`.
7425f5a7458SNico Weber   // Get the (old) namespace that contains the forward declaration.
7435f5a7458SNico Weber   const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
7445f5a7458SNico Weber   // The namespace contains the forward declaration, so it must not be empty.
7455f5a7458SNico Weber   assert(!NsDecl->decls_empty());
7465f5a7458SNico Weber   const auto Insertion = createInsertion(
7475f5a7458SNico Weber       getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
7485f5a7458SNico Weber       Code, SM);
7495f5a7458SNico Weber   InsertForwardDeclaration InsertFwd;
7505f5a7458SNico Weber   InsertFwd.InsertionOffset = Insertion.getOffset();
7515f5a7458SNico Weber   InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
752adcd0268SBenjamin Kramer   InsertFwdDecls[std::string(Insertion.getFilePath())].push_back(InsertFwd);
7535f5a7458SNico Weber }
7545f5a7458SNico Weber 
7555f5a7458SNico Weber // Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
7565f5a7458SNico Weber // FromDecl with the shortest qualified name possible when the reference is in
7575f5a7458SNico Weber // `NewNamespace`.
7585f5a7458SNico Weber void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
7595f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result,
7605f5a7458SNico Weber     const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
7615f5a7458SNico Weber     const NamedDecl *FromDecl) {
7625f5a7458SNico Weber   const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
7635f5a7458SNico Weber   if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
7645f5a7458SNico Weber     // This should not happen in usual unless the TypeLoc is in function type
7655f5a7458SNico Weber     // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
7665f5a7458SNico Weber     // `T` will be the translation unit. We simply use fully-qualified name
7675f5a7458SNico Weber     // here.
7685f5a7458SNico Weber     // Note that `FromDecl` must not be defined in the old namespace (according
7695f5a7458SNico Weber     // to `DeclMatcher`), so its fully-qualified name will not change after
7705f5a7458SNico Weber     // changing the namespace.
7715f5a7458SNico Weber     addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
7725f5a7458SNico Weber                         *Result.SourceManager, &FileToReplacements);
7735f5a7458SNico Weber     return;
7745f5a7458SNico Weber   }
7755f5a7458SNico Weber   const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
7765f5a7458SNico Weber   // Calculate the name of the `NsDecl` after it is moved to new namespace.
7775f5a7458SNico Weber   std::string OldNs = NsDecl->getQualifiedNameAsString();
7785f5a7458SNico Weber   llvm::StringRef Postfix = OldNs;
7795f5a7458SNico Weber   bool Consumed = Postfix.consume_front(OldNamespace);
7805f5a7458SNico Weber   assert(Consumed && "Expect OldNS to start with OldNamespace.");
7815f5a7458SNico Weber   (void)Consumed;
7825f5a7458SNico Weber   const std::string NewNs = (NewNamespace + Postfix).str();
7835f5a7458SNico Weber 
7845f5a7458SNico Weber   llvm::StringRef NestedName = Lexer::getSourceText(
7855f5a7458SNico Weber       CharSourceRange::getTokenRange(
7865f5a7458SNico Weber           Result.SourceManager->getSpellingLoc(Start),
7875f5a7458SNico Weber           Result.SourceManager->getSpellingLoc(End)),
7885f5a7458SNico Weber       *Result.SourceManager, Result.Context->getLangOpts());
7895f5a7458SNico Weber   std::string FromDeclName = FromDecl->getQualifiedNameAsString();
79025ed42f0SEric Christopher   for (llvm::Regex &RE : AllowedSymbolRegexes)
7915f5a7458SNico Weber     if (RE.match(FromDeclName))
7925f5a7458SNico Weber       return;
7935f5a7458SNico Weber   std::string ReplaceName =
7945f5a7458SNico Weber       getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
7955f5a7458SNico Weber   // Checks if there is any using namespace declarations that can shorten the
7965f5a7458SNico Weber   // qualified name.
7975f5a7458SNico Weber   for (const auto *UsingNamespace : UsingNamespaceDecls) {
7985f5a7458SNico Weber     if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
7995f5a7458SNico Weber                                  Start))
8005f5a7458SNico Weber       continue;
8015f5a7458SNico Weber     StringRef FromDeclNameRef = FromDeclName;
8025f5a7458SNico Weber     if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
8035f5a7458SNico Weber                                           ->getQualifiedNameAsString())) {
8045f5a7458SNico Weber       FromDeclNameRef = FromDeclNameRef.drop_front(2);
8055f5a7458SNico Weber       if (FromDeclNameRef.size() < ReplaceName.size())
806adcd0268SBenjamin Kramer         ReplaceName = std::string(FromDeclNameRef);
8075f5a7458SNico Weber     }
8085f5a7458SNico Weber   }
8095f5a7458SNico Weber   // Checks if there is any namespace alias declarations that can shorten the
8105f5a7458SNico Weber   // qualified name.
8115f5a7458SNico Weber   for (const auto *NamespaceAlias : NamespaceAliasDecls) {
8125f5a7458SNico Weber     if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
8135f5a7458SNico Weber                                  Start))
8145f5a7458SNico Weber       continue;
8155f5a7458SNico Weber     StringRef FromDeclNameRef = FromDeclName;
8165f5a7458SNico Weber     if (FromDeclNameRef.consume_front(
8175f5a7458SNico Weber             NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
8185f5a7458SNico Weber             "::")) {
8195f5a7458SNico Weber       std::string AliasName = NamespaceAlias->getNameAsString();
8205f5a7458SNico Weber       std::string AliasQualifiedName =
8215f5a7458SNico Weber           NamespaceAlias->getQualifiedNameAsString();
822dd5571d5SKazuaki Ishizaki       // We only consider namespace aliases define in the global namespace or
8235f5a7458SNico Weber       // in namespaces that are directly visible from the reference, i.e.
8245f5a7458SNico Weber       // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
8255f5a7458SNico Weber       // but not visible in the new namespace is filtered out by
8265f5a7458SNico Weber       // "IsVisibleInNewNs" matcher.
8275f5a7458SNico Weber       if (AliasQualifiedName != AliasName) {
8285f5a7458SNico Weber         // The alias is defined in some namespace.
829732bccb8SKazu Hirata         assert(StringRef(AliasQualifiedName).ends_with("::" + AliasName));
8305f5a7458SNico Weber         llvm::StringRef AliasNs =
8315f5a7458SNico Weber             StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
832732bccb8SKazu Hirata         if (!llvm::StringRef(OldNs).starts_with(AliasNs))
8335f5a7458SNico Weber           continue;
8345f5a7458SNico Weber       }
8355f5a7458SNico Weber       std::string NameWithAliasNamespace =
8365f5a7458SNico Weber           (AliasName + "::" + FromDeclNameRef).str();
8375f5a7458SNico Weber       if (NameWithAliasNamespace.size() < ReplaceName.size())
8385f5a7458SNico Weber         ReplaceName = NameWithAliasNamespace;
8395f5a7458SNico Weber     }
8405f5a7458SNico Weber   }
8415f5a7458SNico Weber   // Checks if there is any using shadow declarations that can shorten the
8425f5a7458SNico Weber   // qualified name.
8435f5a7458SNico Weber   bool Matched = false;
8445f5a7458SNico Weber   for (const UsingDecl *Using : UsingDecls) {
8455f5a7458SNico Weber     if (Matched)
8465f5a7458SNico Weber       break;
8475f5a7458SNico Weber     if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
8485f5a7458SNico Weber       for (const auto *UsingShadow : Using->shadows()) {
8495f5a7458SNico Weber         const auto *TargetDecl = UsingShadow->getTargetDecl();
8505f5a7458SNico Weber         if (TargetDecl->getQualifiedNameAsString() ==
8515f5a7458SNico Weber             FromDecl->getQualifiedNameAsString()) {
8525f5a7458SNico Weber           ReplaceName = FromDecl->getNameAsString();
8535f5a7458SNico Weber           Matched = true;
8545f5a7458SNico Weber           break;
8555f5a7458SNico Weber         }
8565f5a7458SNico Weber       }
8575f5a7458SNico Weber     }
8585f5a7458SNico Weber   }
8595f5a7458SNico Weber   bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
8605f5a7458SNico Weber                                       ReplaceName, NewNamespace);
8615f5a7458SNico Weber   // If the new nested name in the new namespace is the same as it was in the
8625f5a7458SNico Weber   // old namespace, we don't create replacement unless there can be ambiguity.
8635f5a7458SNico Weber   if ((NestedName == ReplaceName && !Conflict) ||
864732bccb8SKazu Hirata       (NestedName.starts_with("::") && NestedName.drop_front(2) == ReplaceName))
8655f5a7458SNico Weber     return;
8665f5a7458SNico Weber   // If the reference need to be fully-qualified, add a leading "::" unless
8675f5a7458SNico Weber   // NewNamespace is the global namespace.
8685f5a7458SNico Weber   if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
8695f5a7458SNico Weber     ReplaceName = "::" + ReplaceName;
8705f5a7458SNico Weber   addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
8715f5a7458SNico Weber                       &FileToReplacements);
8725f5a7458SNico Weber }
8735f5a7458SNico Weber 
8745f5a7458SNico Weber // Replace the [Start, End] of `Type` with the shortest qualified name when the
8755f5a7458SNico Weber // `Type` is in `NewNamespace`.
8765f5a7458SNico Weber void ChangeNamespaceTool::fixTypeLoc(
8775f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
8785f5a7458SNico Weber     SourceLocation End, TypeLoc Type) {
8795f5a7458SNico Weber   // FIXME: do not rename template parameter.
8805f5a7458SNico Weber   if (Start.isInvalid() || End.isInvalid())
8815f5a7458SNico Weber     return;
8825f5a7458SNico Weber   // Types of CXXCtorInitializers do not need to be fixed.
8835f5a7458SNico Weber   if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
8845f5a7458SNico Weber     return;
8855f5a7458SNico Weber   if (isTemplateParameter(Type))
8865f5a7458SNico Weber     return;
8875f5a7458SNico Weber   // The declaration which this TypeLoc refers to.
8885f5a7458SNico Weber   const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
8895f5a7458SNico Weber   // `hasDeclaration` gives underlying declaration, but if the type is
8905f5a7458SNico Weber   // a typedef type, we need to use the typedef type instead.
8915f5a7458SNico Weber   auto IsInMovedNs = [&](const NamedDecl *D) {
8925f5a7458SNico Weber     if (!llvm::StringRef(D->getQualifiedNameAsString())
893732bccb8SKazu Hirata              .starts_with(OldNamespace + "::"))
8945f5a7458SNico Weber       return false;
8955f5a7458SNico Weber     auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
8965f5a7458SNico Weber     if (ExpansionLoc.isInvalid())
8975f5a7458SNico Weber       return false;
8985f5a7458SNico Weber     llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
8995f5a7458SNico Weber     return FilePatternRE.match(Filename);
9005f5a7458SNico Weber   };
9015f5a7458SNico Weber   // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
9025f5a7458SNico Weber   // `Type` is an alias type, we make `FromDecl` the type alias declaration.
9035f5a7458SNico Weber   // Also, don't fix the \p Type if it refers to a type alias decl in the moved
9045f5a7458SNico Weber   // namespace since the alias decl will be moved along with the type reference.
9055f5a7458SNico Weber   if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
9065f5a7458SNico Weber     FromDecl = Typedef->getDecl();
9075f5a7458SNico Weber     if (IsInMovedNs(FromDecl))
9085f5a7458SNico Weber       return;
9095f5a7458SNico Weber   } else if (auto *TemplateType =
9105f5a7458SNico Weber                  Type.getType()->getAs<TemplateSpecializationType>()) {
9115f5a7458SNico Weber     if (TemplateType->isTypeAlias()) {
9125f5a7458SNico Weber       FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
9135f5a7458SNico Weber       if (IsInMovedNs(FromDecl))
9145f5a7458SNico Weber         return;
9155f5a7458SNico Weber     }
9165f5a7458SNico Weber   }
9175f5a7458SNico Weber   const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
9185f5a7458SNico Weber   assert(DeclCtx && "Empty decl context.");
9195f5a7458SNico Weber   replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
9205f5a7458SNico Weber                                       End, FromDecl);
9215f5a7458SNico Weber }
9225f5a7458SNico Weber 
9235f5a7458SNico Weber void ChangeNamespaceTool::fixUsingShadowDecl(
9245f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result,
9255f5a7458SNico Weber     const UsingDecl *UsingDeclaration) {
9265f5a7458SNico Weber   SourceLocation Start = UsingDeclaration->getBeginLoc();
9275f5a7458SNico Weber   SourceLocation End = UsingDeclaration->getEndLoc();
9285f5a7458SNico Weber   if (Start.isInvalid() || End.isInvalid())
9295f5a7458SNico Weber     return;
9305f5a7458SNico Weber 
9315f5a7458SNico Weber   assert(UsingDeclaration->shadow_size() > 0);
9325f5a7458SNico Weber   // FIXME: it might not be always accurate to use the first using-decl.
9335f5a7458SNico Weber   const NamedDecl *TargetDecl =
9345f5a7458SNico Weber       UsingDeclaration->shadow_begin()->getTargetDecl();
9355f5a7458SNico Weber   std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
9365f5a7458SNico Weber   // FIXME: check if target_decl_name is in moved ns, which doesn't make much
9375f5a7458SNico Weber   // sense. If this happens, we need to use name with the new namespace.
9385f5a7458SNico Weber   // Use fully qualified name in UsingDecl for now.
9395f5a7458SNico Weber   addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
9405f5a7458SNico Weber                       *Result.SourceManager, &FileToReplacements);
9415f5a7458SNico Weber }
9425f5a7458SNico Weber 
9435f5a7458SNico Weber void ChangeNamespaceTool::fixDeclRefExpr(
9445f5a7458SNico Weber     const ast_matchers::MatchFinder::MatchResult &Result,
9455f5a7458SNico Weber     const DeclContext *UseContext, const NamedDecl *From,
9465f5a7458SNico Weber     const DeclRefExpr *Ref) {
9475f5a7458SNico Weber   SourceRange RefRange = Ref->getSourceRange();
9485f5a7458SNico Weber   replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
9495f5a7458SNico Weber                                       RefRange.getEnd(), From);
9505f5a7458SNico Weber }
9515f5a7458SNico Weber 
9525f5a7458SNico Weber void ChangeNamespaceTool::onEndOfTranslationUnit() {
9535f5a7458SNico Weber   // Move namespace blocks and insert forward declaration to old namespace.
9545f5a7458SNico Weber   for (const auto &FileAndNsMoves : MoveNamespaces) {
9555f5a7458SNico Weber     auto &NsMoves = FileAndNsMoves.second;
9565f5a7458SNico Weber     if (NsMoves.empty())
9575f5a7458SNico Weber       continue;
9585f5a7458SNico Weber     const std::string &FilePath = FileAndNsMoves.first;
9595f5a7458SNico Weber     auto &Replaces = FileToReplacements[FilePath];
9605f5a7458SNico Weber     auto &SM = *NsMoves.begin()->SourceMgr;
9615f5a7458SNico Weber     llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
9625f5a7458SNico Weber     auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
9635f5a7458SNico Weber     if (!ChangedCode) {
9645f5a7458SNico Weber       llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
9655f5a7458SNico Weber       continue;
9665f5a7458SNico Weber     }
9675f5a7458SNico Weber     // Replacements on the changed code for moving namespaces and inserting
9685f5a7458SNico Weber     // forward declarations to old namespaces.
9695f5a7458SNico Weber     tooling::Replacements NewReplacements;
9705f5a7458SNico Weber     // Cut the changed code from the old namespace and paste the code in the new
9715f5a7458SNico Weber     // namespace.
9725f5a7458SNico Weber     for (const auto &NsMove : NsMoves) {
9735f5a7458SNico Weber       // Calculate the range of the old namespace block in the changed
9745f5a7458SNico Weber       // code.
9755f5a7458SNico Weber       const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
9765f5a7458SNico Weber       const unsigned NewLength =
9775f5a7458SNico Weber           Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
9785f5a7458SNico Weber           NewOffset;
9795f5a7458SNico Weber       tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
9805f5a7458SNico Weber       std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
9815f5a7458SNico Weber       std::string MovedCodeWrappedInNewNs =
9825f5a7458SNico Weber           wrapCodeInNamespace(DiffNewNamespace, MovedCode);
9835f5a7458SNico Weber       // Calculate the new offset at which the code will be inserted in the
9845f5a7458SNico Weber       // changed code.
9855f5a7458SNico Weber       unsigned NewInsertionOffset =
9865f5a7458SNico Weber           Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
9875f5a7458SNico Weber       tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
9885f5a7458SNico Weber                                      MovedCodeWrappedInNewNs);
9895f5a7458SNico Weber       addOrMergeReplacement(Deletion, &NewReplacements);
9905f5a7458SNico Weber       addOrMergeReplacement(Insertion, &NewReplacements);
9915f5a7458SNico Weber     }
9925f5a7458SNico Weber     // After moving namespaces, insert forward declarations back to old
9935f5a7458SNico Weber     // namespaces.
9945f5a7458SNico Weber     const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
9955f5a7458SNico Weber     for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
9965f5a7458SNico Weber       unsigned NewInsertionOffset =
9975f5a7458SNico Weber           Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
9985f5a7458SNico Weber       tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
9995f5a7458SNico Weber                                      FwdDeclInsertion.ForwardDeclText);
10005f5a7458SNico Weber       addOrMergeReplacement(Insertion, &NewReplacements);
10015f5a7458SNico Weber     }
10025f5a7458SNico Weber     // Add replacements referring to the changed code to existing replacements,
10035f5a7458SNico Weber     // which refers to the original code.
10045f5a7458SNico Weber     Replaces = Replaces.merge(NewReplacements);
10055f5a7458SNico Weber     auto Style =
10065f5a7458SNico Weber         format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
10075f5a7458SNico Weber     if (!Style) {
10085f5a7458SNico Weber       llvm::errs() << llvm::toString(Style.takeError()) << "\n";
10095f5a7458SNico Weber       continue;
10105f5a7458SNico Weber     }
10115f5a7458SNico Weber     // Clean up old namespaces if there is nothing in it after moving.
10125f5a7458SNico Weber     auto CleanReplacements =
10135f5a7458SNico Weber         format::cleanupAroundReplacements(Code, Replaces, *Style);
10145f5a7458SNico Weber     if (!CleanReplacements) {
10155f5a7458SNico Weber       llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
10165f5a7458SNico Weber       continue;
10175f5a7458SNico Weber     }
10185f5a7458SNico Weber     FileToReplacements[FilePath] = *CleanReplacements;
10195f5a7458SNico Weber   }
10205f5a7458SNico Weber 
10215f5a7458SNico Weber   // Make sure we don't generate replacements for files that do not match
10225f5a7458SNico Weber   // FilePattern.
10235f5a7458SNico Weber   for (auto &Entry : FileToReplacements)
10245f5a7458SNico Weber     if (!FilePatternRE.match(Entry.first))
10255f5a7458SNico Weber       Entry.second.clear();
10265f5a7458SNico Weber }
10275f5a7458SNico Weber 
10285f5a7458SNico Weber } // namespace change_namespace
10295f5a7458SNico Weber } // namespace clang
1030