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