1 //===-- ChangeNamespace.cpp - Change namespace implementation -------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 #include "ChangeNamespace.h"
9 #include "clang/AST/ASTContext.h"
10 #include "clang/Format/Format.h"
11 #include "clang/Lex/Lexer.h"
12 #include "llvm/Support/Casting.h"
13 #include "llvm/Support/ErrorHandling.h"
14 
15 using namespace clang::ast_matchers;
16 
17 namespace clang {
18 namespace change_namespace {
19 
20 namespace {
21 
joinNamespaces(ArrayRef<StringRef> Namespaces)22 inline std::string joinNamespaces(ArrayRef<StringRef> Namespaces) {
23   return llvm::join(Namespaces, "::");
24 }
25 
26 // Given "a::b::c", returns {"a", "b", "c"}.
splitSymbolName(llvm::StringRef Name)27 llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
28   llvm::SmallVector<llvm::StringRef, 4> Splitted;
29   Name.split(Splitted, "::", /*MaxSplit=*/-1,
30              /*KeepEmpty=*/false);
31   return Splitted;
32 }
33 
startLocationForType(TypeLoc TLoc)34 SourceLocation startLocationForType(TypeLoc TLoc) {
35   // For elaborated types (e.g. `struct a::A`) we want the portion after the
36   // `struct` but including the namespace qualifier, `a::`.
37   if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
38     NestedNameSpecifierLoc NestedNameSpecifier =
39         TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
40     if (NestedNameSpecifier.getNestedNameSpecifier())
41       return NestedNameSpecifier.getBeginLoc();
42     TLoc = TLoc.getNextTypeLoc();
43   }
44   return TLoc.getBeginLoc();
45 }
46 
endLocationForType(TypeLoc TLoc)47 SourceLocation endLocationForType(TypeLoc TLoc) {
48   // Dig past any namespace or keyword qualifications.
49   while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
50          TLoc.getTypeLocClass() == TypeLoc::Qualified)
51     TLoc = TLoc.getNextTypeLoc();
52 
53   // The location for template specializations (e.g. Foo<int>) includes the
54   // templated types in its location range.  We want to restrict this to just
55   // before the `<` character.
56   if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
57     return TLoc.castAs<TemplateSpecializationTypeLoc>()
58         .getLAngleLoc()
59         .getLocWithOffset(-1);
60   return TLoc.getEndLoc();
61 }
62 
63 // Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
64 // If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
65 // is empty, nullptr is returned.
66 // For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
67 // the NamespaceDecl of namespace "a" will be returned.
getOuterNamespace(const NamespaceDecl * InnerNs,llvm::StringRef PartialNsName)68 const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
69                                        llvm::StringRef PartialNsName) {
70   if (!InnerNs || PartialNsName.empty())
71     return nullptr;
72   const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
73   const auto *CurrentNs = InnerNs;
74   auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
75   while (!PartialNsNameSplitted.empty()) {
76     // Get the inner-most namespace in CurrentContext.
77     while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
78       CurrentContext = CurrentContext->getParent();
79     if (!CurrentContext)
80       return nullptr;
81     CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
82     if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
83       return nullptr;
84     PartialNsNameSplitted.pop_back();
85     CurrentContext = CurrentContext->getParent();
86   }
87   return CurrentNs;
88 }
89 
90 static std::unique_ptr<Lexer>
getLexerStartingFromLoc(SourceLocation Loc,const SourceManager & SM,const LangOptions & LangOpts)91 getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
92                         const LangOptions &LangOpts) {
93   if (Loc.isMacroID() &&
94       !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
95     return nullptr;
96   // Break down the source location.
97   std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
98   // Try to load the file buffer.
99   bool InvalidTemp = false;
100   llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
101   if (InvalidTemp)
102     return nullptr;
103 
104   const char *TokBegin = File.data() + LocInfo.second;
105   // Lex from the start of the given location.
106   return std::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
107                                   LangOpts, File.begin(), TokBegin, File.end());
108 }
109 
110 // FIXME: get rid of this helper function if this is supported in clang-refactor
111 // library.
getStartOfNextLine(SourceLocation Loc,const SourceManager & SM,const LangOptions & LangOpts)112 static SourceLocation getStartOfNextLine(SourceLocation Loc,
113                                          const SourceManager &SM,
114                                          const LangOptions &LangOpts) {
115   std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
116   if (!Lex.get())
117     return SourceLocation();
118   llvm::SmallVector<char, 16> Line;
119   // FIXME: this is a bit hacky to get ReadToEndOfLine work.
120   Lex->setParsingPreprocessorDirective(true);
121   Lex->ReadToEndOfLine(&Line);
122   auto End = Loc.getLocWithOffset(Line.size());
123   return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
124              ? End
125              : End.getLocWithOffset(1);
126 }
127 
128 // Returns `R` with new range that refers to code after `Replaces` being
129 // applied.
130 tooling::Replacement
getReplacementInChangedCode(const tooling::Replacements & Replaces,const tooling::Replacement & R)131 getReplacementInChangedCode(const tooling::Replacements &Replaces,
132                             const tooling::Replacement &R) {
133   unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
134   unsigned NewEnd =
135       Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
136   return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
137                               R.getReplacementText());
138 }
139 
140 // Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
141 // applying all existing Replaces first if there is conflict.
addOrMergeReplacement(const tooling::Replacement & R,tooling::Replacements * Replaces)142 void addOrMergeReplacement(const tooling::Replacement &R,
143                            tooling::Replacements *Replaces) {
144   auto Err = Replaces->add(R);
145   if (Err) {
146     llvm::consumeError(std::move(Err));
147     auto Replace = getReplacementInChangedCode(*Replaces, R);
148     *Replaces = Replaces->merge(tooling::Replacements(Replace));
149   }
150 }
151 
createReplacement(SourceLocation Start,SourceLocation End,llvm::StringRef ReplacementText,const SourceManager & SM)152 tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
153                                        llvm::StringRef ReplacementText,
154                                        const SourceManager &SM) {
155   if (!Start.isValid() || !End.isValid()) {
156     llvm::errs() << "start or end location were invalid\n";
157     return tooling::Replacement();
158   }
159   if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
160     llvm::errs()
161         << "start or end location were in different macro expansions\n";
162     return tooling::Replacement();
163   }
164   Start = SM.getSpellingLoc(Start);
165   End = SM.getSpellingLoc(End);
166   if (SM.getFileID(Start) != SM.getFileID(End)) {
167     llvm::errs() << "start or end location were in different files\n";
168     return tooling::Replacement();
169   }
170   return tooling::Replacement(
171       SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
172                                          SM.getSpellingLoc(End)),
173       ReplacementText);
174 }
175 
addReplacementOrDie(SourceLocation Start,SourceLocation End,llvm::StringRef ReplacementText,const SourceManager & SM,std::map<std::string,tooling::Replacements> * FileToReplacements)176 void addReplacementOrDie(
177     SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
178     const SourceManager &SM,
179     std::map<std::string, tooling::Replacements> *FileToReplacements) {
180   const auto R = createReplacement(Start, End, ReplacementText, SM);
181   auto Err = (*FileToReplacements)[std::string(R.getFilePath())].add(R);
182   if (Err)
183     llvm_unreachable(llvm::toString(std::move(Err)).c_str());
184 }
185 
createInsertion(SourceLocation Loc,llvm::StringRef InsertText,const SourceManager & SM)186 tooling::Replacement createInsertion(SourceLocation Loc,
187                                      llvm::StringRef InsertText,
188                                      const SourceManager &SM) {
189   if (Loc.isInvalid()) {
190     llvm::errs() << "insert Location is invalid.\n";
191     return tooling::Replacement();
192   }
193   Loc = SM.getSpellingLoc(Loc);
194   return tooling::Replacement(SM, Loc, 0, InsertText);
195 }
196 
197 // Returns the shortest qualified name for declaration `DeclName` in the
198 // namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
199 // is "a::c::d", then "b::X" will be returned.
200 // Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
201 // "::b::X" instead of "b::X" since there will be a name conflict otherwise.
202 // \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
203 // \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
204 //        will have empty name.
getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,llvm::StringRef NsName)205 std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
206                                                 llvm::StringRef NsName) {
207   DeclName = DeclName.ltrim(':');
208   NsName = NsName.ltrim(':');
209   if (DeclName.find(':') == llvm::StringRef::npos)
210     return std::string(DeclName);
211 
212   auto NsNameSplitted = splitSymbolName(NsName);
213   auto DeclNsSplitted = splitSymbolName(DeclName);
214   llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
215   // If the Decl is in global namespace, there is no need to shorten it.
216   if (DeclNsSplitted.empty())
217     return std::string(UnqualifiedDeclName);
218   // If NsName is the global namespace, we can simply use the DeclName sans
219   // leading "::".
220   if (NsNameSplitted.empty())
221     return std::string(DeclName);
222 
223   if (NsNameSplitted.front() != DeclNsSplitted.front()) {
224     // The DeclName must be fully-qualified, but we still need to decide if a
225     // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
226     // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
227     // to avoid conflict.
228     if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
229       return ("::" + DeclName).str();
230     return std::string(DeclName);
231   }
232   // Since there is already an overlap namespace, we know that `DeclName` can be
233   // shortened, so we reduce the longest common prefix.
234   auto DeclI = DeclNsSplitted.begin();
235   auto DeclE = DeclNsSplitted.end();
236   auto NsI = NsNameSplitted.begin();
237   auto NsE = NsNameSplitted.end();
238   for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
239   }
240   return (DeclI == DeclE)
241              ? UnqualifiedDeclName.str()
242              : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
243                    .str();
244 }
245 
wrapCodeInNamespace(StringRef NestedNs,std::string Code)246 std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
247   if (Code.back() != '\n')
248     Code += "\n";
249   auto NsSplitted = splitSymbolName(NestedNs);
250   while (!NsSplitted.empty()) {
251     // FIXME: consider code style for comments.
252     Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
253             "} // namespace " + NsSplitted.back() + "\n")
254                .str();
255     NsSplitted.pop_back();
256   }
257   return Code;
258 }
259 
260 // Returns true if \p D is a nested DeclContext in \p Context
isNestedDeclContext(const DeclContext * D,const DeclContext * Context)261 bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
262   while (D) {
263     if (D == Context)
264       return true;
265     D = D->getParent();
266   }
267   return false;
268 }
269 
270 // Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
isDeclVisibleAtLocation(const SourceManager & SM,const Decl * D,const DeclContext * DeclCtx,SourceLocation Loc)271 bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
272                              const DeclContext *DeclCtx, SourceLocation Loc) {
273   SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
274   Loc = SM.getSpellingLoc(Loc);
275   return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
276          (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
277           isNestedDeclContext(DeclCtx, D->getDeclContext()));
278 }
279 
280 // Given a qualified symbol name, returns true if the symbol will be
281 // incorrectly qualified without leading "::". For example, a symbol
282 // "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
283 // "util::X" in namespace "na" can potentially conflict with "na::util" (if this
284 // exists).
conflictInNamespace(const ASTContext & AST,llvm::StringRef QualifiedSymbol,llvm::StringRef Namespace)285 bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
286                          llvm::StringRef Namespace) {
287   auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
288   assert(!SymbolSplitted.empty());
289   SymbolSplitted.pop_back();  // We are only interested in namespaces.
290 
291   if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
292     auto SymbolTopNs = SymbolSplitted.front();
293     auto NsSplitted = splitSymbolName(Namespace.trim(":"));
294     assert(!NsSplitted.empty());
295 
296     auto LookupDecl = [&AST](const Decl &Scope,
297                              llvm::StringRef Name) -> const NamedDecl * {
298       const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
299       if (!DC)
300         return nullptr;
301       auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
302       if (LookupRes.empty())
303         return nullptr;
304       return LookupRes.front();
305     };
306     // We do not check the outermost namespace since it would not be a
307     // conflict if it equals to the symbol's outermost namespace and the
308     // symbol name would have been shortened.
309     const NamedDecl *Scope =
310         LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
311     for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
312       if (*I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
313         return true;
314       // Handles "::util" and "::nx::util" conflicts.
315       if (Scope) {
316         if (LookupDecl(*Scope, SymbolTopNs))
317           return true;
318         Scope = LookupDecl(*Scope, *I);
319       }
320     }
321     if (Scope && LookupDecl(*Scope, SymbolTopNs))
322       return true;
323   }
324   return false;
325 }
326 
isTemplateParameter(TypeLoc Type)327 bool isTemplateParameter(TypeLoc Type) {
328   while (!Type.isNull()) {
329     if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
330       return true;
331     Type = Type.getNextTypeLoc();
332   }
333   return false;
334 }
335 
336 } // anonymous namespace
337 
ChangeNamespaceTool(llvm::StringRef OldNs,llvm::StringRef NewNs,llvm::StringRef FilePattern,llvm::ArrayRef<std::string> AllowedSymbolPatterns,std::map<std::string,tooling::Replacements> * FileToReplacements,llvm::StringRef FallbackStyle)338 ChangeNamespaceTool::ChangeNamespaceTool(
339     llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
340     llvm::ArrayRef<std::string> AllowedSymbolPatterns,
341     std::map<std::string, tooling::Replacements> *FileToReplacements,
342     llvm::StringRef FallbackStyle)
343     : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
344       OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
345       FilePattern(FilePattern), FilePatternRE(FilePattern) {
346   FileToReplacements->clear();
347   auto OldNsSplitted = splitSymbolName(OldNamespace);
348   auto NewNsSplitted = splitSymbolName(NewNamespace);
349   // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
350   while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
351          OldNsSplitted.front() == NewNsSplitted.front()) {
352     OldNsSplitted.erase(OldNsSplitted.begin());
353     NewNsSplitted.erase(NewNsSplitted.begin());
354   }
355   DiffOldNamespace = joinNamespaces(OldNsSplitted);
356   DiffNewNamespace = joinNamespaces(NewNsSplitted);
357 
358   for (const auto &Pattern : AllowedSymbolPatterns)
359     AllowedSymbolRegexes.emplace_back(Pattern);
360 }
361 
registerMatchers(ast_matchers::MatchFinder * Finder)362 void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
363   std::string FullOldNs = "::" + OldNamespace;
364   // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
365   // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
366   // be "a::b". Declarations in this namespace will not be visible in the new
367   // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
368   llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
369   llvm::StringRef(DiffOldNamespace)
370       .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
371              /*KeepEmpty=*/false);
372   std::string Prefix = "-";
373   if (!DiffOldNsSplitted.empty())
374     Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
375               DiffOldNsSplitted.front())
376                  .str();
377   auto IsInMovedNs =
378       allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
379             isExpansionInFileMatching(FilePattern));
380   auto IsVisibleInNewNs = anyOf(
381       IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
382   // Match using declarations.
383   Finder->addMatcher(
384       usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
385           .bind("using"),
386       this);
387   // Match using namespace declarations.
388   Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
389                                         IsVisibleInNewNs)
390                          .bind("using_namespace"),
391                      this);
392   // Match namespace alias declarations.
393   Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
394                                         IsVisibleInNewNs)
395                          .bind("namespace_alias"),
396                      this);
397 
398   // Match old namespace blocks.
399   Finder->addMatcher(
400       namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
401           .bind("old_ns"),
402       this);
403 
404   // Match class forward-declarations in the old namespace.
405   // Note that forward-declarations in classes are not matched.
406   Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
407                                    IsInMovedNs, hasParent(namespaceDecl()))
408                          .bind("class_fwd_decl"),
409                      this);
410 
411   // Match template class forward-declarations in the old namespace.
412   Finder->addMatcher(
413       classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
414                         IsInMovedNs, hasParent(namespaceDecl()))
415           .bind("template_class_fwd_decl"),
416       this);
417 
418   // Match references to types that are not defined in the old namespace.
419   // Forward-declarations in the old namespace are also matched since they will
420   // be moved back to the old namespace.
421   auto DeclMatcher = namedDecl(
422       hasAncestor(namespaceDecl()),
423       unless(anyOf(
424           isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
425           hasAncestor(cxxRecordDecl()),
426           allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
427 
428   // Using shadow declarations in classes always refers to base class, which
429   // does not need to be qualified since it can be inferred from inheritance.
430   // Note that this does not match using alias declarations.
431   auto UsingShadowDeclInClass =
432       usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
433 
434   // Match TypeLocs on the declaration. Carefully match only the outermost
435   // TypeLoc and template specialization arguments (which are not outermost)
436   // that are directly linked to types matching `DeclMatcher`. Nested name
437   // specifier locs are handled separately below.
438   Finder->addMatcher(
439       typeLoc(IsInMovedNs,
440               loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
441               unless(anyOf(hasParent(typeLoc(loc(qualType(
442                                hasDeclaration(DeclMatcher),
443                                unless(templateSpecializationType()))))),
444                            hasParent(nestedNameSpecifierLoc()),
445                            hasAncestor(isImplicit()),
446                            hasAncestor(UsingShadowDeclInClass),
447                            hasAncestor(functionDecl(isDefaulted())))),
448               hasAncestor(decl().bind("dc")))
449           .bind("type"),
450       this);
451 
452   // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
453   // special case it.
454   // Since using declarations inside classes must have the base class in the
455   // nested name specifier, we leave it to the nested name specifier matcher.
456   Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
457                                unless(UsingShadowDeclInClass))
458                          .bind("using_with_shadow"),
459                      this);
460 
461   // Handle types in nested name specifier. Specifiers that are in a TypeLoc
462   // matched above are not matched, e.g. "A::" in "A::A" is not matched since
463   // "A::A" would have already been fixed.
464   Finder->addMatcher(
465       nestedNameSpecifierLoc(
466           hasAncestor(decl(IsInMovedNs).bind("dc")),
467           loc(nestedNameSpecifier(
468               specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
469           unless(anyOf(hasAncestor(isImplicit()),
470                        hasAncestor(UsingShadowDeclInClass),
471                        hasAncestor(functionDecl(isDefaulted())),
472                        hasAncestor(typeLoc(loc(qualType(hasDeclaration(
473                            decl(equalsBoundNode("from_decl"))))))))))
474           .bind("nested_specifier_loc"),
475       this);
476 
477   // Matches base class initializers in constructors. TypeLocs of base class
478   // initializers do not need to be fixed. For example,
479   //    class X : public a::b::Y {
480   //      public:
481   //        X() : Y::Y() {} // Y::Y do not need namespace specifier.
482   //    };
483   Finder->addMatcher(
484       cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
485 
486   // Handle function.
487   // Only handle functions that are defined in a namespace excluding member
488   // function, static methods (qualified by nested specifier), and functions
489   // defined in the global namespace.
490   // Note that the matcher does not exclude calls to out-of-line static method
491   // definitions, so we need to exclude them in the callback handler.
492   auto FuncMatcher =
493       functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
494                                 hasAncestor(namespaceDecl(isAnonymous())),
495                                 hasAncestor(cxxRecordDecl()))),
496                    hasParent(namespaceDecl()));
497   Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
498                           unless(hasAncestor(isImplicit())),
499                           anyOf(callExpr(callee(FuncMatcher)).bind("call"),
500                                 declRefExpr(to(FuncMatcher.bind("func_decl")))
501                                     .bind("func_ref"))),
502                      this);
503 
504   auto GlobalVarMatcher = varDecl(
505       hasGlobalStorage(), hasParent(namespaceDecl()),
506       unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
507   Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
508                                  to(GlobalVarMatcher.bind("var_decl")))
509                          .bind("var_ref"),
510                      this);
511 
512   // Handle unscoped enum constant.
513   auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
514       hasParent(namespaceDecl()),
515       unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
516                    hasAncestor(namespaceDecl(isAnonymous())))))));
517   Finder->addMatcher(
518       declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
519                   to(UnscopedEnumMatcher.bind("enum_const_decl")))
520           .bind("enum_const_ref"),
521       this);
522 }
523 
run(const ast_matchers::MatchFinder::MatchResult & Result)524 void ChangeNamespaceTool::run(
525     const ast_matchers::MatchFinder::MatchResult &Result) {
526   if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
527     UsingDecls.insert(Using);
528   } else if (const auto *UsingNamespace =
529                  Result.Nodes.getNodeAs<UsingDirectiveDecl>(
530                      "using_namespace")) {
531     UsingNamespaceDecls.insert(UsingNamespace);
532   } else if (const auto *NamespaceAlias =
533                  Result.Nodes.getNodeAs<NamespaceAliasDecl>(
534                      "namespace_alias")) {
535     NamespaceAliasDecls.insert(NamespaceAlias);
536   } else if (const auto *NsDecl =
537                  Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
538     moveOldNamespace(Result, NsDecl);
539   } else if (const auto *FwdDecl =
540                  Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
541     moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
542   } else if (const auto *TemplateFwdDecl =
543                  Result.Nodes.getNodeAs<ClassTemplateDecl>(
544                      "template_class_fwd_decl")) {
545     moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
546   } else if (const auto *UsingWithShadow =
547                  Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
548     fixUsingShadowDecl(Result, UsingWithShadow);
549   } else if (const auto *Specifier =
550                  Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
551                      "nested_specifier_loc")) {
552     SourceLocation Start = Specifier->getBeginLoc();
553     SourceLocation End = endLocationForType(Specifier->getTypeLoc());
554     fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
555   } else if (const auto *BaseInitializer =
556                  Result.Nodes.getNodeAs<CXXCtorInitializer>(
557                      "base_initializer")) {
558     BaseCtorInitializerTypeLocs.push_back(
559         BaseInitializer->getTypeSourceInfo()->getTypeLoc());
560   } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
561     // This avoids fixing types with record types as qualifier, which is not
562     // filtered by matchers in some cases, e.g. the type is templated. We should
563     // handle the record type qualifier instead.
564     TypeLoc Loc = *TLoc;
565     while (Loc.getTypeLocClass() == TypeLoc::Qualified)
566       Loc = Loc.getNextTypeLoc();
567     if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
568       NestedNameSpecifierLoc NestedNameSpecifier =
569           Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
570       // This happens for friend declaration of a base class with injected class
571       // name.
572       if (!NestedNameSpecifier.getNestedNameSpecifier())
573         return;
574       const Type *SpecifierType =
575           NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
576       if (SpecifierType && SpecifierType->isRecordType())
577         return;
578     }
579     fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
580   } else if (const auto *VarRef =
581                  Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
582     const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
583     assert(Var);
584     if (Var->getCanonicalDecl()->isStaticDataMember())
585       return;
586     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
587     assert(Context && "Empty decl context.");
588     fixDeclRefExpr(Result, Context->getDeclContext(),
589                    llvm::cast<NamedDecl>(Var), VarRef);
590   } else if (const auto *EnumConstRef =
591                  Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
592     // Do not rename the reference if it is already scoped by the EnumDecl name.
593     if (EnumConstRef->hasQualifier() &&
594         EnumConstRef->getQualifier()->getKind() ==
595             NestedNameSpecifier::SpecifierKind::TypeSpec &&
596         EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
597       return;
598     const auto *EnumConstDecl =
599         Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
600     assert(EnumConstDecl);
601     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
602     assert(Context && "Empty decl context.");
603     // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
604     // if it turns out to be an issue.
605     fixDeclRefExpr(Result, Context->getDeclContext(),
606                    llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
607   } else if (const auto *FuncRef =
608                  Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
609     // If this reference has been processed as a function call, we do not
610     // process it again.
611     if (ProcessedFuncRefs.count(FuncRef))
612       return;
613     ProcessedFuncRefs.insert(FuncRef);
614     const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
615     assert(Func);
616     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
617     assert(Context && "Empty decl context.");
618     fixDeclRefExpr(Result, Context->getDeclContext(),
619                    llvm::cast<NamedDecl>(Func), FuncRef);
620   } else {
621     const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
622     assert(Call != nullptr && "Expecting callback for CallExpr.");
623     const auto *CalleeFuncRef =
624         llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
625     ProcessedFuncRefs.insert(CalleeFuncRef);
626     const FunctionDecl *Func = Call->getDirectCallee();
627     assert(Func != nullptr);
628     // FIXME: ignore overloaded operators. This would miss cases where operators
629     // are called by qualified names (i.e. "ns::operator <"). Ignore such
630     // cases for now.
631     if (Func->isOverloadedOperator())
632       return;
633     // Ignore out-of-line static methods since they will be handled by nested
634     // name specifiers.
635     if (Func->getCanonicalDecl()->getStorageClass() ==
636             StorageClass::SC_Static &&
637         Func->isOutOfLine())
638       return;
639     const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
640     assert(Context && "Empty decl context.");
641     SourceRange CalleeRange = Call->getCallee()->getSourceRange();
642     replaceQualifiedSymbolInDeclContext(
643         Result, Context->getDeclContext(), CalleeRange.getBegin(),
644         CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
645   }
646 }
647 
getLocAfterNamespaceLBrace(const NamespaceDecl * NsDecl,const SourceManager & SM,const LangOptions & LangOpts)648 static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
649                                                  const SourceManager &SM,
650                                                  const LangOptions &LangOpts) {
651   std::unique_ptr<Lexer> Lex =
652       getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
653   assert(Lex.get() &&
654          "Failed to create lexer from the beginning of namespace.");
655   if (!Lex.get())
656     return SourceLocation();
657   Token Tok;
658   while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
659   }
660   return Tok.isNot(tok::TokenKind::l_brace)
661              ? SourceLocation()
662              : Tok.getEndLoc().getLocWithOffset(1);
663 }
664 
665 // Stores information about a moved namespace in `MoveNamespaces` and leaves
666 // the actual movement to `onEndOfTranslationUnit()`.
moveOldNamespace(const ast_matchers::MatchFinder::MatchResult & Result,const NamespaceDecl * NsDecl)667 void ChangeNamespaceTool::moveOldNamespace(
668     const ast_matchers::MatchFinder::MatchResult &Result,
669     const NamespaceDecl *NsDecl) {
670   // If the namespace is empty, do nothing.
671   if (Decl::castToDeclContext(NsDecl)->decls_empty())
672     return;
673 
674   const SourceManager &SM = *Result.SourceManager;
675   // Get the range of the code in the old namespace.
676   SourceLocation Start =
677       getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
678   assert(Start.isValid() && "Can't find l_brace for namespace.");
679   MoveNamespace MoveNs;
680   MoveNs.Offset = SM.getFileOffset(Start);
681   // The range of the moved namespace is from the location just past the left
682   // brace to the location right before the right brace.
683   MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
684 
685   // Insert the new namespace after `DiffOldNamespace`. For example, if
686   // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
687   // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
688   // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
689   // in the above example.
690   // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
691   // namespace will be a nested namespace in the old namespace.
692   const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
693   SourceLocation InsertionLoc = Start;
694   if (OuterNs) {
695     SourceLocation LocAfterNs = getStartOfNextLine(
696         OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
697     assert(LocAfterNs.isValid() &&
698            "Failed to get location after DiffOldNamespace");
699     InsertionLoc = LocAfterNs;
700   }
701   MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
702   MoveNs.FID = SM.getFileID(Start);
703   MoveNs.SourceMgr = Result.SourceManager;
704   MoveNamespaces[std::string(SM.getFilename(Start))].push_back(MoveNs);
705 }
706 
707 // Removes a class forward declaration from the code in the moved namespace and
708 // creates an `InsertForwardDeclaration` to insert the forward declaration back
709 // into the old namespace after moving code from the old namespace to the new
710 // namespace.
711 // For example, changing "a" to "x":
712 // Old code:
713 //   namespace a {
714 //   class FWD;
715 //   class A { FWD *fwd; }
716 //   }  // a
717 // New code:
718 //   namespace a {
719 //   class FWD;
720 //   }  // a
721 //   namespace x {
722 //   class A { a::FWD *fwd; }
723 //   }  // x
moveClassForwardDeclaration(const ast_matchers::MatchFinder::MatchResult & Result,const NamedDecl * FwdDecl)724 void ChangeNamespaceTool::moveClassForwardDeclaration(
725     const ast_matchers::MatchFinder::MatchResult &Result,
726     const NamedDecl *FwdDecl) {
727   SourceLocation Start = FwdDecl->getBeginLoc();
728   SourceLocation End = FwdDecl->getEndLoc();
729   const SourceManager &SM = *Result.SourceManager;
730   SourceLocation AfterSemi = Lexer::findLocationAfterToken(
731       End, tok::semi, SM, Result.Context->getLangOpts(),
732       /*SkipTrailingWhitespaceAndNewLine=*/true);
733   if (AfterSemi.isValid())
734     End = AfterSemi.getLocWithOffset(-1);
735   // Delete the forward declaration from the code to be moved.
736   addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
737   llvm::StringRef Code = Lexer::getSourceText(
738       CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
739                                      SM.getSpellingLoc(End)),
740       SM, Result.Context->getLangOpts());
741   // Insert the forward declaration back into the old namespace after moving the
742   // code from old namespace to new namespace.
743   // Insertion information is stored in `InsertFwdDecls` and actual
744   // insertion will be performed in `onEndOfTranslationUnit`.
745   // Get the (old) namespace that contains the forward declaration.
746   const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
747   // The namespace contains the forward declaration, so it must not be empty.
748   assert(!NsDecl->decls_empty());
749   const auto Insertion = createInsertion(
750       getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
751       Code, SM);
752   InsertForwardDeclaration InsertFwd;
753   InsertFwd.InsertionOffset = Insertion.getOffset();
754   InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
755   InsertFwdDecls[std::string(Insertion.getFilePath())].push_back(InsertFwd);
756 }
757 
758 // Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
759 // FromDecl with the shortest qualified name possible when the reference is in
760 // `NewNamespace`.
replaceQualifiedSymbolInDeclContext(const ast_matchers::MatchFinder::MatchResult & Result,const DeclContext * DeclCtx,SourceLocation Start,SourceLocation End,const NamedDecl * FromDecl)761 void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
762     const ast_matchers::MatchFinder::MatchResult &Result,
763     const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
764     const NamedDecl *FromDecl) {
765   const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
766   if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
767     // This should not happen in usual unless the TypeLoc is in function type
768     // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
769     // `T` will be the translation unit. We simply use fully-qualified name
770     // here.
771     // Note that `FromDecl` must not be defined in the old namespace (according
772     // to `DeclMatcher`), so its fully-qualified name will not change after
773     // changing the namespace.
774     addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
775                         *Result.SourceManager, &FileToReplacements);
776     return;
777   }
778   const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
779   // Calculate the name of the `NsDecl` after it is moved to new namespace.
780   std::string OldNs = NsDecl->getQualifiedNameAsString();
781   llvm::StringRef Postfix = OldNs;
782   bool Consumed = Postfix.consume_front(OldNamespace);
783   assert(Consumed && "Expect OldNS to start with OldNamespace.");
784   (void)Consumed;
785   const std::string NewNs = (NewNamespace + Postfix).str();
786 
787   llvm::StringRef NestedName = Lexer::getSourceText(
788       CharSourceRange::getTokenRange(
789           Result.SourceManager->getSpellingLoc(Start),
790           Result.SourceManager->getSpellingLoc(End)),
791       *Result.SourceManager, Result.Context->getLangOpts());
792   std::string FromDeclName = FromDecl->getQualifiedNameAsString();
793   for (llvm::Regex &RE : AllowedSymbolRegexes)
794     if (RE.match(FromDeclName))
795       return;
796   std::string ReplaceName =
797       getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
798   // Checks if there is any using namespace declarations that can shorten the
799   // qualified name.
800   for (const auto *UsingNamespace : UsingNamespaceDecls) {
801     if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
802                                  Start))
803       continue;
804     StringRef FromDeclNameRef = FromDeclName;
805     if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
806                                           ->getQualifiedNameAsString())) {
807       FromDeclNameRef = FromDeclNameRef.drop_front(2);
808       if (FromDeclNameRef.size() < ReplaceName.size())
809         ReplaceName = std::string(FromDeclNameRef);
810     }
811   }
812   // Checks if there is any namespace alias declarations that can shorten the
813   // qualified name.
814   for (const auto *NamespaceAlias : NamespaceAliasDecls) {
815     if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
816                                  Start))
817       continue;
818     StringRef FromDeclNameRef = FromDeclName;
819     if (FromDeclNameRef.consume_front(
820             NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
821             "::")) {
822       std::string AliasName = NamespaceAlias->getNameAsString();
823       std::string AliasQualifiedName =
824           NamespaceAlias->getQualifiedNameAsString();
825       // We only consider namespace aliases define in the global namespace or
826       // in namespaces that are directly visible from the reference, i.e.
827       // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
828       // but not visible in the new namespace is filtered out by
829       // "IsVisibleInNewNs" matcher.
830       if (AliasQualifiedName != AliasName) {
831         // The alias is defined in some namespace.
832         assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
833         llvm::StringRef AliasNs =
834             StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
835         if (!llvm::StringRef(OldNs).startswith(AliasNs))
836           continue;
837       }
838       std::string NameWithAliasNamespace =
839           (AliasName + "::" + FromDeclNameRef).str();
840       if (NameWithAliasNamespace.size() < ReplaceName.size())
841         ReplaceName = NameWithAliasNamespace;
842     }
843   }
844   // Checks if there is any using shadow declarations that can shorten the
845   // qualified name.
846   bool Matched = false;
847   for (const UsingDecl *Using : UsingDecls) {
848     if (Matched)
849       break;
850     if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
851       for (const auto *UsingShadow : Using->shadows()) {
852         const auto *TargetDecl = UsingShadow->getTargetDecl();
853         if (TargetDecl->getQualifiedNameAsString() ==
854             FromDecl->getQualifiedNameAsString()) {
855           ReplaceName = FromDecl->getNameAsString();
856           Matched = true;
857           break;
858         }
859       }
860     }
861   }
862   bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
863                                       ReplaceName, NewNamespace);
864   // If the new nested name in the new namespace is the same as it was in the
865   // old namespace, we don't create replacement unless there can be ambiguity.
866   if ((NestedName == ReplaceName && !Conflict) ||
867       (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
868     return;
869   // If the reference need to be fully-qualified, add a leading "::" unless
870   // NewNamespace is the global namespace.
871   if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
872     ReplaceName = "::" + ReplaceName;
873   addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
874                       &FileToReplacements);
875 }
876 
877 // Replace the [Start, End] of `Type` with the shortest qualified name when the
878 // `Type` is in `NewNamespace`.
fixTypeLoc(const ast_matchers::MatchFinder::MatchResult & Result,SourceLocation Start,SourceLocation End,TypeLoc Type)879 void ChangeNamespaceTool::fixTypeLoc(
880     const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
881     SourceLocation End, TypeLoc Type) {
882   // FIXME: do not rename template parameter.
883   if (Start.isInvalid() || End.isInvalid())
884     return;
885   // Types of CXXCtorInitializers do not need to be fixed.
886   if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
887     return;
888   if (isTemplateParameter(Type))
889     return;
890   // The declaration which this TypeLoc refers to.
891   const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
892   // `hasDeclaration` gives underlying declaration, but if the type is
893   // a typedef type, we need to use the typedef type instead.
894   auto IsInMovedNs = [&](const NamedDecl *D) {
895     if (!llvm::StringRef(D->getQualifiedNameAsString())
896              .startswith(OldNamespace + "::"))
897       return false;
898     auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
899     if (ExpansionLoc.isInvalid())
900       return false;
901     llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
902     return FilePatternRE.match(Filename);
903   };
904   // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
905   // `Type` is an alias type, we make `FromDecl` the type alias declaration.
906   // Also, don't fix the \p Type if it refers to a type alias decl in the moved
907   // namespace since the alias decl will be moved along with the type reference.
908   if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
909     FromDecl = Typedef->getDecl();
910     if (IsInMovedNs(FromDecl))
911       return;
912   } else if (auto *TemplateType =
913                  Type.getType()->getAs<TemplateSpecializationType>()) {
914     if (TemplateType->isTypeAlias()) {
915       FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
916       if (IsInMovedNs(FromDecl))
917         return;
918     }
919   }
920   const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
921   assert(DeclCtx && "Empty decl context.");
922   replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
923                                       End, FromDecl);
924 }
925 
fixUsingShadowDecl(const ast_matchers::MatchFinder::MatchResult & Result,const UsingDecl * UsingDeclaration)926 void ChangeNamespaceTool::fixUsingShadowDecl(
927     const ast_matchers::MatchFinder::MatchResult &Result,
928     const UsingDecl *UsingDeclaration) {
929   SourceLocation Start = UsingDeclaration->getBeginLoc();
930   SourceLocation End = UsingDeclaration->getEndLoc();
931   if (Start.isInvalid() || End.isInvalid())
932     return;
933 
934   assert(UsingDeclaration->shadow_size() > 0);
935   // FIXME: it might not be always accurate to use the first using-decl.
936   const NamedDecl *TargetDecl =
937       UsingDeclaration->shadow_begin()->getTargetDecl();
938   std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
939   // FIXME: check if target_decl_name is in moved ns, which doesn't make much
940   // sense. If this happens, we need to use name with the new namespace.
941   // Use fully qualified name in UsingDecl for now.
942   addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
943                       *Result.SourceManager, &FileToReplacements);
944 }
945 
fixDeclRefExpr(const ast_matchers::MatchFinder::MatchResult & Result,const DeclContext * UseContext,const NamedDecl * From,const DeclRefExpr * Ref)946 void ChangeNamespaceTool::fixDeclRefExpr(
947     const ast_matchers::MatchFinder::MatchResult &Result,
948     const DeclContext *UseContext, const NamedDecl *From,
949     const DeclRefExpr *Ref) {
950   SourceRange RefRange = Ref->getSourceRange();
951   replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
952                                       RefRange.getEnd(), From);
953 }
954 
onEndOfTranslationUnit()955 void ChangeNamespaceTool::onEndOfTranslationUnit() {
956   // Move namespace blocks and insert forward declaration to old namespace.
957   for (const auto &FileAndNsMoves : MoveNamespaces) {
958     auto &NsMoves = FileAndNsMoves.second;
959     if (NsMoves.empty())
960       continue;
961     const std::string &FilePath = FileAndNsMoves.first;
962     auto &Replaces = FileToReplacements[FilePath];
963     auto &SM = *NsMoves.begin()->SourceMgr;
964     llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
965     auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
966     if (!ChangedCode) {
967       llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
968       continue;
969     }
970     // Replacements on the changed code for moving namespaces and inserting
971     // forward declarations to old namespaces.
972     tooling::Replacements NewReplacements;
973     // Cut the changed code from the old namespace and paste the code in the new
974     // namespace.
975     for (const auto &NsMove : NsMoves) {
976       // Calculate the range of the old namespace block in the changed
977       // code.
978       const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
979       const unsigned NewLength =
980           Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
981           NewOffset;
982       tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
983       std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
984       std::string MovedCodeWrappedInNewNs =
985           wrapCodeInNamespace(DiffNewNamespace, MovedCode);
986       // Calculate the new offset at which the code will be inserted in the
987       // changed code.
988       unsigned NewInsertionOffset =
989           Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
990       tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
991                                      MovedCodeWrappedInNewNs);
992       addOrMergeReplacement(Deletion, &NewReplacements);
993       addOrMergeReplacement(Insertion, &NewReplacements);
994     }
995     // After moving namespaces, insert forward declarations back to old
996     // namespaces.
997     const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
998     for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
999       unsigned NewInsertionOffset =
1000           Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
1001       tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1002                                      FwdDeclInsertion.ForwardDeclText);
1003       addOrMergeReplacement(Insertion, &NewReplacements);
1004     }
1005     // Add replacements referring to the changed code to existing replacements,
1006     // which refers to the original code.
1007     Replaces = Replaces.merge(NewReplacements);
1008     auto Style =
1009         format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
1010     if (!Style) {
1011       llvm::errs() << llvm::toString(Style.takeError()) << "\n";
1012       continue;
1013     }
1014     // Clean up old namespaces if there is nothing in it after moving.
1015     auto CleanReplacements =
1016         format::cleanupAroundReplacements(Code, Replaces, *Style);
1017     if (!CleanReplacements) {
1018       llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
1019       continue;
1020     }
1021     FileToReplacements[FilePath] = *CleanReplacements;
1022   }
1023 
1024   // Make sure we don't generate replacements for files that do not match
1025   // FilePattern.
1026   for (auto &Entry : FileToReplacements)
1027     if (!FilePatternRE.match(Entry.first))
1028       Entry.second.clear();
1029 }
1030 
1031 } // namespace change_namespace
1032 } // namespace clang
1033