blob: e07066794b51995ac9682d7ca7244749f3a72f89 [file] [log] [blame]
Eric Liu495b2112016-09-19 17:40:321//===-- ChangeNamespace.cpp - Change namespace implementation -------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9#include "ChangeNamespace.h"
10#include "clang/Format/Format.h"
11#include "clang/Lex/Lexer.h"
Eric Liuff51f012016-11-16 16:54:5312#include "llvm/Support/ErrorHandling.h"
Eric Liu495b2112016-09-19 17:40:3213
14using namespace clang::ast_matchers;
15
16namespace clang {
17namespace change_namespace {
18
19namespace {
20
21inline std::string
22joinNamespaces(const llvm::SmallVectorImpl<StringRef> &Namespaces) {
23 if (Namespaces.empty())
24 return "";
25 std::string Result = Namespaces.front();
26 for (auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
27 Result += ("::" + *I).str();
28 return Result;
29}
30
31SourceLocation startLocationForType(TypeLoc TLoc) {
32 // For elaborated types (e.g. `struct a::A`) we want the portion after the
33 // `struct` but including the namespace qualifier, `a::`.
34 if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
35 NestedNameSpecifierLoc NestedNameSpecifier =
36 TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
37 if (NestedNameSpecifier.getNestedNameSpecifier())
38 return NestedNameSpecifier.getBeginLoc();
39 TLoc = TLoc.getNextTypeLoc();
40 }
41 return TLoc.getLocStart();
42}
43
Eric Liuc265b022016-12-01 17:25:5544SourceLocation endLocationForType(TypeLoc TLoc) {
Eric Liu495b2112016-09-19 17:40:3245 // Dig past any namespace or keyword qualifications.
46 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
47 TLoc.getTypeLocClass() == TypeLoc::Qualified)
48 TLoc = TLoc.getNextTypeLoc();
49
50 // The location for template specializations (e.g. Foo<int>) includes the
51 // templated types in its location range. We want to restrict this to just
52 // before the `<` character.
53 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
54 return TLoc.castAs<TemplateSpecializationTypeLoc>()
55 .getLAngleLoc()
56 .getLocWithOffset(-1);
57 return TLoc.getEndLoc();
58}
59
60// Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
Eric Liu6aa94162016-11-10 18:29:0161// If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
62// is empty, nullptr is returned.
Eric Liu495b2112016-09-19 17:40:3263// For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
64// the NamespaceDecl of namespace "a" will be returned.
65const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
66 llvm::StringRef PartialNsName) {
Eric Liu6aa94162016-11-10 18:29:0167 if (!InnerNs || PartialNsName.empty())
68 return nullptr;
Eric Liu495b2112016-09-19 17:40:3269 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
70 const auto *CurrentNs = InnerNs;
71 llvm::SmallVector<llvm::StringRef, 4> PartialNsNameSplitted;
Eric Liu6aa94162016-11-10 18:29:0172 PartialNsName.split(PartialNsNameSplitted, "::", /*MaxSplit=*/-1,
73 /*KeepEmpty=*/false);
Eric Liu495b2112016-09-19 17:40:3274 while (!PartialNsNameSplitted.empty()) {
75 // Get the inner-most namespace in CurrentContext.
76 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
77 CurrentContext = CurrentContext->getParent();
78 if (!CurrentContext)
79 return nullptr;
80 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
81 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
82 return nullptr;
83 PartialNsNameSplitted.pop_back();
84 CurrentContext = CurrentContext->getParent();
85 }
86 return CurrentNs;
87}
88
Eric Liu73f49fd2016-10-12 12:34:1889static std::unique_ptr<Lexer>
90getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
91 const LangOptions &LangOpts) {
Eric Liu495b2112016-09-19 17:40:3292 if (Loc.isMacroID() &&
93 !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
Eric Liu73f49fd2016-10-12 12:34:1894 return nullptr;
Eric Liu495b2112016-09-19 17:40:3295 // Break down the source location.
96 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
97 // Try to load the file buffer.
98 bool InvalidTemp = false;
99 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
100 if (InvalidTemp)
Eric Liu73f49fd2016-10-12 12:34:18101 return nullptr;
Eric Liu495b2112016-09-19 17:40:32102
103 const char *TokBegin = File.data() + LocInfo.second;
104 // Lex from the start of the given location.
Eric Liu73f49fd2016-10-12 12:34:18105 return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
106 LangOpts, File.begin(), TokBegin, File.end());
107}
Eric Liu495b2112016-09-19 17:40:32108
Eric Liu73f49fd2016-10-12 12:34:18109// FIXME: get rid of this helper function if this is supported in clang-refactor
110// library.
111static SourceLocation getStartOfNextLine(SourceLocation Loc,
112 const SourceManager &SM,
113 const LangOptions &LangOpts) {
114 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
115 if (!Lex.get())
116 return SourceLocation();
Eric Liu495b2112016-09-19 17:40:32117 llvm::SmallVector<char, 16> Line;
118 // FIXME: this is a bit hacky to get ReadToEndOfLine work.
Eric Liu73f49fd2016-10-12 12:34:18119 Lex->setParsingPreprocessorDirective(true);
120 Lex->ReadToEndOfLine(&Line);
Haojian Wuef8a6dc2016-10-04 10:35:53121 auto End = Loc.getLocWithOffset(Line.size());
Eric Liu73f49fd2016-10-12 12:34:18122 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
123 ? End
124 : End.getLocWithOffset(1);
Eric Liu495b2112016-09-19 17:40:32125}
126
127// Returns `R` with new range that refers to code after `Replaces` being
128// applied.
129tooling::Replacement
130getReplacementInChangedCode(const tooling::Replacements &Replaces,
131 const tooling::Replacement &R) {
132 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
133 unsigned NewEnd =
134 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
135 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
136 R.getReplacementText());
137}
138
139// Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
140// applying all existing Replaces first if there is conflict.
141void addOrMergeReplacement(const tooling::Replacement &R,
142 tooling::Replacements *Replaces) {
143 auto Err = Replaces->add(R);
144 if (Err) {
145 llvm::consumeError(std::move(Err));
146 auto Replace = getReplacementInChangedCode(*Replaces, R);
147 *Replaces = Replaces->merge(tooling::Replacements(Replace));
148 }
149}
150
151tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
152 llvm::StringRef ReplacementText,
153 const SourceManager &SM) {
154 if (!Start.isValid() || !End.isValid()) {
155 llvm::errs() << "start or end location were invalid\n";
156 return tooling::Replacement();
157 }
158 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
159 llvm::errs()
160 << "start or end location were in different macro expansions\n";
161 return tooling::Replacement();
162 }
163 Start = SM.getSpellingLoc(Start);
164 End = SM.getSpellingLoc(End);
165 if (SM.getFileID(Start) != SM.getFileID(End)) {
166 llvm::errs() << "start or end location were in different files\n";
167 return tooling::Replacement();
168 }
169 return tooling::Replacement(
170 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
171 SM.getSpellingLoc(End)),
172 ReplacementText);
173}
174
Eric Liu4fe99e12016-12-14 17:01:52175void addReplacementOrDie(
176 SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
177 const SourceManager &SM,
178 std::map<std::string, tooling::Replacements> *FileToReplacements) {
179 const auto R = createReplacement(Start, End, ReplacementText, SM);
180 auto Err = (*FileToReplacements)[R.getFilePath()].add(R);
181 if (Err)
182 llvm_unreachable(llvm::toString(std::move(Err)).c_str());
183}
184
Eric Liu495b2112016-09-19 17:40:32185tooling::Replacement createInsertion(SourceLocation Loc,
186 llvm::StringRef InsertText,
187 const SourceManager &SM) {
188 if (Loc.isInvalid()) {
189 llvm::errs() << "insert Location is invalid.\n";
190 return tooling::Replacement();
191 }
192 Loc = SM.getSpellingLoc(Loc);
193 return tooling::Replacement(SM, Loc, 0, InsertText);
194}
195
196// Returns the shortest qualified name for declaration `DeclName` in the
197// namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
198// is "a::c::d", then "b::X" will be returned.
Eric Liubc715502017-01-26 15:08:44199// Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
200// "::b::X" instead of "b::X" since there will be a name conflict otherwise.
Eric Liu447164d2016-10-05 15:52:39201// \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
202// \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
203// will have empty name.
Eric Liu495b2112016-09-19 17:40:32204std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
205 llvm::StringRef NsName) {
Eric Liu447164d2016-10-05 15:52:39206 DeclName = DeclName.ltrim(':');
207 NsName = NsName.ltrim(':');
Eric Liu447164d2016-10-05 15:52:39208 if (DeclName.find(':') == llvm::StringRef::npos)
Eric Liub9bf1b52016-11-08 22:44:17209 return DeclName;
Eric Liu447164d2016-10-05 15:52:39210
Eric Liubc715502017-01-26 15:08:44211 llvm::SmallVector<llvm::StringRef, 4> NsNameSplitted;
212 NsName.split(NsNameSplitted, "::", /*MaxSplit=*/-1,
213 /*KeepEmpty=*/false);
214 llvm::SmallVector<llvm::StringRef, 4> DeclNsSplitted;
215 DeclName.split(DeclNsSplitted, "::", /*MaxSplit=*/-1,
216 /*KeepEmpty=*/false);
217 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
218 // If the Decl is in global namespace, there is no need to shorten it.
219 if (DeclNsSplitted.empty())
220 return UnqualifiedDeclName;
221 // If NsName is the global namespace, we can simply use the DeclName sans
222 // leading "::".
223 if (NsNameSplitted.empty())
224 return DeclName;
225
226 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
227 // The DeclName must be fully-qualified, but we still need to decide if a
228 // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
229 // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
230 // to avoid conflict.
231 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
232 return ("::" + DeclName).str();
233 return DeclName;
Eric Liu495b2112016-09-19 17:40:32234 }
Eric Liubc715502017-01-26 15:08:44235 // Since there is already an overlap namespace, we know that `DeclName` can be
236 // shortened, so we reduce the longest common prefix.
237 auto DeclI = DeclNsSplitted.begin();
238 auto DeclE = DeclNsSplitted.end();
239 auto NsI = NsNameSplitted.begin();
240 auto NsE = NsNameSplitted.end();
241 for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
242 }
243 return (DeclI == DeclE)
244 ? UnqualifiedDeclName.str()
245 : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
246 .str();
Eric Liu495b2112016-09-19 17:40:32247}
248
249std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
250 if (Code.back() != '\n')
251 Code += "\n";
252 llvm::SmallVector<StringRef, 4> NsSplitted;
Eric Liu2dd0e1b2016-12-05 11:17:04253 NestedNs.split(NsSplitted, "::", /*MaxSplit=*/-1,
254 /*KeepEmpty=*/false);
Eric Liu495b2112016-09-19 17:40:32255 while (!NsSplitted.empty()) {
256 // FIXME: consider code style for comments.
257 Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
258 "} // namespace " + NsSplitted.back() + "\n")
259 .str();
260 NsSplitted.pop_back();
261 }
262 return Code;
263}
264
Eric Liub9bf1b52016-11-08 22:44:17265// Returns true if \p D is a nested DeclContext in \p Context
266bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
267 while (D) {
268 if (D == Context)
269 return true;
270 D = D->getParent();
271 }
272 return false;
273}
274
275// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
276bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
277 const DeclContext *DeclCtx, SourceLocation Loc) {
Eric Liua13c4192017-02-13 17:24:14278 SourceLocation DeclLoc = SM.getSpellingLoc(D->getLocStart());
Eric Liub9bf1b52016-11-08 22:44:17279 Loc = SM.getSpellingLoc(Loc);
280 return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
281 (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
282 isNestedDeclContext(DeclCtx, D->getDeclContext()));
283}
284
Eric Liu0325a772017-02-02 17:40:38285AST_MATCHER(EnumDecl, isScoped) {
286 return Node.isScoped();
287}
288
Eric Liu284b97c2017-03-17 14:05:39289bool isTemplateParameter(TypeLoc Type) {
290 while (!Type.isNull()) {
291 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
292 return true;
293 Type = Type.getNextTypeLoc();
294 }
295 return false;
296}
297
Eric Liu495b2112016-09-19 17:40:32298} // anonymous namespace
299
300ChangeNamespaceTool::ChangeNamespaceTool(
301 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
Eric Liu7fccc992017-02-24 11:54:45302 llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
Eric Liu495b2112016-09-19 17:40:32303 std::map<std::string, tooling::Replacements> *FileToReplacements,
304 llvm::StringRef FallbackStyle)
305 : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
306 OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
Eric Liuc265b022016-12-01 17:25:55307 FilePattern(FilePattern), FilePatternRE(FilePattern) {
Eric Liu495b2112016-09-19 17:40:32308 FileToReplacements->clear();
309 llvm::SmallVector<llvm::StringRef, 4> OldNsSplitted;
310 llvm::SmallVector<llvm::StringRef, 4> NewNsSplitted;
311 llvm::StringRef(OldNamespace).split(OldNsSplitted, "::");
312 llvm::StringRef(NewNamespace).split(NewNsSplitted, "::");
313 // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
314 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
315 OldNsSplitted.front() == NewNsSplitted.front()) {
316 OldNsSplitted.erase(OldNsSplitted.begin());
317 NewNsSplitted.erase(NewNsSplitted.begin());
318 }
319 DiffOldNamespace = joinNamespaces(OldNsSplitted);
320 DiffNewNamespace = joinNamespaces(NewNsSplitted);
Eric Liu7fccc992017-02-24 11:54:45321
322 for (const auto &Pattern : WhiteListedSymbolPatterns)
323 WhiteListedSymbolRegexes.emplace_back(Pattern);
Eric Liu495b2112016-09-19 17:40:32324}
325
Eric Liu495b2112016-09-19 17:40:32326void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
Eric Liu495b2112016-09-19 17:40:32327 std::string FullOldNs = "::" + OldNamespace;
Eric Liub9bf1b52016-11-08 22:44:17328 // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
329 // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
330 // be "a::b". Declarations in this namespace will not be visible in the new
331 // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
332 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
Eric Liu2dd0e1b2016-12-05 11:17:04333 llvm::StringRef(DiffOldNamespace)
334 .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
335 /*KeepEmpty=*/false);
Eric Liub9bf1b52016-11-08 22:44:17336 std::string Prefix = "-";
337 if (!DiffOldNsSplitted.empty())
338 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
339 DiffOldNsSplitted.front())
340 .str();
341 auto IsInMovedNs =
342 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
343 isExpansionInFileMatching(FilePattern));
344 auto IsVisibleInNewNs = anyOf(
345 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
346 // Match using declarations.
347 Finder->addMatcher(
348 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
349 .bind("using"),
350 this);
351 // Match using namespace declarations.
352 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
353 IsVisibleInNewNs)
354 .bind("using_namespace"),
355 this);
Eric Liu180dac62016-12-23 10:47:09356 // Match namespace alias declarations.
357 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
358 IsVisibleInNewNs)
359 .bind("namespace_alias"),
360 this);
Eric Liub9bf1b52016-11-08 22:44:17361
362 // Match old namespace blocks.
Eric Liu495b2112016-09-19 17:40:32363 Finder->addMatcher(
364 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
365 .bind("old_ns"),
366 this);
367
Eric Liu41552d62016-12-07 14:20:52368 // Match class forward-declarations in the old namespace.
369 // Note that forward-declarations in classes are not matched.
370 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
371 IsInMovedNs, hasParent(namespaceDecl()))
372 .bind("class_fwd_decl"),
373 this);
374
375 // Match template class forward-declarations in the old namespace.
Eric Liu495b2112016-09-19 17:40:32376 Finder->addMatcher(
Eric Liu41552d62016-12-07 14:20:52377 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
378 IsInMovedNs, hasParent(namespaceDecl()))
379 .bind("template_class_fwd_decl"),
Eric Liu495b2112016-09-19 17:40:32380 this);
381
382 // Match references to types that are not defined in the old namespace.
383 // Forward-declarations in the old namespace are also matched since they will
384 // be moved back to the old namespace.
385 auto DeclMatcher = namedDecl(
386 hasAncestor(namespaceDecl()),
387 unless(anyOf(
Eric Liu912d0392016-09-27 12:54:48388 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
Eric Liu495b2112016-09-19 17:40:32389 hasAncestor(cxxRecordDecl()),
390 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
Eric Liu912d0392016-09-27 12:54:48391
Eric Liu8685c762016-12-07 17:04:07392 // Using shadow declarations in classes always refers to base class, which
393 // does not need to be qualified since it can be inferred from inheritance.
394 // Note that this does not match using alias declarations.
395 auto UsingShadowDeclInClass =
396 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
397
Eric Liu495b2112016-09-19 17:40:32398 // Match TypeLocs on the declaration. Carefully match only the outermost
Eric Liu8393cb02016-10-31 08:28:29399 // TypeLoc and template specialization arguments (which are not outermost)
400 // that are directly linked to types matching `DeclMatcher`. Nested name
401 // specifier locs are handled separately below.
Eric Liu495b2112016-09-19 17:40:32402 Finder->addMatcher(
403 typeLoc(IsInMovedNs,
404 loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
Eric Liu8393cb02016-10-31 08:28:29405 unless(anyOf(hasParent(typeLoc(loc(qualType(
406 allOf(hasDeclaration(DeclMatcher),
407 unless(templateSpecializationType())))))),
Eric Liu8685c762016-12-07 17:04:07408 hasParent(nestedNameSpecifierLoc()),
409 hasAncestor(isImplicit()),
410 hasAncestor(UsingShadowDeclInClass))),
Eric Liu495b2112016-09-19 17:40:32411 hasAncestor(decl().bind("dc")))
412 .bind("type"),
413 this);
Eric Liu912d0392016-09-27 12:54:48414
Eric Liu68765a82016-09-21 15:06:12415 // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
416 // special case it.
Eric Liu8685c762016-12-07 17:04:07417 // Since using declarations inside classes must have the base class in the
418 // nested name specifier, we leave it to the nested name specifier matcher.
419 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
420 unless(UsingShadowDeclInClass))
Eric Liub9bf1b52016-11-08 22:44:17421 .bind("using_with_shadow"),
422 this);
Eric Liu912d0392016-09-27 12:54:48423
Eric Liuff51f012016-11-16 16:54:53424 // Handle types in nested name specifier. Specifiers that are in a TypeLoc
425 // matched above are not matched, e.g. "A::" in "A::A" is not matched since
426 // "A::A" would have already been fixed.
Eric Liu8685c762016-12-07 17:04:07427 Finder->addMatcher(
428 nestedNameSpecifierLoc(
429 hasAncestor(decl(IsInMovedNs).bind("dc")),
430 loc(nestedNameSpecifier(
431 specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
432 unless(anyOf(hasAncestor(isImplicit()),
433 hasAncestor(UsingShadowDeclInClass),
434 hasAncestor(typeLoc(loc(qualType(hasDeclaration(
435 decl(equalsBoundNode("from_decl"))))))))))
436 .bind("nested_specifier_loc"),
437 this);
Eric Liu12068d82016-09-22 11:54:00438
Eric Liuff51f012016-11-16 16:54:53439 // Matches base class initializers in constructors. TypeLocs of base class
440 // initializers do not need to be fixed. For example,
441 // class X : public a::b::Y {
442 // public:
443 // X() : Y::Y() {} // Y::Y do not need namespace specifier.
444 // };
445 Finder->addMatcher(
446 cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
447
Eric Liu12068d82016-09-22 11:54:00448 // Handle function.
Eric Liu912d0392016-09-27 12:54:48449 // Only handle functions that are defined in a namespace excluding member
450 // function, static methods (qualified by nested specifier), and functions
451 // defined in the global namespace.
Eric Liu12068d82016-09-22 11:54:00452 // Note that the matcher does not exclude calls to out-of-line static method
453 // definitions, so we need to exclude them in the callback handler.
Eric Liu912d0392016-09-27 12:54:48454 auto FuncMatcher =
455 functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
456 hasAncestor(namespaceDecl(isAnonymous())),
457 hasAncestor(cxxRecordDecl()))),
458 hasParent(namespaceDecl()));
Eric Liuda22b3c2016-11-29 14:15:14459 Finder->addMatcher(decl(forEachDescendant(expr(anyOf(
460 callExpr(callee(FuncMatcher)).bind("call"),
461 declRefExpr(to(FuncMatcher.bind("func_decl")))
462 .bind("func_ref")))),
463 IsInMovedNs, unless(isImplicit()))
464 .bind("dc"),
465 this);
Eric Liu159f0132016-09-30 04:32:39466
467 auto GlobalVarMatcher = varDecl(
468 hasGlobalStorage(), hasParent(namespaceDecl()),
469 unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
470 Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
471 to(GlobalVarMatcher.bind("var_decl")))
472 .bind("var_ref"),
473 this);
Eric Liu0325a772017-02-02 17:40:38474
475 // Handle unscoped enum constant.
476 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
477 hasParent(namespaceDecl()),
478 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
479 hasAncestor(namespaceDecl(isAnonymous())))))));
480 Finder->addMatcher(
481 declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
482 to(UnscopedEnumMatcher.bind("enum_const_decl")))
483 .bind("enum_const_ref"),
484 this);
Eric Liu495b2112016-09-19 17:40:32485}
486
487void ChangeNamespaceTool::run(
488 const ast_matchers::MatchFinder::MatchResult &Result) {
Eric Liub9bf1b52016-11-08 22:44:17489 if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
490 UsingDecls.insert(Using);
491 } else if (const auto *UsingNamespace =
492 Result.Nodes.getNodeAs<UsingDirectiveDecl>(
493 "using_namespace")) {
494 UsingNamespaceDecls.insert(UsingNamespace);
Eric Liu180dac62016-12-23 10:47:09495 } else if (const auto *NamespaceAlias =
496 Result.Nodes.getNodeAs<NamespaceAliasDecl>(
497 "namespace_alias")) {
498 NamespaceAliasDecls.insert(NamespaceAlias);
Eric Liub9bf1b52016-11-08 22:44:17499 } else if (const auto *NsDecl =
500 Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
Eric Liu495b2112016-09-19 17:40:32501 moveOldNamespace(Result, NsDecl);
502 } else if (const auto *FwdDecl =
Eric Liu41552d62016-12-07 14:20:52503 Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
504 moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
505 } else if (const auto *TemplateFwdDecl =
506 Result.Nodes.getNodeAs<ClassTemplateDecl>(
507 "template_class_fwd_decl")) {
508 moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
Eric Liub9bf1b52016-11-08 22:44:17509 } else if (const auto *UsingWithShadow =
510 Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
511 fixUsingShadowDecl(Result, UsingWithShadow);
Eric Liu68765a82016-09-21 15:06:12512 } else if (const auto *Specifier =
513 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
514 "nested_specifier_loc")) {
515 SourceLocation Start = Specifier->getBeginLoc();
Eric Liuc265b022016-12-01 17:25:55516 SourceLocation End = endLocationForType(Specifier->getTypeLoc());
Eric Liu68765a82016-09-21 15:06:12517 fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
Eric Liuff51f012016-11-16 16:54:53518 } else if (const auto *BaseInitializer =
519 Result.Nodes.getNodeAs<CXXCtorInitializer>(
520 "base_initializer")) {
521 BaseCtorInitializerTypeLocs.push_back(
522 BaseInitializer->getTypeSourceInfo()->getTypeLoc());
Eric Liu12068d82016-09-22 11:54:00523 } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
Eric Liu26cf68a2016-12-15 10:42:35524 // This avoids fixing types with record types as qualifier, which is not
525 // filtered by matchers in some cases, e.g. the type is templated. We should
526 // handle the record type qualifier instead.
Eric Liu0c0aea02016-12-15 13:02:41527 TypeLoc Loc = *TLoc;
528 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
529 Loc = Loc.getNextTypeLoc();
530 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
Eric Liu26cf68a2016-12-15 10:42:35531 NestedNameSpecifierLoc NestedNameSpecifier =
Eric Liu0c0aea02016-12-15 13:02:41532 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
Eric Liu26cf68a2016-12-15 10:42:35533 const Type *SpecifierType =
534 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
535 if (SpecifierType && SpecifierType->isRecordType())
536 return;
537 }
Eric Liu0c0aea02016-12-15 13:02:41538 fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19539 } else if (const auto *VarRef =
540 Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
Eric Liu159f0132016-09-30 04:32:39541 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
542 assert(Var);
543 if (Var->getCanonicalDecl()->isStaticDataMember())
544 return;
Eric Liuda22b3c2016-11-29 14:15:14545 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu159f0132016-09-30 04:32:39546 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14547 fixDeclRefExpr(Result, Context->getDeclContext(),
548 llvm::cast<NamedDecl>(Var), VarRef);
Eric Liu0325a772017-02-02 17:40:38549 } else if (const auto *EnumConstRef =
550 Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
551 // Do not rename the reference if it is already scoped by the EnumDecl name.
552 if (EnumConstRef->hasQualifier() &&
Eric Liu28c30ce2017-02-02 19:46:12553 EnumConstRef->getQualifier()->getKind() ==
554 NestedNameSpecifier::SpecifierKind::TypeSpec &&
Eric Liu0325a772017-02-02 17:40:38555 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
556 return;
557 const auto *EnumConstDecl =
558 Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
559 assert(EnumConstDecl);
560 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
561 assert(Context && "Empty decl context.");
562 // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
563 // if it turns out to be an issue.
564 fixDeclRefExpr(Result, Context->getDeclContext(),
565 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
Eric Liuda22b3c2016-11-29 14:15:14566 } else if (const auto *FuncRef =
567 Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
Eric Liue3f35e42016-12-20 14:39:04568 // If this reference has been processed as a function call, we do not
569 // process it again.
570 if (ProcessedFuncRefs.count(FuncRef))
571 return;
572 ProcessedFuncRefs.insert(FuncRef);
Eric Liuda22b3c2016-11-29 14:15:14573 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
574 assert(Func);
575 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
576 assert(Context && "Empty decl context.");
577 fixDeclRefExpr(Result, Context->getDeclContext(),
578 llvm::cast<NamedDecl>(Func), FuncRef);
Eric Liu12068d82016-09-22 11:54:00579 } else {
Eric Liuda22b3c2016-11-29 14:15:14580 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19581 assert(Call != nullptr && "Expecting callback for CallExpr.");
Eric Liue3f35e42016-12-20 14:39:04582 const auto *CalleeFuncRef =
583 llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
584 ProcessedFuncRefs.insert(CalleeFuncRef);
Eric Liuda22b3c2016-11-29 14:15:14585 const FunctionDecl *Func = Call->getDirectCallee();
Eric Liu12068d82016-09-22 11:54:00586 assert(Func != nullptr);
Eric Liue3f35e42016-12-20 14:39:04587 // FIXME: ignore overloaded operators. This would miss cases where operators
588 // are called by qualified names (i.e. "ns::operator <"). Ignore such
589 // cases for now.
590 if (Func->isOverloadedOperator())
591 return;
Eric Liu12068d82016-09-22 11:54:00592 // Ignore out-of-line static methods since they will be handled by nested
593 // name specifiers.
594 if (Func->getCanonicalDecl()->getStorageClass() ==
Eric Liuda22b3c2016-11-29 14:15:14595 StorageClass::SC_Static &&
Eric Liu12068d82016-09-22 11:54:00596 Func->isOutOfLine())
597 return;
Eric Liuda22b3c2016-11-29 14:15:14598 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu12068d82016-09-22 11:54:00599 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14600 SourceRange CalleeRange = Call->getCallee()->getSourceRange();
Eric Liub9bf1b52016-11-08 22:44:17601 replaceQualifiedSymbolInDeclContext(
602 Result, Context->getDeclContext(), CalleeRange.getBegin(),
Eric Liu231c6552016-11-10 18:15:34603 CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
Eric Liu495b2112016-09-19 17:40:32604 }
605}
606
Eric Liu73f49fd2016-10-12 12:34:18607static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
608 const SourceManager &SM,
609 const LangOptions &LangOpts) {
610 std::unique_ptr<Lexer> Lex =
611 getLexerStartingFromLoc(NsDecl->getLocStart(), SM, LangOpts);
612 assert(Lex.get() &&
613 "Failed to create lexer from the beginning of namespace.");
614 if (!Lex.get())
615 return SourceLocation();
616 Token Tok;
617 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
618 }
619 return Tok.isNot(tok::TokenKind::l_brace)
620 ? SourceLocation()
621 : Tok.getEndLoc().getLocWithOffset(1);
622}
623
Eric Liu495b2112016-09-19 17:40:32624// Stores information about a moved namespace in `MoveNamespaces` and leaves
625// the actual movement to `onEndOfTranslationUnit()`.
626void ChangeNamespaceTool::moveOldNamespace(
627 const ast_matchers::MatchFinder::MatchResult &Result,
628 const NamespaceDecl *NsDecl) {
629 // If the namespace is empty, do nothing.
630 if (Decl::castToDeclContext(NsDecl)->decls_empty())
631 return;
632
Eric Liuee5104b2017-01-04 14:49:08633 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32634 // Get the range of the code in the old namespace.
Eric Liuee5104b2017-01-04 14:49:08635 SourceLocation Start =
636 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
Eric Liu73f49fd2016-10-12 12:34:18637 assert(Start.isValid() && "Can't find l_brace for namespace.");
Eric Liu495b2112016-09-19 17:40:32638 MoveNamespace MoveNs;
Eric Liuee5104b2017-01-04 14:49:08639 MoveNs.Offset = SM.getFileOffset(Start);
640 // The range of the moved namespace is from the location just past the left
641 // brace to the location right before the right brace.
642 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
Eric Liu495b2112016-09-19 17:40:32643
644 // Insert the new namespace after `DiffOldNamespace`. For example, if
645 // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
646 // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
647 // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
648 // in the above example.
Eric Liu6aa94162016-11-10 18:29:01649 // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
650 // namespace will be a nested namespace in the old namespace.
Eric Liu495b2112016-09-19 17:40:32651 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
Eric Liu6aa94162016-11-10 18:29:01652 SourceLocation InsertionLoc = Start;
653 if (OuterNs) {
Eric Liuee5104b2017-01-04 14:49:08654 SourceLocation LocAfterNs = getStartOfNextLine(
655 OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
Eric Liu6aa94162016-11-10 18:29:01656 assert(LocAfterNs.isValid() &&
657 "Failed to get location after DiffOldNamespace");
658 InsertionLoc = LocAfterNs;
659 }
Eric Liuee5104b2017-01-04 14:49:08660 MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
661 MoveNs.FID = SM.getFileID(Start);
Eric Liucc83c662016-09-19 17:58:59662 MoveNs.SourceMgr = Result.SourceManager;
Eric Liuee5104b2017-01-04 14:49:08663 MoveNamespaces[SM.getFilename(Start)].push_back(MoveNs);
Eric Liu495b2112016-09-19 17:40:32664}
665
666// Removes a class forward declaration from the code in the moved namespace and
667// creates an `InsertForwardDeclaration` to insert the forward declaration back
668// into the old namespace after moving code from the old namespace to the new
669// namespace.
670// For example, changing "a" to "x":
671// Old code:
672// namespace a {
673// class FWD;
674// class A { FWD *fwd; }
675// } // a
676// New code:
677// namespace a {
678// class FWD;
679// } // a
680// namespace x {
681// class A { a::FWD *fwd; }
682// } // x
683void ChangeNamespaceTool::moveClassForwardDeclaration(
684 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liu41552d62016-12-07 14:20:52685 const NamedDecl *FwdDecl) {
Eric Liu495b2112016-09-19 17:40:32686 SourceLocation Start = FwdDecl->getLocStart();
687 SourceLocation End = FwdDecl->getLocEnd();
Eric Liu41367152017-03-01 10:29:39688 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32689 SourceLocation AfterSemi = Lexer::findLocationAfterToken(
Eric Liu41367152017-03-01 10:29:39690 End, tok::semi, SM, Result.Context->getLangOpts(),
Eric Liu495b2112016-09-19 17:40:32691 /*SkipTrailingWhitespaceAndNewLine=*/true);
692 if (AfterSemi.isValid())
693 End = AfterSemi.getLocWithOffset(-1);
694 // Delete the forward declaration from the code to be moved.
Eric Liu41367152017-03-01 10:29:39695 addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32696 llvm::StringRef Code = Lexer::getSourceText(
Eric Liu41367152017-03-01 10:29:39697 CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
698 SM.getSpellingLoc(End)),
699 SM, Result.Context->getLangOpts());
Eric Liu495b2112016-09-19 17:40:32700 // Insert the forward declaration back into the old namespace after moving the
701 // code from old namespace to new namespace.
702 // Insertion information is stored in `InsertFwdDecls` and actual
703 // insertion will be performed in `onEndOfTranslationUnit`.
704 // Get the (old) namespace that contains the forward declaration.
705 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
706 // The namespace contains the forward declaration, so it must not be empty.
707 assert(!NsDecl->decls_empty());
Eric Liu41367152017-03-01 10:29:39708 const auto Insertion = createInsertion(
709 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
710 Code, SM);
Eric Liu495b2112016-09-19 17:40:32711 InsertForwardDeclaration InsertFwd;
712 InsertFwd.InsertionOffset = Insertion.getOffset();
713 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
714 InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
715}
716
Eric Liub9bf1b52016-11-08 22:44:17717// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
718// FromDecl with the shortest qualified name possible when the reference is in
719// `NewNamespace`.
Eric Liu495b2112016-09-19 17:40:32720void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
Eric Liub9bf1b52016-11-08 22:44:17721 const ast_matchers::MatchFinder::MatchResult &Result,
722 const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
723 const NamedDecl *FromDecl) {
724 const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
Eric Liu4fe99e12016-12-14 17:01:52725 if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
726 // This should not happen in usual unless the TypeLoc is in function type
727 // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
728 // `T` will be the translation unit. We simply use fully-qualified name
729 // here.
730 // Note that `FromDecl` must not be defined in the old namespace (according
731 // to `DeclMatcher`), so its fully-qualified name will not change after
732 // changing the namespace.
733 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
734 *Result.SourceManager, &FileToReplacements);
735 return;
736 }
Eric Liu231c6552016-11-10 18:15:34737 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
Eric Liu495b2112016-09-19 17:40:32738 // Calculate the name of the `NsDecl` after it is moved to new namespace.
739 std::string OldNs = NsDecl->getQualifiedNameAsString();
740 llvm::StringRef Postfix = OldNs;
741 bool Consumed = Postfix.consume_front(OldNamespace);
742 assert(Consumed && "Expect OldNS to start with OldNamespace.");
743 (void)Consumed;
744 const std::string NewNs = (NewNamespace + Postfix).str();
745
746 llvm::StringRef NestedName = Lexer::getSourceText(
747 CharSourceRange::getTokenRange(
748 Result.SourceManager->getSpellingLoc(Start),
749 Result.SourceManager->getSpellingLoc(End)),
750 *Result.SourceManager, Result.Context->getLangOpts());
Eric Liub9bf1b52016-11-08 22:44:17751 std::string FromDeclName = FromDecl->getQualifiedNameAsString();
Eric Liu7fccc992017-02-24 11:54:45752 for (llvm::Regex &RE : WhiteListedSymbolRegexes)
753 if (RE.match(FromDeclName))
754 return;
Eric Liu495b2112016-09-19 17:40:32755 std::string ReplaceName =
Eric Liub9bf1b52016-11-08 22:44:17756 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
757 // Checks if there is any using namespace declarations that can shorten the
758 // qualified name.
759 for (const auto *UsingNamespace : UsingNamespaceDecls) {
760 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
761 Start))
762 continue;
763 StringRef FromDeclNameRef = FromDeclName;
764 if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
765 ->getQualifiedNameAsString())) {
766 FromDeclNameRef = FromDeclNameRef.drop_front(2);
767 if (FromDeclNameRef.size() < ReplaceName.size())
768 ReplaceName = FromDeclNameRef;
769 }
770 }
Eric Liu180dac62016-12-23 10:47:09771 // Checks if there is any namespace alias declarations that can shorten the
772 // qualified name.
773 for (const auto *NamespaceAlias : NamespaceAliasDecls) {
774 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
775 Start))
776 continue;
777 StringRef FromDeclNameRef = FromDeclName;
778 if (FromDeclNameRef.consume_front(
779 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
780 "::")) {
781 std::string AliasName = NamespaceAlias->getNameAsString();
782 std::string AliasQualifiedName =
783 NamespaceAlias->getQualifiedNameAsString();
784 // We only consider namespace aliases define in the global namepspace or
785 // in namespaces that are directly visible from the reference, i.e.
786 // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
787 // but not visible in the new namespace is filtered out by
788 // "IsVisibleInNewNs" matcher.
789 if (AliasQualifiedName != AliasName) {
790 // The alias is defined in some namespace.
791 assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
792 llvm::StringRef AliasNs =
793 StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
794 if (!llvm::StringRef(OldNs).startswith(AliasNs))
795 continue;
796 }
797 std::string NameWithAliasNamespace =
798 (AliasName + "::" + FromDeclNameRef).str();
799 if (NameWithAliasNamespace.size() < ReplaceName.size())
800 ReplaceName = NameWithAliasNamespace;
801 }
802 }
Eric Liub9bf1b52016-11-08 22:44:17803 // Checks if there is any using shadow declarations that can shorten the
804 // qualified name.
805 bool Matched = false;
806 for (const UsingDecl *Using : UsingDecls) {
807 if (Matched)
808 break;
809 if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
810 for (const auto *UsingShadow : Using->shadows()) {
811 const auto *TargetDecl = UsingShadow->getTargetDecl();
Eric Liuae7de712017-02-02 15:29:54812 if (TargetDecl->getQualifiedNameAsString() ==
813 FromDecl->getQualifiedNameAsString()) {
Eric Liub9bf1b52016-11-08 22:44:17814 ReplaceName = FromDecl->getNameAsString();
815 Matched = true;
816 break;
817 }
818 }
819 }
820 }
Eric Liu495b2112016-09-19 17:40:32821 // If the new nested name in the new namespace is the same as it was in the
822 // old namespace, we don't create replacement.
Eric Liu91229162017-01-26 16:31:32823 if (NestedName == ReplaceName ||
824 (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
Eric Liu495b2112016-09-19 17:40:32825 return;
Eric Liu97f87ad2016-12-07 20:08:02826 // If the reference need to be fully-qualified, add a leading "::" unless
827 // NewNamespace is the global namespace.
828 if (ReplaceName == FromDeclName && !NewNamespace.empty())
829 ReplaceName = "::" + ReplaceName;
Eric Liu4fe99e12016-12-14 17:01:52830 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
831 &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32832}
833
834// Replace the [Start, End] of `Type` with the shortest qualified name when the
835// `Type` is in `NewNamespace`.
836void ChangeNamespaceTool::fixTypeLoc(
837 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
838 SourceLocation End, TypeLoc Type) {
839 // FIXME: do not rename template parameter.
840 if (Start.isInvalid() || End.isInvalid())
841 return;
Eric Liuff51f012016-11-16 16:54:53842 // Types of CXXCtorInitializers do not need to be fixed.
843 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
844 return;
Eric Liu284b97c2017-03-17 14:05:39845 if (isTemplateParameter(Type))
846 return;
Eric Liu495b2112016-09-19 17:40:32847 // The declaration which this TypeLoc refers to.
848 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
849 // `hasDeclaration` gives underlying declaration, but if the type is
850 // a typedef type, we need to use the typedef type instead.
Eric Liu26cf68a2016-12-15 10:42:35851 auto IsInMovedNs = [&](const NamedDecl *D) {
852 if (!llvm::StringRef(D->getQualifiedNameAsString())
853 .startswith(OldNamespace + "::"))
854 return false;
855 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getLocStart());
856 if (ExpansionLoc.isInvalid())
857 return false;
858 llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
859 return FilePatternRE.match(Filename);
860 };
861 // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
862 // `Type` is an alias type, we make `FromDecl` the type alias declaration.
863 // Also, don't fix the \p Type if it refers to a type alias decl in the moved
864 // namespace since the alias decl will be moved along with the type reference.
Eric Liu32158862016-11-14 19:37:55865 if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
Eric Liu495b2112016-09-19 17:40:32866 FromDecl = Typedef->getDecl();
Eric Liu32158862016-11-14 19:37:55867 if (IsInMovedNs(FromDecl))
868 return;
Eric Liu26cf68a2016-12-15 10:42:35869 } else if (auto *TemplateType =
870 Type.getType()->getAs<TemplateSpecializationType>()) {
871 if (TemplateType->isTypeAlias()) {
872 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
873 if (IsInMovedNs(FromDecl))
874 return;
875 }
Eric Liu32158862016-11-14 19:37:55876 }
Piotr Padlewski08124b12016-12-14 15:29:23877 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu495b2112016-09-19 17:40:32878 assert(DeclCtx && "Empty decl context.");
Eric Liub9bf1b52016-11-08 22:44:17879 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
880 End, FromDecl);
Eric Liu495b2112016-09-19 17:40:32881}
882
Eric Liu68765a82016-09-21 15:06:12883void ChangeNamespaceTool::fixUsingShadowDecl(
884 const ast_matchers::MatchFinder::MatchResult &Result,
885 const UsingDecl *UsingDeclaration) {
886 SourceLocation Start = UsingDeclaration->getLocStart();
887 SourceLocation End = UsingDeclaration->getLocEnd();
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19888 if (Start.isInvalid() || End.isInvalid())
889 return;
Eric Liu68765a82016-09-21 15:06:12890
891 assert(UsingDeclaration->shadow_size() > 0);
892 // FIXME: it might not be always accurate to use the first using-decl.
893 const NamedDecl *TargetDecl =
894 UsingDeclaration->shadow_begin()->getTargetDecl();
895 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
896 // FIXME: check if target_decl_name is in moved ns, which doesn't make much
897 // sense. If this happens, we need to use name with the new namespace.
898 // Use fully qualified name in UsingDecl for now.
Eric Liu4fe99e12016-12-14 17:01:52899 addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
900 *Result.SourceManager, &FileToReplacements);
Eric Liu68765a82016-09-21 15:06:12901}
902
Eric Liuda22b3c2016-11-29 14:15:14903void ChangeNamespaceTool::fixDeclRefExpr(
904 const ast_matchers::MatchFinder::MatchResult &Result,
905 const DeclContext *UseContext, const NamedDecl *From,
906 const DeclRefExpr *Ref) {
907 SourceRange RefRange = Ref->getSourceRange();
908 replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
909 RefRange.getEnd(), From);
910}
911
Eric Liu495b2112016-09-19 17:40:32912void ChangeNamespaceTool::onEndOfTranslationUnit() {
913 // Move namespace blocks and insert forward declaration to old namespace.
914 for (const auto &FileAndNsMoves : MoveNamespaces) {
915 auto &NsMoves = FileAndNsMoves.second;
916 if (NsMoves.empty())
917 continue;
918 const std::string &FilePath = FileAndNsMoves.first;
919 auto &Replaces = FileToReplacements[FilePath];
Eric Liucc83c662016-09-19 17:58:59920 auto &SM = *NsMoves.begin()->SourceMgr;
921 llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
Eric Liu495b2112016-09-19 17:40:32922 auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
923 if (!ChangedCode) {
924 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
925 continue;
926 }
927 // Replacements on the changed code for moving namespaces and inserting
928 // forward declarations to old namespaces.
929 tooling::Replacements NewReplacements;
930 // Cut the changed code from the old namespace and paste the code in the new
931 // namespace.
932 for (const auto &NsMove : NsMoves) {
933 // Calculate the range of the old namespace block in the changed
934 // code.
935 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
936 const unsigned NewLength =
937 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
938 NewOffset;
939 tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
940 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
941 std::string MovedCodeWrappedInNewNs =
942 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
943 // Calculate the new offset at which the code will be inserted in the
944 // changed code.
945 unsigned NewInsertionOffset =
946 Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
947 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
948 MovedCodeWrappedInNewNs);
949 addOrMergeReplacement(Deletion, &NewReplacements);
950 addOrMergeReplacement(Insertion, &NewReplacements);
951 }
952 // After moving namespaces, insert forward declarations back to old
953 // namespaces.
954 const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
955 for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
956 unsigned NewInsertionOffset =
957 Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
958 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
959 FwdDeclInsertion.ForwardDeclText);
960 addOrMergeReplacement(Insertion, &NewReplacements);
961 }
962 // Add replacements referring to the changed code to existing replacements,
963 // which refers to the original code.
964 Replaces = Replaces.merge(NewReplacements);
Antonio Maiorano0d7d9c22017-01-17 00:13:32965 auto Style = format::getStyle("file", FilePath, FallbackStyle);
966 if (!Style) {
967 llvm::errs() << llvm::toString(Style.takeError()) << "\n";
968 continue;
969 }
Eric Liu495b2112016-09-19 17:40:32970 // Clean up old namespaces if there is nothing in it after moving.
971 auto CleanReplacements =
Antonio Maiorano0d7d9c22017-01-17 00:13:32972 format::cleanupAroundReplacements(Code, Replaces, *Style);
Eric Liu495b2112016-09-19 17:40:32973 if (!CleanReplacements) {
974 llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
975 continue;
976 }
977 FileToReplacements[FilePath] = *CleanReplacements;
978 }
Eric Liuc265b022016-12-01 17:25:55979
980 // Make sure we don't generate replacements for files that do not match
981 // FilePattern.
982 for (auto &Entry : FileToReplacements)
983 if (!FilePatternRE.match(Entry.first))
984 Entry.second.clear();
Eric Liu495b2112016-09-19 17:40:32985}
986
987} // namespace change_namespace
988} // namespace clang