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" 19 namespace change_namespace {
24 joinNamespaces(
const llvm::SmallVectorImpl<StringRef> &Namespaces) {
25 if (Namespaces.empty())
27 std::string
Result = Namespaces.front();
28 for (
auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
29 Result += (
"::" + *I).str();
34 llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef
Name) {
35 llvm::SmallVector<llvm::StringRef, 4> Splitted;
36 Name.split(Splitted,
"::", -1,
41 SourceLocation startLocationForType(TypeLoc TLoc) {
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();
51 return TLoc.getBeginLoc();
54 SourceLocation endLocationForType(TypeLoc TLoc) {
56 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
57 TLoc.getTypeLocClass() == TypeLoc::Qualified)
58 TLoc = TLoc.getNextTypeLoc();
63 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
64 return TLoc.castAs<TemplateSpecializationTypeLoc>()
66 .getLocWithOffset(-1);
67 return TLoc.getEndLoc();
75 const NamespaceDecl *getOuterNamespace(
const NamespaceDecl *InnerNs,
76 llvm::StringRef PartialNsName) {
77 if (!InnerNs || PartialNsName.empty())
79 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
80 const auto *CurrentNs = InnerNs;
81 auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
82 while (!PartialNsNameSplitted.empty()) {
84 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
85 CurrentContext = CurrentContext->getParent();
88 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
89 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
91 PartialNsNameSplitted.pop_back();
92 CurrentContext = CurrentContext->getParent();
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))
104 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
106 bool InvalidTemp =
false;
107 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
111 const char *TokBegin = File.data() + LocInfo.second;
113 return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
114 LangOpts, File.begin(), TokBegin, File.end());
119 static SourceLocation getStartOfNextLine(SourceLocation Loc,
120 const SourceManager &SM,
121 const LangOptions &LangOpts) {
122 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
124 return SourceLocation();
125 llvm::SmallVector<char, 16>
Line;
127 Lex->setParsingPreprocessorDirective(
true);
128 Lex->ReadToEndOfLine(&Line);
129 auto End = Loc.getLocWithOffset(Line.size());
130 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
132 : End.getLocWithOffset(1);
138 getReplacementInChangedCode(
const tooling::Replacements &Replaces,
139 const tooling::Replacement &R) {
140 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
142 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
143 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
144 R.getReplacementText());
149 void addOrMergeReplacement(
const tooling::Replacement &R,
150 tooling::Replacements *Replaces) {
151 auto Err = Replaces->add(R);
153 llvm::consumeError(std::move(Err));
154 auto Replace = getReplacementInChangedCode(*Replaces, R);
155 *Replaces = Replaces->merge(tooling::Replacements(Replace));
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();
166 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
168 <<
"start or end location were in different macro expansions\n";
169 return tooling::Replacement();
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();
177 return tooling::Replacement(
178 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
179 SM.getSpellingLoc(End)),
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);
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();
200 Loc = SM.getSpellingLoc(Loc);
201 return tooling::Replacement(SM, Loc, 0, InsertText);
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)
219 auto NsNameSplitted = splitSymbolName(NsName);
220 auto DeclNsSplitted = splitSymbolName(DeclName);
221 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
223 if (DeclNsSplitted.empty())
224 return UnqualifiedDeclName;
227 if (NsNameSplitted.empty())
230 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
235 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
236 return (
"::" + DeclName).str();
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) {
247 return (DeclI == DeclE)
248 ? UnqualifiedDeclName.str()
249 : (
llvm::join(DeclI, DeclE,
"::") +
"::" + UnqualifiedDeclName)
253 std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
254 if (Code.back() !=
'\n')
256 auto NsSplitted = splitSymbolName(NestedNs);
257 while (!NsSplitted.empty()) {
259 Code = (
"namespace " + NsSplitted.back() +
" {\n" + Code +
260 "} // namespace " + NsSplitted.back() +
"\n")
262 NsSplitted.pop_back();
268 bool isNestedDeclContext(
const DeclContext *
D,
const DeclContext *Context) {
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()));
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();
298 if (SymbolSplitted.size() >= 1 && !Namespace.empty()) {
299 auto SymbolTopNs = SymbolSplitted.front();
300 auto NsSplitted = splitSymbolName(Namespace.trim(
":"));
301 assert(!NsSplitted.empty());
303 auto LookupDecl = [&AST](
const Decl &Scope,
304 llvm::StringRef
Name) ->
const NamedDecl * {
305 const auto *DC = llvm::dyn_cast<DeclContext>(&Scope);
308 auto LookupRes = DC->lookup(DeclarationName(&AST.Idents.get(Name)));
309 if (LookupRes.empty())
311 return LookupRes.front();
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)
323 if (LookupDecl(*Scope, SymbolTopNs))
325 Scope = LookupDecl(*Scope, *I);
328 if (Scope && LookupDecl(*Scope, SymbolTopNs))
335 return Node.isScoped();
338 bool isTemplateParameter(TypeLoc Type) {
339 while (!Type.isNull()) {
340 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
342 Type = Type.getNextTypeLoc();
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);
361 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
362 OldNsSplitted.front() == NewNsSplitted.front()) {
363 OldNsSplitted.erase(OldNsSplitted.begin());
364 NewNsSplitted.erase(NewNsSplitted.begin());
366 DiffOldNamespace = joinNamespaces(OldNsSplitted);
367 DiffNewNamespace = joinNamespaces(NewNsSplitted);
369 for (
const auto &Pattern : WhiteListedSymbolPatterns)
370 WhiteListedSymbolRegexes.emplace_back(Pattern);
374 std::string FullOldNs =
"::" + OldNamespace;
379 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
380 llvm::StringRef(DiffOldNamespace)
381 .split(DiffOldNsSplitted,
"::", -1,
383 std::string Prefix =
"-";
384 if (!DiffOldNsSplitted.empty())
385 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
386 DiffOldNsSplitted.front())
389 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind(
"ns_decl")),
390 isExpansionInFileMatching(FilePattern));
391 auto IsVisibleInNewNs = anyOf(
392 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
395 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
399 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
401 .bind(
"using_namespace"),
404 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
406 .bind(
"namespace_alias"),
411 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
417 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
418 IsInMovedNs, hasParent(namespaceDecl()))
419 .bind(
"class_fwd_decl"),
424 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
425 IsInMovedNs, hasParent(namespaceDecl()))
426 .bind(
"template_class_fwd_decl"),
432 auto DeclMatcher = namedDecl(
433 hasAncestor(namespaceDecl()),
435 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
436 hasAncestor(cxxRecordDecl()),
437 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
442 auto UsingShadowDeclInClass =
443 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
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")))
467 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
468 unless(UsingShadowDeclInClass))
469 .bind(
"using_with_shadow"),
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"),
495 cxxCtorInitializer(isBaseInitializer()).bind(
"base_initializer"),
this);
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")))
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")))
524 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
525 hasParent(namespaceDecl()),
526 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
527 hasAncestor(namespaceDecl(isAnonymous())))))));
529 declRefExpr(IsInMovedNs, hasAncestor(decl().bind(
"dc")),
530 to(UnscopedEnumMatcher.bind(
"enum_const_decl")))
531 .bind(
"enum_const_ref"),
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")) {
576 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
577 Loc = Loc.getNextTypeLoc();
578 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
579 NestedNameSpecifierLoc NestedNameSpecifier =
580 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
583 if (!NestedNameSpecifier.getNestedNameSpecifier())
585 const Type *SpecifierType =
586 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
587 if (SpecifierType && SpecifierType->isRecordType())
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");
595 if (Var->getCanonicalDecl()->isStaticDataMember())
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")) {
604 if (EnumConstRef->hasQualifier() &&
605 EnumConstRef->getQualifier()->getKind() ==
606 NestedNameSpecifier::SpecifierKind::TypeSpec &&
607 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
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.");
616 fixDeclRefExpr(Result, Context->getDeclContext(),
617 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
618 }
else if (
const auto *FuncRef =
619 Result.Nodes.getNodeAs<DeclRefExpr>(
"func_ref")) {
622 if (ProcessedFuncRefs.count(FuncRef))
624 ProcessedFuncRefs.insert(FuncRef);
625 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func_decl");
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);
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);
642 if (Func->isOverloadedOperator())
646 if (Func->getCanonicalDecl()->getStorageClass() ==
647 StorageClass::SC_Static &&
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));
660 const SourceManager &SM,
661 const LangOptions &LangOpts) {
662 std::unique_ptr<Lexer> Lex =
663 getLexerStartingFromLoc(NsDecl->getBeginLoc(), SM, LangOpts);
665 "Failed to create lexer from the beginning of namespace.");
667 return SourceLocation();
669 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
671 return Tok.isNot(tok::TokenKind::l_brace)
673 : Tok.getEndLoc().getLocWithOffset(1);
678 void ChangeNamespaceTool::moveOldNamespace(
679 const ast_matchers::MatchFinder::MatchResult &
Result,
680 const NamespaceDecl *NsDecl) {
682 if (Decl::castToDeclContext(NsDecl)->decls_empty())
685 const SourceManager &SM = *Result.SourceManager;
687 SourceLocation Start =
689 assert(Start.isValid() &&
"Can't find l_brace for namespace.");
690 MoveNamespace MoveNs;
691 MoveNs.Offset = SM.getFileOffset(Start);
694 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
703 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
704 SourceLocation InsertionLoc = Start;
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;
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);
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(),
744 if (AfterSemi.isValid())
745 End = AfterSemi.getLocWithOffset(-1);
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());
757 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>(
"ns_decl");
759 assert(!NsDecl->decls_empty());
760 const auto Insertion = createInsertion(
763 InsertForwardDeclaration InsertFwd;
764 InsertFwd.InsertionOffset = Insertion.getOffset();
765 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
766 InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
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)) {
785 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
786 *Result.SourceManager, &FileToReplacements);
789 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
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.");
796 const std::string NewNs = (NewNamespace + Postfix).str();
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))
807 std::string ReplaceName =
808 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
811 for (
const auto *UsingNamespace : UsingNamespaceDecls) {
812 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
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;
825 for (
const auto *NamespaceAlias : NamespaceAliasDecls) {
826 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
829 StringRef FromDeclNameRef = FromDeclName;
830 if (FromDeclNameRef.consume_front(
831 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
833 std::string AliasName = NamespaceAlias->getNameAsString();
834 std::string AliasQualifiedName =
835 NamespaceAlias->getQualifiedNameAsString();
841 if (AliasQualifiedName != AliasName) {
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))
849 std::string NameWithAliasNamespace =
850 (AliasName +
"::" + FromDeclNameRef).str();
851 if (NameWithAliasNamespace.size() < ReplaceName.size())
852 ReplaceName = NameWithAliasNamespace;
857 bool Matched =
false;
858 for (
const UsingDecl *Using : UsingDecls) {
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();
873 bool Conflict = conflictInNamespace(DeclCtx->getParentASTContext(),
874 ReplaceName, NewNamespace);
877 if ((NestedName == ReplaceName && !Conflict) ||
878 (NestedName.startswith(
"::") && NestedName.drop_front(2) == ReplaceName))
882 if (ReplaceName == FromDeclName && !NewNamespace.empty() && Conflict)
883 ReplaceName =
"::" + ReplaceName;
884 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
885 &FileToReplacements);
890 void ChangeNamespaceTool::fixTypeLoc(
891 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
892 SourceLocation End, TypeLoc Type) {
894 if (Start.isInvalid() || End.isInvalid())
897 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
899 if (isTemplateParameter(Type))
902 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>(
"from_decl");
905 auto IsInMovedNs = [&](
const NamedDecl *
D) {
906 if (!llvm::StringRef(
D->getQualifiedNameAsString())
907 .startswith(OldNamespace +
"::"))
909 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(
D->getBeginLoc());
910 if (ExpansionLoc.isInvalid())
912 llvm::StringRef
Filename = Result.SourceManager->getFilename(ExpansionLoc);
913 return FilePatternRE.match(Filename);
919 if (
auto *Typedef = Type.getType()->getAs<TypedefType>()) {
920 FromDecl = Typedef->getDecl();
921 if (IsInMovedNs(FromDecl))
923 }
else if (
auto *TemplateType =
924 Type.getType()->getAs<TemplateSpecializationType>()) {
925 if (TemplateType->isTypeAlias()) {
926 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
927 if (IsInMovedNs(FromDecl))
931 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>(
"dc");
932 assert(DeclCtx &&
"Empty decl context.");
933 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
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())
945 assert(UsingDeclaration->shadow_size() > 0);
947 const NamedDecl *TargetDecl =
948 UsingDeclaration->shadow_begin()->getTargetDecl();
949 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
953 addReplacementOrDie(Start, End,
"using ::" + TargetDeclName,
954 *Result.SourceManager, &FileToReplacements);
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);
968 for (
const auto &FileAndNsMoves : MoveNamespaces) {
969 auto &NsMoves = FileAndNsMoves.second;
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);
983 tooling::Replacements NewReplacements;
986 for (
const auto &NsMove : NsMoves) {
989 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
990 const unsigned NewLength =
991 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
993 tooling::Replacement Deletion(FilePath, NewOffset, NewLength,
"");
994 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
995 std::string MovedCodeWrappedInNewNs =
996 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
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);
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);
1018 Replaces = Replaces.merge(NewReplacements);
1020 format::getStyle(format::DefaultFormatStyle, FilePath, FallbackStyle);
1026 auto CleanReplacements =
1027 format::cleanupAroundReplacements(Code, Replaces, *Style);
1028 if (!CleanReplacements) {
1029 llvm::errs() <<
llvm::toString(CleanReplacements.takeError()) <<
"\n";
1032 FileToReplacements[FilePath] = *CleanReplacements;
1037 for (
auto &
Entry : FileToReplacements)
1038 if (!FilePatternRE.match(
Entry.first))
1039 Entry.second.clear();
SourceLocation Loc
'#' location in the include directive
AST_MATCHER(BinaryOperator, isAssignmentOperator)
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
std::string Filename
Filename as a string.
static constexpr llvm::StringLiteral Name
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)