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