blob: 7a7103181f506954d716274a58329267508dc9f0 [file] [log] [blame]
Eric Liu495b2112016-09-19 17:40:32 +00001//===-- 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"
Eric Liuc6c894b2018-10-22 12:48:49 +000010#include "clang/AST/ASTContext.h"
Eric Liu495b2112016-09-19 17:40:32 +000011#include "clang/Format/Format.h"
12#include "clang/Lex/Lexer.h"
Eric Liuc6c894b2018-10-22 12:48:49 +000013#include "llvm/Support/Casting.h"
Eric Liuff51f012016-11-16 16:54:53 +000014#include "llvm/Support/ErrorHandling.h"
Eric Liu495b2112016-09-19 17:40:32 +000015
16using namespace clang::ast_matchers;
17
18namespace clang {
19namespace change_namespace {
20
21namespace {
22
23inline std::string
24joinNamespaces(const llvm::SmallVectorImpl<StringRef> &Namespaces) {
25 if (Namespaces.empty())
26 return "";
27 std::string Result = Namespaces.front();
28 for (auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
29 Result += ("::" + *I).str();
30 return Result;
31}
32
Eric Liu8bc24162017-03-21 12:41:59 +000033// Given "a::b::c", returns {"a", "b", "c"}.
34llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
35 llvm::SmallVector<llvm::StringRef, 4> Splitted;
36 Name.split(Splitted, "::", /*MaxSplit=*/-1,
37 /*KeepEmpty=*/false);
38 return Splitted;
39}
40
Eric Liu495b2112016-09-19 17:40:32 +000041SourceLocation startLocationForType(TypeLoc TLoc) {
42 // For elaborated types (e.g. `struct a::A`) we want the portion after the
43 // `struct` but including the namespace qualifier, `a::`.
44 if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
45 NestedNameSpecifierLoc NestedNameSpecifier =
46 TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
47 if (NestedNameSpecifier.getNestedNameSpecifier())
48 return NestedNameSpecifier.getBeginLoc();
49 TLoc = TLoc.getNextTypeLoc();
50 }
Stephen Kelly43465bf2018-08-09 22:42:26 +000051 return TLoc.getBeginLoc();
Eric Liu495b2112016-09-19 17:40:32 +000052}
53
Eric Liuc265b022016-12-01 17:25:55 +000054SourceLocation endLocationForType(TypeLoc TLoc) {
Eric Liu495b2112016-09-19 17:40:32 +000055 // Dig past any namespace or keyword qualifications.
56 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
57 TLoc.getTypeLocClass() == TypeLoc::Qualified)
58 TLoc = TLoc.getNextTypeLoc();
59
60 // The location for template specializations (e.g. Foo<int>) includes the
61 // templated types in its location range. We want to restrict this to just
62 // before the `<` character.
63 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
64 return TLoc.castAs<TemplateSpecializationTypeLoc>()
65 .getLAngleLoc()
66 .getLocWithOffset(-1);
67 return TLoc.getEndLoc();
68}
69
70// Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
Eric Liu6aa94162016-11-10 18:29:01 +000071// If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
72// is empty, nullptr is returned.
Eric Liu495b2112016-09-19 17:40:32 +000073// For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
74// the NamespaceDecl of namespace "a" will be returned.
75const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
76 llvm::StringRef PartialNsName) {
Eric Liu6aa94162016-11-10 18:29:01 +000077 if (!InnerNs || PartialNsName.empty())
78 return nullptr;
Eric Liu495b2112016-09-19 17:40:32 +000079 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
80 const auto *CurrentNs = InnerNs;
Eric Liu8bc24162017-03-21 12:41:59 +000081 auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
Eric Liu495b2112016-09-19 17:40:32 +000082 while (!PartialNsNameSplitted.empty()) {
83 // Get the inner-most namespace in CurrentContext.
84 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
85 CurrentContext = CurrentContext->getParent();
86 if (!CurrentContext)
87 return nullptr;
88 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
89 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
90 return nullptr;
91 PartialNsNameSplitted.pop_back();
92 CurrentContext = CurrentContext->getParent();
93 }
94 return CurrentNs;
95}
96
Eric Liu73f49fd2016-10-12 12:34:18 +000097static std::unique_ptr<Lexer>
98getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
99 const LangOptions &LangOpts) {
Eric Liu495b2112016-09-19 17:40:32 +0000100 if (Loc.isMacroID() &&
101 !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
Eric Liu73f49fd2016-10-12 12:34:18 +0000102 return nullptr;
Eric Liu495b2112016-09-19 17:40:32 +0000103 // Break down the source location.
104 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
105 // Try to load the file buffer.
106 bool InvalidTemp = false;
107 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
108 if (InvalidTemp)
Eric Liu73f49fd2016-10-12 12:34:18 +0000109 return nullptr;
Eric Liu495b2112016-09-19 17:40:32 +0000110
111 const char *TokBegin = File.data() + LocInfo.second;
112 // Lex from the start of the given location.
Eric Liu73f49fd2016-10-12 12:34:18 +0000113 return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
114 LangOpts, File.begin(), TokBegin, File.end());
115}
Eric Liu495b2112016-09-19 17:40:32 +0000116
Eric Liu73f49fd2016-10-12 12:34:18 +0000117// FIXME: get rid of this helper function if this is supported in clang-refactor
118// library.
119static SourceLocation getStartOfNextLine(SourceLocation Loc,
120 const SourceManager &SM,
121 const LangOptions &LangOpts) {
122 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
123 if (!Lex.get())
124 return SourceLocation();
Eric Liu495b2112016-09-19 17:40:32 +0000125 llvm::SmallVector<char, 16> Line;
126 // FIXME: this is a bit hacky to get ReadToEndOfLine work.
Eric Liu73f49fd2016-10-12 12:34:18 +0000127 Lex->setParsingPreprocessorDirective(true);
128 Lex->ReadToEndOfLine(&Line);
Haojian Wuef8a6dc2016-10-04 10:35:53 +0000129 auto End = Loc.getLocWithOffset(Line.size());
Eric Liu73f49fd2016-10-12 12:34:18 +0000130 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
131 ? End
132 : End.getLocWithOffset(1);
Eric Liu495b2112016-09-19 17:40:32 +0000133}
134
135// Returns `R` with new range that refers to code after `Replaces` being
136// applied.
137tooling::Replacement
138getReplacementInChangedCode(const tooling::Replacements &Replaces,
139 const tooling::Replacement &R) {
140 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
141 unsigned NewEnd =
142 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
143 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
144 R.getReplacementText());
145}
146
147// Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
148// applying all existing Replaces first if there is conflict.
149void addOrMergeReplacement(const tooling::Replacement &R,
150 tooling::Replacements *Replaces) {
151 auto Err = Replaces->add(R);
152 if (Err) {
153 llvm::consumeError(std::move(Err));
154 auto Replace = getReplacementInChangedCode(*Replaces, R);
155 *Replaces = Replaces->merge(tooling::Replacements(Replace));
156 }
157}
158
159tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
160 llvm::StringRef ReplacementText,
161 const SourceManager &SM) {
162 if (!Start.isValid() || !End.isValid()) {
163 llvm::errs() << "start or end location were invalid\n";
164 return tooling::Replacement();
165 }
166 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
167 llvm::errs()
168 << "start or end location were in different macro expansions\n";
169 return tooling::Replacement();
170 }
171 Start = SM.getSpellingLoc(Start);
172 End = SM.getSpellingLoc(End);
173 if (SM.getFileID(Start) != SM.getFileID(End)) {
174 llvm::errs() << "start or end location were in different files\n";
175 return tooling::Replacement();
176 }
177 return tooling::Replacement(
178 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
179 SM.getSpellingLoc(End)),
180 ReplacementText);
181}
182
Eric Liu4fe99e12016-12-14 17:01:52 +0000183void addReplacementOrDie(
184 SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
185 const SourceManager &SM,
186 std::map<std::string, tooling::Replacements> *FileToReplacements) {
187 const auto R = createReplacement(Start, End, ReplacementText, SM);
188 auto Err = (*FileToReplacements)[R.getFilePath()].add(R);
189 if (Err)
190 llvm_unreachable(llvm::toString(std::move(Err)).c_str());
191}
192
Eric Liu495b2112016-09-19 17:40:32 +0000193tooling::Replacement createInsertion(SourceLocation Loc,
194 llvm::StringRef InsertText,
195 const SourceManager &SM) {
196 if (Loc.isInvalid()) {
197 llvm::errs() << "insert Location is invalid.\n";
198 return tooling::Replacement();
199 }
200 Loc = SM.getSpellingLoc(Loc);
201 return tooling::Replacement(SM, Loc, 0, InsertText);
202}
203
204// Returns the shortest qualified name for declaration `DeclName` in the
205// namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
206// is "a::c::d", then "b::X" will be returned.
Eric Liubc715502017-01-26 15:08:44 +0000207// Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
208// "::b::X" instead of "b::X" since there will be a name conflict otherwise.
Eric Liu447164d2016-10-05 15:52:39 +0000209// \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
210// \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
211// will have empty name.
Eric Liu495b2112016-09-19 17:40:32 +0000212std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
213 llvm::StringRef NsName) {
Eric Liu447164d2016-10-05 15:52:39 +0000214 DeclName = DeclName.ltrim(':');
215 NsName = NsName.ltrim(':');
Eric Liu447164d2016-10-05 15:52:39 +0000216 if (DeclName.find(':') == llvm::StringRef::npos)
Eric Liub9bf1b52016-11-08 22:44:17 +0000217 return DeclName;
Eric Liu447164d2016-10-05 15:52:39 +0000218
Eric Liu8bc24162017-03-21 12:41:59 +0000219 auto NsNameSplitted = splitSymbolName(NsName);
220 auto DeclNsSplitted = splitSymbolName(DeclName);
Eric Liubc715502017-01-26 15:08:44 +0000221 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
222 // If the Decl is in global namespace, there is no need to shorten it.
223 if (DeclNsSplitted.empty())
224 return UnqualifiedDeclName;
225 // If NsName is the global namespace, we can simply use the DeclName sans
226 // leading "::".
227 if (NsNameSplitted.empty())
228 return DeclName;
229
230 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
231 // The DeclName must be fully-qualified, but we still need to decide if a
232 // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
233 // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
234 // to avoid conflict.
235 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
236 return ("::" + DeclName).str();
237 return DeclName;
Eric Liu495b2112016-09-19 17:40:32 +0000238 }
Eric Liubc715502017-01-26 15:08:44 +0000239 // Since there is already an overlap namespace, we know that `DeclName` can be
240 // shortened, so we reduce the longest common prefix.
241 auto DeclI = DeclNsSplitted.begin();
242 auto DeclE = DeclNsSplitted.end();
243 auto NsI = NsNameSplitted.begin();
244 auto NsE = NsNameSplitted.end();
245 for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
246 }
247 return (DeclI == DeclE)
248 ? UnqualifiedDeclName.str()
249 : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
250 .str();
Eric Liu495b2112016-09-19 17:40:32 +0000251}
252
253std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
254 if (Code.back() != '\n')
255 Code += "\n";
Eric Liu8bc24162017-03-21 12:41:59 +0000256 auto NsSplitted = splitSymbolName(NestedNs);
Eric Liu495b2112016-09-19 17:40:32 +0000257 while (!NsSplitted.empty()) {
258 // FIXME: consider code style for comments.
259 Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
260 "} // namespace " + NsSplitted.back() + "\n")
261 .str();
262 NsSplitted.pop_back();
263 }
264 return Code;
265}
266
Eric Liub9bf1b52016-11-08 22:44:17 +0000267// Returns true if \p D is a nested DeclContext in \p Context
268bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
269 while (D) {
270 if (D == Context)
271 return true;
272 D = D->getParent();
273 }
274 return false;
275}
276
277// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
278bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
279 const DeclContext *DeclCtx, SourceLocation Loc) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000280 SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
Eric Liub9bf1b52016-11-08 22:44:17 +0000281 Loc = SM.getSpellingLoc(Loc);
282 return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
283 (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
284 isNestedDeclContext(DeclCtx, D->getDeclContext()));
285}
286
Eric Liu8bc24162017-03-21 12:41:59 +0000287// Given a qualified symbol name, returns true if the symbol will be
Eric Liuc6c894b2018-10-22 12:48:49 +0000288// incorrectly qualified without leading "::". For example, a symbol
289// "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
290// "util::X" in namespace "na" can potentially conflict with "na::util" (if this
291// exists).
292bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
Eric Liu8bc24162017-03-21 12:41:59 +0000293 llvm::StringRef Namespace) {
294 auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
295 assert(!SymbolSplitted.empty());
296 SymbolSplitted.pop_back(); // We are only interested in namespaces.
297
Eric Liuc6c894b2018-10-22 12:48:49 +0000298 if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
299 auto SymbolTopNs = SymbolSplitted.front();
Eric Liu8bc24162017-03-21 12:41:59 +0000300 auto NsSplitted = splitSymbolName(Namespace.trim(":"));
301 assert(!NsSplitted.empty());
Eric Liuc6c894b2018-10-22 12:48:49 +0000302
303 auto LookupDecl = [&AST](const Decl &Scope,
304 llvm::StringRef Name) -> const NamedDecl * {
305 const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
306 if (!DC)
307 return nullptr;
308 auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
309 if (LookupRes.empty())
310 return nullptr;
311 return LookupRes.front();
312 };
313 // We do not check the outermost namespace since it would not be a
314 // conflict if it equals to the symbol's outermost namespace and the
315 // symbol name would have been shortened.
316 const NamedDecl *Scope =
317 LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
Eric Liu8bc24162017-03-21 12:41:59 +0000318 for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
Eric Liuc6c894b2018-10-22 12:48:49 +0000319 if (*I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
Eric Liu8bc24162017-03-21 12:41:59 +0000320 return true;
Eric Liuc6c894b2018-10-22 12:48:49 +0000321 // Handles "::util" and "::nx::util" conflicts.
322 if (Scope) {
323 if (LookupDecl(*Scope, SymbolTopNs))
324 return true;
325 Scope = LookupDecl(*Scope, *I);
326 }
Eric Liu8bc24162017-03-21 12:41:59 +0000327 }
Eric Liuc6c894b2018-10-22 12:48:49 +0000328 if (Scope && LookupDecl(*Scope, SymbolTopNs))
329 return true;
Eric Liu8bc24162017-03-21 12:41:59 +0000330 }
331 return false;
332}
333
Eric Liu0325a772017-02-02 17:40:38 +0000334AST_MATCHER(EnumDecl, isScoped) {
335 return Node.isScoped();
336}
337
Eric Liu284b97c2017-03-17 14:05:39 +0000338bool isTemplateParameter(TypeLoc Type) {
339 while (!Type.isNull()) {
340 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
341 return true;
342 Type = Type.getNextTypeLoc();
343 }
344 return false;
345}
346
Eric Liu495b2112016-09-19 17:40:32 +0000347} // anonymous namespace
348
349ChangeNamespaceTool::ChangeNamespaceTool(
350 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
Eric Liu7fccc992017-02-24 11:54:45 +0000351 llvm::ArrayRef<std::string> WhiteListedSymbolPatterns,
Eric Liu495b2112016-09-19 17:40:32 +0000352 std::map<std::string, tooling::Replacements> *FileToReplacements,
353 llvm::StringRef FallbackStyle)
354 : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
355 OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
Eric Liuc265b022016-12-01 17:25:55 +0000356 FilePattern(FilePattern), FilePatternRE(FilePattern) {
Eric Liu495b2112016-09-19 17:40:32 +0000357 FileToReplacements->clear();
Eric Liu8bc24162017-03-21 12:41:59 +0000358 auto OldNsSplitted = splitSymbolName(OldNamespace);
359 auto NewNsSplitted = splitSymbolName(NewNamespace);
Eric Liu495b2112016-09-19 17:40:32 +0000360 // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
361 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
362 OldNsSplitted.front() == NewNsSplitted.front()) {
363 OldNsSplitted.erase(OldNsSplitted.begin());
364 NewNsSplitted.erase(NewNsSplitted.begin());
365 }
366 DiffOldNamespace = joinNamespaces(OldNsSplitted);
367 DiffNewNamespace = joinNamespaces(NewNsSplitted);
Eric Liu7fccc992017-02-24 11:54:45 +0000368
369 for (const auto &Pattern : WhiteListedSymbolPatterns)
370 WhiteListedSymbolRegexes.emplace_back(Pattern);
Eric Liu495b2112016-09-19 17:40:32 +0000371}
372
Eric Liu495b2112016-09-19 17:40:32 +0000373void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
Eric Liu495b2112016-09-19 17:40:32 +0000374 std::string FullOldNs = "::" + OldNamespace;
Eric Liub9bf1b52016-11-08 22:44:17 +0000375 // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
376 // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
377 // be "a::b". Declarations in this namespace will not be visible in the new
378 // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
379 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
Eric Liu2dd0e1b2016-12-05 11:17:04 +0000380 llvm::StringRef(DiffOldNamespace)
381 .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
382 /*KeepEmpty=*/false);
Eric Liub9bf1b52016-11-08 22:44:17 +0000383 std::string Prefix = "-";
384 if (!DiffOldNsSplitted.empty())
385 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
386 DiffOldNsSplitted.front())
387 .str();
388 auto IsInMovedNs =
389 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
390 isExpansionInFileMatching(FilePattern));
391 auto IsVisibleInNewNs = anyOf(
392 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
393 // Match using declarations.
394 Finder->addMatcher(
395 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
396 .bind("using"),
397 this);
398 // Match using namespace declarations.
399 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
400 IsVisibleInNewNs)
401 .bind("using_namespace"),
402 this);
Eric Liu180dac62016-12-23 10:47:09 +0000403 // Match namespace alias declarations.
404 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
405 IsVisibleInNewNs)
406 .bind("namespace_alias"),
407 this);
Eric Liub9bf1b52016-11-08 22:44:17 +0000408
409 // Match old namespace blocks.
Eric Liu495b2112016-09-19 17:40:32 +0000410 Finder->addMatcher(
411 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
412 .bind("old_ns"),
413 this);
414
Eric Liu41552d62016-12-07 14:20:52 +0000415 // Match class forward-declarations in the old namespace.
416 // Note that forward-declarations in classes are not matched.
417 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
418 IsInMovedNs, hasParent(namespaceDecl()))
419 .bind("class_fwd_decl"),
420 this);
421
422 // Match template class forward-declarations in the old namespace.
Eric Liu495b2112016-09-19 17:40:32 +0000423 Finder->addMatcher(
Eric Liu41552d62016-12-07 14:20:52 +0000424 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
425 IsInMovedNs, hasParent(namespaceDecl()))
426 .bind("template_class_fwd_decl"),
Eric Liu495b2112016-09-19 17:40:32 +0000427 this);
428
429 // Match references to types that are not defined in the old namespace.
430 // Forward-declarations in the old namespace are also matched since they will
431 // be moved back to the old namespace.
432 auto DeclMatcher = namedDecl(
433 hasAncestor(namespaceDecl()),
434 unless(anyOf(
Eric Liu912d0392016-09-27 12:54:48 +0000435 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
Eric Liu495b2112016-09-19 17:40:32 +0000436 hasAncestor(cxxRecordDecl()),
437 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
Eric Liu912d0392016-09-27 12:54:48 +0000438
Eric Liu8685c762016-12-07 17:04:07 +0000439 // Using shadow declarations in classes always refers to base class, which
440 // does not need to be qualified since it can be inferred from inheritance.
441 // Note that this does not match using alias declarations.
442 auto UsingShadowDeclInClass =
443 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
444
Eric Liu495b2112016-09-19 17:40:32 +0000445 // Match TypeLocs on the declaration. Carefully match only the outermost
Eric Liu8393cb02016-10-31 08:28:29 +0000446 // TypeLoc and template specialization arguments (which are not outermost)
447 // that are directly linked to types matching `DeclMatcher`. Nested name
448 // specifier locs are handled separately below.
Eric Liu495b2112016-09-19 17:40:32 +0000449 Finder->addMatcher(
450 typeLoc(IsInMovedNs,
451 loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
Eric Liu8393cb02016-10-31 08:28:29 +0000452 unless(anyOf(hasParent(typeLoc(loc(qualType(
Alexander Kornienko976e0c02018-11-25 02:41:01 +0000453 hasDeclaration(DeclMatcher),
454 unless(templateSpecializationType()))))),
Eric Liu8685c762016-12-07 17:04:07 +0000455 hasParent(nestedNameSpecifierLoc()),
456 hasAncestor(isImplicit()),
Eric Liub583a7e2017-10-16 08:20:10 +0000457 hasAncestor(UsingShadowDeclInClass),
458 hasAncestor(functionDecl(isDefaulted())))),
Eric Liu495b2112016-09-19 17:40:32 +0000459 hasAncestor(decl().bind("dc")))
460 .bind("type"),
461 this);
Eric Liu912d0392016-09-27 12:54:48 +0000462
Eric Liu68765a82016-09-21 15:06:12 +0000463 // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
464 // special case it.
Eric Liu8685c762016-12-07 17:04:07 +0000465 // Since using declarations inside classes must have the base class in the
466 // nested name specifier, we leave it to the nested name specifier matcher.
467 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
468 unless(UsingShadowDeclInClass))
Eric Liub9bf1b52016-11-08 22:44:17 +0000469 .bind("using_with_shadow"),
470 this);
Eric Liu912d0392016-09-27 12:54:48 +0000471
Eric Liuff51f012016-11-16 16:54:53 +0000472 // Handle types in nested name specifier. Specifiers that are in a TypeLoc
473 // matched above are not matched, e.g. "A::" in "A::A" is not matched since
474 // "A::A" would have already been fixed.
Eric Liu8685c762016-12-07 17:04:07 +0000475 Finder->addMatcher(
476 nestedNameSpecifierLoc(
477 hasAncestor(decl(IsInMovedNs).bind("dc")),
478 loc(nestedNameSpecifier(
479 specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
480 unless(anyOf(hasAncestor(isImplicit()),
481 hasAncestor(UsingShadowDeclInClass),
Eric Liub583a7e2017-10-16 08:20:10 +0000482 hasAncestor(functionDecl(isDefaulted())),
Eric Liu8685c762016-12-07 17:04:07 +0000483 hasAncestor(typeLoc(loc(qualType(hasDeclaration(
484 decl(equalsBoundNode("from_decl"))))))))))
485 .bind("nested_specifier_loc"),
486 this);
Eric Liu12068d82016-09-22 11:54:00 +0000487
Eric Liuff51f012016-11-16 16:54:53 +0000488 // Matches base class initializers in constructors. TypeLocs of base class
489 // initializers do not need to be fixed. For example,
490 // class X : public a::b::Y {
491 // public:
492 // X() : Y::Y() {} // Y::Y do not need namespace specifier.
493 // };
494 Finder->addMatcher(
495 cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
496
Eric Liu12068d82016-09-22 11:54:00 +0000497 // Handle function.
Eric Liu912d0392016-09-27 12:54:48 +0000498 // Only handle functions that are defined in a namespace excluding member
499 // function, static methods (qualified by nested specifier), and functions
500 // defined in the global namespace.
Eric Liu12068d82016-09-22 11:54:00 +0000501 // Note that the matcher does not exclude calls to out-of-line static method
502 // definitions, so we need to exclude them in the callback handler.
Eric Liu912d0392016-09-27 12:54:48 +0000503 auto FuncMatcher =
504 functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
505 hasAncestor(namespaceDecl(isAnonymous())),
506 hasAncestor(cxxRecordDecl()))),
507 hasParent(namespaceDecl()));
Alexander Kornienko976e0c02018-11-25 02:41:01 +0000508 Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
509 unless(hasAncestor(isImplicit())),
510 anyOf(callExpr(callee(FuncMatcher)).bind("call"),
511 declRefExpr(to(FuncMatcher.bind("func_decl")))
512 .bind("func_ref"))),
513 this);
Eric Liu159f0132016-09-30 04:32:39 +0000514
515 auto GlobalVarMatcher = varDecl(
516 hasGlobalStorage(), hasParent(namespaceDecl()),
517 unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
518 Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
519 to(GlobalVarMatcher.bind("var_decl")))
520 .bind("var_ref"),
521 this);
Eric Liu0325a772017-02-02 17:40:38 +0000522
523 // Handle unscoped enum constant.
524 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
525 hasParent(namespaceDecl()),
526 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
527 hasAncestor(namespaceDecl(isAnonymous())))))));
528 Finder->addMatcher(
529 declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
530 to(UnscopedEnumMatcher.bind("enum_const_decl")))
531 .bind("enum_const_ref"),
532 this);
Eric Liu495b2112016-09-19 17:40:32 +0000533}
534
535void ChangeNamespaceTool::run(
536 const ast_matchers::MatchFinder::MatchResult &Result) {
Eric Liub9bf1b52016-11-08 22:44:17 +0000537 if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
538 UsingDecls.insert(Using);
539 } else if (const auto *UsingNamespace =
540 Result.Nodes.getNodeAs<UsingDirectiveDecl>(
541 "using_namespace")) {
542 UsingNamespaceDecls.insert(UsingNamespace);
Eric Liu180dac62016-12-23 10:47:09 +0000543 } else if (const auto *NamespaceAlias =
544 Result.Nodes.getNodeAs<NamespaceAliasDecl>(
545 "namespace_alias")) {
546 NamespaceAliasDecls.insert(NamespaceAlias);
Eric Liub9bf1b52016-11-08 22:44:17 +0000547 } else if (const auto *NsDecl =
548 Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
Eric Liu495b2112016-09-19 17:40:32 +0000549 moveOldNamespace(Result, NsDecl);
550 } else if (const auto *FwdDecl =
Eric Liu41552d62016-12-07 14:20:52 +0000551 Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
552 moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
553 } else if (const auto *TemplateFwdDecl =
554 Result.Nodes.getNodeAs<ClassTemplateDecl>(
555 "template_class_fwd_decl")) {
556 moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
Eric Liub9bf1b52016-11-08 22:44:17 +0000557 } else if (const auto *UsingWithShadow =
558 Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
559 fixUsingShadowDecl(Result, UsingWithShadow);
Eric Liu68765a82016-09-21 15:06:12 +0000560 } else if (const auto *Specifier =
561 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
562 "nested_specifier_loc")) {
563 SourceLocation Start = Specifier->getBeginLoc();
Eric Liuc265b022016-12-01 17:25:55 +0000564 SourceLocation End = endLocationForType(Specifier->getTypeLoc());
Eric Liu68765a82016-09-21 15:06:12 +0000565 fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
Eric Liuff51f012016-11-16 16:54:53 +0000566 } else if (const auto *BaseInitializer =
567 Result.Nodes.getNodeAs<CXXCtorInitializer>(
568 "base_initializer")) {
569 BaseCtorInitializerTypeLocs.push_back(
570 BaseInitializer->getTypeSourceInfo()->getTypeLoc());
Eric Liu12068d82016-09-22 11:54:00 +0000571 } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
Eric Liu26cf68a2016-12-15 10:42:35 +0000572 // This avoids fixing types with record types as qualifier, which is not
573 // filtered by matchers in some cases, e.g. the type is templated. We should
574 // handle the record type qualifier instead.
Eric Liu0c0aea02016-12-15 13:02:41 +0000575 TypeLoc Loc = *TLoc;
576 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
577 Loc = Loc.getNextTypeLoc();
578 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
Eric Liu26cf68a2016-12-15 10:42:35 +0000579 NestedNameSpecifierLoc NestedNameSpecifier =
Eric Liu0c0aea02016-12-15 13:02:41 +0000580 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
Eric Liu5a6d57c2017-12-08 10:06:16 +0000581 // This happens for friend declaration of a base class with injected class
582 // name.
583 if (!NestedNameSpecifier.getNestedNameSpecifier())
584 return;
Eric Liu26cf68a2016-12-15 10:42:35 +0000585 const Type *SpecifierType =
586 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
587 if (SpecifierType && SpecifierType->isRecordType())
588 return;
589 }
Eric Liu0c0aea02016-12-15 13:02:41 +0000590 fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +0000591 } else if (const auto *VarRef =
592 Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
Eric Liu159f0132016-09-30 04:32:39 +0000593 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
594 assert(Var);
595 if (Var->getCanonicalDecl()->isStaticDataMember())
596 return;
Eric Liuda22b3c2016-11-29 14:15:14 +0000597 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu159f0132016-09-30 04:32:39 +0000598 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14 +0000599 fixDeclRefExpr(Result, Context->getDeclContext(),
600 llvm::cast<NamedDecl>(Var), VarRef);
Eric Liu0325a772017-02-02 17:40:38 +0000601 } else if (const auto *EnumConstRef =
602 Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
603 // Do not rename the reference if it is already scoped by the EnumDecl name.
604 if (EnumConstRef->hasQualifier() &&
Eric Liu28c30ce2017-02-02 19:46:12 +0000605 EnumConstRef->getQualifier()->getKind() ==
606 NestedNameSpecifier::SpecifierKind::TypeSpec &&
Eric Liu0325a772017-02-02 17:40:38 +0000607 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
608 return;
609 const auto *EnumConstDecl =
610 Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
611 assert(EnumConstDecl);
612 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
613 assert(Context && "Empty decl context.");
614 // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
615 // if it turns out to be an issue.
616 fixDeclRefExpr(Result, Context->getDeclContext(),
617 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
Eric Liuda22b3c2016-11-29 14:15:14 +0000618 } else if (const auto *FuncRef =
619 Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
Eric Liue3f35e42016-12-20 14:39:04 +0000620 // If this reference has been processed as a function call, we do not
621 // process it again.
622 if (ProcessedFuncRefs.count(FuncRef))
623 return;
624 ProcessedFuncRefs.insert(FuncRef);
Eric Liuda22b3c2016-11-29 14:15:14 +0000625 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
626 assert(Func);
627 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
628 assert(Context && "Empty decl context.");
629 fixDeclRefExpr(Result, Context->getDeclContext(),
630 llvm::cast<NamedDecl>(Func), FuncRef);
Eric Liu12068d82016-09-22 11:54:00 +0000631 } else {
Eric Liuda22b3c2016-11-29 14:15:14 +0000632 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +0000633 assert(Call != nullptr && "Expecting callback for CallExpr.");
Eric Liue3f35e42016-12-20 14:39:04 +0000634 const auto *CalleeFuncRef =
635 llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
636 ProcessedFuncRefs.insert(CalleeFuncRef);
Eric Liuda22b3c2016-11-29 14:15:14 +0000637 const FunctionDecl *Func = Call->getDirectCallee();
Eric Liu12068d82016-09-22 11:54:00 +0000638 assert(Func != nullptr);
Eric Liue3f35e42016-12-20 14:39:04 +0000639 // FIXME: ignore overloaded operators. This would miss cases where operators
640 // are called by qualified names (i.e. "ns::operator <"). Ignore such
641 // cases for now.
642 if (Func->isOverloadedOperator())
643 return;
Eric Liu12068d82016-09-22 11:54:00 +0000644 // Ignore out-of-line static methods since they will be handled by nested
645 // name specifiers.
646 if (Func->getCanonicalDecl()->getStorageClass() ==
Eric Liuda22b3c2016-11-29 14:15:14 +0000647 StorageClass::SC_Static &&
Eric Liu12068d82016-09-22 11:54:00 +0000648 Func->isOutOfLine())
649 return;
Eric Liuda22b3c2016-11-29 14:15:14 +0000650 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu12068d82016-09-22 11:54:00 +0000651 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14 +0000652 SourceRange CalleeRange = Call->getCallee()->getSourceRange();
Eric Liub9bf1b52016-11-08 22:44:17 +0000653 replaceQualifiedSymbolInDeclContext(
654 Result, Context->getDeclContext(), CalleeRange.getBegin(),
Eric Liu231c6552016-11-10 18:15:34 +0000655 CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
Eric Liu495b2112016-09-19 17:40:32 +0000656 }
657}
658
Eric Liu73f49fd2016-10-12 12:34:18 +0000659static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
660 const SourceManager &SM,
661 const LangOptions &LangOpts) {
662 std::unique_ptr<Lexer> Lex =
Stephen Kelly43465bf2018-08-09 22:42:26 +0000663 getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
Eric Liu73f49fd2016-10-12 12:34:18 +0000664 assert(Lex.get() &&
665 "Failed to create lexer from the beginning of namespace.");
666 if (!Lex.get())
667 return SourceLocation();
668 Token Tok;
669 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
670 }
671 return Tok.isNot(tok::TokenKind::l_brace)
672 ? SourceLocation()
673 : Tok.getEndLoc().getLocWithOffset(1);
674}
675
Eric Liu495b2112016-09-19 17:40:32 +0000676// Stores information about a moved namespace in `MoveNamespaces` and leaves
677// the actual movement to `onEndOfTranslationUnit()`.
678void ChangeNamespaceTool::moveOldNamespace(
679 const ast_matchers::MatchFinder::MatchResult &Result,
680 const NamespaceDecl *NsDecl) {
681 // If the namespace is empty, do nothing.
682 if (Decl::castToDeclContext(NsDecl)->decls_empty())
683 return;
684
Eric Liuee5104b2017-01-04 14:49:08 +0000685 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32 +0000686 // Get the range of the code in the old namespace.
Eric Liuee5104b2017-01-04 14:49:08 +0000687 SourceLocation Start =
688 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
Eric Liu73f49fd2016-10-12 12:34:18 +0000689 assert(Start.isValid() && "Can't find l_brace for namespace.");
Eric Liu495b2112016-09-19 17:40:32 +0000690 MoveNamespace MoveNs;
Eric Liuee5104b2017-01-04 14:49:08 +0000691 MoveNs.Offset = SM.getFileOffset(Start);
692 // The range of the moved namespace is from the location just past the left
693 // brace to the location right before the right brace.
694 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
Eric Liu495b2112016-09-19 17:40:32 +0000695
696 // Insert the new namespace after `DiffOldNamespace`. For example, if
697 // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
698 // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
699 // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
700 // in the above example.
Eric Liu6aa94162016-11-10 18:29:01 +0000701 // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
702 // namespace will be a nested namespace in the old namespace.
Eric Liu495b2112016-09-19 17:40:32 +0000703 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
Eric Liu6aa94162016-11-10 18:29:01 +0000704 SourceLocation InsertionLoc = Start;
705 if (OuterNs) {
Eric Liuee5104b2017-01-04 14:49:08 +0000706 SourceLocation LocAfterNs = getStartOfNextLine(
707 OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
Eric Liu6aa94162016-11-10 18:29:01 +0000708 assert(LocAfterNs.isValid() &&
709 "Failed to get location after DiffOldNamespace");
710 InsertionLoc = LocAfterNs;
711 }
Eric Liuee5104b2017-01-04 14:49:08 +0000712 MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
713 MoveNs.FID = SM.getFileID(Start);
Eric Liucc83c662016-09-19 17:58:59 +0000714 MoveNs.SourceMgr = Result.SourceManager;
Eric Liuee5104b2017-01-04 14:49:08 +0000715 MoveNamespaces[SM.getFilename(Start)].push_back(MoveNs);
Eric Liu495b2112016-09-19 17:40:32 +0000716}
717
718// Removes a class forward declaration from the code in the moved namespace and
719// creates an `InsertForwardDeclaration` to insert the forward declaration back
720// into the old namespace after moving code from the old namespace to the new
721// namespace.
722// For example, changing "a" to "x":
723// Old code:
724// namespace a {
725// class FWD;
726// class A { FWD *fwd; }
727// } // a
728// New code:
729// namespace a {
730// class FWD;
731// } // a
732// namespace x {
733// class A { a::FWD *fwd; }
734// } // x
735void ChangeNamespaceTool::moveClassForwardDeclaration(
736 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liu41552d62016-12-07 14:20:52 +0000737 const NamedDecl *FwdDecl) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000738 SourceLocation Start = FwdDecl->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02 +0000739 SourceLocation End = FwdDecl->getEndLoc();
Eric Liu41367152017-03-01 10:29:39 +0000740 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32 +0000741 SourceLocation AfterSemi = Lexer::findLocationAfterToken(
Eric Liu41367152017-03-01 10:29:39 +0000742 End, tok::semi, SM, Result.Context->getLangOpts(),
Eric Liu495b2112016-09-19 17:40:32 +0000743 /*SkipTrailingWhitespaceAndNewLine=*/true);
744 if (AfterSemi.isValid())
745 End = AfterSemi.getLocWithOffset(-1);
746 // Delete the forward declaration from the code to be moved.
Eric Liu41367152017-03-01 10:29:39 +0000747 addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32 +0000748 llvm::StringRef Code = Lexer::getSourceText(
Eric Liu41367152017-03-01 10:29:39 +0000749 CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
750 SM.getSpellingLoc(End)),
751 SM, Result.Context->getLangOpts());
Eric Liu495b2112016-09-19 17:40:32 +0000752 // Insert the forward declaration back into the old namespace after moving the
753 // code from old namespace to new namespace.
754 // Insertion information is stored in `InsertFwdDecls` and actual
755 // insertion will be performed in `onEndOfTranslationUnit`.
756 // Get the (old) namespace that contains the forward declaration.
757 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
758 // The namespace contains the forward declaration, so it must not be empty.
759 assert(!NsDecl->decls_empty());
Eric Liu41367152017-03-01 10:29:39 +0000760 const auto Insertion = createInsertion(
761 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
762 Code, SM);
Eric Liu495b2112016-09-19 17:40:32 +0000763 InsertForwardDeclaration InsertFwd;
764 InsertFwd.InsertionOffset = Insertion.getOffset();
765 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
766 InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
767}
768
Eric Liub9bf1b52016-11-08 22:44:17 +0000769// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
770// FromDecl with the shortest qualified name possible when the reference is in
771// `NewNamespace`.
Eric Liu495b2112016-09-19 17:40:32 +0000772void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
Eric Liub9bf1b52016-11-08 22:44:17 +0000773 const ast_matchers::MatchFinder::MatchResult &Result,
774 const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
775 const NamedDecl *FromDecl) {
776 const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
Eric Liu4fe99e12016-12-14 17:01:52 +0000777 if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
778 // This should not happen in usual unless the TypeLoc is in function type
779 // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
780 // `T` will be the translation unit. We simply use fully-qualified name
781 // here.
782 // Note that `FromDecl` must not be defined in the old namespace (according
783 // to `DeclMatcher`), so its fully-qualified name will not change after
784 // changing the namespace.
785 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
786 *Result.SourceManager, &FileToReplacements);
787 return;
788 }
Eric Liu231c6552016-11-10 18:15:34 +0000789 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
Eric Liu495b2112016-09-19 17:40:32 +0000790 // Calculate the name of the `NsDecl` after it is moved to new namespace.
791 std::string OldNs = NsDecl->getQualifiedNameAsString();
792 llvm::StringRef Postfix = OldNs;
793 bool Consumed = Postfix.consume_front(OldNamespace);
794 assert(Consumed && "Expect OldNS to start with OldNamespace.");
795 (void)Consumed;
796 const std::string NewNs = (NewNamespace + Postfix).str();
797
798 llvm::StringRef NestedName = Lexer::getSourceText(
799 CharSourceRange::getTokenRange(
800 Result.SourceManager->getSpellingLoc(Start),
801 Result.SourceManager->getSpellingLoc(End)),
802 *Result.SourceManager, Result.Context->getLangOpts());
Eric Liub9bf1b52016-11-08 22:44:17 +0000803 std::string FromDeclName = FromDecl->getQualifiedNameAsString();
Eric Liu7fccc992017-02-24 11:54:45 +0000804 for (llvm::Regex &RE : WhiteListedSymbolRegexes)
805 if (RE.match(FromDeclName))
806 return;
Eric Liu495b2112016-09-19 17:40:32 +0000807 std::string ReplaceName =
Eric Liub9bf1b52016-11-08 22:44:17 +0000808 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
809 // Checks if there is any using namespace declarations that can shorten the
810 // qualified name.
811 for (const auto *UsingNamespace : UsingNamespaceDecls) {
812 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
813 Start))
814 continue;
815 StringRef FromDeclNameRef = FromDeclName;
816 if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
817 ->getQualifiedNameAsString())) {
818 FromDeclNameRef = FromDeclNameRef.drop_front(2);
819 if (FromDeclNameRef.size() < ReplaceName.size())
820 ReplaceName = FromDeclNameRef;
821 }
822 }
Eric Liu180dac62016-12-23 10:47:09 +0000823 // Checks if there is any namespace alias declarations that can shorten the
824 // qualified name.
825 for (const auto *NamespaceAlias : NamespaceAliasDecls) {
826 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
827 Start))
828 continue;
829 StringRef FromDeclNameRef = FromDeclName;
830 if (FromDeclNameRef.consume_front(
831 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
832 "::")) {
833 std::string AliasName = NamespaceAlias->getNameAsString();
834 std::string AliasQualifiedName =
835 NamespaceAlias->getQualifiedNameAsString();
836 // We only consider namespace aliases define in the global namepspace or
837 // in namespaces that are directly visible from the reference, i.e.
838 // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
839 // but not visible in the new namespace is filtered out by
840 // "IsVisibleInNewNs" matcher.
841 if (AliasQualifiedName != AliasName) {
842 // The alias is defined in some namespace.
843 assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
844 llvm::StringRef AliasNs =
845 StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
846 if (!llvm::StringRef(OldNs).startswith(AliasNs))
847 continue;
848 }
849 std::string NameWithAliasNamespace =
850 (AliasName + "::" + FromDeclNameRef).str();
851 if (NameWithAliasNamespace.size() < ReplaceName.size())
852 ReplaceName = NameWithAliasNamespace;
853 }
854 }
Eric Liub9bf1b52016-11-08 22:44:17 +0000855 // Checks if there is any using shadow declarations that can shorten the
856 // qualified name.
857 bool Matched = false;
858 for (const UsingDecl *Using : UsingDecls) {
859 if (Matched)
860 break;
861 if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
862 for (const auto *UsingShadow : Using->shadows()) {
863 const auto *TargetDecl = UsingShadow->getTargetDecl();
Eric Liuae7de712017-02-02 15:29:54 +0000864 if (TargetDecl->getQualifiedNameAsString() ==
865 FromDecl->getQualifiedNameAsString()) {
Eric Liub9bf1b52016-11-08 22:44:17 +0000866 ReplaceName = FromDecl->getNameAsString();
867 Matched = true;
868 break;
869 }
870 }
871 }
872 }
Eric Liuc6c894b2018-10-22 12:48:49 +0000873 bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
874 ReplaceName, NewNamespace);
Eric Liu495b2112016-09-19 17:40:32 +0000875 // If the new nested name in the new namespace is the same as it was in the
Eric Liuc6c894b2018-10-22 12:48:49 +0000876 // old namespace, we don't create replacement unless there can be ambiguity.
877 if ((NestedName == ReplaceName && !Conflict) ||
Eric Liu91229162017-01-26 16:31:32 +0000878 (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
Eric Liu495b2112016-09-19 17:40:32 +0000879 return;
Eric Liu97f87ad2016-12-07 20:08:02 +0000880 // If the reference need to be fully-qualified, add a leading "::" unless
881 // NewNamespace is the global namespace.
Eric Liuc6c894b2018-10-22 12:48:49 +0000882 if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
Eric Liu97f87ad2016-12-07 20:08:02 +0000883 ReplaceName = "::" + ReplaceName;
Eric Liu4fe99e12016-12-14 17:01:52 +0000884 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
885 &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32 +0000886}
887
888// Replace the [Start, End] of `Type` with the shortest qualified name when the
889// `Type` is in `NewNamespace`.
890void ChangeNamespaceTool::fixTypeLoc(
891 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
892 SourceLocation End, TypeLoc Type) {
893 // FIXME: do not rename template parameter.
894 if (Start.isInvalid() || End.isInvalid())
895 return;
Eric Liuff51f012016-11-16 16:54:53 +0000896 // Types of CXXCtorInitializers do not need to be fixed.
897 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
898 return;
Eric Liu284b97c2017-03-17 14:05:39 +0000899 if (isTemplateParameter(Type))
900 return;
Eric Liu495b2112016-09-19 17:40:32 +0000901 // The declaration which this TypeLoc refers to.
902 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
903 // `hasDeclaration` gives underlying declaration, but if the type is
904 // a typedef type, we need to use the typedef type instead.
Eric Liu26cf68a2016-12-15 10:42:35 +0000905 auto IsInMovedNs = [&](const NamedDecl *D) {
906 if (!llvm::StringRef(D->getQualifiedNameAsString())
907 .startswith(OldNamespace + "::"))
908 return false;
Stephen Kelly43465bf2018-08-09 22:42:26 +0000909 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
Eric Liu26cf68a2016-12-15 10:42:35 +0000910 if (ExpansionLoc.isInvalid())
911 return false;
912 llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
913 return FilePatternRE.match(Filename);
914 };
915 // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
916 // `Type` is an alias type, we make `FromDecl` the type alias declaration.
917 // Also, don't fix the \p Type if it refers to a type alias decl in the moved
918 // namespace since the alias decl will be moved along with the type reference.
Eric Liu32158862016-11-14 19:37:55 +0000919 if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
Eric Liu495b2112016-09-19 17:40:32 +0000920 FromDecl = Typedef->getDecl();
Eric Liu32158862016-11-14 19:37:55 +0000921 if (IsInMovedNs(FromDecl))
922 return;
Eric Liu26cf68a2016-12-15 10:42:35 +0000923 } else if (auto *TemplateType =
924 Type.getType()->getAs<TemplateSpecializationType>()) {
925 if (TemplateType->isTypeAlias()) {
926 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
927 if (IsInMovedNs(FromDecl))
928 return;
929 }
Eric Liu32158862016-11-14 19:37:55 +0000930 }
Piotr Padlewski08124b12016-12-14 15:29:23 +0000931 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu495b2112016-09-19 17:40:32 +0000932 assert(DeclCtx && "Empty decl context.");
Eric Liub9bf1b52016-11-08 22:44:17 +0000933 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
934 End, FromDecl);
Eric Liu495b2112016-09-19 17:40:32 +0000935}
936
Eric Liu68765a82016-09-21 15:06:12 +0000937void ChangeNamespaceTool::fixUsingShadowDecl(
938 const ast_matchers::MatchFinder::MatchResult &Result,
939 const UsingDecl *UsingDeclaration) {
Stephen Kelly43465bf2018-08-09 22:42:26 +0000940 SourceLocation Start = UsingDeclaration->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02 +0000941 SourceLocation End = UsingDeclaration->getEndLoc();
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19 +0000942 if (Start.isInvalid() || End.isInvalid())
943 return;
Eric Liu68765a82016-09-21 15:06:12 +0000944
945 assert(UsingDeclaration->shadow_size() > 0);
946 // FIXME: it might not be always accurate to use the first using-decl.
947 const NamedDecl *TargetDecl =
948 UsingDeclaration->shadow_begin()->getTargetDecl();
949 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
950 // FIXME: check if target_decl_name is in moved ns, which doesn't make much
951 // sense. If this happens, we need to use name with the new namespace.
952 // Use fully qualified name in UsingDecl for now.
Eric Liu4fe99e12016-12-14 17:01:52 +0000953 addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
954 *Result.SourceManager, &FileToReplacements);
Eric Liu68765a82016-09-21 15:06:12 +0000955}
956
Eric Liuda22b3c2016-11-29 14:15:14 +0000957void ChangeNamespaceTool::fixDeclRefExpr(
958 const ast_matchers::MatchFinder::MatchResult &Result,
959 const DeclContext *UseContext, const NamedDecl *From,
960 const DeclRefExpr *Ref) {
961 SourceRange RefRange = Ref->getSourceRange();
962 replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
963 RefRange.getEnd(), From);
964}
965
Eric Liu495b2112016-09-19 17:40:32 +0000966void ChangeNamespaceTool::onEndOfTranslationUnit() {
967 // Move namespace blocks and insert forward declaration to old namespace.
968 for (const auto &FileAndNsMoves : MoveNamespaces) {
969 auto &NsMoves = FileAndNsMoves.second;
970 if (NsMoves.empty())
971 continue;
972 const std::string &FilePath = FileAndNsMoves.first;
973 auto &Replaces = FileToReplacements[FilePath];
Eric Liucc83c662016-09-19 17:58:59 +0000974 auto &SM = *NsMoves.begin()->SourceMgr;
975 llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
Eric Liu495b2112016-09-19 17:40:32 +0000976 auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
977 if (!ChangedCode) {
978 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
979 continue;
980 }
981 // Replacements on the changed code for moving namespaces and inserting
982 // forward declarations to old namespaces.
983 tooling::Replacements NewReplacements;
984 // Cut the changed code from the old namespace and paste the code in the new
985 // namespace.
986 for (const auto &NsMove : NsMoves) {
987 // Calculate the range of the old namespace block in the changed
988 // code.
989 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
990 const unsigned NewLength =
991 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
992 NewOffset;
993 tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
994 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
995 std::string MovedCodeWrappedInNewNs =
996 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
997 // Calculate the new offset at which the code will be inserted in the
998 // changed code.
999 unsigned NewInsertionOffset =
1000 Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
1001 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1002 MovedCodeWrappedInNewNs);
1003 addOrMergeReplacement(Deletion, &NewReplacements);
1004 addOrMergeReplacement(Insertion, &NewReplacements);
1005 }
1006 // After moving namespaces, insert forward declarations back to old
1007 // namespaces.
1008 const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
1009 for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
1010 unsigned NewInsertionOffset =
1011 Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
1012 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1013 FwdDeclInsertion.ForwardDeclText);
1014 addOrMergeReplacement(Insertion, &NewReplacements);
1015 }
1016 // Add replacements referring to the changed code to existing replacements,
1017 // which refers to the original code.
1018 Replaces = Replaces.merge(NewReplacements);
Eric Liufa63e982018-08-02 10:30:56 +00001019 auto Style =
1020 format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +00001021 if (!Style) {
1022 llvm::errs() << llvm::toString(Style.takeError()) << "\n";
1023 continue;
1024 }
Eric Liu495b2112016-09-19 17:40:32 +00001025 // Clean up old namespaces if there is nothing in it after moving.
1026 auto CleanReplacements =
Antonio Maiorano0d7d9c22017-01-17 00:13:32 +00001027 format::cleanupAroundReplacements(Code, Replaces, *Style);
Eric Liu495b2112016-09-19 17:40:32 +00001028 if (!CleanReplacements) {
1029 llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
1030 continue;
1031 }
1032 FileToReplacements[FilePath] = *CleanReplacements;
1033 }
Eric Liuc265b022016-12-01 17:25:55 +00001034
1035 // Make sure we don't generate replacements for files that do not match
1036 // FilePattern.
1037 for (auto &Entry : FileToReplacements)
1038 if (!FilePatternRE.match(Entry.first))
1039 Entry.second.clear();
Eric Liu495b2112016-09-19 17:40:32 +00001040}
1041
1042} // namespace change_namespace
1043} // namespace clang