10 #include "clang/Format/Format.h" 11 #include "clang/Lex/Lexer.h" 12 #include "llvm/Support/ErrorHandling.h" 17 namespace change_namespace {
22 joinNamespaces(
const llvm::SmallVectorImpl<StringRef> &Namespaces) {
23 if (Namespaces.empty())
25 std::string Result = Namespaces.front();
26 for (
auto I = Namespaces.begin() + 1, E = Namespaces.end(); I != E; ++I)
27 Result += (
"::" + *I).str();
32 llvm::SmallVector<llvm::StringRef, 4> splitSymbolName(llvm::StringRef
Name) {
33 llvm::SmallVector<llvm::StringRef, 4> Splitted;
34 Name.split(Splitted,
"::", -1,
39 SourceLocation startLocationForType(TypeLoc TLoc) {
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();
49 return TLoc.getLocStart();
52 SourceLocation endLocationForType(TypeLoc TLoc) {
54 while (TLoc.getTypeLocClass() == TypeLoc::Elaborated ||
55 TLoc.getTypeLocClass() == TypeLoc::Qualified)
56 TLoc = TLoc.getNextTypeLoc();
61 if (TLoc.getTypeLocClass() == TypeLoc::TemplateSpecialization)
62 return TLoc.castAs<TemplateSpecializationTypeLoc>()
64 .getLocWithOffset(-1);
65 return TLoc.getEndLoc();
73 const NamespaceDecl *getOuterNamespace(
const NamespaceDecl *InnerNs,
74 llvm::StringRef PartialNsName) {
75 if (!InnerNs || PartialNsName.empty())
77 const auto *CurrentContext = llvm::cast<DeclContext>(InnerNs);
78 const auto *CurrentNs = InnerNs;
79 auto PartialNsNameSplitted = splitSymbolName(PartialNsName);
80 while (!PartialNsNameSplitted.empty()) {
82 while (CurrentContext && !llvm::isa<NamespaceDecl>(CurrentContext))
83 CurrentContext = CurrentContext->getParent();
86 CurrentNs = llvm::cast<NamespaceDecl>(CurrentContext);
87 if (PartialNsNameSplitted.back() != CurrentNs->getNameAsString())
89 PartialNsNameSplitted.pop_back();
90 CurrentContext = CurrentContext->getParent();
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))
102 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(Loc);
104 bool InvalidTemp =
false;
105 llvm::StringRef
File = SM.getBufferData(LocInfo.first, &InvalidTemp);
109 const char *TokBegin = File.data() + LocInfo.second;
111 return llvm::make_unique<Lexer>(SM.getLocForStartOfFile(LocInfo.first),
112 LangOpts, File.begin(), TokBegin, File.end());
117 static SourceLocation getStartOfNextLine(SourceLocation Loc,
118 const SourceManager &SM,
119 const LangOptions &LangOpts) {
120 std::unique_ptr<Lexer> Lex = getLexerStartingFromLoc(Loc, SM, LangOpts);
122 return SourceLocation();
123 llvm::SmallVector<char, 16>
Line;
125 Lex->setParsingPreprocessorDirective(
true);
126 Lex->ReadToEndOfLine(&Line);
127 auto End = Loc.getLocWithOffset(Line.size());
128 return SM.getLocForEndOfFile(SM.getDecomposedLoc(Loc).first) == End
130 : End.getLocWithOffset(1);
136 getReplacementInChangedCode(
const tooling::Replacements &Replaces,
137 const tooling::Replacement &R) {
138 unsigned NewStart = Replaces.getShiftedCodePosition(R.getOffset());
140 Replaces.getShiftedCodePosition(R.getOffset() + R.getLength());
141 return tooling::Replacement(R.getFilePath(), NewStart, NewEnd - NewStart,
142 R.getReplacementText());
147 void addOrMergeReplacement(
const tooling::Replacement &R,
148 tooling::Replacements *Replaces) {
149 auto Err = Replaces->add(R);
151 llvm::consumeError(std::move(Err));
152 auto Replace = getReplacementInChangedCode(*Replaces, R);
153 *Replaces = Replaces->merge(tooling::Replacements(Replace));
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();
164 if (SM.getDecomposedLoc(Start).first != SM.getDecomposedLoc(End).first) {
166 <<
"start or end location were in different macro expansions\n";
167 return tooling::Replacement();
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();
175 return tooling::Replacement(
176 SM, CharSourceRange::getTokenRange(SM.getSpellingLoc(Start),
177 SM.getSpellingLoc(End)),
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);
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();
198 Loc = SM.getSpellingLoc(Loc);
199 return tooling::Replacement(SM, Loc, 0, InsertText);
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)
217 auto NsNameSplitted = splitSymbolName(NsName);
218 auto DeclNsSplitted = splitSymbolName(DeclName);
219 llvm::StringRef UnqualifiedDeclName = DeclNsSplitted.pop_back_val();
221 if (DeclNsSplitted.empty())
222 return UnqualifiedDeclName;
225 if (NsNameSplitted.empty())
228 if (NsNameSplitted.front() != DeclNsSplitted.front()) {
233 if (llvm::is_contained(NsNameSplitted, DeclNsSplitted.front()))
234 return (
"::" + DeclName).str();
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) {
245 return (DeclI == DeclE)
246 ? UnqualifiedDeclName.str()
247 : (
llvm::join(DeclI, DeclE,
"::") +
"::" + UnqualifiedDeclName)
251 std::string wrapCodeInNamespace(StringRef NestedNs, std::string Code) {
252 if (Code.back() !=
'\n')
254 auto NsSplitted = splitSymbolName(NestedNs);
255 while (!NsSplitted.empty()) {
257 Code = (
"namespace " + NsSplitted.back() +
" {\n" + Code +
258 "} // namespace " + NsSplitted.back() +
"\n")
260 NsSplitted.pop_back();
266 bool isNestedDeclContext(
const DeclContext *D,
const DeclContext *Context) {
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()));
287 bool conflictInNamespace(llvm::StringRef QualifiedSymbol,
288 llvm::StringRef Namespace) {
289 auto SymbolSplitted = splitSymbolName(QualifiedSymbol.trim(
":"));
290 assert(!SymbolSplitted.empty());
291 SymbolSplitted.pop_back();
293 if (SymbolSplitted.size() > 1 && !Namespace.empty()) {
294 auto NsSplitted = splitSymbolName(Namespace.trim(
":"));
295 assert(!NsSplitted.empty());
299 for (
auto I = NsSplitted.begin() + 1, E = NsSplitted.end(); I != E; ++I) {
300 if (*I == SymbolSplitted.front())
308 return Node.isScoped();
311 bool isTemplateParameter(TypeLoc Type) {
312 while (!Type.isNull()) {
313 if (Type.getTypeLocClass() == TypeLoc::SubstTemplateTypeParm)
315 Type = Type.getNextTypeLoc();
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);
334 while (!OldNsSplitted.empty() && !NewNsSplitted.empty() &&
335 OldNsSplitted.front() == NewNsSplitted.front()) {
336 OldNsSplitted.erase(OldNsSplitted.begin());
337 NewNsSplitted.erase(NewNsSplitted.begin());
339 DiffOldNamespace = joinNamespaces(OldNsSplitted);
340 DiffNewNamespace = joinNamespaces(NewNsSplitted);
342 for (
const auto &Pattern : WhiteListedSymbolPatterns)
343 WhiteListedSymbolRegexes.emplace_back(Pattern);
347 std::string FullOldNs =
"::" + OldNamespace;
352 llvm::SmallVector<llvm::StringRef, 4> DiffOldNsSplitted;
353 llvm::StringRef(DiffOldNamespace)
354 .split(DiffOldNsSplitted,
"::", -1,
356 std::string Prefix =
"-";
357 if (!DiffOldNsSplitted.empty())
358 Prefix = (StringRef(FullOldNs).drop_back(DiffOldNamespace.size()) +
359 DiffOldNsSplitted.front())
362 allOf(hasAncestor(namespaceDecl(hasName(FullOldNs)).bind(
"ns_decl")),
363 isExpansionInFileMatching(FilePattern));
364 auto IsVisibleInNewNs = anyOf(
365 IsInMovedNs, unless(hasAncestor(namespaceDecl(hasName(Prefix)))));
368 usingDecl(isExpansionInFileMatching(FilePattern), IsVisibleInNewNs)
372 Finder->addMatcher(usingDirectiveDecl(isExpansionInFileMatching(FilePattern),
374 .bind(
"using_namespace"),
377 Finder->addMatcher(namespaceAliasDecl(isExpansionInFileMatching(FilePattern),
379 .bind(
"namespace_alias"),
384 namespaceDecl(hasName(FullOldNs), isExpansionInFileMatching(FilePattern))
390 Finder->addMatcher(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())),
391 IsInMovedNs, hasParent(namespaceDecl()))
392 .bind(
"class_fwd_decl"),
397 classTemplateDecl(unless(hasDescendant(cxxRecordDecl(isDefinition()))),
398 IsInMovedNs, hasParent(namespaceDecl()))
399 .bind(
"template_class_fwd_decl"),
405 auto DeclMatcher = namedDecl(
406 hasAncestor(namespaceDecl()),
408 isImplicit(), hasAncestor(namespaceDecl(isAnonymous())),
409 hasAncestor(cxxRecordDecl()),
410 allOf(IsInMovedNs, unless(cxxRecordDecl(unless(isDefinition())))))));
415 auto UsingShadowDeclInClass =
416 usingDecl(hasAnyUsingShadowDecl(decl()), hasParent(cxxRecordDecl()));
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")))
440 Finder->addMatcher(usingDecl(IsInMovedNs, hasAnyUsingShadowDecl(decl()),
441 unless(UsingShadowDeclInClass))
442 .bind(
"using_with_shadow"),
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"),
468 cxxCtorInitializer(isBaseInitializer()).bind(
"base_initializer"),
this);
477 functionDecl(unless(anyOf(cxxMethodDecl(), IsInMovedNs,
478 hasAncestor(namespaceDecl(isAnonymous())),
479 hasAncestor(cxxRecordDecl()))),
480 hasParent(namespaceDecl()));
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")))),
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")))
498 auto UnscopedEnumMatcher = enumConstantDecl(hasParent(enumDecl(
499 hasParent(namespaceDecl()),
500 unless(anyOf(isScoped(), IsInMovedNs, hasAncestor(cxxRecordDecl()),
501 hasAncestor(namespaceDecl(isAnonymous())))))));
503 declRefExpr(IsInMovedNs, hasAncestor(decl().bind(
"dc")),
504 to(UnscopedEnumMatcher.bind(
"enum_const_decl")))
505 .bind(
"enum_const_ref"),
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")) {
550 while (Loc.getTypeLocClass() == TypeLoc::Qualified)
551 Loc = Loc.getNextTypeLoc();
552 if (Loc.getTypeLocClass() == TypeLoc::Elaborated) {
553 NestedNameSpecifierLoc NestedNameSpecifier =
554 Loc.castAs<ElaboratedTypeLoc>().getQualifierLoc();
557 if (!NestedNameSpecifier.getNestedNameSpecifier())
559 const Type *SpecifierType =
560 NestedNameSpecifier.getNestedNameSpecifier()->getAsType();
561 if (SpecifierType && SpecifierType->isRecordType())
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");
569 if (Var->getCanonicalDecl()->isStaticDataMember())
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")) {
578 if (EnumConstRef->hasQualifier() &&
579 EnumConstRef->getQualifier()->getKind() ==
580 NestedNameSpecifier::SpecifierKind::TypeSpec &&
581 EnumConstRef->getQualifier()->getAsType()->isEnumeralType())
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.");
590 fixDeclRefExpr(Result, Context->getDeclContext(),
591 llvm::cast<NamedDecl>(EnumConstDecl), EnumConstRef);
592 }
else if (
const auto *FuncRef =
593 Result.Nodes.getNodeAs<DeclRefExpr>(
"func_ref")) {
596 if (ProcessedFuncRefs.count(FuncRef))
598 ProcessedFuncRefs.insert(FuncRef);
599 const auto *Func = Result.Nodes.getNodeAs<FunctionDecl>(
"func_decl");
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);
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);
616 if (Func->isOverloadedOperator())
620 if (Func->getCanonicalDecl()->getStorageClass() ==
621 StorageClass::SC_Static &&
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));
634 const SourceManager &SM,
635 const LangOptions &LangOpts) {
636 std::unique_ptr<Lexer> Lex =
637 getLexerStartingFromLoc(NsDecl->getLocStart(), SM, LangOpts);
639 "Failed to create lexer from the beginning of namespace.");
641 return SourceLocation();
643 while (!Lex->LexFromRawLexer(Tok) && Tok.isNot(tok::TokenKind::l_brace)) {
645 return Tok.isNot(tok::TokenKind::l_brace)
647 : Tok.getEndLoc().getLocWithOffset(1);
652 void ChangeNamespaceTool::moveOldNamespace(
653 const ast_matchers::MatchFinder::MatchResult &Result,
654 const NamespaceDecl *NsDecl) {
656 if (Decl::castToDeclContext(NsDecl)->decls_empty())
659 const SourceManager &SM = *Result.SourceManager;
661 SourceLocation Start =
663 assert(Start.isValid() &&
"Can't find l_brace for namespace.");
664 MoveNamespace MoveNs;
665 MoveNs.Offset = SM.getFileOffset(Start);
668 MoveNs.Length = SM.getFileOffset(NsDecl->getRBraceLoc()) - MoveNs.Offset;
677 const NamespaceDecl *OuterNs = getOuterNamespace(NsDecl, DiffOldNamespace);
678 SourceLocation InsertionLoc = Start;
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;
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);
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(),
718 if (AfterSemi.isValid())
719 End = AfterSemi.getLocWithOffset(-1);
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());
731 const auto *NsDecl = Result.Nodes.getNodeAs<NamespaceDecl>(
"ns_decl");
733 assert(!NsDecl->decls_empty());
734 const auto Insertion = createInsertion(
737 InsertForwardDeclaration InsertFwd;
738 InsertFwd.InsertionOffset = Insertion.getOffset();
739 InsertFwd.ForwardDeclText = Insertion.getReplacementText().str();
740 InsertFwdDecls[Insertion.getFilePath()].push_back(InsertFwd);
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)) {
759 addReplacementOrDie(Start, End, FromDecl->getQualifiedNameAsString(),
760 *Result.SourceManager, &FileToReplacements);
763 const auto *NsDecl = llvm::cast<NamespaceDecl>(NsDeclContext);
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.");
770 const std::string NewNs = (NewNamespace + Postfix).str();
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))
781 std::string ReplaceName =
782 getShortestQualifiedNameInNamespace(FromDeclName, NewNs);
785 for (
const auto *UsingNamespace : UsingNamespaceDecls) {
786 if (!isDeclVisibleAtLocation(*Result.SourceManager, UsingNamespace, DeclCtx,
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;
799 for (
const auto *NamespaceAlias : NamespaceAliasDecls) {
800 if (!isDeclVisibleAtLocation(*Result.SourceManager, NamespaceAlias, DeclCtx,
803 StringRef FromDeclNameRef = FromDeclName;
804 if (FromDeclNameRef.consume_front(
805 NamespaceAlias->getNamespace()->getQualifiedNameAsString() +
807 std::string AliasName = NamespaceAlias->getNameAsString();
808 std::string AliasQualifiedName =
809 NamespaceAlias->getQualifiedNameAsString();
815 if (AliasQualifiedName != AliasName) {
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))
823 std::string NameWithAliasNamespace =
824 (AliasName +
"::" + FromDeclNameRef).str();
825 if (NameWithAliasNamespace.size() < ReplaceName.size())
826 ReplaceName = NameWithAliasNamespace;
831 bool Matched =
false;
832 for (
const UsingDecl *Using : UsingDecls) {
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();
849 if (NestedName == ReplaceName ||
850 (NestedName.startswith(
"::") && NestedName.drop_front(2) == ReplaceName))
854 if (ReplaceName == FromDeclName && !NewNamespace.empty() &&
855 conflictInNamespace(ReplaceName, NewNamespace))
856 ReplaceName =
"::" + ReplaceName;
857 addReplacementOrDie(Start, End, ReplaceName, *Result.SourceManager,
858 &FileToReplacements);
863 void ChangeNamespaceTool::fixTypeLoc(
864 const ast_matchers::MatchFinder::MatchResult &Result, SourceLocation Start,
865 SourceLocation End, TypeLoc Type) {
867 if (Start.isInvalid() || End.isInvalid())
870 if (llvm::is_contained(BaseCtorInitializerTypeLocs, Type))
872 if (isTemplateParameter(Type))
875 const auto *FromDecl = Result.Nodes.getNodeAs<NamedDecl>(
"from_decl");
878 auto IsInMovedNs = [&](
const NamedDecl *D) {
879 if (!llvm::StringRef(D->getQualifiedNameAsString())
880 .startswith(OldNamespace +
"::"))
882 auto ExpansionLoc = Result.SourceManager->getExpansionLoc(D->getLocStart());
883 if (ExpansionLoc.isInvalid())
885 llvm::StringRef
Filename = Result.SourceManager->getFilename(ExpansionLoc);
886 return FilePatternRE.match(Filename);
892 if (
auto *Typedef = Type.getType()->getAs<TypedefType>()) {
893 FromDecl = Typedef->getDecl();
894 if (IsInMovedNs(FromDecl))
896 }
else if (
auto *TemplateType =
897 Type.getType()->getAs<TemplateSpecializationType>()) {
898 if (TemplateType->isTypeAlias()) {
899 FromDecl = TemplateType->getTemplateName().getAsTemplateDecl();
900 if (IsInMovedNs(FromDecl))
904 const auto *DeclCtx = Result.Nodes.getNodeAs<Decl>(
"dc");
905 assert(DeclCtx &&
"Empty decl context.");
906 replaceQualifiedSymbolInDeclContext(Result, DeclCtx->getDeclContext(), Start,
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())
918 assert(UsingDeclaration->shadow_size() > 0);
920 const NamedDecl *TargetDecl =
921 UsingDeclaration->shadow_begin()->getTargetDecl();
922 std::string TargetDeclName = TargetDecl->getQualifiedNameAsString();
926 addReplacementOrDie(Start, End,
"using ::" + TargetDeclName,
927 *Result.SourceManager, &FileToReplacements);
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);
941 for (
const auto &FileAndNsMoves : MoveNamespaces) {
942 auto &NsMoves = FileAndNsMoves.second;
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);
956 tooling::Replacements NewReplacements;
959 for (
const auto &NsMove : NsMoves) {
962 const unsigned NewOffset = Replaces.getShiftedCodePosition(NsMove.Offset);
963 const unsigned NewLength =
964 Replaces.getShiftedCodePosition(NsMove.Offset + NsMove.Length) -
966 tooling::Replacement Deletion(FilePath, NewOffset, NewLength,
"");
967 std::string MovedCode = ChangedCode->substr(NewOffset, NewLength);
968 std::string MovedCodeWrappedInNewNs =
969 wrapCodeInNamespace(DiffNewNamespace, MovedCode);
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);
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);
991 Replaces = Replaces.merge(NewReplacements);
992 auto Style = format::getStyle(
"file", FilePath, FallbackStyle);
998 auto CleanReplacements =
999 format::cleanupAroundReplacements(Code, Replaces, *Style);
1000 if (!CleanReplacements) {
1001 llvm::errs() <<
llvm::toString(CleanReplacements.takeError()) <<
"\n";
1004 FileToReplacements[FilePath] = *CleanReplacements;
1009 for (
auto &
Entry : FileToReplacements)
1010 if (!FilePatternRE.match(
Entry.first))
1011 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.
===– 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)