blob: e2a70db4102b2adc37e2d1efc4ab2b4537fbeba6 [file] [log] [blame]
Eric Liu495b2112016-09-19 17:40:321//===-- ChangeNamespace.cpp - Change namespace implementation -------------===//
2//
Chandler Carruth2946cd72019-01-19 08:50:563// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Eric Liu495b2112016-09-19 17:40:326//
7//===----------------------------------------------------------------------===//
8#include "ChangeNamespace.h"
Eric Liuc6c894b2018-10-22 12:48:499#include "clang/AST/ASTContext.h"
Eric Liu495b2112016-09-19 17:40:3210#include "clang/Format/Format.h"
11#include "clang/Lex/Lexer.h"
Eric Liuc6c894b2018-10-22 12:48:4912#include "llvm/Support/Casting.h"
Eric Liuff51f012016-11-16 16:54:5313#include "llvm/Support/ErrorHandling.h"
Eric Liu495b2112016-09-19 17:40:3214
15using namespace clang::ast_matchers;
16
17namespace clang {
18namespace change_namespace {
19
20namespace {
21
22inline std::string
23joinNamespaces(const llvm::SmallVectorImpl<StringRef> &Namespaces) {
24 if (Namespaces.empty())
25 return "";
Benjamin Krameradcd0262020-01-28 19:23:4626 std::string Result(Namespaces.front());
Eric Liu495b2112016-09-19 17:40:3227 for (auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
28 Result += ("::" + *I).str();
29 return Result;
30}
31
Eric Liu8bc24162017-03-21 12:41:5932// Given "a::b::c", returns {"a", "b", "c"}.
33llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
34 llvm::SmallVector<llvm::StringRef, 4> Splitted;
35 Name.split(Splitted, "::", /*MaxSplit=*/-1,
36 /*KeepEmpty=*/false);
37 return Splitted;
38}
39
Eric Liu495b2112016-09-19 17:40:3240SourceLocation startLocationForType(TypeLoc TLoc) {
41 // For elaborated types (e.g. `struct a::A`) we want the portion after the
42 // `struct` but including the namespace qualifier, `a::`.
43 if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
44 NestedNameSpecifierLoc NestedNameSpecifier =
45 TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
46 if (NestedNameSpecifier.getNestedNameSpecifier())
47 return NestedNameSpecifier.getBeginLoc();
48 TLoc = TLoc.getNextTypeLoc();
49 }
Stephen Kelly43465bf2018-08-09 22:42:2650 return TLoc.getBeginLoc();
Eric Liu495b2112016-09-19 17:40:3251}
52
Eric Liuc265b022016-12-01 17:25:5553SourceLocation endLocationForType(TypeLoc TLoc) {
Eric Liu495b2112016-09-19 17:40:3254 // Dig past any namespace or keyword qualifications.
55 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
56 TLoc.getTypeLocClass() == TypeLoc::Qualified)
57 TLoc = TLoc.getNextTypeLoc();
58
59 // The location for template specializations (e.g. Foo<int>) includes the
60 // templated types in its location range. We want to restrict this to just
61 // before the `<` character.
62 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
63 return TLoc.castAs<TemplateSpecializationTypeLoc>()
64 .getLAngleLoc()
65 .getLocWithOffset(-1);
66 return TLoc.getEndLoc();
67}
68
69// Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
Eric Liu6aa94162016-11-10 18:29:0170// If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
71// is empty, nullptr is returned.
Eric Liu495b2112016-09-19 17:40:3272// For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
73// the NamespaceDecl of namespace "a" will be returned.
74const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
75 llvm::StringRef PartialNsName) {
Eric Liu6aa94162016-11-10 18:29:0176 if (!InnerNs || PartialNsName.empty())
77 return nullptr;
Eric Liu495b2112016-09-19 17:40:3278 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
79 const auto *CurrentNs = InnerNs;
Eric Liu8bc24162017-03-21 12:41:5980 auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
Eric Liu495b2112016-09-19 17:40:3281 while (!PartialNsNameSplitted.empty()) {
82 // Get the inner-most namespace in CurrentContext.
83 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
84 CurrentContext = CurrentContext->getParent();
85 if (!CurrentContext)
86 return nullptr;
87 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
88 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
89 return nullptr;
90 PartialNsNameSplitted.pop_back();
91 CurrentContext = CurrentContext->getParent();
92 }
93 return CurrentNs;
94}
95
Eric Liu73f49fd2016-10-12 12:34:1896static std::unique_ptr<Lexer>
97getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
98 const LangOptions &LangOpts) {
Eric Liu495b2112016-09-19 17:40:3299 if (Loc.isMacroID() &&
100 !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
Eric Liu73f49fd2016-10-12 12:34:18101 return nullptr;
Eric Liu495b2112016-09-19 17:40:32102 // Break down the source location.
103 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
104 // Try to load the file buffer.
105 bool InvalidTemp = false;
106 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
107 if (InvalidTemp)
Eric Liu73f49fd2016-10-12 12:34:18108 return nullptr;
Eric Liu495b2112016-09-19 17:40:32109
110 const char *TokBegin = File.data() + LocInfo.second;
111 // Lex from the start of the given location.
Jonas Devlieghere1c705d92019-08-14 23:52:23112 return std::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
Eric Liu73f49fd2016-10-12 12:34:18113 LangOpts, File.begin(), TokBegin, File.end());
114}
Eric Liu495b2112016-09-19 17:40:32115
Eric Liu73f49fd2016-10-12 12:34:18116// FIXME: get rid of this helper function if this is supported in clang-refactor
117// library.
118static SourceLocation getStartOfNextLine(SourceLocation Loc,
119 const SourceManager &SM,
120 const LangOptions &LangOpts) {
121 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
122 if (!Lex.get())
123 return SourceLocation();
Eric Liu495b2112016-09-19 17:40:32124 llvm::SmallVector<char, 16> Line;
125 // FIXME: this is a bit hacky to get ReadToEndOfLine work.
Eric Liu73f49fd2016-10-12 12:34:18126 Lex->setParsingPreprocessorDirective(true);
127 Lex->ReadToEndOfLine(&Line);
Haojian Wuef8a6dc2016-10-04 10:35:53128 auto End = Loc.getLocWithOffset(Line.size());
Eric Liu73f49fd2016-10-12 12:34:18129 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
130 ? End
131 : End.getLocWithOffset(1);
Eric Liu495b2112016-09-19 17:40:32132}
133
134// Returns `R` with new range that refers to code after `Replaces` being
135// applied.
136tooling::Replacement
137getReplacementInChangedCode(const tooling::Replacements &Replaces,
138 const tooling::Replacement &R) {
139 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
140 unsigned NewEnd =
141 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
142 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
143 R.getReplacementText());
144}
145
146// Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
147// applying all existing Replaces first if there is conflict.
148void addOrMergeReplacement(const tooling::Replacement &R,
149 tooling::Replacements *Replaces) {
150 auto Err = Replaces->add(R);
151 if (Err) {
152 llvm::consumeError(std::move(Err));
153 auto Replace = getReplacementInChangedCode(*Replaces, R);
154 *Replaces = Replaces->merge(tooling::Replacements(Replace));
155 }
156}
157
158tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
159 llvm::StringRef ReplacementText,
160 const SourceManager &SM) {
161 if (!Start.isValid() || !End.isValid()) {
162 llvm::errs() << "start or end location were invalid\n";
163 return tooling::Replacement();
164 }
165 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
166 llvm::errs()
167 << "start or end location were in different macro expansions\n";
168 return tooling::Replacement();
169 }
170 Start = SM.getSpellingLoc(Start);
171 End = SM.getSpellingLoc(End);
172 if (SM.getFileID(Start) != SM.getFileID(End)) {
173 llvm::errs() << "start or end location were in different files\n";
174 return tooling::Replacement();
175 }
176 return tooling::Replacement(
177 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
178 SM.getSpellingLoc(End)),
179 ReplacementText);
180}
181
Eric Liu4fe99e12016-12-14 17:01:52182void addReplacementOrDie(
183 SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
184 const SourceManager &SM,
185 std::map<std::string, tooling::Replacements> *FileToReplacements) {
186 const auto R = createReplacement(Start, End, ReplacementText, SM);
Benjamin Krameradcd0262020-01-28 19:23:46187 auto Err = (*FileToReplacements)[std::string(R.getFilePath())].add(R);
Eric Liu4fe99e12016-12-14 17:01:52188 if (Err)
189 llvm_unreachable(llvm::toString(std::move(Err)).c_str());
190}
191
Eric Liu495b2112016-09-19 17:40:32192tooling::Replacement createInsertion(SourceLocation Loc,
193 llvm::StringRef InsertText,
194 const SourceManager &SM) {
195 if (Loc.isInvalid()) {
196 llvm::errs() << "insert Location is invalid.\n";
197 return tooling::Replacement();
198 }
199 Loc = SM.getSpellingLoc(Loc);
200 return tooling::Replacement(SM, Loc, 0, InsertText);
201}
202
203// Returns the shortest qualified name for declaration `DeclName` in the
204// namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
205// is "a::c::d", then "b::X" will be returned.
Eric Liubc715502017-01-26 15:08:44206// Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
207// "::b::X" instead of "b::X" since there will be a name conflict otherwise.
Eric Liu447164d2016-10-05 15:52:39208// \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
209// \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
210// will have empty name.
Eric Liu495b2112016-09-19 17:40:32211std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
212 llvm::StringRef NsName) {
Eric Liu447164d2016-10-05 15:52:39213 DeclName = DeclName.ltrim(':');
214 NsName = NsName.ltrim(':');
Eric Liu447164d2016-10-05 15:52:39215 if (DeclName.find(':') == llvm::StringRef::npos)
Benjamin Krameradcd0262020-01-28 19:23:46216 return std::string(DeclName);
Eric Liu447164d2016-10-05 15:52:39217
Eric Liu8bc24162017-03-21 12:41:59218 auto NsNameSplitted = splitSymbolName(NsName);
219 auto DeclNsSplitted = splitSymbolName(DeclName);
Eric Liubc715502017-01-26 15:08:44220 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
221 // If the Decl is in global namespace, there is no need to shorten it.
222 if (DeclNsSplitted.empty())
Benjamin Krameradcd0262020-01-28 19:23:46223 return std::string(UnqualifiedDeclName);
Eric Liubc715502017-01-26 15:08:44224 // If NsName is the global namespace, we can simply use the DeclName sans
225 // leading "::".
226 if (NsNameSplitted.empty())
Benjamin Krameradcd0262020-01-28 19:23:46227 return std::string(DeclName);
Eric Liubc715502017-01-26 15:08:44228
229 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
230 // The DeclName must be fully-qualified, but we still need to decide if a
231 // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
232 // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
233 // to avoid conflict.
234 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
235 return ("::" + DeclName).str();
Benjamin Krameradcd0262020-01-28 19:23:46236 return std::string(DeclName);
Eric Liu495b2112016-09-19 17:40:32237 }
Eric Liubc715502017-01-26 15:08:44238 // Since there is already an overlap namespace, we know that `DeclName` can be
239 // shortened, so we reduce the longest common prefix.
240 auto DeclI = DeclNsSplitted.begin();
241 auto DeclE = DeclNsSplitted.end();
242 auto NsI = NsNameSplitted.begin();
243 auto NsE = NsNameSplitted.end();
244 for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
245 }
246 return (DeclI == DeclE)
247 ? UnqualifiedDeclName.str()
248 : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
249 .str();
Eric Liu495b2112016-09-19 17:40:32250}
251
252std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
253 if (Code.back() != '\n')
254 Code += "\n";
Eric Liu8bc24162017-03-21 12:41:59255 auto NsSplitted = splitSymbolName(NestedNs);
Eric Liu495b2112016-09-19 17:40:32256 while (!NsSplitted.empty()) {
257 // FIXME: consider code style for comments.
258 Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
259 "} // namespace " + NsSplitted.back() + "\n")
260 .str();
261 NsSplitted.pop_back();
262 }
263 return Code;
264}
265
Eric Liub9bf1b52016-11-08 22:44:17266// Returns true if \p D is a nested DeclContext in \p Context
267bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
268 while (D) {
269 if (D == Context)
270 return true;
271 D = D->getParent();
272 }
273 return false;
274}
275
276// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
277bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
278 const DeclContext *DeclCtx, SourceLocation Loc) {
Stephen Kelly43465bf2018-08-09 22:42:26279 SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
Eric Liub9bf1b52016-11-08 22:44:17280 Loc = SM.getSpellingLoc(Loc);
281 return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
282 (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
283 isNestedDeclContext(DeclCtx, D->getDeclContext()));
284}
285
Eric Liu8bc24162017-03-21 12:41:59286// Given a qualified symbol name, returns true if the symbol will be
Eric Liuc6c894b2018-10-22 12:48:49287// incorrectly qualified without leading "::". For example, a symbol
288// "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
289// "util::X" in namespace "na" can potentially conflict with "na::util" (if this
290// exists).
291bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
Eric Liu8bc24162017-03-21 12:41:59292 llvm::StringRef Namespace) {
293 auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
294 assert(!SymbolSplitted.empty());
295 SymbolSplitted.pop_back(); // We are only interested in namespaces.
296
Eric Liuc6c894b2018-10-22 12:48:49297 if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
298 auto SymbolTopNs = SymbolSplitted.front();
Eric Liu8bc24162017-03-21 12:41:59299 auto NsSplitted = splitSymbolName(Namespace.trim(":"));
300 assert(!NsSplitted.empty());
Eric Liuc6c894b2018-10-22 12:48:49301
302 auto LookupDecl = [&AST](const Decl &Scope,
303 llvm::StringRef Name) -> const NamedDecl * {
304 const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
305 if (!DC)
306 return nullptr;
307 auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
308 if (LookupRes.empty())
309 return nullptr;
310 return LookupRes.front();
311 };
312 // We do not check the outermost namespace since it would not be a
313 // conflict if it equals to the symbol's outermost namespace and the
314 // symbol name would have been shortened.
315 const NamedDecl *Scope =
316 LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
Eric Liu8bc24162017-03-21 12:41:59317 for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
Eric Liuc6c894b2018-10-22 12:48:49318 if (*I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
Eric Liu8bc24162017-03-21 12:41:59319 return true;
Eric Liuc6c894b2018-10-22 12:48:49320 // Handles "::util" and "::nx::util" conflicts.
321 if (Scope) {
322 if (LookupDecl(*Scope, SymbolTopNs))
323 return true;
324 Scope = LookupDecl(*Scope, *I);
325 }
Eric Liu8bc24162017-03-21 12:41:59326 }
Eric Liuc6c894b2018-10-22 12:48:49327 if (Scope && LookupDecl(*Scope, SymbolTopNs))
328 return true;
Eric Liu8bc24162017-03-21 12:41:59329 }
330 return false;
331}
332
Eric Liu0325a772017-02-02 17:40:38333AST_MATCHER(EnumDecl, isScoped) {
334 return Node.isScoped();
335}
336
Eric Liu284b97c2017-03-17 14:05:39337bool isTemplateParameter(TypeLoc Type) {
338 while (!Type.isNull()) {
339 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
340 return true;
341 Type = Type.getNextTypeLoc();
342 }
343 return false;
344}
345
Eric Liu495b2112016-09-19 17:40:32346} // anonymous namespace
347
348ChangeNamespaceTool::ChangeNamespaceTool(
349 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
Eric Christopher25ed42f2020-06-20 06:01:42350 llvm::ArrayRef<std::string> AllowedSymbolPatterns,
Eric Liu495b2112016-09-19 17:40:32351 std::map<std::string, tooling::Replacements> *FileToReplacements,
352 llvm::StringRef FallbackStyle)
353 : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
354 OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
Eric Liuc265b022016-12-01 17:25:55355 FilePattern(FilePattern), FilePatternRE(FilePattern) {
Eric Liu495b2112016-09-19 17:40:32356 FileToReplacements->clear();
Eric Liu8bc24162017-03-21 12:41:59357 auto OldNsSplitted = splitSymbolName(OldNamespace);
358 auto NewNsSplitted = splitSymbolName(NewNamespace);
Eric Liu495b2112016-09-19 17:40:32359 // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
360 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
361 OldNsSplitted.front() == NewNsSplitted.front()) {
362 OldNsSplitted.erase(OldNsSplitted.begin());
363 NewNsSplitted.erase(NewNsSplitted.begin());
364 }
365 DiffOldNamespace = joinNamespaces(OldNsSplitted);
366 DiffNewNamespace = joinNamespaces(NewNsSplitted);
Eric Liu7fccc992017-02-24 11:54:45367
Eric Christopher25ed42f2020-06-20 06:01:42368 for (const auto &Pattern : AllowedSymbolPatterns)
369 AllowedSymbolRegexes.emplace_back(Pattern);
Eric Liu495b2112016-09-19 17:40:32370}
371
Eric Liu495b2112016-09-19 17:40:32372void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
Eric Liu495b2112016-09-19 17:40:32373 std::string FullOldNs = "::" + OldNamespace;
Eric Liub9bf1b52016-11-08 22:44:17374 // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
375 // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
376 // be "a::b". Declarations in this namespace will not be visible in the new
377 // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
378 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
Eric Liu2dd0e1b2016-12-05 11:17:04379 llvm::StringRef(DiffOldNamespace)
380 .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
381 /*KeepEmpty=*/false);
Eric Liub9bf1b52016-11-08 22:44:17382 std::string Prefix = "-";
383 if (!DiffOldNsSplitted.empty())
384 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
385 DiffOldNsSplitted.front())
386 .str();
387 auto IsInMovedNs =
388 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
389 isExpansionInFileMatching(FilePattern));
390 auto IsVisibleInNewNs = anyOf(
391 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
392 // Match using declarations.
393 Finder->addMatcher(
394 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
395 .bind("using"),
396 this);
397 // Match using namespace declarations.
398 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
399 IsVisibleInNewNs)
400 .bind("using_namespace"),
401 this);
Eric Liu180dac62016-12-23 10:47:09402 // Match namespace alias declarations.
403 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
404 IsVisibleInNewNs)
405 .bind("namespace_alias"),
406 this);
Eric Liub9bf1b52016-11-08 22:44:17407
408 // Match old namespace blocks.
Eric Liu495b2112016-09-19 17:40:32409 Finder->addMatcher(
410 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
411 .bind("old_ns"),
412 this);
413
Eric Liu41552d62016-12-07 14:20:52414 // Match class forward-declarations in the old namespace.
415 // Note that forward-declarations in classes are not matched.
416 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
417 IsInMovedNs, hasParent(namespaceDecl()))
418 .bind("class_fwd_decl"),
419 this);
420
421 // Match template class forward-declarations in the old namespace.
Eric Liu495b2112016-09-19 17:40:32422 Finder->addMatcher(
Eric Liu41552d62016-12-07 14:20:52423 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
424 IsInMovedNs, hasParent(namespaceDecl()))
425 .bind("template_class_fwd_decl"),
Eric Liu495b2112016-09-19 17:40:32426 this);
427
428 // Match references to types that are not defined in the old namespace.
429 // Forward-declarations in the old namespace are also matched since they will
430 // be moved back to the old namespace.
431 auto DeclMatcher = namedDecl(
432 hasAncestor(namespaceDecl()),
433 unless(anyOf(
Eric Liu912d0392016-09-27 12:54:48434 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
Eric Liu495b2112016-09-19 17:40:32435 hasAncestor(cxxRecordDecl()),
436 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
Eric Liu912d0392016-09-27 12:54:48437
Eric Liu8685c762016-12-07 17:04:07438 // Using shadow declarations in classes always refers to base class, which
439 // does not need to be qualified since it can be inferred from inheritance.
440 // Note that this does not match using alias declarations.
441 auto UsingShadowDeclInClass =
442 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
443
Eric Liu495b2112016-09-19 17:40:32444 // Match TypeLocs on the declaration. Carefully match only the outermost
Eric Liu8393cb02016-10-31 08:28:29445 // TypeLoc and template specialization arguments (which are not outermost)
446 // that are directly linked to types matching `DeclMatcher`. Nested name
447 // specifier locs are handled separately below.
Eric Liu495b2112016-09-19 17:40:32448 Finder->addMatcher(
449 typeLoc(IsInMovedNs,
450 loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
Eric Liu8393cb02016-10-31 08:28:29451 unless(anyOf(hasParent(typeLoc(loc(qualType(
Alexander Kornienko976e0c02018-11-25 02:41:01452 hasDeclaration(DeclMatcher),
453 unless(templateSpecializationType()))))),
Eric Liu8685c762016-12-07 17:04:07454 hasParent(nestedNameSpecifierLoc()),
455 hasAncestor(isImplicit()),
Eric Liub583a7e2017-10-16 08:20:10456 hasAncestor(UsingShadowDeclInClass),
457 hasAncestor(functionDecl(isDefaulted())))),
Eric Liu495b2112016-09-19 17:40:32458 hasAncestor(decl().bind("dc")))
459 .bind("type"),
460 this);
Eric Liu912d0392016-09-27 12:54:48461
Eric Liu68765a82016-09-21 15:06:12462 // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
463 // special case it.
Eric Liu8685c762016-12-07 17:04:07464 // Since using declarations inside classes must have the base class in the
465 // nested name specifier, we leave it to the nested name specifier matcher.
466 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
467 unless(UsingShadowDeclInClass))
Eric Liub9bf1b52016-11-08 22:44:17468 .bind("using_with_shadow"),
469 this);
Eric Liu912d0392016-09-27 12:54:48470
Eric Liuff51f012016-11-16 16:54:53471 // Handle types in nested name specifier. Specifiers that are in a TypeLoc
472 // matched above are not matched, e.g. "A::" in "A::A" is not matched since
473 // "A::A" would have already been fixed.
Eric Liu8685c762016-12-07 17:04:07474 Finder->addMatcher(
475 nestedNameSpecifierLoc(
476 hasAncestor(decl(IsInMovedNs).bind("dc")),
477 loc(nestedNameSpecifier(
478 specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
479 unless(anyOf(hasAncestor(isImplicit()),
480 hasAncestor(UsingShadowDeclInClass),
Eric Liub583a7e2017-10-16 08:20:10481 hasAncestor(functionDecl(isDefaulted())),
Eric Liu8685c762016-12-07 17:04:07482 hasAncestor(typeLoc(loc(qualType(hasDeclaration(
483 decl(equalsBoundNode("from_decl"))))))))))
484 .bind("nested_specifier_loc"),
485 this);
Eric Liu12068d82016-09-22 11:54:00486
Eric Liuff51f012016-11-16 16:54:53487 // Matches base class initializers in constructors. TypeLocs of base class
488 // initializers do not need to be fixed. For example,
489 // class X : public a::b::Y {
490 // public:
491 // X() : Y::Y() {} // Y::Y do not need namespace specifier.
492 // };
493 Finder->addMatcher(
494 cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
495
Eric Liu12068d82016-09-22 11:54:00496 // Handle function.
Eric Liu912d0392016-09-27 12:54:48497 // Only handle functions that are defined in a namespace excluding member
498 // function, static methods (qualified by nested specifier), and functions
499 // defined in the global namespace.
Eric Liu12068d82016-09-22 11:54:00500 // Note that the matcher does not exclude calls to out-of-line static method
501 // definitions, so we need to exclude them in the callback handler.
Eric Liu912d0392016-09-27 12:54:48502 auto FuncMatcher =
503 functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
504 hasAncestor(namespaceDecl(isAnonymous())),
505 hasAncestor(cxxRecordDecl()))),
506 hasParent(namespaceDecl()));
Alexander Kornienko976e0c02018-11-25 02:41:01507 Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
508 unless(hasAncestor(isImplicit())),
509 anyOf(callExpr(callee(FuncMatcher)).bind("call"),
510 declRefExpr(to(FuncMatcher.bind("func_decl")))
511 .bind("func_ref"))),
512 this);
Eric Liu159f0132016-09-30 04:32:39513
514 auto GlobalVarMatcher = varDecl(
515 hasGlobalStorage(), hasParent(namespaceDecl()),
516 unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
517 Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
518 to(GlobalVarMatcher.bind("var_decl")))
519 .bind("var_ref"),
520 this);
Eric Liu0325a772017-02-02 17:40:38521
522 // Handle unscoped enum constant.
523 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
524 hasParent(namespaceDecl()),
525 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
526 hasAncestor(namespaceDecl(isAnonymous())))))));
527 Finder->addMatcher(
528 declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
529 to(UnscopedEnumMatcher.bind("enum_const_decl")))
530 .bind("enum_const_ref"),
531 this);
Eric Liu495b2112016-09-19 17:40:32532}
533
534void ChangeNamespaceTool::run(
535 const ast_matchers::MatchFinder::MatchResult &Result) {
Eric Liub9bf1b52016-11-08 22:44:17536 if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
537 UsingDecls.insert(Using);
538 } else if (const auto *UsingNamespace =
539 Result.Nodes.getNodeAs<UsingDirectiveDecl>(
540 "using_namespace")) {
541 UsingNamespaceDecls.insert(UsingNamespace);
Eric Liu180dac62016-12-23 10:47:09542 } else if (const auto *NamespaceAlias =
543 Result.Nodes.getNodeAs<NamespaceAliasDecl>(
544 "namespace_alias")) {
545 NamespaceAliasDecls.insert(NamespaceAlias);
Eric Liub9bf1b52016-11-08 22:44:17546 } else if (const auto *NsDecl =
547 Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
Eric Liu495b2112016-09-19 17:40:32548 moveOldNamespace(Result, NsDecl);
549 } else if (const auto *FwdDecl =
Eric Liu41552d62016-12-07 14:20:52550 Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
551 moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
552 } else if (const auto *TemplateFwdDecl =
553 Result.Nodes.getNodeAs<ClassTemplateDecl>(
554 "template_class_fwd_decl")) {
555 moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
Eric Liub9bf1b52016-11-08 22:44:17556 } else if (const auto *UsingWithShadow =
557 Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
558 fixUsingShadowDecl(Result, UsingWithShadow);
Eric Liu68765a82016-09-21 15:06:12559 } else if (const auto *Specifier =
560 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
561 "nested_specifier_loc")) {
562 SourceLocation Start = Specifier->getBeginLoc();
Eric Liuc265b022016-12-01 17:25:55563 SourceLocation End = endLocationForType(Specifier->getTypeLoc());
Eric Liu68765a82016-09-21 15:06:12564 fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
Eric Liuff51f012016-11-16 16:54:53565 } else if (const auto *BaseInitializer =
566 Result.Nodes.getNodeAs<CXXCtorInitializer>(
567 "base_initializer")) {
568 BaseCtorInitializerTypeLocs.push_back(
569 BaseInitializer->getTypeSourceInfo()->getTypeLoc());
Eric Liu12068d82016-09-22 11:54:00570 } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
Eric Liu26cf68a2016-12-15 10:42:35571 // This avoids fixing types with record types as qualifier, which is not
572 // filtered by matchers in some cases, e.g. the type is templated. We should
573 // handle the record type qualifier instead.
Eric Liu0c0aea02016-12-15 13:02:41574 TypeLoc Loc = *TLoc;
575 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
576 Loc = Loc.getNextTypeLoc();
577 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
Eric Liu26cf68a2016-12-15 10:42:35578 NestedNameSpecifierLoc NestedNameSpecifier =
Eric Liu0c0aea02016-12-15 13:02:41579 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
Eric Liu5a6d57c2017-12-08 10:06:16580 // This happens for friend declaration of a base class with injected class
581 // name.
582 if (!NestedNameSpecifier.getNestedNameSpecifier())
583 return;
Eric Liu26cf68a2016-12-15 10:42:35584 const Type *SpecifierType =
585 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
586 if (SpecifierType && SpecifierType->isRecordType())
587 return;
588 }
Eric Liu0c0aea02016-12-15 13:02:41589 fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19590 } else if (const auto *VarRef =
591 Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
Eric Liu159f0132016-09-30 04:32:39592 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
593 assert(Var);
594 if (Var->getCanonicalDecl()->isStaticDataMember())
595 return;
Eric Liuda22b3c2016-11-29 14:15:14596 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu159f0132016-09-30 04:32:39597 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14598 fixDeclRefExpr(Result, Context->getDeclContext(),
599 llvm::cast<NamedDecl>(Var), VarRef);
Eric Liu0325a772017-02-02 17:40:38600 } else if (const auto *EnumConstRef =
601 Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
602 // Do not rename the reference if it is already scoped by the EnumDecl name.
603 if (EnumConstRef->hasQualifier() &&
Eric Liu28c30ce2017-02-02 19:46:12604 EnumConstRef->getQualifier()->getKind() ==
605 NestedNameSpecifier::SpecifierKind::TypeSpec &&
Eric Liu0325a772017-02-02 17:40:38606 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
607 return;
608 const auto *EnumConstDecl =
609 Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
610 assert(EnumConstDecl);
611 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
612 assert(Context && "Empty decl context.");
613 // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
614 // if it turns out to be an issue.
615 fixDeclRefExpr(Result, Context->getDeclContext(),
616 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
Eric Liuda22b3c2016-11-29 14:15:14617 } else if (const auto *FuncRef =
618 Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
Eric Liue3f35e42016-12-20 14:39:04619 // If this reference has been processed as a function call, we do not
620 // process it again.
621 if (ProcessedFuncRefs.count(FuncRef))
622 return;
623 ProcessedFuncRefs.insert(FuncRef);
Eric Liuda22b3c2016-11-29 14:15:14624 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
625 assert(Func);
626 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
627 assert(Context && "Empty decl context.");
628 fixDeclRefExpr(Result, Context->getDeclContext(),
629 llvm::cast<NamedDecl>(Func), FuncRef);
Eric Liu12068d82016-09-22 11:54:00630 } else {
Eric Liuda22b3c2016-11-29 14:15:14631 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19632 assert(Call != nullptr && "Expecting callback for CallExpr.");
Eric Liue3f35e42016-12-20 14:39:04633 const auto *CalleeFuncRef =
634 llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
635 ProcessedFuncRefs.insert(CalleeFuncRef);
Eric Liuda22b3c2016-11-29 14:15:14636 const FunctionDecl *Func = Call->getDirectCallee();
Eric Liu12068d82016-09-22 11:54:00637 assert(Func != nullptr);
Eric Liue3f35e42016-12-20 14:39:04638 // FIXME: ignore overloaded operators. This would miss cases where operators
639 // are called by qualified names (i.e. "ns::operator <"). Ignore such
640 // cases for now.
641 if (Func->isOverloadedOperator())
642 return;
Eric Liu12068d82016-09-22 11:54:00643 // Ignore out-of-line static methods since they will be handled by nested
644 // name specifiers.
645 if (Func->getCanonicalDecl()->getStorageClass() ==
Eric Liuda22b3c2016-11-29 14:15:14646 StorageClass::SC_Static &&
Eric Liu12068d82016-09-22 11:54:00647 Func->isOutOfLine())
648 return;
Eric Liuda22b3c2016-11-29 14:15:14649 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu12068d82016-09-22 11:54:00650 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14651 SourceRange CalleeRange = Call->getCallee()->getSourceRange();
Eric Liub9bf1b52016-11-08 22:44:17652 replaceQualifiedSymbolInDeclContext(
653 Result, Context->getDeclContext(), CalleeRange.getBegin(),
Eric Liu231c6552016-11-10 18:15:34654 CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
Eric Liu495b2112016-09-19 17:40:32655 }
656}
657
Eric Liu73f49fd2016-10-12 12:34:18658static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
659 const SourceManager &SM,
660 const LangOptions &LangOpts) {
661 std::unique_ptr<Lexer> Lex =
Stephen Kelly43465bf2018-08-09 22:42:26662 getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
Eric Liu73f49fd2016-10-12 12:34:18663 assert(Lex.get() &&
664 "Failed to create lexer from the beginning of namespace.");
665 if (!Lex.get())
666 return SourceLocation();
667 Token Tok;
668 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
669 }
670 return Tok.isNot(tok::TokenKind::l_brace)
671 ? SourceLocation()
672 : Tok.getEndLoc().getLocWithOffset(1);
673}
674
Eric Liu495b2112016-09-19 17:40:32675// Stores information about a moved namespace in `MoveNamespaces` and leaves
676// the actual movement to `onEndOfTranslationUnit()`.
677void ChangeNamespaceTool::moveOldNamespace(
678 const ast_matchers::MatchFinder::MatchResult &Result,
679 const NamespaceDecl *NsDecl) {
680 // If the namespace is empty, do nothing.
681 if (Decl::castToDeclContext(NsDecl)->decls_empty())
682 return;
683
Eric Liuee5104b2017-01-04 14:49:08684 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32685 // Get the range of the code in the old namespace.
Eric Liuee5104b2017-01-04 14:49:08686 SourceLocation Start =
687 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
Eric Liu73f49fd2016-10-12 12:34:18688 assert(Start.isValid() && "Can't find l_brace for namespace.");
Eric Liu495b2112016-09-19 17:40:32689 MoveNamespace MoveNs;
Eric Liuee5104b2017-01-04 14:49:08690 MoveNs.Offset = SM.getFileOffset(Start);
691 // The range of the moved namespace is from the location just past the left
692 // brace to the location right before the right brace.
693 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
Eric Liu495b2112016-09-19 17:40:32694
695 // Insert the new namespace after `DiffOldNamespace`. For example, if
696 // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
697 // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
698 // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
699 // in the above example.
Eric Liu6aa94162016-11-10 18:29:01700 // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
701 // namespace will be a nested namespace in the old namespace.
Eric Liu495b2112016-09-19 17:40:32702 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
Eric Liu6aa94162016-11-10 18:29:01703 SourceLocation InsertionLoc = Start;
704 if (OuterNs) {
Eric Liuee5104b2017-01-04 14:49:08705 SourceLocation LocAfterNs = getStartOfNextLine(
706 OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
Eric Liu6aa94162016-11-10 18:29:01707 assert(LocAfterNs.isValid() &&
708 "Failed to get location after DiffOldNamespace");
709 InsertionLoc = LocAfterNs;
710 }
Eric Liuee5104b2017-01-04 14:49:08711 MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
712 MoveNs.FID = SM.getFileID(Start);
Eric Liucc83c662016-09-19 17:58:59713 MoveNs.SourceMgr = Result.SourceManager;
Benjamin Krameradcd0262020-01-28 19:23:46714 MoveNamespaces[std::string(SM.getFilename(Start))].push_back(MoveNs);
Eric Liu495b2112016-09-19 17:40:32715}
716
717// Removes a class forward declaration from the code in the moved namespace and
718// creates an `InsertForwardDeclaration` to insert the forward declaration back
719// into the old namespace after moving code from the old namespace to the new
720// namespace.
721// For example, changing "a" to "x":
722// Old code:
723// namespace a {
724// class FWD;
725// class A { FWD *fwd; }
726// } // a
727// New code:
728// namespace a {
729// class FWD;
730// } // a
731// namespace x {
732// class A { a::FWD *fwd; }
733// } // x
734void ChangeNamespaceTool::moveClassForwardDeclaration(
735 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liu41552d62016-12-07 14:20:52736 const NamedDecl *FwdDecl) {
Stephen Kelly43465bf2018-08-09 22:42:26737 SourceLocation Start = FwdDecl->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02738 SourceLocation End = FwdDecl->getEndLoc();
Eric Liu41367152017-03-01 10:29:39739 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32740 SourceLocation AfterSemi = Lexer::findLocationAfterToken(
Eric Liu41367152017-03-01 10:29:39741 End, tok::semi, SM, Result.Context->getLangOpts(),
Eric Liu495b2112016-09-19 17:40:32742 /*SkipTrailingWhitespaceAndNewLine=*/true);
743 if (AfterSemi.isValid())
744 End = AfterSemi.getLocWithOffset(-1);
745 // Delete the forward declaration from the code to be moved.
Eric Liu41367152017-03-01 10:29:39746 addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32747 llvm::StringRef Code = Lexer::getSourceText(
Eric Liu41367152017-03-01 10:29:39748 CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
749 SM.getSpellingLoc(End)),
750 SM, Result.Context->getLangOpts());
Eric Liu495b2112016-09-19 17:40:32751 // Insert the forward declaration back into the old namespace after moving the
752 // code from old namespace to new namespace.
753 // Insertion information is stored in `InsertFwdDecls` and actual
754 // insertion will be performed in `onEndOfTranslationUnit`.
755 // Get the (old) namespace that contains the forward declaration.
756 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
757 // The namespace contains the forward declaration, so it must not be empty.
758 assert(!NsDecl->decls_empty());
Eric Liu41367152017-03-01 10:29:39759 const auto Insertion = createInsertion(
760 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
761 Code, SM);
Eric Liu495b2112016-09-19 17:40:32762 InsertForwardDeclaration InsertFwd;
763 InsertFwd.InsertionOffset = Insertion.getOffset();
764 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
Benjamin Krameradcd0262020-01-28 19:23:46765 InsertFwdDecls[std::string(Insertion.getFilePath())].push_back(InsertFwd);
Eric Liu495b2112016-09-19 17:40:32766}
767
Eric Liub9bf1b52016-11-08 22:44:17768// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
769// FromDecl with the shortest qualified name possible when the reference is in
770// `NewNamespace`.
Eric Liu495b2112016-09-19 17:40:32771void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
Eric Liub9bf1b52016-11-08 22:44:17772 const ast_matchers::MatchFinder::MatchResult &Result,
773 const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
774 const NamedDecl *FromDecl) {
775 const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
Eric Liu4fe99e12016-12-14 17:01:52776 if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
777 // This should not happen in usual unless the TypeLoc is in function type
778 // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
779 // `T` will be the translation unit. We simply use fully-qualified name
780 // here.
781 // Note that `FromDecl` must not be defined in the old namespace (according
782 // to `DeclMatcher`), so its fully-qualified name will not change after
783 // changing the namespace.
784 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
785 *Result.SourceManager, &FileToReplacements);
786 return;
787 }
Eric Liu231c6552016-11-10 18:15:34788 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
Eric Liu495b2112016-09-19 17:40:32789 // Calculate the name of the `NsDecl` after it is moved to new namespace.
790 std::string OldNs = NsDecl->getQualifiedNameAsString();
791 llvm::StringRef Postfix = OldNs;
792 bool Consumed = Postfix.consume_front(OldNamespace);
793 assert(Consumed && "Expect OldNS to start with OldNamespace.");
794 (void)Consumed;
795 const std::string NewNs = (NewNamespace + Postfix).str();
796
797 llvm::StringRef NestedName = Lexer::getSourceText(
798 CharSourceRange::getTokenRange(
799 Result.SourceManager->getSpellingLoc(Start),
800 Result.SourceManager->getSpellingLoc(End)),
801 *Result.SourceManager, Result.Context->getLangOpts());
Eric Liub9bf1b52016-11-08 22:44:17802 std::string FromDeclName = FromDecl->getQualifiedNameAsString();
Eric Christopher25ed42f2020-06-20 06:01:42803 for (llvm::Regex &RE : AllowedSymbolRegexes)
Eric Liu7fccc992017-02-24 11:54:45804 if (RE.match(FromDeclName))
805 return;
Eric Liu495b2112016-09-19 17:40:32806 std::string ReplaceName =
Eric Liub9bf1b52016-11-08 22:44:17807 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
808 // Checks if there is any using namespace declarations that can shorten the
809 // qualified name.
810 for (const auto *UsingNamespace : UsingNamespaceDecls) {
811 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
812 Start))
813 continue;
814 StringRef FromDeclNameRef = FromDeclName;
815 if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
816 ->getQualifiedNameAsString())) {
817 FromDeclNameRef = FromDeclNameRef.drop_front(2);
818 if (FromDeclNameRef.size() < ReplaceName.size())
Benjamin Krameradcd0262020-01-28 19:23:46819 ReplaceName = std::string(FromDeclNameRef);
Eric Liub9bf1b52016-11-08 22:44:17820 }
821 }
Eric Liu180dac62016-12-23 10:47:09822 // Checks if there is any namespace alias declarations that can shorten the
823 // qualified name.
824 for (const auto *NamespaceAlias : NamespaceAliasDecls) {
825 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
826 Start))
827 continue;
828 StringRef FromDeclNameRef = FromDeclName;
829 if (FromDeclNameRef.consume_front(
830 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
831 "::")) {
832 std::string AliasName = NamespaceAlias->getNameAsString();
833 std::string AliasQualifiedName =
834 NamespaceAlias->getQualifiedNameAsString();
Kazuaki Ishizakidd5571d2020-04-05 06:28:11835 // We only consider namespace aliases define in the global namespace or
Eric Liu180dac62016-12-23 10:47:09836 // in namespaces that are directly visible from the reference, i.e.
837 // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
838 // but not visible in the new namespace is filtered out by
839 // "IsVisibleInNewNs" matcher.
840 if (AliasQualifiedName != AliasName) {
841 // The alias is defined in some namespace.
842 assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
843 llvm::StringRef AliasNs =
844 StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
845 if (!llvm::StringRef(OldNs).startswith(AliasNs))
846 continue;
847 }
848 std::string NameWithAliasNamespace =
849 (AliasName + "::" + FromDeclNameRef).str();
850 if (NameWithAliasNamespace.size() < ReplaceName.size())
851 ReplaceName = NameWithAliasNamespace;
852 }
853 }
Eric Liub9bf1b52016-11-08 22:44:17854 // Checks if there is any using shadow declarations that can shorten the
855 // qualified name.
856 bool Matched = false;
857 for (const UsingDecl *Using : UsingDecls) {
858 if (Matched)
859 break;
860 if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
861 for (const auto *UsingShadow : Using->shadows()) {
862 const auto *TargetDecl = UsingShadow->getTargetDecl();
Eric Liuae7de712017-02-02 15:29:54863 if (TargetDecl->getQualifiedNameAsString() ==
864 FromDecl->getQualifiedNameAsString()) {
Eric Liub9bf1b52016-11-08 22:44:17865 ReplaceName = FromDecl->getNameAsString();
866 Matched = true;
867 break;
868 }
869 }
870 }
871 }
Eric Liuc6c894b2018-10-22 12:48:49872 bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
873 ReplaceName, NewNamespace);
Eric Liu495b2112016-09-19 17:40:32874 // If the new nested name in the new namespace is the same as it was in the
Eric Liuc6c894b2018-10-22 12:48:49875 // old namespace, we don't create replacement unless there can be ambiguity.
876 if ((NestedName == ReplaceName && !Conflict) ||
Eric Liu91229162017-01-26 16:31:32877 (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
Eric Liu495b2112016-09-19 17:40:32878 return;
Eric Liu97f87ad2016-12-07 20:08:02879 // If the reference need to be fully-qualified, add a leading "::" unless
880 // NewNamespace is the global namespace.
Eric Liuc6c894b2018-10-22 12:48:49881 if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
Eric Liu97f87ad2016-12-07 20:08:02882 ReplaceName = "::" + ReplaceName;
Eric Liu4fe99e12016-12-14 17:01:52883 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
884 &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32885}
886
887// Replace the [Start, End] of `Type` with the shortest qualified name when the
888// `Type` is in `NewNamespace`.
889void ChangeNamespaceTool::fixTypeLoc(
890 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
891 SourceLocation End, TypeLoc Type) {
892 // FIXME: do not rename template parameter.
893 if (Start.isInvalid() || End.isInvalid())
894 return;
Eric Liuff51f012016-11-16 16:54:53895 // Types of CXXCtorInitializers do not need to be fixed.
896 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
897 return;
Eric Liu284b97c2017-03-17 14:05:39898 if (isTemplateParameter(Type))
899 return;
Eric Liu495b2112016-09-19 17:40:32900 // The declaration which this TypeLoc refers to.
901 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
902 // `hasDeclaration` gives underlying declaration, but if the type is
903 // a typedef type, we need to use the typedef type instead.
Eric Liu26cf68a2016-12-15 10:42:35904 auto IsInMovedNs = [&](const NamedDecl *D) {
905 if (!llvm::StringRef(D->getQualifiedNameAsString())
906 .startswith(OldNamespace + "::"))
907 return false;
Stephen Kelly43465bf2018-08-09 22:42:26908 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
Eric Liu26cf68a2016-12-15 10:42:35909 if (ExpansionLoc.isInvalid())
910 return false;
911 llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
912 return FilePatternRE.match(Filename);
913 };
914 // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
915 // `Type` is an alias type, we make `FromDecl` the type alias declaration.
916 // Also, don't fix the \p Type if it refers to a type alias decl in the moved
917 // namespace since the alias decl will be moved along with the type reference.
Eric Liu32158862016-11-14 19:37:55918 if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
Eric Liu495b2112016-09-19 17:40:32919 FromDecl = Typedef->getDecl();
Eric Liu32158862016-11-14 19:37:55920 if (IsInMovedNs(FromDecl))
921 return;
Eric Liu26cf68a2016-12-15 10:42:35922 } else if (auto *TemplateType =
923 Type.getType()->getAs<TemplateSpecializationType>()) {
924 if (TemplateType->isTypeAlias()) {
925 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
926 if (IsInMovedNs(FromDecl))
927 return;
928 }
Eric Liu32158862016-11-14 19:37:55929 }
Piotr Padlewski08124b12016-12-14 15:29:23930 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu495b2112016-09-19 17:40:32931 assert(DeclCtx && "Empty decl context.");
Eric Liub9bf1b52016-11-08 22:44:17932 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
933 End, FromDecl);
Eric Liu495b2112016-09-19 17:40:32934}
935
Eric Liu68765a82016-09-21 15:06:12936void ChangeNamespaceTool::fixUsingShadowDecl(
937 const ast_matchers::MatchFinder::MatchResult &Result,
938 const UsingDecl *UsingDeclaration) {
Stephen Kelly43465bf2018-08-09 22:42:26939 SourceLocation Start = UsingDeclaration->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02940 SourceLocation End = UsingDeclaration->getEndLoc();
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19941 if (Start.isInvalid() || End.isInvalid())
942 return;
Eric Liu68765a82016-09-21 15:06:12943
944 assert(UsingDeclaration->shadow_size() > 0);
945 // FIXME: it might not be always accurate to use the first using-decl.
946 const NamedDecl *TargetDecl =
947 UsingDeclaration->shadow_begin()->getTargetDecl();
948 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
949 // FIXME: check if target_decl_name is in moved ns, which doesn't make much
950 // sense. If this happens, we need to use name with the new namespace.
951 // Use fully qualified name in UsingDecl for now.
Eric Liu4fe99e12016-12-14 17:01:52952 addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
953 *Result.SourceManager, &FileToReplacements);
Eric Liu68765a82016-09-21 15:06:12954}
955
Eric Liuda22b3c2016-11-29 14:15:14956void ChangeNamespaceTool::fixDeclRefExpr(
957 const ast_matchers::MatchFinder::MatchResult &Result,
958 const DeclContext *UseContext, const NamedDecl *From,
959 const DeclRefExpr *Ref) {
960 SourceRange RefRange = Ref->getSourceRange();
961 replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
962 RefRange.getEnd(), From);
963}
964
Eric Liu495b2112016-09-19 17:40:32965void ChangeNamespaceTool::onEndOfTranslationUnit() {
966 // Move namespace blocks and insert forward declaration to old namespace.
967 for (const auto &FileAndNsMoves : MoveNamespaces) {
968 auto &NsMoves = FileAndNsMoves.second;
969 if (NsMoves.empty())
970 continue;
971 const std::string &FilePath = FileAndNsMoves.first;
972 auto &Replaces = FileToReplacements[FilePath];
Eric Liucc83c662016-09-19 17:58:59973 auto &SM = *NsMoves.begin()->SourceMgr;
974 llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
Eric Liu495b2112016-09-19 17:40:32975 auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
976 if (!ChangedCode) {
977 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
978 continue;
979 }
980 // Replacements on the changed code for moving namespaces and inserting
981 // forward declarations to old namespaces.
982 tooling::Replacements NewReplacements;
983 // Cut the changed code from the old namespace and paste the code in the new
984 // namespace.
985 for (const auto &NsMove : NsMoves) {
986 // Calculate the range of the old namespace block in the changed
987 // code.
988 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
989 const unsigned NewLength =
990 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
991 NewOffset;
992 tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
993 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
994 std::string MovedCodeWrappedInNewNs =
995 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
996 // Calculate the new offset at which the code will be inserted in the
997 // changed code.
998 unsigned NewInsertionOffset =
999 Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
1000 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1001 MovedCodeWrappedInNewNs);
1002 addOrMergeReplacement(Deletion, &NewReplacements);
1003 addOrMergeReplacement(Insertion, &NewReplacements);
1004 }
1005 // After moving namespaces, insert forward declarations back to old
1006 // namespaces.
1007 const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
1008 for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
1009 unsigned NewInsertionOffset =
1010 Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
1011 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1012 FwdDeclInsertion.ForwardDeclText);
1013 addOrMergeReplacement(Insertion, &NewReplacements);
1014 }
1015 // Add replacements referring to the changed code to existing replacements,
1016 // which refers to the original code.
1017 Replaces = Replaces.merge(NewReplacements);
Eric Liufa63e982018-08-02 10:30:561018 auto Style =
1019 format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
Antonio Maiorano0d7d9c22017-01-17 00:13:321020 if (!Style) {
1021 llvm::errs() << llvm::toString(Style.takeError()) << "\n";
1022 continue;
1023 }
Eric Liu495b2112016-09-19 17:40:321024 // Clean up old namespaces if there is nothing in it after moving.
1025 auto CleanReplacements =
Antonio Maiorano0d7d9c22017-01-17 00:13:321026 format::cleanupAroundReplacements(Code, Replaces, *Style);
Eric Liu495b2112016-09-19 17:40:321027 if (!CleanReplacements) {
1028 llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
1029 continue;
1030 }
1031 FileToReplacements[FilePath] = *CleanReplacements;
1032 }
Eric Liuc265b022016-12-01 17:25:551033
1034 // Make sure we don't generate replacements for files that do not match
1035 // FilePattern.
1036 for (auto &Entry : FileToReplacements)
1037 if (!FilePatternRE.match(Entry.first))
1038 Entry.second.clear();
Eric Liu495b2112016-09-19 17:40:321039}
1040
1041} // namespace change_namespace
1042} // namespace clang