12 #include "clang/ASTMatchers/ASTMatchers.h" 13 #include "clang/Basic/SourceManager.h" 14 #include "clang/Format/Format.h" 15 #include "clang/Frontend/CompilerInstance.h" 16 #include "clang/Lex/Lexer.h" 17 #include "clang/Lex/Preprocessor.h" 18 #include "clang/Rewrite/Core/Rewriter.h" 19 #include "clang/Tooling/Core/Replacement.h" 20 #include "llvm/Support/Debug.h" 21 #include "llvm/Support/Path.h" 23 #define DEBUG_TYPE "clang-move" 32 AST_MATCHER(VarDecl, isStaticDataMember) {
return Node.isStaticDataMember(); }
34 AST_MATCHER(NamedDecl, notInMacro) {
return !Node.getLocation().isMacroID(); }
37 ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
38 const auto *Context = Node.getDeclContext();
41 while (
const auto *NextContext = Context->getParent()) {
42 if (isa<NamespaceDecl>(NextContext) ||
43 isa<TranslationUnitDecl>(NextContext))
45 Context = NextContext;
47 return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
52 ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
53 const CXXRecordDecl *Parent = Node.getParent();
56 while (
const auto *NextParent =
57 dyn_cast<CXXRecordDecl>(Parent->getParent())) {
61 return InnerMatcher.matches(*Parent, Finder, Builder);
64 std::string CleanPath(StringRef
PathRef) {
65 llvm::SmallString<128>
Path(PathRef);
66 llvm::sys::path::remove_dots(Path,
true);
68 llvm::sys::path::native(Path);
74 std::string MakeAbsolutePath(StringRef CurrentDir, StringRef
Path) {
77 llvm::SmallString<128> InitialDirectory(CurrentDir);
78 llvm::SmallString<128> AbsolutePath(Path);
79 if (std::error_code EC =
81 llvm::errs() <<
"Warning: could not make absolute file: '" << EC.message()
83 return CleanPath(std::move(AbsolutePath));
91 std::string MakeAbsolutePath(
const SourceManager &SM, StringRef Path) {
92 llvm::SmallString<128> AbsolutePath(Path);
93 if (std::error_code EC =
94 SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
96 llvm::errs() <<
"Warning: could not make absolute file: '" << EC.message()
100 const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
101 llvm::sys::path::parent_path(AbsolutePath.str()));
103 StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
105 if (llvm::sys::path::is_absolute(DirName)) {
106 SmallString<128> AbsoluteFilename;
107 llvm::sys::path::append(AbsoluteFilename, DirName,
108 llvm::sys::path::filename(AbsolutePath.str()));
109 return CleanPath(AbsoluteFilename);
112 return CleanPath(AbsolutePath);
116 AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
117 AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
118 std::string, AbsoluteFilePath) {
119 auto &SourceManager = Finder->getASTContext().getSourceManager();
120 auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
121 if (ExpansionLoc.isInvalid())
124 SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
127 return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
131 class FindAllIncludes :
public clang::PPCallbacks {
133 explicit FindAllIncludes(SourceManager *SM,
ClangMoveTool *
const MoveTool)
134 : SM(*SM), MoveTool(MoveTool) {}
136 void InclusionDirective(clang::SourceLocation HashLoc,
137 const clang::Token & ,
139 clang::CharSourceRange FilenameRange,
140 const clang::FileEntry * ,
141 StringRef SearchPath, StringRef ,
142 const clang::Module * ,
143 SrcMgr::CharacteristicKind )
override {
144 if (
const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
145 MoveTool->
addIncludes(FileName, IsAngled, SearchPath,
146 FileEntry->getName(), FilenameRange, SM);
150 const SourceManager &SM;
156 void MoveDeclFromOldFileToNewFile(
ClangMoveTool *MoveTool,
const NamedDecl *D) {
162 class FunctionDeclarationMatch :
public MatchFinder::MatchCallback {
165 : MoveTool(MoveTool) {}
167 void run(
const MatchFinder::MatchResult &Result)
override {
168 const auto *FD = Result.Nodes.getNodeAs<clang::FunctionDecl>(
"function");
170 const clang::NamedDecl *D = FD;
171 if (
const auto *FTD = FD->getDescribedFunctionTemplate())
173 MoveDeclFromOldFileToNewFile(MoveTool, D);
180 class VarDeclarationMatch :
public MatchFinder::MatchCallback {
183 : MoveTool(MoveTool) {}
185 void run(
const MatchFinder::MatchResult &Result)
override {
186 const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
"var");
188 MoveDeclFromOldFileToNewFile(MoveTool, VD);
195 class TypeAliasMatch :
public MatchFinder::MatchCallback {
198 : MoveTool(MoveTool) {}
200 void run(
const MatchFinder::MatchResult &Result)
override {
201 if (
const auto *TD = Result.Nodes.getNodeAs<clang::TypedefDecl>(
"typedef"))
202 MoveDeclFromOldFileToNewFile(MoveTool, TD);
203 else if (
const auto *TAD =
204 Result.Nodes.getNodeAs<clang::TypeAliasDecl>(
"type_alias")) {
205 const NamedDecl * D = TAD;
206 if (
const auto * TD = TAD->getDescribedAliasTemplate())
208 MoveDeclFromOldFileToNewFile(MoveTool, D);
216 class EnumDeclarationMatch :
public MatchFinder::MatchCallback {
219 : MoveTool(MoveTool) {}
221 void run(
const MatchFinder::MatchResult &Result)
override {
222 const auto *ED = Result.Nodes.getNodeAs<clang::EnumDecl>(
"enum");
224 MoveDeclFromOldFileToNewFile(MoveTool, ED);
231 class ClassDeclarationMatch :
public MatchFinder::MatchCallback {
234 : MoveTool(MoveTool) {}
235 void run(
const MatchFinder::MatchResult &Result)
override {
236 clang::SourceManager* SM = &Result.Context->getSourceManager();
237 if (
const auto *CMD =
238 Result.Nodes.getNodeAs<clang::CXXMethodDecl>(
"class_method"))
239 MatchClassMethod(CMD, SM);
240 else if (
const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
241 "class_static_var_decl"))
242 MatchClassStaticVariable(VD, SM);
243 else if (
const auto *CD = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
245 MatchClassDeclaration(CD, SM);
249 void MatchClassMethod(
const clang::CXXMethodDecl* CMD,
250 clang::SourceManager* SM) {
253 if (!CMD->isInlined()) {
258 if (
const auto *FTD = CMD->getDescribedFunctionTemplate())
265 void MatchClassStaticVariable(
const clang::NamedDecl *VD,
266 clang::SourceManager* SM) {
267 MoveDeclFromOldFileToNewFile(MoveTool, VD);
270 void MatchClassDeclaration(
const clang::CXXRecordDecl *CD,
271 clang::SourceManager* SM) {
274 if (
const auto *TC = CD->getDescribedClassTemplate())
289 getLocForEndOfDecl(
const clang::Decl *D,
290 const LangOptions &LangOpts = clang::LangOptions()) {
291 const auto &SM = D->getASTContext().getSourceManager();
295 auto EndExpansionLoc = SM.getExpansionRange(D->getLocEnd()).getEnd();
296 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
298 bool InvalidTemp =
false;
299 llvm::StringRef
File = SM.getBufferData(LocInfo.first, &InvalidTemp);
301 return SourceLocation();
303 const char *TokBegin = File.data() + LocInfo.second;
305 Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
306 TokBegin, File.end());
308 llvm::SmallVector<char, 16>
Line;
310 Lex.setParsingPreprocessorDirective(
true);
311 Lex.ReadToEndOfLine(&Line);
312 SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
316 return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
318 : EndLoc.getLocWithOffset(1);
322 clang::CharSourceRange
323 getFullRange(
const clang::Decl *D,
324 const clang::LangOptions &options = clang::LangOptions()) {
325 const auto &SM = D->getASTContext().getSourceManager();
326 clang::SourceRange Full(SM.getExpansionLoc(D->getLocStart()),
327 getLocForEndOfDecl(D));
329 if (
const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
330 if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getLocEnd()))
331 Full.setEnd(Comment->getLocEnd());
334 if (SM.isBeforeInTranslationUnit(Comment->getLocStart(), Full.getBegin()))
335 Full.setBegin(Comment->getLocStart());
338 return clang::CharSourceRange::getCharRange(Full);
341 std::string getDeclarationSourceText(
const clang::Decl *D) {
342 const auto &SM = D->getASTContext().getSourceManager();
343 llvm::StringRef SourceText =
344 clang::Lexer::getSourceText(getFullRange(D), SM, clang::LangOptions());
345 return SourceText.str();
348 bool isInHeaderFile(
const clang::Decl *D,
349 llvm::StringRef OriginalRunningDirectory,
350 llvm::StringRef OldHeader) {
351 const auto &SM = D->getASTContext().getSourceManager();
352 if (OldHeader.empty())
354 auto ExpansionLoc = SM.getExpansionLoc(D->getLocStart());
355 if (ExpansionLoc.isInvalid())
358 if (
const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
359 return MakeAbsolutePath(SM, FE->getName()) ==
360 MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
366 std::vector<std::string> getNamespaces(
const clang::Decl *D) {
367 std::vector<std::string> Namespaces;
368 for (
const auto *Context = D->getDeclContext(); Context;
369 Context = Context->getParent()) {
370 if (llvm::isa<clang::TranslationUnitDecl>(Context) ||
371 llvm::isa<clang::LinkageSpecDecl>(Context))
374 if (
const auto *ND = llvm::dyn_cast<clang::NamespaceDecl>(Context))
375 Namespaces.push_back(ND->getName().str());
377 std::reverse(Namespaces.begin(), Namespaces.end());
381 clang::tooling::Replacements
382 createInsertedReplacements(
const std::vector<std::string> &Includes,
383 const std::vector<const NamedDecl *> &Decls,
384 llvm::StringRef
FileName,
bool IsHeader =
false,
385 StringRef OldHeaderInclude =
"") {
387 std::string GuardName(FileName);
389 for (
size_t i = 0; i < GuardName.size(); ++i) {
390 if (!isAlphanumeric(GuardName[i]))
393 GuardName = StringRef(GuardName).upper();
394 NewCode +=
"#ifndef " + GuardName +
"\n";
395 NewCode +=
"#define " + GuardName +
"\n\n";
398 NewCode += OldHeaderInclude;
400 for (
const auto &Include : Includes)
403 if (!Includes.empty())
410 std::vector<std::string> CurrentNamespaces;
411 for (
const auto *MovedDecl : Decls) {
413 std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
414 auto CurrentIt = CurrentNamespaces.begin();
415 auto DeclIt = DeclNamespaces.begin();
417 while (CurrentIt != CurrentNamespaces.end() &&
418 DeclIt != DeclNamespaces.end()) {
419 if (*CurrentIt != *DeclIt)
426 std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
428 NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
432 bool HasEndCurrentNamespace =
false;
433 auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
434 for (
auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
435 --RemainingSize, ++It) {
436 assert(It < CurrentNamespaces.rend());
437 NewCode +=
"} // namespace " + *It +
"\n";
438 HasEndCurrentNamespace =
true;
441 if (HasEndCurrentNamespace)
446 bool IsInNewNamespace =
false;
447 while (DeclIt != DeclNamespaces.end()) {
448 NewCode +=
"namespace " + *DeclIt +
" {\n";
449 IsInNewNamespace =
true;
455 if (!IsInNewNamespace)
457 NewCode += getDeclarationSourceText(MovedDecl);
458 CurrentNamespaces = std::move(NextNamespaces);
460 std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
461 for (
const auto &NS : CurrentNamespaces)
462 NewCode +=
"} // namespace " + NS +
"\n";
465 NewCode +=
"\n#endif // " + GuardName +
"\n";
466 return clang::tooling::Replacements(
467 clang::tooling::Replacement(FileName, 0, 0, NewCode));
473 llvm::DenseSet<const Decl *>
475 const std::vector<const NamedDecl *> &Decls) {
477 llvm::DenseSet<const CallGraphNode *> Nodes;
478 for (
const auto *D : Decls) {
480 HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
481 Nodes.insert(Result.begin(), Result.end());
483 llvm::DenseSet<const Decl *>
Results;
484 for (
const auto *Node : Nodes)
485 Results.insert(Node->getDecl());
491 std::unique_ptr<clang::ASTConsumer>
492 ClangMoveAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
494 Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
495 &Compiler.getSourceManager(), &MoveTool));
496 return MatchFinder.newASTConsumer();
501 : Context(Context), Reporter(Reporter) {
503 CCIncludes.push_back(
"#include \"" + Context->
Spec.
NewHeader +
"\"\n");
507 const auto &SM = Decl->getASTContext().getSourceManager();
508 auto Loc = Decl->getLocation();
509 StringRef FilePath = SM.getFilename(
Loc);
510 FilePathToFileID[FilePath] = SM.getFileID(
Loc);
511 RemovedDecls.push_back(Decl);
516 isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldHeader));
517 auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldCC));
518 auto InOldFiles = anyOf(InOldHeader, InOldCC);
519 auto classTemplateForwardDecls =
520 classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
521 auto ForwardClassDecls = namedDecl(
522 anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
523 classTemplateForwardDecls));
525 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
535 auto AllDeclsInHeader = namedDecl(
536 unless(ForwardClassDecls), unless(namespaceDecl()),
537 unless(usingDirectiveDecl()),
540 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
541 hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
542 Finder->addMatcher(AllDeclsInHeader.bind(
"decls_in_header"),
this);
549 Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind(
"fwd_decl"),
555 auto IsOldCCTopLevelDecl = allOf(
556 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
560 Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
561 usingDirectiveDecl(IsOldCCTopLevelDecl),
562 typeAliasDecl(IsOldCCTopLevelDecl)),
569 Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
570 for (StringRef SymbolName : Context->
Spec.
Names) {
571 llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(
':');
572 const auto HasName = hasName((
"::" + GlobalSymbolName).str());
574 HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
577 if (!HasAnySymbolNames) {
578 llvm::errs() <<
"No symbols being moved.\n";
582 hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
585 auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
586 auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
588 allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
597 auto HelperFuncOrVar =
598 namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
599 varDecl(isDefinition(), IsOldCCHelper)));
601 cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
604 namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind(
"helper_decls"),
614 declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind(
"dc")))
619 typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind(
"used_class")))),
620 hasAncestor(decl().bind(
"dc"))),
627 MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(
this));
629 auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
630 isDefinition(), TopLevelDecl)
631 .bind(
"moved_class");
632 Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
636 cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
638 .bind(
"class_method"),
639 MatchCallbacks.back().get());
642 varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
643 .bind(
"class_static_var_decl"),
644 MatchCallbacks.back().get());
646 MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(
this));
647 Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
649 MatchCallbacks.back().get());
651 MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(
this));
653 varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind(
"var"),
654 MatchCallbacks.back().get());
658 MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(
this));
660 enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
662 MatchCallbacks.back().get());
667 MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(
this));
668 Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind(
"typedef"),
669 typeAliasDecl().bind(
"type_alias")),
670 InOldHeader, *HasAnySymbolNames, TopLevelDecl),
671 MatchCallbacks.back().get());
676 Result.Nodes.getNodeAs<clang::NamedDecl>(
"decls_in_header")) {
677 UnremovedDeclsInOldHeader.insert(D);
678 }
else if (
const auto *FWD =
679 Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
"fwd_decl")) {
681 if (RemovedDecls.empty()) {
682 if (
const auto *DCT = FWD->getDescribedClassTemplate())
683 MovedDecls.push_back(DCT);
685 MovedDecls.push_back(FWD);
687 }
else if (
const auto *ND =
688 Result.Nodes.getNodeAs<clang::NamedDecl>(
"helper_decls")) {
689 MovedDecls.push_back(ND);
690 HelperDeclarations.push_back(ND);
691 LLVM_DEBUG(llvm::dbgs() <<
"Add helper : " << ND->getNameAsString() <<
" (" 693 }
else if (
const auto *UD =
694 Result.Nodes.getNodeAs<clang::NamedDecl>(
"using_decl")) {
695 MovedDecls.push_back(UD);
699 std::string ClangMoveTool::makeAbsolutePath(StringRef
Path) {
704 llvm::StringRef SearchPath,
706 clang::CharSourceRange IncludeFilenameRange,
707 const SourceManager &SM) {
708 SmallVector<char, 128> HeaderWithSearchPath;
709 llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
710 std::string AbsoluteIncludeHeader =
711 MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
712 HeaderWithSearchPath.size()));
713 std::string IncludeLine =
714 IsAngled ? (
"#include <" + IncludeHeader +
">\n").str()
715 : (
"#include \"" + IncludeHeader +
"\"\n").str();
717 std::string AbsoluteOldHeader = makeAbsolutePath(Context->
Spec.
OldHeader);
718 std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
719 if (AbsoluteOldHeader == AbsoluteCurrentFile) {
721 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
722 OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
725 HeaderIncludes.push_back(IncludeLine);
726 }
else if (makeAbsolutePath(Context->
Spec.
OldCC) == AbsoluteCurrentFile) {
728 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
729 OldHeaderIncludeRangeInCC = IncludeFilenameRange;
732 CCIncludes.push_back(IncludeLine);
736 void ClangMoveTool::removeDeclsInOldFiles() {
737 if (RemovedDecls.empty())
return;
743 std::vector<const NamedDecl *> UnremovedDecls;
744 for (
const auto *D : UnremovedDeclsInOldHeader)
745 UnremovedDecls.push_back(D);
747 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), UnremovedDecls);
751 for (
const auto *D : HelperDeclarations) {
752 LLVM_DEBUG(llvm::dbgs() <<
"Check helper is used: " 753 << D->getNameAsString() <<
" (" << D <<
")\n");
755 D->getCanonicalDecl()))) {
756 LLVM_DEBUG(llvm::dbgs() <<
"Helper removed in old.cc: " 757 << D->getNameAsString() <<
" (" << D <<
")\n");
758 RemovedDecls.push_back(D);
763 for (
const auto *RemovedDecl : RemovedDecls) {
764 const auto &SM = RemovedDecl->getASTContext().getSourceManager();
765 auto Range = getFullRange(RemovedDecl);
766 clang::tooling::Replacement RemoveReplacement(
768 clang::CharSourceRange::getCharRange(
Range.getBegin(),
Range.getEnd()),
770 std::string FilePath = RemoveReplacement.getFilePath().str();
775 const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
779 StringRef FilePath = FileAndReplacements.first;
782 MakeAbsolutePath(SM, FilePath) ==
785 std::string IncludeNewH =
788 auto Err = FileAndReplacements.second.add(
789 tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
794 auto SI = FilePathToFileID.find(FilePath);
796 if (SI == FilePathToFileID.end())
continue;
797 llvm::StringRef Code = SM.getBufferData(SI->second);
798 auto Style = format::getStyle(
"file", FilePath, Context->
FallbackStyle);
803 auto CleanReplacements = format::cleanupAroundReplacements(
806 if (!CleanReplacements) {
807 llvm::errs() <<
llvm::toString(CleanReplacements.takeError()) <<
"\n";
814 void ClangMoveTool::moveDeclsToNewFiles() {
815 std::vector<const NamedDecl *> NewHeaderDecls;
816 std::vector<const NamedDecl *> NewCCDecls;
817 for (
const auto *MovedDecl : MovedDecls) {
820 NewHeaderDecls.push_back(MovedDecl);
822 NewCCDecls.push_back(MovedDecl);
825 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), RemovedDecls);
826 std::vector<const NamedDecl *> ActualNewCCDecls;
831 for (
const auto *D : NewCCDecls) {
832 if (llvm::is_contained(HelperDeclarations, D) &&
834 D->getCanonicalDecl())))
837 LLVM_DEBUG(llvm::dbgs() <<
"Helper used in new.cc: " << D->getNameAsString()
838 <<
" " << D <<
"\n");
839 ActualNewCCDecls.push_back(D);
843 std::string OldHeaderInclude =
848 createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
854 createInsertedReplacements(CCIncludes, ActualNewCCDecls,
859 void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
861 const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
863 llvm::errs() <<
"Failed to get file: " << OldFile <<
"\n";
866 FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
867 auto Begin = SM.getLocForStartOfFile(ID);
868 auto End = SM.getLocForEndOfFile(ID);
869 clang::tooling::Replacement RemoveAll (
870 SM, clang::CharSourceRange::getCharRange(Begin, End),
"");
871 std::string FilePath = RemoveAll.getFilePath().str();
873 clang::tooling::Replacements(RemoveAll);
875 StringRef Code = SM.getBufferData(ID);
876 if (!NewFile.empty()) {
877 auto AllCode = clang::tooling::Replacements(
878 clang::tooling::Replacement(NewFile, 0, 0, Code));
879 auto ReplaceOldInclude = [&](clang::CharSourceRange OldHeaderIncludeRange) {
880 AllCode = AllCode.merge(clang::tooling::Replacements(
881 clang::tooling::Replacement(SM, OldHeaderIncludeRange,
886 if (Context->
Spec.
NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
887 ReplaceOldInclude(OldHeaderIncludeRangeInCC);
889 OldHeaderIncludeRangeInHeader.isValid())
890 ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
898 for (
const auto *Decl : UnremovedDeclsInOldHeader) {
899 auto Kind = Decl->getKind();
900 const std::string QualifiedName = Decl->getQualifiedNameAsString();
901 if (
Kind == Decl::Kind::Var)
903 else if (
Kind == Decl::Kind::Function ||
904 Kind == Decl::Kind::FunctionTemplate)
906 else if (
Kind == Decl::Kind::ClassTemplate ||
907 Kind == Decl::Kind::CXXRecord)
909 else if (
Kind == Decl::Kind::Enum)
911 else if (
Kind == Decl::Kind::Typedef ||
912 Kind == Decl::Kind::TypeAlias ||
913 Kind == Decl::Kind::TypeAliasTemplate)
919 if (RemovedDecls.empty())
924 auto IsSupportedKind = [](
const clang::NamedDecl *Decl) {
925 switch (Decl->getKind()) {
926 case Decl::Kind::Function:
927 case Decl::Kind::FunctionTemplate:
928 case Decl::Kind::ClassTemplate:
929 case Decl::Kind::CXXRecord:
930 case Decl::Kind::Enum:
931 case Decl::Kind::Typedef:
932 case Decl::Kind::TypeAlias:
933 case Decl::Kind::TypeAliasTemplate:
934 case Decl::Kind::Var:
940 if (std::none_of(UnremovedDeclsInOldHeader.begin(),
941 UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
943 auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
949 moveDeclsToNewFiles();
950 removeDeclsInOldFiles();
SourceLocation Loc
'#' location in the include directive
AST_MATCHER(BinaryOperator, isAssignmentOperator)
std::string OriginalRunningDirectory
void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type)
llvm::DenseSet< const CallGraphNode * > getReachableNodes(const Decl *D) const
llvm::StringRef PathRef
A typedef to represent a ref to file path.
static llvm::StringRef toString(SpecialMemberFunctionsCheck::SpecialMemberFunctionKind K)
std::vector< CodeCompletionResult > Results
def make_absolute(f, directory)
SmallVector< std::string, 4 > Names
std::vector< HeaderHandle > Path
static const Decl * getOutmostClassOrFunDecl(const Decl *D)
std::string FallbackStyle
bool IsAngled
true if this was an include with angle brackets
const HelperDeclRefGraph * getGraph() const
std::map< std::string, tooling::Replacements > & FileToReplacements
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
AST_MATCHER_P(FunctionDecl, throws, internal::Matcher< Type >, InnerMatcher)
CharSourceRange Range
SourceRange for the file name.