blob: 61ae7c4cc7036cc7bcede9952808e8ef872054b6 [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
Nathan James6a3b10e2020-07-09 10:29:4922inline std::string joinNamespaces(ArrayRef<StringRef> Namespaces) {
23 return llvm::join(Namespaces, "::");
Eric Liu495b2112016-09-19 17:40:3224}
25
Eric Liu8bc24162017-03-21 12:41:5926// Given "a::b::c", returns {"a", "b", "c"}.
27llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef Name) {
28 llvm::SmallVector<llvm::StringRef, 4> Splitted;
29 Name.split(Splitted, "::", /*MaxSplit=*/-1,
30 /*KeepEmpty=*/false);
31 return Splitted;
32}
33
Eric Liu495b2112016-09-19 17:40:3234SourceLocation startLocationForType(TypeLoc TLoc) {
35 // For elaborated types (e.g. `struct a::A`) we want the portion after the
36 // `struct` but including the namespace qualifier, `a::`.
37 if (TLoc.getTypeLocClass() == TypeLoc::Elaborated) {
38 NestedNameSpecifierLoc NestedNameSpecifier =
39 TLoc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
40 if (NestedNameSpecifier.getNestedNameSpecifier())
41 return NestedNameSpecifier.getBeginLoc();
42 TLoc = TLoc.getNextTypeLoc();
43 }
Stephen Kelly43465bf2018-08-09 22:42:2644 return TLoc.getBeginLoc();
Eric Liu495b2112016-09-19 17:40:3245}
46
Eric Liuc265b022016-12-01 17:25:5547SourceLocation endLocationForType(TypeLoc TLoc) {
Eric Liu495b2112016-09-19 17:40:3248 // Dig past any namespace or keyword qualifications.
49 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
50 TLoc.getTypeLocClass() == TypeLoc::Qualified)
51 TLoc = TLoc.getNextTypeLoc();
52
53 // The location for template specializations (e.g. Foo<int>) includes the
54 // templated types in its location range. We want to restrict this to just
55 // before the `<` character.
56 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
57 return TLoc.castAs<TemplateSpecializationTypeLoc>()
58 .getLAngleLoc()
59 .getLocWithOffset(-1);
60 return TLoc.getEndLoc();
61}
62
63// Returns the containing namespace of `InnerNs` by skipping `PartialNsName`.
Eric Liu6aa94162016-11-10 18:29:0164// If the `InnerNs` does not have `PartialNsName` as suffix, or `PartialNsName`
65// is empty, nullptr is returned.
Eric Liu495b2112016-09-19 17:40:3266// For example, if `InnerNs` is "a::b::c" and `PartialNsName` is "b::c", then
67// the NamespaceDecl of namespace "a" will be returned.
68const NamespaceDecl *getOuterNamespace(const NamespaceDecl *InnerNs,
69 llvm::StringRef PartialNsName) {
Eric Liu6aa94162016-11-10 18:29:0170 if (!InnerNs || PartialNsName.empty())
71 return nullptr;
Eric Liu495b2112016-09-19 17:40:3272 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
73 const auto *CurrentNs = InnerNs;
Eric Liu8bc24162017-03-21 12:41:5974 auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
Eric Liu495b2112016-09-19 17:40:3275 while (!PartialNsNameSplitted.empty()) {
76 // Get the inner-most namespace in CurrentContext.
77 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
78 CurrentContext = CurrentContext->getParent();
79 if (!CurrentContext)
80 return nullptr;
81 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
82 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
83 return nullptr;
84 PartialNsNameSplitted.pop_back();
85 CurrentContext = CurrentContext->getParent();
86 }
87 return CurrentNs;
88}
89
Eric Liu73f49fd2016-10-12 12:34:1890static std::unique_ptr<Lexer>
91getLexerStartingFromLoc(SourceLocation Loc, const SourceManager &SM,
92 const LangOptions &LangOpts) {
Eric Liu495b2112016-09-19 17:40:3293 if (Loc.isMacroID() &&
94 !Lexer::isAtEndOfMacroExpansion(Loc, SM, LangOpts, &Loc))
Eric Liu73f49fd2016-10-12 12:34:1895 return nullptr;
Eric Liu495b2112016-09-19 17:40:3296 // Break down the source location.
97 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
98 // Try to load the file buffer.
99 bool InvalidTemp = false;
100 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
101 if (InvalidTemp)
Eric Liu73f49fd2016-10-12 12:34:18102 return nullptr;
Eric Liu495b2112016-09-19 17:40:32103
104 const char *TokBegin = File.data() + LocInfo.second;
105 // Lex from the start of the given location.
Jonas Devlieghere1c705d92019-08-14 23:52:23106 return std::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
Eric Liu73f49fd2016-10-12 12:34:18107 LangOpts, File.begin(), TokBegin, File.end());
108}
Eric Liu495b2112016-09-19 17:40:32109
Eric Liu73f49fd2016-10-12 12:34:18110// FIXME: get rid of this helper function if this is supported in clang-refactor
111// library.
112static SourceLocation getStartOfNextLine(SourceLocation Loc,
113 const SourceManager &SM,
114 const LangOptions &LangOpts) {
115 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
116 if (!Lex.get())
117 return SourceLocation();
Eric Liu495b2112016-09-19 17:40:32118 llvm::SmallVector<char, 16> Line;
119 // FIXME: this is a bit hacky to get ReadToEndOfLine work.
Eric Liu73f49fd2016-10-12 12:34:18120 Lex->setParsingPreprocessorDirective(true);
121 Lex->ReadToEndOfLine(&Line);
Haojian Wuef8a6dc2016-10-04 10:35:53122 auto End = Loc.getLocWithOffset(Line.size());
Eric Liu73f49fd2016-10-12 12:34:18123 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
124 ? End
125 : End.getLocWithOffset(1);
Eric Liu495b2112016-09-19 17:40:32126}
127
128// Returns `R` with new range that refers to code after `Replaces` being
129// applied.
130tooling::Replacement
131getReplacementInChangedCode(const tooling::Replacements &Replaces,
132 const tooling::Replacement &R) {
133 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
134 unsigned NewEnd =
135 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
136 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
137 R.getReplacementText());
138}
139
140// Adds a replacement `R` into `Replaces` or merges it into `Replaces` by
141// applying all existing Replaces first if there is conflict.
142void addOrMergeReplacement(const tooling::Replacement &R,
143 tooling::Replacements *Replaces) {
144 auto Err = Replaces->add(R);
145 if (Err) {
146 llvm::consumeError(std::move(Err));
147 auto Replace = getReplacementInChangedCode(*Replaces, R);
148 *Replaces = Replaces->merge(tooling::Replacements(Replace));
149 }
150}
151
152tooling::Replacement createReplacement(SourceLocation Start, SourceLocation End,
153 llvm::StringRef ReplacementText,
154 const SourceManager &SM) {
155 if (!Start.isValid() || !End.isValid()) {
156 llvm::errs() << "start or end location were invalid\n";
157 return tooling::Replacement();
158 }
159 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
160 llvm::errs()
161 << "start or end location were in different macro expansions\n";
162 return tooling::Replacement();
163 }
164 Start = SM.getSpellingLoc(Start);
165 End = SM.getSpellingLoc(End);
166 if (SM.getFileID(Start) != SM.getFileID(End)) {
167 llvm::errs() << "start or end location were in different files\n";
168 return tooling::Replacement();
169 }
170 return tooling::Replacement(
171 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
172 SM.getSpellingLoc(End)),
173 ReplacementText);
174}
175
Eric Liu4fe99e12016-12-14 17:01:52176void addReplacementOrDie(
177 SourceLocation Start, SourceLocation End, llvm::StringRef ReplacementText,
178 const SourceManager &SM,
179 std::map<std::string, tooling::Replacements> *FileToReplacements) {
180 const auto R = createReplacement(Start, End, ReplacementText, SM);
Benjamin Krameradcd0262020-01-28 19:23:46181 auto Err = (*FileToReplacements)[std::string(R.getFilePath())].add(R);
Eric Liu4fe99e12016-12-14 17:01:52182 if (Err)
183 llvm_unreachable(llvm::toString(std::move(Err)).c_str());
184}
185
Eric Liu495b2112016-09-19 17:40:32186tooling::Replacement createInsertion(SourceLocation Loc,
187 llvm::StringRef InsertText,
188 const SourceManager &SM) {
189 if (Loc.isInvalid()) {
190 llvm::errs() << "insert Location is invalid.\n";
191 return tooling::Replacement();
192 }
193 Loc = SM.getSpellingLoc(Loc);
194 return tooling::Replacement(SM, Loc, 0, InsertText);
195}
196
197// Returns the shortest qualified name for declaration `DeclName` in the
198// namespace `NsName`. For example, if `DeclName` is "a::b::X" and `NsName`
199// is "a::c::d", then "b::X" will be returned.
Eric Liubc715502017-01-26 15:08:44200// Note that if `DeclName` is `::b::X` and `NsName` is `::a::b`, this returns
201// "::b::X" instead of "b::X" since there will be a name conflict otherwise.
Eric Liu447164d2016-10-05 15:52:39202// \param DeclName A fully qualified name, "::a::b::X" or "a::b::X".
203// \param NsName A fully qualified name, "::a::b" or "a::b". Global namespace
204// will have empty name.
Eric Liu495b2112016-09-19 17:40:32205std::string getShortestQualifiedNameInNamespace(llvm::StringRef DeclName,
206 llvm::StringRef NsName) {
Eric Liu447164d2016-10-05 15:52:39207 DeclName = DeclName.ltrim(':');
208 NsName = NsName.ltrim(':');
Eric Liu447164d2016-10-05 15:52:39209 if (DeclName.find(':') == llvm::StringRef::npos)
Benjamin Krameradcd0262020-01-28 19:23:46210 return std::string(DeclName);
Eric Liu447164d2016-10-05 15:52:39211
Eric Liu8bc24162017-03-21 12:41:59212 auto NsNameSplitted = splitSymbolName(NsName);
213 auto DeclNsSplitted = splitSymbolName(DeclName);
Eric Liubc715502017-01-26 15:08:44214 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
215 // If the Decl is in global namespace, there is no need to shorten it.
216 if (DeclNsSplitted.empty())
Benjamin Krameradcd0262020-01-28 19:23:46217 return std::string(UnqualifiedDeclName);
Eric Liubc715502017-01-26 15:08:44218 // If NsName is the global namespace, we can simply use the DeclName sans
219 // leading "::".
220 if (NsNameSplitted.empty())
Benjamin Krameradcd0262020-01-28 19:23:46221 return std::string(DeclName);
Eric Liubc715502017-01-26 15:08:44222
223 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
224 // The DeclName must be fully-qualified, but we still need to decide if a
225 // leading "::" is necessary. For example, if `NsName` is "a::b::c" and the
226 // `DeclName` is "b::X", then the reference must be qualified as "::b::X"
227 // to avoid conflict.
228 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
229 return ("::" + DeclName).str();
Benjamin Krameradcd0262020-01-28 19:23:46230 return std::string(DeclName);
Eric Liu495b2112016-09-19 17:40:32231 }
Eric Liubc715502017-01-26 15:08:44232 // Since there is already an overlap namespace, we know that `DeclName` can be
233 // shortened, so we reduce the longest common prefix.
234 auto DeclI = DeclNsSplitted.begin();
235 auto DeclE = DeclNsSplitted.end();
236 auto NsI = NsNameSplitted.begin();
237 auto NsE = NsNameSplitted.end();
238 for (; DeclI != DeclE && NsI != NsE && *DeclI == *NsI; ++DeclI, ++NsI) {
239 }
240 return (DeclI == DeclE)
241 ? UnqualifiedDeclName.str()
242 : (llvm::join(DeclI, DeclE, "::") + "::" + UnqualifiedDeclName)
243 .str();
Eric Liu495b2112016-09-19 17:40:32244}
245
246std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
247 if (Code.back() != '\n')
248 Code += "\n";
Eric Liu8bc24162017-03-21 12:41:59249 auto NsSplitted = splitSymbolName(NestedNs);
Eric Liu495b2112016-09-19 17:40:32250 while (!NsSplitted.empty()) {
251 // FIXME: consider code style for comments.
252 Code = ("namespace " + NsSplitted.back() + " {\n" + Code +
253 "} // namespace " + NsSplitted.back() + "\n")
254 .str();
255 NsSplitted.pop_back();
256 }
257 return Code;
258}
259
Eric Liub9bf1b52016-11-08 22:44:17260// Returns true if \p D is a nested DeclContext in \p Context
261bool isNestedDeclContext(const DeclContext *D, const DeclContext *Context) {
262 while (D) {
263 if (D == Context)
264 return true;
265 D = D->getParent();
266 }
267 return false;
268}
269
270// Returns true if \p D is visible at \p Loc with DeclContext \p DeclCtx.
271bool isDeclVisibleAtLocation(const SourceManager &SM, const Decl *D,
272 const DeclContext *DeclCtx, SourceLocation Loc) {
Stephen Kelly43465bf2018-08-09 22:42:26273 SourceLocation DeclLoc = SM.getSpellingLoc(D->getBeginLoc());
Eric Liub9bf1b52016-11-08 22:44:17274 Loc = SM.getSpellingLoc(Loc);
275 return SM.isBeforeInTranslationUnit(DeclLoc, Loc) &&
276 (SM.getFileID(DeclLoc) == SM.getFileID(Loc) &&
277 isNestedDeclContext(DeclCtx, D->getDeclContext()));
278}
279
Eric Liu8bc24162017-03-21 12:41:59280// Given a qualified symbol name, returns true if the symbol will be
Eric Liuc6c894b2018-10-22 12:48:49281// incorrectly qualified without leading "::". For example, a symbol
282// "nx::ny::Foo" in namespace "na::nx::ny" without leading "::"; a symbol
283// "util::X" in namespace "na" can potentially conflict with "na::util" (if this
284// exists).
285bool conflictInNamespace(const ASTContext &AST, llvm::StringRef QualifiedSymbol,
Eric Liu8bc24162017-03-21 12:41:59286 llvm::StringRef Namespace) {
287 auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(":"));
288 assert(!SymbolSplitted.empty());
289 SymbolSplitted.pop_back(); // We are only interested in namespaces.
290
Eric Liuc6c894b2018-10-22 12:48:49291 if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
292 auto SymbolTopNs = SymbolSplitted.front();
Eric Liu8bc24162017-03-21 12:41:59293 auto NsSplitted = splitSymbolName(Namespace.trim(":"));
294 assert(!NsSplitted.empty());
Eric Liuc6c894b2018-10-22 12:48:49295
296 auto LookupDecl = [&AST](const Decl &Scope,
297 llvm::StringRef Name) -> const NamedDecl * {
298 const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
299 if (!DC)
300 return nullptr;
301 auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
302 if (LookupRes.empty())
303 return nullptr;
304 return LookupRes.front();
305 };
306 // We do not check the outermost namespace since it would not be a
307 // conflict if it equals to the symbol's outermost namespace and the
308 // symbol name would have been shortened.
309 const NamedDecl *Scope =
310 LookupDecl(*AST.getTranslationUnitDecl(), NsSplitted.front());
Eric Liu8bc24162017-03-21 12:41:59311 for (auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
Eric Liuc6c894b2018-10-22 12:48:49312 if (*I == SymbolTopNs) // Handles "::ny" in "::nx::ny" case.
Eric Liu8bc24162017-03-21 12:41:59313 return true;
Eric Liuc6c894b2018-10-22 12:48:49314 // Handles "::util" and "::nx::util" conflicts.
315 if (Scope) {
316 if (LookupDecl(*Scope, SymbolTopNs))
317 return true;
318 Scope = LookupDecl(*Scope, *I);
319 }
Eric Liu8bc24162017-03-21 12:41:59320 }
Eric Liuc6c894b2018-10-22 12:48:49321 if (Scope && LookupDecl(*Scope, SymbolTopNs))
322 return true;
Eric Liu8bc24162017-03-21 12:41:59323 }
324 return false;
325}
326
Eric Liu0325a772017-02-02 17:40:38327AST_MATCHER(EnumDecl, isScoped) {
328 return Node.isScoped();
329}
330
Eric Liu284b97c2017-03-17 14:05:39331bool isTemplateParameter(TypeLoc Type) {
332 while (!Type.isNull()) {
333 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
334 return true;
335 Type = Type.getNextTypeLoc();
336 }
337 return false;
338}
339
Eric Liu495b2112016-09-19 17:40:32340} // anonymous namespace
341
342ChangeNamespaceTool::ChangeNamespaceTool(
343 llvm::StringRef OldNs, llvm::StringRef NewNs, llvm::StringRef FilePattern,
Eric Christopher25ed42f2020-06-20 06:01:42344 llvm::ArrayRef<std::string> AllowedSymbolPatterns,
Eric Liu495b2112016-09-19 17:40:32345 std::map<std::string, tooling::Replacements> *FileToReplacements,
346 llvm::StringRef FallbackStyle)
347 : FallbackStyle(FallbackStyle), FileToReplacements(*FileToReplacements),
348 OldNamespace(OldNs.ltrim(':')), NewNamespace(NewNs.ltrim(':')),
Eric Liuc265b022016-12-01 17:25:55349 FilePattern(FilePattern), FilePatternRE(FilePattern) {
Eric Liu495b2112016-09-19 17:40:32350 FileToReplacements->clear();
Eric Liu8bc24162017-03-21 12:41:59351 auto OldNsSplitted = splitSymbolName(OldNamespace);
352 auto NewNsSplitted = splitSymbolName(NewNamespace);
Eric Liu495b2112016-09-19 17:40:32353 // Calculates `DiffOldNamespace` and `DiffNewNamespace`.
354 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
355 OldNsSplitted.front() == NewNsSplitted.front()) {
356 OldNsSplitted.erase(OldNsSplitted.begin());
357 NewNsSplitted.erase(NewNsSplitted.begin());
358 }
359 DiffOldNamespace = joinNamespaces(OldNsSplitted);
360 DiffNewNamespace = joinNamespaces(NewNsSplitted);
Eric Liu7fccc992017-02-24 11:54:45361
Eric Christopher25ed42f2020-06-20 06:01:42362 for (const auto &Pattern : AllowedSymbolPatterns)
363 AllowedSymbolRegexes.emplace_back(Pattern);
Eric Liu495b2112016-09-19 17:40:32364}
365
Eric Liu495b2112016-09-19 17:40:32366void ChangeNamespaceTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
Eric Liu495b2112016-09-19 17:40:32367 std::string FullOldNs = "::" + OldNamespace;
Eric Liub9bf1b52016-11-08 22:44:17368 // Prefix is the outer-most namespace in DiffOldNamespace. For example, if the
369 // OldNamespace is "a::b::c" and DiffOldNamespace is "b::c", then Prefix will
370 // be "a::b". Declarations in this namespace will not be visible in the new
371 // namespace. If DiffOldNamespace is empty, Prefix will be a invalid name "-".
372 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
Eric Liu2dd0e1b2016-12-05 11:17:04373 llvm::StringRef(DiffOldNamespace)
374 .split(DiffOldNsSplitted, "::", /*MaxSplit=*/-1,
375 /*KeepEmpty=*/false);
Eric Liub9bf1b52016-11-08 22:44:17376 std::string Prefix = "-";
377 if (!DiffOldNsSplitted.empty())
378 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
379 DiffOldNsSplitted.front())
380 .str();
381 auto IsInMovedNs =
382 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind("ns_decl")),
383 isExpansionInFileMatching(FilePattern));
384 auto IsVisibleInNewNs = anyOf(
385 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
386 // Match using declarations.
387 Finder->addMatcher(
388 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
389 .bind("using"),
390 this);
391 // Match using namespace declarations.
392 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
393 IsVisibleInNewNs)
394 .bind("using_namespace"),
395 this);
Eric Liu180dac62016-12-23 10:47:09396 // Match namespace alias declarations.
397 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
398 IsVisibleInNewNs)
399 .bind("namespace_alias"),
400 this);
Eric Liub9bf1b52016-11-08 22:44:17401
402 // Match old namespace blocks.
Eric Liu495b2112016-09-19 17:40:32403 Finder->addMatcher(
404 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
405 .bind("old_ns"),
406 this);
407
Eric Liu41552d62016-12-07 14:20:52408 // Match class forward-declarations in the old namespace.
409 // Note that forward-declarations in classes are not matched.
410 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
411 IsInMovedNs, hasParent(namespaceDecl()))
412 .bind("class_fwd_decl"),
413 this);
414
415 // Match template class forward-declarations in the old namespace.
Eric Liu495b2112016-09-19 17:40:32416 Finder->addMatcher(
Eric Liu41552d62016-12-07 14:20:52417 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
418 IsInMovedNs, hasParent(namespaceDecl()))
419 .bind("template_class_fwd_decl"),
Eric Liu495b2112016-09-19 17:40:32420 this);
421
422 // Match references to types that are not defined in the old namespace.
423 // Forward-declarations in the old namespace are also matched since they will
424 // be moved back to the old namespace.
425 auto DeclMatcher = namedDecl(
426 hasAncestor(namespaceDecl()),
427 unless(anyOf(
Eric Liu912d0392016-09-27 12:54:48428 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
Eric Liu495b2112016-09-19 17:40:32429 hasAncestor(cxxRecordDecl()),
430 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
Eric Liu912d0392016-09-27 12:54:48431
Eric Liu8685c762016-12-07 17:04:07432 // Using shadow declarations in classes always refers to base class, which
433 // does not need to be qualified since it can be inferred from inheritance.
434 // Note that this does not match using alias declarations.
435 auto UsingShadowDeclInClass =
436 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
437
Eric Liu495b2112016-09-19 17:40:32438 // Match TypeLocs on the declaration. Carefully match only the outermost
Eric Liu8393cb02016-10-31 08:28:29439 // TypeLoc and template specialization arguments (which are not outermost)
440 // that are directly linked to types matching `DeclMatcher`. Nested name
441 // specifier locs are handled separately below.
Eric Liu495b2112016-09-19 17:40:32442 Finder->addMatcher(
443 typeLoc(IsInMovedNs,
444 loc(qualType(hasDeclaration(DeclMatcher.bind("from_decl")))),
Eric Liu8393cb02016-10-31 08:28:29445 unless(anyOf(hasParent(typeLoc(loc(qualType(
Alexander Kornienko976e0c02018-11-25 02:41:01446 hasDeclaration(DeclMatcher),
447 unless(templateSpecializationType()))))),
Eric Liu8685c762016-12-07 17:04:07448 hasParent(nestedNameSpecifierLoc()),
449 hasAncestor(isImplicit()),
Eric Liub583a7e2017-10-16 08:20:10450 hasAncestor(UsingShadowDeclInClass),
451 hasAncestor(functionDecl(isDefaulted())))),
Eric Liu495b2112016-09-19 17:40:32452 hasAncestor(decl().bind("dc")))
453 .bind("type"),
454 this);
Eric Liu912d0392016-09-27 12:54:48455
Eric Liu68765a82016-09-21 15:06:12456 // Types in `UsingShadowDecl` is not matched by `typeLoc` above, so we need to
457 // special case it.
Eric Liu8685c762016-12-07 17:04:07458 // Since using declarations inside classes must have the base class in the
459 // nested name specifier, we leave it to the nested name specifier matcher.
460 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
461 unless(UsingShadowDeclInClass))
Eric Liub9bf1b52016-11-08 22:44:17462 .bind("using_with_shadow"),
463 this);
Eric Liu912d0392016-09-27 12:54:48464
Eric Liuff51f012016-11-16 16:54:53465 // Handle types in nested name specifier. Specifiers that are in a TypeLoc
466 // matched above are not matched, e.g. "A::" in "A::A" is not matched since
467 // "A::A" would have already been fixed.
Eric Liu8685c762016-12-07 17:04:07468 Finder->addMatcher(
469 nestedNameSpecifierLoc(
470 hasAncestor(decl(IsInMovedNs).bind("dc")),
471 loc(nestedNameSpecifier(
472 specifiesType(hasDeclaration(DeclMatcher.bind("from_decl"))))),
473 unless(anyOf(hasAncestor(isImplicit()),
474 hasAncestor(UsingShadowDeclInClass),
Eric Liub583a7e2017-10-16 08:20:10475 hasAncestor(functionDecl(isDefaulted())),
Eric Liu8685c762016-12-07 17:04:07476 hasAncestor(typeLoc(loc(qualType(hasDeclaration(
477 decl(equalsBoundNode("from_decl"))))))))))
478 .bind("nested_specifier_loc"),
479 this);
Eric Liu12068d82016-09-22 11:54:00480
Eric Liuff51f012016-11-16 16:54:53481 // Matches base class initializers in constructors. TypeLocs of base class
482 // initializers do not need to be fixed. For example,
483 // class X : public a::b::Y {
484 // public:
485 // X() : Y::Y() {} // Y::Y do not need namespace specifier.
486 // };
487 Finder->addMatcher(
488 cxxCtorInitializer(isBaseInitializer()).bind("base_initializer"), this);
489
Eric Liu12068d82016-09-22 11:54:00490 // Handle function.
Eric Liu912d0392016-09-27 12:54:48491 // Only handle functions that are defined in a namespace excluding member
492 // function, static methods (qualified by nested specifier), and functions
493 // defined in the global namespace.
Eric Liu12068d82016-09-22 11:54:00494 // Note that the matcher does not exclude calls to out-of-line static method
495 // definitions, so we need to exclude them in the callback handler.
Eric Liu912d0392016-09-27 12:54:48496 auto FuncMatcher =
497 functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
498 hasAncestor(namespaceDecl(isAnonymous())),
499 hasAncestor(cxxRecordDecl()))),
500 hasParent(namespaceDecl()));
Alexander Kornienko976e0c02018-11-25 02:41:01501 Finder->addMatcher(expr(hasAncestor(decl().bind("dc")), IsInMovedNs,
502 unless(hasAncestor(isImplicit())),
503 anyOf(callExpr(callee(FuncMatcher)).bind("call"),
504 declRefExpr(to(FuncMatcher.bind("func_decl")))
505 .bind("func_ref"))),
506 this);
Eric Liu159f0132016-09-30 04:32:39507
508 auto GlobalVarMatcher = varDecl(
509 hasGlobalStorage(), hasParent(namespaceDecl()),
510 unless(anyOf(IsInMovedNs, hasAncestor(namespaceDecl(isAnonymous())))));
511 Finder->addMatcher(declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
512 to(GlobalVarMatcher.bind("var_decl")))
513 .bind("var_ref"),
514 this);
Eric Liu0325a772017-02-02 17:40:38515
516 // Handle unscoped enum constant.
517 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
518 hasParent(namespaceDecl()),
519 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
520 hasAncestor(namespaceDecl(isAnonymous())))))));
521 Finder->addMatcher(
522 declRefExpr(IsInMovedNs, hasAncestor(decl().bind("dc")),
523 to(UnscopedEnumMatcher.bind("enum_const_decl")))
524 .bind("enum_const_ref"),
525 this);
Eric Liu495b2112016-09-19 17:40:32526}
527
528void ChangeNamespaceTool::run(
529 const ast_matchers::MatchFinder::MatchResult &Result) {
Eric Liub9bf1b52016-11-08 22:44:17530 if (const auto *Using = Result.Nodes.getNodeAs<UsingDecl>("using")) {
531 UsingDecls.insert(Using);
532 } else if (const auto *UsingNamespace =
533 Result.Nodes.getNodeAs<UsingDirectiveDecl>(
534 "using_namespace")) {
535 UsingNamespaceDecls.insert(UsingNamespace);
Eric Liu180dac62016-12-23 10:47:09536 } else if (const auto *NamespaceAlias =
537 Result.Nodes.getNodeAs<NamespaceAliasDecl>(
538 "namespace_alias")) {
539 NamespaceAliasDecls.insert(NamespaceAlias);
Eric Liub9bf1b52016-11-08 22:44:17540 } else if (const auto *NsDecl =
541 Result.Nodes.getNodeAs<NamespaceDecl>("old_ns")) {
Eric Liu495b2112016-09-19 17:40:32542 moveOldNamespace(Result, NsDecl);
543 } else if (const auto *FwdDecl =
Eric Liu41552d62016-12-07 14:20:52544 Result.Nodes.getNodeAs<CXXRecordDecl>("class_fwd_decl")) {
545 moveClassForwardDeclaration(Result, cast<NamedDecl>(FwdDecl));
546 } else if (const auto *TemplateFwdDecl =
547 Result.Nodes.getNodeAs<ClassTemplateDecl>(
548 "template_class_fwd_decl")) {
549 moveClassForwardDeclaration(Result, cast<NamedDecl>(TemplateFwdDecl));
Eric Liub9bf1b52016-11-08 22:44:17550 } else if (const auto *UsingWithShadow =
551 Result.Nodes.getNodeAs<UsingDecl>("using_with_shadow")) {
552 fixUsingShadowDecl(Result, UsingWithShadow);
Eric Liu68765a82016-09-21 15:06:12553 } else if (const auto *Specifier =
554 Result.Nodes.getNodeAs<NestedNameSpecifierLoc>(
555 "nested_specifier_loc")) {
556 SourceLocation Start = Specifier->getBeginLoc();
Eric Liuc265b022016-12-01 17:25:55557 SourceLocation End = endLocationForType(Specifier->getTypeLoc());
Eric Liu68765a82016-09-21 15:06:12558 fixTypeLoc(Result, Start, End, Specifier->getTypeLoc());
Eric Liuff51f012016-11-16 16:54:53559 } else if (const auto *BaseInitializer =
560 Result.Nodes.getNodeAs<CXXCtorInitializer>(
561 "base_initializer")) {
562 BaseCtorInitializerTypeLocs.push_back(
563 BaseInitializer->getTypeSourceInfo()->getTypeLoc());
Eric Liu12068d82016-09-22 11:54:00564 } else if (const auto *TLoc = Result.Nodes.getNodeAs<TypeLoc>("type")) {
Eric Liu26cf68a2016-12-15 10:42:35565 // This avoids fixing types with record types as qualifier, which is not
566 // filtered by matchers in some cases, e.g. the type is templated. We should
567 // handle the record type qualifier instead.
Eric Liu0c0aea02016-12-15 13:02:41568 TypeLoc Loc = *TLoc;
569 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
570 Loc = Loc.getNextTypeLoc();
571 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
Eric Liu26cf68a2016-12-15 10:42:35572 NestedNameSpecifierLoc NestedNameSpecifier =
Eric Liu0c0aea02016-12-15 13:02:41573 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
Eric Liu5a6d57c2017-12-08 10:06:16574 // This happens for friend declaration of a base class with injected class
575 // name.
576 if (!NestedNameSpecifier.getNestedNameSpecifier())
577 return;
Eric Liu26cf68a2016-12-15 10:42:35578 const Type *SpecifierType =
579 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
580 if (SpecifierType && SpecifierType->isRecordType())
581 return;
582 }
Eric Liu0c0aea02016-12-15 13:02:41583 fixTypeLoc(Result, startLocationForType(Loc), endLocationForType(Loc), Loc);
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19584 } else if (const auto *VarRef =
585 Result.Nodes.getNodeAs<DeclRefExpr>("var_ref")) {
Eric Liu159f0132016-09-30 04:32:39586 const auto *Var = Result.Nodes.getNodeAs<VarDecl>("var_decl");
587 assert(Var);
588 if (Var->getCanonicalDecl()->isStaticDataMember())
589 return;
Eric Liuda22b3c2016-11-29 14:15:14590 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu159f0132016-09-30 04:32:39591 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14592 fixDeclRefExpr(Result, Context->getDeclContext(),
593 llvm::cast<NamedDecl>(Var), VarRef);
Eric Liu0325a772017-02-02 17:40:38594 } else if (const auto *EnumConstRef =
595 Result.Nodes.getNodeAs<DeclRefExpr>("enum_const_ref")) {
596 // Do not rename the reference if it is already scoped by the EnumDecl name.
597 if (EnumConstRef->hasQualifier() &&
Eric Liu28c30ce2017-02-02 19:46:12598 EnumConstRef->getQualifier()->getKind() ==
599 NestedNameSpecifier::SpecifierKind::TypeSpec &&
Eric Liu0325a772017-02-02 17:40:38600 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
601 return;
602 const auto *EnumConstDecl =
603 Result.Nodes.getNodeAs<EnumConstantDecl>("enum_const_decl");
604 assert(EnumConstDecl);
605 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
606 assert(Context && "Empty decl context.");
607 // FIXME: this would qualify "ns::VALUE" as "ns::EnumValue::VALUE". Fix it
608 // if it turns out to be an issue.
609 fixDeclRefExpr(Result, Context->getDeclContext(),
610 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
Eric Liuda22b3c2016-11-29 14:15:14611 } else if (const auto *FuncRef =
612 Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
Eric Liue3f35e42016-12-20 14:39:04613 // If this reference has been processed as a function call, we do not
614 // process it again.
615 if (ProcessedFuncRefs.count(FuncRef))
616 return;
617 ProcessedFuncRefs.insert(FuncRef);
Eric Liuda22b3c2016-11-29 14:15:14618 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>("func_decl");
619 assert(Func);
620 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
621 assert(Context && "Empty decl context.");
622 fixDeclRefExpr(Result, Context->getDeclContext(),
623 llvm::cast<NamedDecl>(Func), FuncRef);
Eric Liu12068d82016-09-22 11:54:00624 } else {
Eric Liuda22b3c2016-11-29 14:15:14625 const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19626 assert(Call != nullptr && "Expecting callback for CallExpr.");
Eric Liue3f35e42016-12-20 14:39:04627 const auto *CalleeFuncRef =
628 llvm::cast<DeclRefExpr>(Call->getCallee()->IgnoreImplicit());
629 ProcessedFuncRefs.insert(CalleeFuncRef);
Eric Liuda22b3c2016-11-29 14:15:14630 const FunctionDecl *Func = Call->getDirectCallee();
Eric Liu12068d82016-09-22 11:54:00631 assert(Func != nullptr);
Eric Liue3f35e42016-12-20 14:39:04632 // FIXME: ignore overloaded operators. This would miss cases where operators
633 // are called by qualified names (i.e. "ns::operator <"). Ignore such
634 // cases for now.
635 if (Func->isOverloadedOperator())
636 return;
Eric Liu12068d82016-09-22 11:54:00637 // Ignore out-of-line static methods since they will be handled by nested
638 // name specifiers.
639 if (Func->getCanonicalDecl()->getStorageClass() ==
Eric Liuda22b3c2016-11-29 14:15:14640 StorageClass::SC_Static &&
Eric Liu12068d82016-09-22 11:54:00641 Func->isOutOfLine())
642 return;
Eric Liuda22b3c2016-11-29 14:15:14643 const auto *Context = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu12068d82016-09-22 11:54:00644 assert(Context && "Empty decl context.");
Eric Liuda22b3c2016-11-29 14:15:14645 SourceRange CalleeRange = Call->getCallee()->getSourceRange();
Eric Liub9bf1b52016-11-08 22:44:17646 replaceQualifiedSymbolInDeclContext(
647 Result, Context->getDeclContext(), CalleeRange.getBegin(),
Eric Liu231c6552016-11-10 18:15:34648 CalleeRange.getEnd(), llvm::cast<NamedDecl>(Func));
Eric Liu495b2112016-09-19 17:40:32649 }
650}
651
Eric Liu73f49fd2016-10-12 12:34:18652static SourceLocation getLocAfterNamespaceLBrace(const NamespaceDecl *NsDecl,
653 const SourceManager &SM,
654 const LangOptions &LangOpts) {
655 std::unique_ptr<Lexer> Lex =
Stephen Kelly43465bf2018-08-09 22:42:26656 getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
Eric Liu73f49fd2016-10-12 12:34:18657 assert(Lex.get() &&
658 "Failed to create lexer from the beginning of namespace.");
659 if (!Lex.get())
660 return SourceLocation();
661 Token Tok;
662 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
663 }
664 return Tok.isNot(tok::TokenKind::l_brace)
665 ? SourceLocation()
666 : Tok.getEndLoc().getLocWithOffset(1);
667}
668
Eric Liu495b2112016-09-19 17:40:32669// Stores information about a moved namespace in `MoveNamespaces` and leaves
670// the actual movement to `onEndOfTranslationUnit()`.
671void ChangeNamespaceTool::moveOldNamespace(
672 const ast_matchers::MatchFinder::MatchResult &Result,
673 const NamespaceDecl *NsDecl) {
674 // If the namespace is empty, do nothing.
675 if (Decl::castToDeclContext(NsDecl)->decls_empty())
676 return;
677
Eric Liuee5104b2017-01-04 14:49:08678 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32679 // Get the range of the code in the old namespace.
Eric Liuee5104b2017-01-04 14:49:08680 SourceLocation Start =
681 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts());
Eric Liu73f49fd2016-10-12 12:34:18682 assert(Start.isValid() && "Can't find l_brace for namespace.");
Eric Liu495b2112016-09-19 17:40:32683 MoveNamespace MoveNs;
Eric Liuee5104b2017-01-04 14:49:08684 MoveNs.Offset = SM.getFileOffset(Start);
685 // The range of the moved namespace is from the location just past the left
686 // brace to the location right before the right brace.
687 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
Eric Liu495b2112016-09-19 17:40:32688
689 // Insert the new namespace after `DiffOldNamespace`. For example, if
690 // `OldNamespace` is "a::b::c" and `NewNamespace` is `a::x::y`, then
691 // "x::y" will be inserted inside the existing namespace "a" and after "a::b".
692 // `OuterNs` is the first namespace in `DiffOldNamespace`, e.g. "namespace b"
693 // in the above example.
Eric Liu6aa94162016-11-10 18:29:01694 // If there is no outer namespace (i.e. DiffOldNamespace is empty), the new
695 // namespace will be a nested namespace in the old namespace.
Eric Liu495b2112016-09-19 17:40:32696 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
Eric Liu6aa94162016-11-10 18:29:01697 SourceLocation InsertionLoc = Start;
698 if (OuterNs) {
Eric Liuee5104b2017-01-04 14:49:08699 SourceLocation LocAfterNs = getStartOfNextLine(
700 OuterNs->getRBraceLoc(), SM, Result.Context->getLangOpts());
Eric Liu6aa94162016-11-10 18:29:01701 assert(LocAfterNs.isValid() &&
702 "Failed to get location after DiffOldNamespace");
703 InsertionLoc = LocAfterNs;
704 }
Eric Liuee5104b2017-01-04 14:49:08705 MoveNs.InsertionOffset = SM.getFileOffset(SM.getSpellingLoc(InsertionLoc));
706 MoveNs.FID = SM.getFileID(Start);
Eric Liucc83c662016-09-19 17:58:59707 MoveNs.SourceMgr = Result.SourceManager;
Benjamin Krameradcd0262020-01-28 19:23:46708 MoveNamespaces[std::string(SM.getFilename(Start))].push_back(MoveNs);
Eric Liu495b2112016-09-19 17:40:32709}
710
711// Removes a class forward declaration from the code in the moved namespace and
712// creates an `InsertForwardDeclaration` to insert the forward declaration back
713// into the old namespace after moving code from the old namespace to the new
714// namespace.
715// For example, changing "a" to "x":
716// Old code:
717// namespace a {
718// class FWD;
719// class A { FWD *fwd; }
720// } // a
721// New code:
722// namespace a {
723// class FWD;
724// } // a
725// namespace x {
726// class A { a::FWD *fwd; }
727// } // x
728void ChangeNamespaceTool::moveClassForwardDeclaration(
729 const ast_matchers::MatchFinder::MatchResult &Result,
Eric Liu41552d62016-12-07 14:20:52730 const NamedDecl *FwdDecl) {
Stephen Kelly43465bf2018-08-09 22:42:26731 SourceLocation Start = FwdDecl->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02732 SourceLocation End = FwdDecl->getEndLoc();
Eric Liu41367152017-03-01 10:29:39733 const SourceManager &SM = *Result.SourceManager;
Eric Liu495b2112016-09-19 17:40:32734 SourceLocation AfterSemi = Lexer::findLocationAfterToken(
Eric Liu41367152017-03-01 10:29:39735 End, tok::semi, SM, Result.Context->getLangOpts(),
Eric Liu495b2112016-09-19 17:40:32736 /*SkipTrailingWhitespaceAndNewLine=*/true);
737 if (AfterSemi.isValid())
738 End = AfterSemi.getLocWithOffset(-1);
739 // Delete the forward declaration from the code to be moved.
Eric Liu41367152017-03-01 10:29:39740 addReplacementOrDie(Start, End, "", SM, &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32741 llvm::StringRef Code = Lexer::getSourceText(
Eric Liu41367152017-03-01 10:29:39742 CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
743 SM.getSpellingLoc(End)),
744 SM, Result.Context->getLangOpts());
Eric Liu495b2112016-09-19 17:40:32745 // Insert the forward declaration back into the old namespace after moving the
746 // code from old namespace to new namespace.
747 // Insertion information is stored in `InsertFwdDecls` and actual
748 // insertion will be performed in `onEndOfTranslationUnit`.
749 // Get the (old) namespace that contains the forward declaration.
750 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>("ns_decl");
751 // The namespace contains the forward declaration, so it must not be empty.
752 assert(!NsDecl->decls_empty());
Eric Liu41367152017-03-01 10:29:39753 const auto Insertion = createInsertion(
754 getLocAfterNamespaceLBrace(NsDecl, SM, Result.Context->getLangOpts()),
755 Code, SM);
Eric Liu495b2112016-09-19 17:40:32756 InsertForwardDeclaration InsertFwd;
757 InsertFwd.InsertionOffset = Insertion.getOffset();
758 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
Benjamin Krameradcd0262020-01-28 19:23:46759 InsertFwdDecls[std::string(Insertion.getFilePath())].push_back(InsertFwd);
Eric Liu495b2112016-09-19 17:40:32760}
761
Eric Liub9bf1b52016-11-08 22:44:17762// Replaces a qualified symbol (in \p DeclCtx) that refers to a declaration \p
763// FromDecl with the shortest qualified name possible when the reference is in
764// `NewNamespace`.
Eric Liu495b2112016-09-19 17:40:32765void ChangeNamespaceTool::replaceQualifiedSymbolInDeclContext(
Eric Liub9bf1b52016-11-08 22:44:17766 const ast_matchers::MatchFinder::MatchResult &Result,
767 const DeclContext *DeclCtx, SourceLocation Start, SourceLocation End,
768 const NamedDecl *FromDecl) {
769 const auto *NsDeclContext = DeclCtx->getEnclosingNamespaceContext();
Eric Liu4fe99e12016-12-14 17:01:52770 if (llvm::isa<TranslationUnitDecl>(NsDeclContext)) {
771 // This should not happen in usual unless the TypeLoc is in function type
772 // parameters, e.g `std::function<void(T)>`. In this case, DeclContext of
773 // `T` will be the translation unit. We simply use fully-qualified name
774 // here.
775 // Note that `FromDecl` must not be defined in the old namespace (according
776 // to `DeclMatcher`), so its fully-qualified name will not change after
777 // changing the namespace.
778 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
779 *Result.SourceManager, &FileToReplacements);
780 return;
781 }
Eric Liu231c6552016-11-10 18:15:34782 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
Eric Liu495b2112016-09-19 17:40:32783 // Calculate the name of the `NsDecl` after it is moved to new namespace.
784 std::string OldNs = NsDecl->getQualifiedNameAsString();
785 llvm::StringRef Postfix = OldNs;
786 bool Consumed = Postfix.consume_front(OldNamespace);
787 assert(Consumed && "Expect OldNS to start with OldNamespace.");
788 (void)Consumed;
789 const std::string NewNs = (NewNamespace + Postfix).str();
790
791 llvm::StringRef NestedName = Lexer::getSourceText(
792 CharSourceRange::getTokenRange(
793 Result.SourceManager->getSpellingLoc(Start),
794 Result.SourceManager->getSpellingLoc(End)),
795 *Result.SourceManager, Result.Context->getLangOpts());
Eric Liub9bf1b52016-11-08 22:44:17796 std::string FromDeclName = FromDecl->getQualifiedNameAsString();
Eric Christopher25ed42f2020-06-20 06:01:42797 for (llvm::Regex &RE : AllowedSymbolRegexes)
Eric Liu7fccc992017-02-24 11:54:45798 if (RE.match(FromDeclName))
799 return;
Eric Liu495b2112016-09-19 17:40:32800 std::string ReplaceName =
Eric Liub9bf1b52016-11-08 22:44:17801 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
802 // Checks if there is any using namespace declarations that can shorten the
803 // qualified name.
804 for (const auto *UsingNamespace : UsingNamespaceDecls) {
805 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
806 Start))
807 continue;
808 StringRef FromDeclNameRef = FromDeclName;
809 if (FromDeclNameRef.consume_front(UsingNamespace->getNominatedNamespace()
810 ->getQualifiedNameAsString())) {
811 FromDeclNameRef = FromDeclNameRef.drop_front(2);
812 if (FromDeclNameRef.size() < ReplaceName.size())
Benjamin Krameradcd0262020-01-28 19:23:46813 ReplaceName = std::string(FromDeclNameRef);
Eric Liub9bf1b52016-11-08 22:44:17814 }
815 }
Eric Liu180dac62016-12-23 10:47:09816 // Checks if there is any namespace alias declarations that can shorten the
817 // qualified name.
818 for (const auto *NamespaceAlias : NamespaceAliasDecls) {
819 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
820 Start))
821 continue;
822 StringRef FromDeclNameRef = FromDeclName;
823 if (FromDeclNameRef.consume_front(
824 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
825 "::")) {
826 std::string AliasName = NamespaceAlias->getNameAsString();
827 std::string AliasQualifiedName =
828 NamespaceAlias->getQualifiedNameAsString();
Kazuaki Ishizakidd5571d2020-04-05 06:28:11829 // We only consider namespace aliases define in the global namespace or
Eric Liu180dac62016-12-23 10:47:09830 // in namespaces that are directly visible from the reference, i.e.
831 // ancestor of the `OldNs`. Note that declarations in ancestor namespaces
832 // but not visible in the new namespace is filtered out by
833 // "IsVisibleInNewNs" matcher.
834 if (AliasQualifiedName != AliasName) {
835 // The alias is defined in some namespace.
836 assert(StringRef(AliasQualifiedName).endswith("::" + AliasName));
837 llvm::StringRef AliasNs =
838 StringRef(AliasQualifiedName).drop_back(AliasName.size() + 2);
839 if (!llvm::StringRef(OldNs).startswith(AliasNs))
840 continue;
841 }
842 std::string NameWithAliasNamespace =
843 (AliasName + "::" + FromDeclNameRef).str();
844 if (NameWithAliasNamespace.size() < ReplaceName.size())
845 ReplaceName = NameWithAliasNamespace;
846 }
847 }
Eric Liub9bf1b52016-11-08 22:44:17848 // Checks if there is any using shadow declarations that can shorten the
849 // qualified name.
850 bool Matched = false;
851 for (const UsingDecl *Using : UsingDecls) {
852 if (Matched)
853 break;
854 if (isDeclVisibleAtLocation(*Result.SourceManager, Using, DeclCtx, Start)) {
855 for (const auto *UsingShadow : Using->shadows()) {
856 const auto *TargetDecl = UsingShadow->getTargetDecl();
Eric Liuae7de712017-02-02 15:29:54857 if (TargetDecl->getQualifiedNameAsString() ==
858 FromDecl->getQualifiedNameAsString()) {
Eric Liub9bf1b52016-11-08 22:44:17859 ReplaceName = FromDecl->getNameAsString();
860 Matched = true;
861 break;
862 }
863 }
864 }
865 }
Eric Liuc6c894b2018-10-22 12:48:49866 bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
867 ReplaceName, NewNamespace);
Eric Liu495b2112016-09-19 17:40:32868 // If the new nested name in the new namespace is the same as it was in the
Eric Liuc6c894b2018-10-22 12:48:49869 // old namespace, we don't create replacement unless there can be ambiguity.
870 if ((NestedName == ReplaceName && !Conflict) ||
Eric Liu91229162017-01-26 16:31:32871 (NestedName.startswith("::") && NestedName.drop_front(2) == ReplaceName))
Eric Liu495b2112016-09-19 17:40:32872 return;
Eric Liu97f87ad2016-12-07 20:08:02873 // If the reference need to be fully-qualified, add a leading "::" unless
874 // NewNamespace is the global namespace.
Eric Liuc6c894b2018-10-22 12:48:49875 if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
Eric Liu97f87ad2016-12-07 20:08:02876 ReplaceName = "::" + ReplaceName;
Eric Liu4fe99e12016-12-14 17:01:52877 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
878 &FileToReplacements);
Eric Liu495b2112016-09-19 17:40:32879}
880
881// Replace the [Start, End] of `Type` with the shortest qualified name when the
882// `Type` is in `NewNamespace`.
883void ChangeNamespaceTool::fixTypeLoc(
884 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
885 SourceLocation End, TypeLoc Type) {
886 // FIXME: do not rename template parameter.
887 if (Start.isInvalid() || End.isInvalid())
888 return;
Eric Liuff51f012016-11-16 16:54:53889 // Types of CXXCtorInitializers do not need to be fixed.
890 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
891 return;
Eric Liu284b97c2017-03-17 14:05:39892 if (isTemplateParameter(Type))
893 return;
Eric Liu495b2112016-09-19 17:40:32894 // The declaration which this TypeLoc refers to.
895 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>("from_decl");
896 // `hasDeclaration` gives underlying declaration, but if the type is
897 // a typedef type, we need to use the typedef type instead.
Eric Liu26cf68a2016-12-15 10:42:35898 auto IsInMovedNs = [&](const NamedDecl *D) {
899 if (!llvm::StringRef(D->getQualifiedNameAsString())
900 .startswith(OldNamespace + "::"))
901 return false;
Stephen Kelly43465bf2018-08-09 22:42:26902 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getBeginLoc());
Eric Liu26cf68a2016-12-15 10:42:35903 if (ExpansionLoc.isInvalid())
904 return false;
905 llvm::StringRef Filename = Result.SourceManager->getFilename(ExpansionLoc);
906 return FilePatternRE.match(Filename);
907 };
908 // Make `FromDecl` the immediate declaration that `Type` refers to, i.e. if
909 // `Type` is an alias type, we make `FromDecl` the type alias declaration.
910 // Also, don't fix the \p Type if it refers to a type alias decl in the moved
911 // namespace since the alias decl will be moved along with the type reference.
Eric Liu32158862016-11-14 19:37:55912 if (auto *Typedef = Type.getType()->getAs<TypedefType>()) {
Eric Liu495b2112016-09-19 17:40:32913 FromDecl = Typedef->getDecl();
Eric Liu32158862016-11-14 19:37:55914 if (IsInMovedNs(FromDecl))
915 return;
Eric Liu26cf68a2016-12-15 10:42:35916 } else if (auto *TemplateType =
917 Type.getType()->getAs<TemplateSpecializationType>()) {
918 if (TemplateType->isTypeAlias()) {
919 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
920 if (IsInMovedNs(FromDecl))
921 return;
922 }
Eric Liu32158862016-11-14 19:37:55923 }
Piotr Padlewski08124b12016-12-14 15:29:23924 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>("dc");
Eric Liu495b2112016-09-19 17:40:32925 assert(DeclCtx && "Empty decl context.");
Eric Liub9bf1b52016-11-08 22:44:17926 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
927 End, FromDecl);
Eric Liu495b2112016-09-19 17:40:32928}
929
Eric Liu68765a82016-09-21 15:06:12930void ChangeNamespaceTool::fixUsingShadowDecl(
931 const ast_matchers::MatchFinder::MatchResult &Result,
932 const UsingDecl *UsingDeclaration) {
Stephen Kelly43465bf2018-08-09 22:42:26933 SourceLocation Start = UsingDeclaration->getBeginLoc();
Stephen Kellyc09197e2018-08-09 22:43:02934 SourceLocation End = UsingDeclaration->getEndLoc();
Mandeep Singh Grang7c7ea7d2016-11-08 07:50:19935 if (Start.isInvalid() || End.isInvalid())
936 return;
Eric Liu68765a82016-09-21 15:06:12937
938 assert(UsingDeclaration->shadow_size() > 0);
939 // FIXME: it might not be always accurate to use the first using-decl.
940 const NamedDecl *TargetDecl =
941 UsingDeclaration->shadow_begin()->getTargetDecl();
942 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
943 // FIXME: check if target_decl_name is in moved ns, which doesn't make much
944 // sense. If this happens, we need to use name with the new namespace.
945 // Use fully qualified name in UsingDecl for now.
Eric Liu4fe99e12016-12-14 17:01:52946 addReplacementOrDie(Start, End, "using ::" + TargetDeclName,
947 *Result.SourceManager, &FileToReplacements);
Eric Liu68765a82016-09-21 15:06:12948}
949
Eric Liuda22b3c2016-11-29 14:15:14950void ChangeNamespaceTool::fixDeclRefExpr(
951 const ast_matchers::MatchFinder::MatchResult &Result,
952 const DeclContext *UseContext, const NamedDecl *From,
953 const DeclRefExpr *Ref) {
954 SourceRange RefRange = Ref->getSourceRange();
955 replaceQualifiedSymbolInDeclContext(Result, UseContext, RefRange.getBegin(),
956 RefRange.getEnd(), From);
957}
958
Eric Liu495b2112016-09-19 17:40:32959void ChangeNamespaceTool::onEndOfTranslationUnit() {
960 // Move namespace blocks and insert forward declaration to old namespace.
961 for (const auto &FileAndNsMoves : MoveNamespaces) {
962 auto &NsMoves = FileAndNsMoves.second;
963 if (NsMoves.empty())
964 continue;
965 const std::string &FilePath = FileAndNsMoves.first;
966 auto &Replaces = FileToReplacements[FilePath];
Eric Liucc83c662016-09-19 17:58:59967 auto &SM = *NsMoves.begin()->SourceMgr;
968 llvm::StringRef Code = SM.getBufferData(NsMoves.begin()->FID);
Eric Liu495b2112016-09-19 17:40:32969 auto ChangedCode = tooling::applyAllReplacements(Code, Replaces);
970 if (!ChangedCode) {
971 llvm::errs() << llvm::toString(ChangedCode.takeError()) << "\n";
972 continue;
973 }
974 // Replacements on the changed code for moving namespaces and inserting
975 // forward declarations to old namespaces.
976 tooling::Replacements NewReplacements;
977 // Cut the changed code from the old namespace and paste the code in the new
978 // namespace.
979 for (const auto &NsMove : NsMoves) {
980 // Calculate the range of the old namespace block in the changed
981 // code.
982 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
983 const unsigned NewLength =
984 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
985 NewOffset;
986 tooling::Replacement Deletion(FilePath, NewOffset, NewLength, "");
987 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
988 std::string MovedCodeWrappedInNewNs =
989 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
990 // Calculate the new offset at which the code will be inserted in the
991 // changed code.
992 unsigned NewInsertionOffset =
993 Replaces.getShiftedCodePosition(NsMove.InsertionOffset);
994 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
995 MovedCodeWrappedInNewNs);
996 addOrMergeReplacement(Deletion, &NewReplacements);
997 addOrMergeReplacement(Insertion, &NewReplacements);
998 }
999 // After moving namespaces, insert forward declarations back to old
1000 // namespaces.
1001 const auto &FwdDeclInsertions = InsertFwdDecls[FilePath];
1002 for (const auto &FwdDeclInsertion : FwdDeclInsertions) {
1003 unsigned NewInsertionOffset =
1004 Replaces.getShiftedCodePosition(FwdDeclInsertion.InsertionOffset);
1005 tooling::Replacement Insertion(FilePath, NewInsertionOffset, 0,
1006 FwdDeclInsertion.ForwardDeclText);
1007 addOrMergeReplacement(Insertion, &NewReplacements);
1008 }
1009 // Add replacements referring to the changed code to existing replacements,
1010 // which refers to the original code.
1011 Replaces = Replaces.merge(NewReplacements);
Eric Liufa63e982018-08-02 10:30:561012 auto Style =
1013 format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
Antonio Maiorano0d7d9c22017-01-17 00:13:321014 if (!Style) {
1015 llvm::errs() << llvm::toString(Style.takeError()) << "\n";
1016 continue;
1017 }
Eric Liu495b2112016-09-19 17:40:321018 // Clean up old namespaces if there is nothing in it after moving.
1019 auto CleanReplacements =
Antonio Maiorano0d7d9c22017-01-17 00:13:321020 format::cleanupAroundReplacements(Code, Replaces, *Style);
Eric Liu495b2112016-09-19 17:40:321021 if (!CleanReplacements) {
1022 llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
1023 continue;
1024 }
1025 FileToReplacements[FilePath] = *CleanReplacements;
1026 }
Eric Liuc265b022016-12-01 17:25:551027
1028 // Make sure we don't generate replacements for files that do not match
1029 // FilePattern.
1030 for (auto &Entry : FileToReplacements)
1031 if (!FilePatternRE.match(Entry.first))
1032 Entry.second.clear();
Eric Liu495b2112016-09-19 17:40:321033}
1034
1035} // namespace change_namespace
1036} // namespace clang