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