11#include "clang/ASTMatchers/ASTMatchers.h"
12#include "clang/Basic/SourceManager.h"
13#include "clang/Format/Format.h"
14#include "clang/Frontend/CompilerInstance.h"
15#include "clang/Lex/Lexer.h"
16#include "clang/Lex/Preprocessor.h"
17#include "clang/Rewrite/Core/Rewriter.h"
18#include "clang/Tooling/Core/Replacement.h"
19#include "llvm/Support/Debug.h"
20#include "llvm/Support/Path.h"
22#define DEBUG_TYPE "clang-move"
31AST_MATCHER(VarDecl, isStaticDataMember) {
return Node.isStaticDataMember(); }
33AST_MATCHER(NamedDecl, notInMacro) {
return !Node.getLocation().isMacroID(); }
35AST_MATCHER_P(
Decl, hasOutermostEnclosingClass,
36 ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
37 const auto *Context = Node.getDeclContext();
40 while (
const auto *NextContext = Context->getParent()) {
41 if (isa<NamespaceDecl>(NextContext) ||
42 isa<TranslationUnitDecl>(NextContext))
44 Context = NextContext;
46 return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
50AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
51 ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
52 const CXXRecordDecl *
Parent = Node.getParent();
55 while (
const auto *NextParent =
56 dyn_cast<CXXRecordDecl>(
Parent->getParent())) {
63std::string CleanPath(StringRef PathRef) {
64 llvm::SmallString<128>
Path(PathRef);
65 llvm::sys::path::remove_dots(
Path,
true);
67 llvm::sys::path::native(
Path);
68 return std::string(
Path.str());
73std::string MakeAbsolutePath(StringRef CurrentDir, StringRef
Path) {
76 llvm::SmallString<128> InitialDirectory(CurrentDir);
77 llvm::SmallString<128> AbsolutePath(
Path);
78 llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
79 return CleanPath(std::move(AbsolutePath));
87std::string MakeAbsolutePath(
const SourceManager &SM, StringRef
Path) {
88 llvm::SmallString<128> AbsolutePath(
Path);
89 if (std::error_code EC =
90 SM.getFileManager().getVirtualFileSystem().makeAbsolute(AbsolutePath))
91 llvm::errs() <<
"Warning: could not make absolute file: '" << EC.message()
95 auto Dir = SM.getFileManager().getDirectory(
96 llvm::sys::path::parent_path(AbsolutePath.str()));
98 StringRef DirName = SM.getFileManager().getCanonicalName(*Dir);
100 if (llvm::sys::path::is_absolute(DirName)) {
101 SmallString<128> AbsoluteFilename;
102 llvm::sys::path::append(AbsoluteFilename, DirName,
103 llvm::sys::path::filename(AbsolutePath.str()));
104 return CleanPath(AbsoluteFilename);
107 return CleanPath(AbsolutePath);
111AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
112 AST_POLYMORPHIC_SUPPORTED_TYPES(
Decl, Stmt, TypeLoc),
113 std::string, AbsoluteFilePath) {
114 auto &SourceManager = Finder->getASTContext().getSourceManager();
115 auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
116 if (ExpansionLoc.isInvalid())
119 SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
122 return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
128 explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *
const MoveTool)
129 : SM(*SM), MoveTool(MoveTool) {}
131 void InclusionDirective(SourceLocation HashLoc,
const Token & ,
133 CharSourceRange FilenameRange,
134 OptionalFileEntryRef , StringRef SearchPath,
137 SrcMgr::CharacteristicKind )
override {
138 if (
const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
140 FileEntry->getName(), FilenameRange, SM);
144 const SourceManager &SM;
145 ClangMoveTool *
const MoveTool;
150void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool,
const NamedDecl *D) {
156class FunctionDeclarationMatch :
public MatchFinder::MatchCallback {
158 explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
159 : MoveTool(MoveTool) {}
161 void run(
const MatchFinder::MatchResult &Result)
override {
162 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(
"function");
164 const NamedDecl *D = FD;
165 if (
const auto *FTD = FD->getDescribedFunctionTemplate())
167 MoveDeclFromOldFileToNewFile(MoveTool, D);
171 ClangMoveTool *MoveTool;
174class VarDeclarationMatch :
public MatchFinder::MatchCallback {
176 explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
177 : MoveTool(MoveTool) {}
179 void run(
const MatchFinder::MatchResult &Result)
override {
180 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"var");
182 MoveDeclFromOldFileToNewFile(MoveTool, VD);
186 ClangMoveTool *MoveTool;
189class TypeAliasMatch :
public MatchFinder::MatchCallback {
191 explicit TypeAliasMatch(ClangMoveTool *MoveTool)
192 : MoveTool(MoveTool) {}
194 void run(
const MatchFinder::MatchResult &Result)
override {
195 if (
const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>(
"typedef"))
196 MoveDeclFromOldFileToNewFile(MoveTool, TD);
197 else if (
const auto *TAD =
198 Result.Nodes.getNodeAs<TypeAliasDecl>(
"type_alias")) {
199 const NamedDecl * D = TAD;
200 if (
const auto * TD = TAD->getDescribedAliasTemplate())
202 MoveDeclFromOldFileToNewFile(MoveTool, D);
207 ClangMoveTool *MoveTool;
210class EnumDeclarationMatch :
public MatchFinder::MatchCallback {
212 explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
213 : MoveTool(MoveTool) {}
215 void run(
const MatchFinder::MatchResult &Result)
override {
216 const auto *ED = Result.Nodes.getNodeAs<EnumDecl>(
"enum");
218 MoveDeclFromOldFileToNewFile(MoveTool, ED);
222 ClangMoveTool *MoveTool;
225class ClassDeclarationMatch :
public MatchFinder::MatchCallback {
227 explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
228 : MoveTool(MoveTool) {}
229 void run(
const MatchFinder::MatchResult &Result)
override {
230 SourceManager *SM = &Result.Context->getSourceManager();
231 if (
const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>(
"class_method"))
232 MatchClassMethod(CMD, SM);
233 else if (
const auto *VD =
234 Result.Nodes.getNodeAs<VarDecl>(
"class_static_var_decl"))
235 MatchClassStaticVariable(VD, SM);
236 else if (
const auto *CD =
237 Result.Nodes.getNodeAs<CXXRecordDecl>(
"moved_class"))
238 MatchClassDeclaration(CD, SM);
242 void MatchClassMethod(
const CXXMethodDecl *CMD, SourceManager *SM) {
245 if (!CMD->isInlined()) {
246 MoveTool->getMovedDecls().push_back(CMD);
247 MoveTool->addRemovedDecl(CMD);
250 if (
const auto *FTD = CMD->getDescribedFunctionTemplate())
251 MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
253 MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
257 void MatchClassStaticVariable(
const NamedDecl *VD, SourceManager *SM) {
258 MoveDeclFromOldFileToNewFile(MoveTool, VD);
261 void MatchClassDeclaration(
const CXXRecordDecl *CD, SourceManager *SM) {
264 if (
const auto *TC = CD->getDescribedClassTemplate())
265 MoveTool->getMovedDecls().push_back(TC);
267 MoveTool->getMovedDecls().push_back(CD);
268 MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
269 MoveTool->getUnremovedDeclsInOldHeader().erase(
270 MoveTool->getMovedDecls().back());
273 ClangMoveTool *MoveTool;
278SourceLocation getLocForEndOfDecl(
const Decl *D,
279 const LangOptions &LangOpts = LangOptions()) {
280 const auto &SM = D->getASTContext().getSourceManager();
284 auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
285 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
287 bool InvalidTemp =
false;
288 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
290 return SourceLocation();
292 const char *TokBegin = File.data() + LocInfo.second;
294 Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
295 TokBegin, File.end());
297 llvm::SmallVector<char, 16>
Line;
299 Lex.setParsingPreprocessorDirective(
true);
300 Lex.ReadToEndOfLine(&
Line);
301 SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(
Line.size());
305 return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
307 : EndLoc.getLocWithOffset(1);
311CharSourceRange getFullRange(
const Decl *D,
312 const LangOptions &options = LangOptions()) {
313 const auto &SM = D->getASTContext().getSourceManager();
314 SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
316 if (
const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
317 if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
318 Full.setEnd(Comment->getEndLoc());
321 if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
322 Full.setBegin(Comment->getBeginLoc());
325 return CharSourceRange::getCharRange(Full);
328std::string getDeclarationSourceText(
const Decl *D) {
329 const auto &SM = D->getASTContext().getSourceManager();
330 llvm::StringRef SourceText =
331 Lexer::getSourceText(getFullRange(D), SM, LangOptions());
332 return SourceText.str();
335bool isInHeaderFile(
const Decl *D, llvm::StringRef OriginalRunningDirectory,
336 llvm::StringRef OldHeader) {
337 const auto &SM = D->getASTContext().getSourceManager();
338 if (OldHeader.empty())
340 auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
341 if (ExpansionLoc.isInvalid())
344 if (
const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
345 return MakeAbsolutePath(SM, FE->getName()) ==
346 MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
352std::vector<std::string> getNamespaces(
const Decl *D) {
353 std::vector<std::string> Namespaces;
354 for (
const auto *Context = D->getDeclContext(); Context;
355 Context = Context->getParent()) {
356 if (llvm::isa<TranslationUnitDecl>(Context) ||
357 llvm::isa<LinkageSpecDecl>(Context))
360 if (
const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
361 Namespaces.push_back(ND->getName().str());
363 std::reverse(Namespaces.begin(), Namespaces.end());
368createInsertedReplacements(
const std::vector<std::string> &Includes,
369 const std::vector<const NamedDecl *> &Decls,
370 llvm::StringRef
FileName,
bool IsHeader =
false,
371 StringRef OldHeaderInclude =
"") {
375 for (
size_t i = 0; i < GuardName.size(); ++i) {
376 if (!isAlphanumeric(GuardName[i]))
379 GuardName = StringRef(GuardName).upper();
380 NewCode +=
"#ifndef " + GuardName +
"\n";
381 NewCode +=
"#define " + GuardName +
"\n\n";
384 NewCode += OldHeaderInclude;
386 for (
const auto &Include : Includes)
389 if (!Includes.empty())
396 std::vector<std::string> CurrentNamespaces;
397 for (
const auto *MovedDecl : Decls) {
399 std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
400 auto CurrentIt = CurrentNamespaces.begin();
401 auto DeclIt = DeclNamespaces.begin();
403 while (CurrentIt != CurrentNamespaces.end() &&
404 DeclIt != DeclNamespaces.end()) {
405 if (*CurrentIt != *DeclIt)
412 std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
414 NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
418 bool HasEndCurrentNamespace =
false;
419 auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
420 for (
auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
421 --RemainingSize, ++It) {
422 assert(It < CurrentNamespaces.rend());
423 NewCode +=
"} // namespace " + *It +
"\n";
424 HasEndCurrentNamespace =
true;
427 if (HasEndCurrentNamespace)
432 bool IsInNewNamespace =
false;
433 while (DeclIt != DeclNamespaces.end()) {
434 NewCode +=
"namespace " + *DeclIt +
" {\n";
435 IsInNewNamespace =
true;
441 if (!IsInNewNamespace)
443 NewCode += getDeclarationSourceText(MovedDecl);
444 CurrentNamespaces = std::move(NextNamespaces);
446 std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
447 for (
const auto &NS : CurrentNamespaces)
448 NewCode +=
"} // namespace " + NS +
"\n";
451 NewCode +=
"\n#endif // " + GuardName +
"\n";
452 return tooling::Replacements(tooling::Replacement(
FileName, 0, 0, NewCode));
458llvm::DenseSet<const Decl *>
459getUsedDecls(
const HelperDeclRefGraph *RG,
460 const std::vector<const NamedDecl *> &Decls) {
462 llvm::DenseSet<const CallGraphNode *> Nodes;
463 for (
const auto *D : Decls) {
464 auto Result = RG->getReachableNodes(
466 Nodes.insert(Result.begin(), Result.end());
468 llvm::DenseSet<const Decl *>
Results;
469 for (
const auto *Node : Nodes)
470 Results.insert(Node->getDecl());
476std::unique_ptr<ASTConsumer>
479 Compiler.getPreprocessor().addPPCallbacks(std::make_unique<FindAllIncludes>(
480 &Compiler.getSourceManager(), &MoveTool));
481 return MatchFinder.newASTConsumer();
486 : Context(Context), Reporter(Reporter) {
487 if (!Context->Spec.NewHeader.empty())
488 CCIncludes.push_back(
"#include \"" + Context->Spec.NewHeader +
"\"\n");
492 const auto &SM =
Decl->getASTContext().getSourceManager();
493 auto Loc =
Decl->getLocation();
494 StringRef FilePath = SM.getFilename(
Loc);
495 FilePathToFileID[FilePath] = SM.getFileID(
Loc);
496 RemovedDecls.push_back(
Decl);
501 isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldHeader));
502 auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldCC));
503 auto InOldFiles = anyOf(InOldHeader, InOldCC);
504 auto classTemplateForwardDecls =
505 classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
506 auto ForwardClassDecls = namedDecl(
507 anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
508 classTemplateForwardDecls));
510 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
520 auto AllDeclsInHeader = namedDecl(
521 unless(ForwardClassDecls), unless(namespaceDecl()),
522 unless(usingDirectiveDecl()),
525 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
526 hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
527 Finder->addMatcher(AllDeclsInHeader.bind(
"decls_in_header"),
this);
534 Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind(
"fwd_decl"),
540 auto IsOldCCTopLevelDecl = allOf(
541 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
545 Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
546 usingDirectiveDecl(unless(isImplicit()),
547 IsOldCCTopLevelDecl),
548 typeAliasDecl(IsOldCCTopLevelDecl)),
555 SmallVector<std::string, 4> QualNames;
556 QualNames.reserve(Context->
Spec.
Names.size());
557 for (StringRef SymbolName : Context->
Spec.
Names) {
558 QualNames.push_back((
"::" + SymbolName.trim().ltrim(
':')).str());
561 if (QualNames.empty()) {
562 llvm::errs() <<
"No symbols being moved.\n";
566 ast_matchers::internal::Matcher<NamedDecl> HasAnySymbolNames =
567 hasAnyName(SmallVector<StringRef, 4>(QualNames.begin(), QualNames.end()));
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(std::make_unique<ClassDeclarationMatch>(
this));
618 cxxRecordDecl(InOldFiles, HasAnySymbolNames, isDefinition(), TopLevelDecl)
619 .bind(
"moved_class");
620 Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
623 Finder->addMatcher(cxxMethodDecl(InOldFiles,
624 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(std::make_unique<FunctionDeclarationMatch>(
this));
635 Finder->addMatcher(functionDecl(InOldFiles, HasAnySymbolNames, TopLevelDecl)
637 MatchCallbacks.back().get());
639 MatchCallbacks.push_back(std::make_unique<VarDeclarationMatch>(
this));
641 varDecl(InOldFiles, HasAnySymbolNames, TopLevelDecl).bind(
"var"),
642 MatchCallbacks.back().get());
646 MatchCallbacks.push_back(std::make_unique<EnumDeclarationMatch>(
this));
648 enumDecl(InOldHeader, HasAnySymbolNames, isDefinition(), TopLevelDecl)
650 MatchCallbacks.back().get());
655 MatchCallbacks.push_back(std::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()
679 <<
"Add helper : " << ND->getDeclName() <<
" (" << ND <<
")\n");
680 }
else if (
const auto *UD = Result.Nodes.getNodeAs<NamedDecl>(
"using_decl")) {
681 MovedDecls.push_back(UD);
685std::string ClangMoveTool::makeAbsolutePath(StringRef
Path) {
690 llvm::StringRef SearchPath,
692 CharSourceRange IncludeFilenameRange,
693 const SourceManager &SM) {
694 SmallString<128> HeaderWithSearchPath;
695 llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
696 std::string AbsoluteIncludeHeader =
697 MakeAbsolutePath(SM, HeaderWithSearchPath);
698 std::string IncludeLine =
699 IsAngled ? (
"#include <" + IncludeHeader +
">\n").str()
700 : (
"#include \"" + IncludeHeader +
"\"\n").str();
702 std::string AbsoluteOldHeader = makeAbsolutePath(Context->
Spec.
OldHeader);
703 std::string AbsoluteCurrentFile = MakeAbsolutePath(SM,
FileName);
704 if (AbsoluteOldHeader == AbsoluteCurrentFile) {
706 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
707 OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
710 HeaderIncludes.push_back(IncludeLine);
711 }
else if (makeAbsolutePath(Context->
Spec.
OldCC) == AbsoluteCurrentFile) {
713 if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
714 OldHeaderIncludeRangeInCC = IncludeFilenameRange;
717 CCIncludes.push_back(IncludeLine);
721void ClangMoveTool::removeDeclsInOldFiles() {
722 if (RemovedDecls.empty())
return;
728 std::vector<const NamedDecl *> UnremovedDecls;
729 for (
const auto *D : UnremovedDeclsInOldHeader)
730 UnremovedDecls.push_back(D);
732 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), UnremovedDecls);
736 for (
const auto *D : HelperDeclarations) {
737 LLVM_DEBUG(llvm::dbgs() <<
"Check helper is used: " << D->getDeclName()
738 <<
" (" << D <<
")\n");
740 D->getCanonicalDecl()))) {
741 LLVM_DEBUG(llvm::dbgs() <<
"Helper removed in old.cc: "
742 << D->getDeclName() <<
" (" << D <<
")\n");
743 RemovedDecls.push_back(D);
748 for (
const auto *RemovedDecl : RemovedDecls) {
749 const auto &SM = RemovedDecl->getASTContext().getSourceManager();
750 auto Range = getFullRange(RemovedDecl);
751 tooling::Replacement RemoveReplacement(
752 SM, CharSourceRange::getCharRange(
Range.getBegin(),
Range.getEnd()),
754 std::string FilePath = RemoveReplacement.getFilePath().str();
757 llvm::errs() << llvm::toString(std::move(Err)) <<
"\n";
759 const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
763 StringRef FilePath = FileAndReplacements.first;
766 MakeAbsolutePath(SM, FilePath) ==
769 std::string IncludeNewH =
772 auto Err = FileAndReplacements.second.add(
773 tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
775 llvm::errs() << llvm::toString(std::move(Err)) <<
"\n";
778 auto SI = FilePathToFileID.find(FilePath);
780 if (SI == FilePathToFileID.end())
continue;
781 llvm::StringRef
Code = SM.getBufferData(SI->second);
782 auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
785 llvm::errs() << llvm::toString(Style.takeError()) <<
"\n";
788 auto CleanReplacements = format::cleanupAroundReplacements(
791 if (!CleanReplacements) {
792 llvm::errs() << llvm::toString(CleanReplacements.takeError()) <<
"\n";
799void ClangMoveTool::moveDeclsToNewFiles() {
800 std::vector<const NamedDecl *> NewHeaderDecls;
801 std::vector<const NamedDecl *> NewCCDecls;
802 for (
const auto *MovedDecl : MovedDecls) {
805 NewHeaderDecls.push_back(MovedDecl);
807 NewCCDecls.push_back(MovedDecl);
810 auto UsedDecls = getUsedDecls(RGBuilder.
getGraph(), RemovedDecls);
811 std::vector<const NamedDecl *> ActualNewCCDecls;
816 for (
const auto *D : NewCCDecls) {
817 if (llvm::is_contained(HelperDeclarations, D) &&
819 D->getCanonicalDecl())))
822 LLVM_DEBUG(llvm::dbgs() <<
"Helper used in new.cc: " <<
D->getDeclName()
823 <<
" " << D <<
"\n");
824 ActualNewCCDecls.push_back(D);
828 std::string OldHeaderInclude =
833 createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
839 createInsertedReplacements(CCIncludes, ActualNewCCDecls,
844void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
846 auto FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
848 llvm::errs() <<
"Failed to get file: " << OldFile <<
"\n";
851 FileID ID = SM.getOrCreateFileID(*FE, SrcMgr::C_User);
852 auto Begin = SM.getLocForStartOfFile(ID);
853 auto End = SM.getLocForEndOfFile(ID);
854 tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
856 std::string FilePath = RemoveAll.getFilePath().str();
859 StringRef
Code = SM.getBufferData(ID);
860 if (!NewFile.empty()) {
862 tooling::Replacements(tooling::Replacement(NewFile, 0, 0,
Code));
863 auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
864 AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
865 SM, OldHeaderIncludeRange,
'"' + Context->
Spec.
NewHeader +
'"')));
869 if (Context->
Spec.
NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
870 ReplaceOldInclude(OldHeaderIncludeRangeInCC);
872 OldHeaderIncludeRangeInHeader.isValid())
873 ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
881 for (
const auto *
Decl : UnremovedDeclsInOldHeader) {
883 bool Templated =
Decl->isTemplated();
884 const std::string QualifiedName =
Decl->getQualifiedNameAsString();
885 if (
Kind == Decl::Kind::Var)
887 else if (
Kind == Decl::Kind::Function ||
888 Kind == Decl::Kind::FunctionTemplate)
890 else if (
Kind == Decl::Kind::ClassTemplate ||
891 Kind == Decl::Kind::CXXRecord)
893 else if (
Kind == Decl::Kind::Enum)
895 else if (
Kind == Decl::Kind::Typedef ||
Kind == Decl::Kind::TypeAlias ||
896 Kind == Decl::Kind::TypeAliasTemplate)
902 if (RemovedDecls.empty())
907 auto IsSupportedKind = [](
const NamedDecl *
Decl) {
908 switch (
Decl->getKind()) {
909 case Decl::Kind::Function:
910 case Decl::Kind::FunctionTemplate:
911 case Decl::Kind::ClassTemplate:
912 case Decl::Kind::CXXRecord:
913 case Decl::Kind::Enum:
914 case Decl::Kind::Typedef:
915 case Decl::Kind::TypeAlias:
916 case Decl::Kind::TypeAliasTemplate:
917 case Decl::Kind::Var:
923 if (llvm::none_of(UnremovedDeclsInOldHeader, IsSupportedKind) &&
925 auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
931 moveDeclsToNewFiles();
932 removeDeclsInOldFiles();
const FunctionDecl * Decl
std::vector< CodeCompletionResult > Results
CodeCompletionBuilder Builder
CharSourceRange Range
SourceRange for the file name.
bool IsAngled
true if this was an include with angle brackets
std::vector< HeaderHandle > Path
std::unique_ptr< clang::ASTConsumer > CreateASTConsumer(clang::CompilerInstance &Compiler, llvm::StringRef InFile) override
void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type, bool Templated)
static const Decl * getOutmostClassOrFunDecl(const Decl *D)
const HelperDeclRefGraph * getGraph() const
AST_MATCHER(Decl, declHasNoReturnAttr)
matches a Decl if it has a "no return" attribute of any kind
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::map< std::string, tooling::Replacements > & FileToReplacements
std::string FallbackStyle
std::string OriginalRunningDirectory
SmallVector< std::string, 4 > Names