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);
80 return CleanPath(std::move(AbsolutePath));
88 std::string MakeAbsolutePath(
const SourceManager &SM, StringRef Path) {
89 llvm::SmallString<128> AbsolutePath(Path);
90 if (std::error_code EC =
91 SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
93 llvm::errs() <<
"Warning: could not make absolute file: '" << EC.message()
97 const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
98 llvm::sys::path::parent_path(AbsolutePath.str()));
100 StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
102 if (llvm::sys::path::is_absolute(DirName)) {
103 SmallString<128> AbsoluteFilename;
104 llvm::sys::path::append(AbsoluteFilename, DirName,
105 llvm::sys::path::filename(AbsolutePath.str()));
106 return CleanPath(AbsoluteFilename);
109 return CleanPath(AbsolutePath);
113 AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
114 AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
115 std::string, AbsoluteFilePath) {
116 auto &SourceManager = Finder->getASTContext().getSourceManager();
117 auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
118 if (ExpansionLoc.isInvalid())
121 SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
124 return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
128 class FindAllIncludes :
public PPCallbacks {
130 explicit FindAllIncludes(SourceManager *SM,
ClangMoveTool *
const MoveTool)
131 : SM(*SM), MoveTool(MoveTool) {}
133 void InclusionDirective(SourceLocation HashLoc,
const Token & ,
135 CharSourceRange FilenameRange,
136 const FileEntry * , StringRef SearchPath,
139 SrcMgr::CharacteristicKind )
override {
140 if (
const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
141 MoveTool->
addIncludes(FileName, IsAngled, SearchPath,
142 FileEntry->getName(), FilenameRange, SM);
146 const SourceManager &SM;
152 void MoveDeclFromOldFileToNewFile(
ClangMoveTool *MoveTool,
const NamedDecl *
D) {
158 class FunctionDeclarationMatch :
public MatchFinder::MatchCallback {
161 : MoveTool(MoveTool) {}
163 void run(
const MatchFinder::MatchResult &
Result)
override {
164 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(
"function");
166 const NamedDecl *D = FD;
167 if (
const auto *FTD = FD->getDescribedFunctionTemplate())
169 MoveDeclFromOldFileToNewFile(MoveTool, D);
176 class VarDeclarationMatch :
public MatchFinder::MatchCallback {
179 : MoveTool(MoveTool) {}
181 void run(
const MatchFinder::MatchResult &
Result)
override {
182 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"var");
184 MoveDeclFromOldFileToNewFile(MoveTool, VD);
191 class TypeAliasMatch :
public MatchFinder::MatchCallback {
194 : MoveTool(MoveTool) {}
196 void run(
const MatchFinder::MatchResult &
Result)
override {
197 if (
const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>(
"typedef"))
198 MoveDeclFromOldFileToNewFile(MoveTool, TD);
199 else if (
const auto *TAD =
200 Result.Nodes.getNodeAs<TypeAliasDecl>(
"type_alias")) {
201 const NamedDecl * D = TAD;
202 if (
const auto * TD = TAD->getDescribedAliasTemplate())
204 MoveDeclFromOldFileToNewFile(MoveTool, D);
212 class EnumDeclarationMatch :
public MatchFinder::MatchCallback {
215 : MoveTool(MoveTool) {}
217 void run(
const MatchFinder::MatchResult &
Result)
override {
218 const auto *ED = Result.Nodes.getNodeAs<EnumDecl>(
"enum");
220 MoveDeclFromOldFileToNewFile(MoveTool, ED);
227 class ClassDeclarationMatch :
public MatchFinder::MatchCallback {
230 : MoveTool(MoveTool) {}
231 void run(
const MatchFinder::MatchResult &
Result)
override {
232 SourceManager *SM = &Result.Context->getSourceManager();
233 if (
const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>(
"class_method"))
234 MatchClassMethod(CMD, SM);
235 else if (
const auto *VD =
236 Result.Nodes.getNodeAs<VarDecl>(
"class_static_var_decl"))
237 MatchClassStaticVariable(VD, SM);
238 else if (
const auto *CD =
239 Result.Nodes.getNodeAs<CXXRecordDecl>(
"moved_class"))
240 MatchClassDeclaration(CD, SM);
244 void MatchClassMethod(
const CXXMethodDecl *CMD, SourceManager *SM) {
247 if (!CMD->isInlined()) {
252 if (
const auto *FTD = CMD->getDescribedFunctionTemplate())
259 void MatchClassStaticVariable(
const NamedDecl *VD, SourceManager *SM) {
260 MoveDeclFromOldFileToNewFile(MoveTool, VD);
263 void MatchClassDeclaration(
const CXXRecordDecl *CD, SourceManager *SM) {
266 if (
const auto *TC = CD->getDescribedClassTemplate())
280 SourceLocation getLocForEndOfDecl(
const Decl *D,
281 const LangOptions &LangOpts = LangOptions()) {
282 const auto &SM = D->getASTContext().getSourceManager();
286 auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
287 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
289 bool InvalidTemp =
false;
290 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
292 return SourceLocation();
294 const char *TokBegin = File.data() + LocInfo.second;
296 Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
297 TokBegin, File.end());
299 llvm::SmallVector<char, 16>
Line;
301 Lex.setParsingPreprocessorDirective(
true);
302 Lex.ReadToEndOfLine(&Line);
303 SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
307 return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
309 : EndLoc.getLocWithOffset(1);
313 CharSourceRange getFullRange(
const Decl *D,
314 const LangOptions &options = LangOptions()) {
315 const auto &SM = D->getASTContext().getSourceManager();
316 SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
318 if (
const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
319 if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
320 Full.setEnd(Comment->getEndLoc());
323 if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
324 Full.setBegin(Comment->getBeginLoc());
327 return CharSourceRange::getCharRange(Full);
330 std::string getDeclarationSourceText(
const Decl *D) {
331 const auto &SM = D->getASTContext().getSourceManager();
332 llvm::StringRef SourceText =
333 Lexer::getSourceText(getFullRange(D), SM, LangOptions());
334 return SourceText.str();
337 bool isInHeaderFile(
const Decl *D, llvm::StringRef OriginalRunningDirectory,
338 llvm::StringRef OldHeader) {
339 const auto &SM = D->getASTContext().getSourceManager();
340 if (OldHeader.empty())
342 auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
343 if (ExpansionLoc.isInvalid())
346 if (
const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
347 return MakeAbsolutePath(SM, FE->getName()) ==
348 MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
354 std::vector<std::string> getNamespaces(
const Decl *D) {
355 std::vector<std::string> Namespaces;
356 for (
const auto *Context = D->getDeclContext(); Context;
357 Context = Context->getParent()) {
358 if (llvm::isa<TranslationUnitDecl>(Context) ||
359 llvm::isa<LinkageSpecDecl>(Context))
362 if (
const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
363 Namespaces.push_back(ND->getName().str());
365 std::reverse(Namespaces.begin(), Namespaces.end());
369 tooling::Replacements
370 createInsertedReplacements(
const std::vector<std::string> &Includes,
371 const std::vector<const NamedDecl *> &Decls,
372 llvm::StringRef
FileName,
bool IsHeader =
false,
373 StringRef OldHeaderInclude =
"") {
375 std::string GuardName(FileName);
377 for (
size_t i = 0; i < GuardName.size(); ++i) {
378 if (!isAlphanumeric(GuardName[i]))
381 GuardName = StringRef(GuardName).upper();
382 NewCode +=
"#ifndef " + GuardName +
"\n";
383 NewCode +=
"#define " + GuardName +
"\n\n";
386 NewCode += OldHeaderInclude;
388 for (
const auto &Include : Includes)
391 if (!Includes.empty())
398 std::vector<std::string> CurrentNamespaces;
399 for (
const auto *MovedDecl : Decls) {
401 std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
402 auto CurrentIt = CurrentNamespaces.begin();
403 auto DeclIt = DeclNamespaces.begin();
405 while (CurrentIt != CurrentNamespaces.end() &&
406 DeclIt != DeclNamespaces.end()) {
407 if (*CurrentIt != *DeclIt)
414 std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
416 NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
420 bool HasEndCurrentNamespace =
false;
421 auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
422 for (
auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
423 --RemainingSize, ++It) {
424 assert(It < CurrentNamespaces.rend());
425 NewCode +=
"} // namespace " + *It +
"\n";
426 HasEndCurrentNamespace =
true;
429 if (HasEndCurrentNamespace)
434 bool IsInNewNamespace =
false;
435 while (DeclIt != DeclNamespaces.end()) {
436 NewCode +=
"namespace " + *DeclIt +
" {\n";
437 IsInNewNamespace =
true;
443 if (!IsInNewNamespace)
445 NewCode += getDeclarationSourceText(MovedDecl);
446 CurrentNamespaces = std::move(NextNamespaces);
448 std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
449 for (
const auto &NS : CurrentNamespaces)
450 NewCode +=
"} // namespace " + NS +
"\n";
453 NewCode +=
"\n#endif // " + GuardName +
"\n";
454 return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
460 llvm::DenseSet<const Decl *>
462 const std::vector<const NamedDecl *> &Decls) {
464 llvm::DenseSet<const CallGraphNode *> Nodes;
465 for (
const auto *D : Decls) {
467 HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
470 llvm::DenseSet<const Decl *>
Results;
471 for (
const auto *Node : Nodes)
472 Results.insert(Node->getDecl());
478 std::unique_ptr<ASTConsumer>
479 ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
481 Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
482 &Compiler.getSourceManager(), &MoveTool));
483 return MatchFinder.newASTConsumer();
488 : Context(Context), Reporter(Reporter) {
490 CCIncludes.push_back(
"#include \"" + Context->
Spec.
NewHeader +
"\"\n");
494 const auto &SM = Decl->getASTContext().getSourceManager();
495 auto Loc = Decl->getLocation();
496 StringRef FilePath = SM.getFilename(
Loc);
497 FilePathToFileID[FilePath] = SM.getFileID(
Loc);
498 RemovedDecls.push_back(Decl);
503 isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldHeader));
504 auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldCC));
505 auto InOldFiles = anyOf(InOldHeader, InOldCC);
506 auto classTemplateForwardDecls =
507 classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
508 auto ForwardClassDecls = namedDecl(
509 anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
510 classTemplateForwardDecls));
512 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
522 auto AllDeclsInHeader = namedDecl(
523 unless(ForwardClassDecls), unless(namespaceDecl()),
524 unless(usingDirectiveDecl()),
527 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
528 hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
529 Finder->addMatcher(AllDeclsInHeader.bind(
"decls_in_header"),
this);
536 Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind(
"fwd_decl"),
542 auto IsOldCCTopLevelDecl = allOf(
543 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
547 Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
548 usingDirectiveDecl(unless(isImplicit()),
549 IsOldCCTopLevelDecl),
550 typeAliasDecl(IsOldCCTopLevelDecl)),
557 Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
558 for (StringRef SymbolName : Context->
Spec.
Names) {
559 llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(
':');
560 const auto HasName = hasName((
"::" + GlobalSymbolName).str());
562 HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
565 if (!HasAnySymbolNames) {
566 llvm::errs() <<
"No symbols being moved.\n";
570 hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
573 auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
574 auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
576 allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
585 auto HelperFuncOrVar =
586 namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
587 varDecl(isDefinition(), IsOldCCHelper)));
589 cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
592 namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind(
"helper_decls"),
602 declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind(
"dc")))
607 typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind(
"used_class")))),
608 hasAncestor(decl().bind(
"dc"))),
615 MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(
this));
617 auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
618 isDefinition(), TopLevelDecl)
619 .bind(
"moved_class");
620 Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
624 cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
626 .bind(
"class_method"),
627 MatchCallbacks.back().get());
630 varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
631 .bind(
"class_static_var_decl"),
632 MatchCallbacks.back().get());
634 MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(
this));
635 Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
637 MatchCallbacks.back().get());
639 MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(
this));
641 varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind(
"var"),
642 MatchCallbacks.back().get());
646 MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(
this));
648 enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
650 MatchCallbacks.back().get());
655 MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(
this));
656 Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind(
"typedef"),
657 typeAliasDecl().bind(
"type_alias")),
658 InOldHeader, *HasAnySymbolNames, TopLevelDecl),
659 MatchCallbacks.back().get());
663 if (
const auto *
D = Result.Nodes.getNodeAs<NamedDecl>(
"decls_in_header")) {
664 UnremovedDeclsInOldHeader.insert(
D);
665 }
else if (
const auto *FWD =
666 Result.Nodes.getNodeAs<CXXRecordDecl>(
"fwd_decl")) {
668 if (RemovedDecls.empty()) {
669 if (
const auto *DCT = FWD->getDescribedClassTemplate())
670 MovedDecls.push_back(DCT);
672 MovedDecls.push_back(FWD);
674 }
else if (
const auto *ND =
675 Result.Nodes.getNodeAs<NamedDecl>(
"helper_decls")) {
676 MovedDecls.push_back(ND);
677 HelperDeclarations.push_back(ND);
678 LLVM_DEBUG(llvm::dbgs() <<
"Add helper : " << ND->getNameAsString() <<
" (" 680 }
else if (
const auto *UD = Result.Nodes.getNodeAs<NamedDecl>(
"using_decl")) {
681 MovedDecls.push_back(UD);
685 std::string ClangMoveTool::makeAbsolutePath(StringRef
Path) {
690 llvm::StringRef SearchPath,
692 CharSourceRange IncludeFilenameRange,
693 const SourceManager &SM) {
694 SmallVector<char, 128> HeaderWithSearchPath;
695 llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
696 std::string AbsoluteIncludeHeader =
697 MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
698 HeaderWithSearchPath.size()));
699 std::string IncludeLine =
700 IsAngled ? (
"#include <" + IncludeHeader +
">\n").str()
701 : (
"#include \"" + IncludeHeader +
"\"\n").str();
703 std::string AbsoluteOldHeader = makeAbsolutePath(Context->
Spec.
OldHeader);
704 std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
705 if (AbsoluteOldHeader == AbsoluteCurrentFile) {
707 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
708 OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
711 HeaderIncludes.push_back(IncludeLine);
712 }
else if (makeAbsolutePath(Context->
Spec.
OldCC) == AbsoluteCurrentFile) {
714 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
715 OldHeaderIncludeRangeInCC = IncludeFilenameRange;
718 CCIncludes.push_back(IncludeLine);
722 void ClangMoveTool::removeDeclsInOldFiles() {
723 if (RemovedDecls.empty())
return;
729 std::vector<const NamedDecl *> UnremovedDecls;
730 for (
const auto *
D : UnremovedDeclsInOldHeader)
731 UnremovedDecls.push_back(
D);
733 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), UnremovedDecls);
737 for (
const auto *
D : HelperDeclarations) {
738 LLVM_DEBUG(llvm::dbgs() <<
"Check helper is used: " 739 <<
D->getNameAsString() <<
" (" <<
D <<
")\n");
741 D->getCanonicalDecl()))) {
742 LLVM_DEBUG(llvm::dbgs() <<
"Helper removed in old.cc: " 743 <<
D->getNameAsString() <<
" (" <<
D <<
")\n");
744 RemovedDecls.push_back(
D);
749 for (
const auto *RemovedDecl : RemovedDecls) {
750 const auto &SM = RemovedDecl->getASTContext().getSourceManager();
751 auto Range = getFullRange(RemovedDecl);
752 tooling::Replacement RemoveReplacement(
753 SM, CharSourceRange::getCharRange(
Range.getBegin(),
Range.getEnd()),
755 std::string FilePath = RemoveReplacement.getFilePath().str();
760 const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
764 StringRef FilePath = FileAndReplacements.first;
767 MakeAbsolutePath(SM, FilePath) ==
770 std::string IncludeNewH =
773 auto Err = FileAndReplacements.second.add(
774 tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
779 auto SI = FilePathToFileID.find(FilePath);
781 if (SI == FilePathToFileID.end())
continue;
782 llvm::StringRef Code = SM.getBufferData(SI->second);
783 auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
789 auto CleanReplacements = format::cleanupAroundReplacements(
792 if (!CleanReplacements) {
793 llvm::errs() <<
llvm::toString(CleanReplacements.takeError()) <<
"\n";
800 void ClangMoveTool::moveDeclsToNewFiles() {
801 std::vector<const NamedDecl *> NewHeaderDecls;
802 std::vector<const NamedDecl *> NewCCDecls;
803 for (
const auto *MovedDecl : MovedDecls) {
806 NewHeaderDecls.push_back(MovedDecl);
808 NewCCDecls.push_back(MovedDecl);
811 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), RemovedDecls);
812 std::vector<const NamedDecl *> ActualNewCCDecls;
817 for (
const auto *
D : NewCCDecls) {
818 if (llvm::is_contained(HelperDeclarations,
D) &&
820 D->getCanonicalDecl())))
823 LLVM_DEBUG(llvm::dbgs() <<
"Helper used in new.cc: " <<
D->getNameAsString()
824 <<
" " <<
D <<
"\n");
825 ActualNewCCDecls.push_back(
D);
829 std::string OldHeaderInclude =
834 createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
840 createInsertedReplacements(CCIncludes, ActualNewCCDecls,
845 void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
847 const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
849 llvm::errs() <<
"Failed to get file: " << OldFile <<
"\n";
852 FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
853 auto Begin = SM.getLocForStartOfFile(ID);
854 auto End = SM.getLocForEndOfFile(ID);
855 tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
857 std::string FilePath = RemoveAll.getFilePath().str();
860 StringRef Code = SM.getBufferData(ID);
861 if (!NewFile.empty()) {
863 tooling::Replacements(tooling::Replacement(NewFile, 0, 0, Code));
864 auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
865 AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
866 SM, OldHeaderIncludeRange,
'"' + Context->
Spec.
NewHeader +
'"')));
870 if (Context->
Spec.
NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
871 ReplaceOldInclude(OldHeaderIncludeRangeInCC);
873 OldHeaderIncludeRangeInHeader.isValid())
874 ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
882 for (
const auto *Decl : UnremovedDeclsInOldHeader) {
883 auto Kind = Decl->getKind();
884 bool Templated = Decl->isTemplated();
885 const std::string QualifiedName = Decl->getQualifiedNameAsString();
886 if (
Kind == Decl::Kind::Var)
888 else if (
Kind == Decl::Kind::Function ||
889 Kind == Decl::Kind::FunctionTemplate)
891 else if (
Kind == Decl::Kind::ClassTemplate ||
892 Kind == Decl::Kind::CXXRecord)
894 else if (
Kind == Decl::Kind::Enum)
896 else if (
Kind == Decl::Kind::Typedef ||
Kind == Decl::Kind::TypeAlias ||
897 Kind == Decl::Kind::TypeAliasTemplate)
903 if (RemovedDecls.empty())
908 auto IsSupportedKind = [](
const NamedDecl *Decl) {
909 switch (Decl->getKind()) {
910 case Decl::Kind::Function:
911 case Decl::Kind::FunctionTemplate:
912 case Decl::Kind::ClassTemplate:
913 case Decl::Kind::CXXRecord:
914 case Decl::Kind::Enum:
915 case Decl::Kind::Typedef:
916 case Decl::Kind::TypeAlias:
917 case Decl::Kind::TypeAliasTemplate:
918 case Decl::Kind::Var:
924 if (std::none_of(UnremovedDeclsInOldHeader.begin(),
925 UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
927 auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
933 moveDeclsToNewFiles();
934 removeDeclsInOldFiles();
SourceLocation Loc
'#' location in the include directive
void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type, bool Templated)
AST_MATCHER(BinaryOperator, isAssignmentOperator)
std::string OriginalRunningDirectory
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
llvm::Optional< llvm::Expected< tooling::AtomicChanges > > Result
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.