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(); }
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,
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);
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().getOptionalDirectoryRef(
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.getFileEntryRefForID(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,
138 SrcMgr::CharacteristicKind )
override {
139 if (
auto FileEntry = SM.getFileEntryRefForID(SM.getFileID(HashLoc)))
141 FileEntry->getName(), FilenameRange, SM);
145 const SourceManager &SM;
146 ClangMoveTool *
const MoveTool;
151void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool,
const NamedDecl *D) {
157class FunctionDeclarationMatch :
public MatchFinder::MatchCallback {
159 explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
160 : MoveTool(MoveTool) {}
162 void run(
const MatchFinder::MatchResult &Result)
override {
163 const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>(
"function");
165 const NamedDecl *D = FD;
166 if (
const auto *FTD = FD->getDescribedFunctionTemplate())
168 MoveDeclFromOldFileToNewFile(MoveTool, D);
172 ClangMoveTool *MoveTool;
175class VarDeclarationMatch :
public MatchFinder::MatchCallback {
177 explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
178 : MoveTool(MoveTool) {}
180 void run(
const MatchFinder::MatchResult &Result)
override {
181 const auto *VD = Result.Nodes.getNodeAs<VarDecl>(
"var");
183 MoveDeclFromOldFileToNewFile(MoveTool, VD);
187 ClangMoveTool *MoveTool;
190class TypeAliasMatch :
public MatchFinder::MatchCallback {
192 explicit TypeAliasMatch(ClangMoveTool *MoveTool)
193 : MoveTool(MoveTool) {}
195 void run(
const MatchFinder::MatchResult &Result)
override {
196 if (
const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>(
"typedef"))
197 MoveDeclFromOldFileToNewFile(MoveTool, TD);
198 else if (
const auto *TAD =
199 Result.Nodes.getNodeAs<TypeAliasDecl>(
"type_alias")) {
200 const NamedDecl * D = TAD;
201 if (
const auto * TD = TAD->getDescribedAliasTemplate())
203 MoveDeclFromOldFileToNewFile(MoveTool, D);
208 ClangMoveTool *MoveTool;
211class EnumDeclarationMatch :
public MatchFinder::MatchCallback {
213 explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
214 : MoveTool(MoveTool) {}
216 void run(
const MatchFinder::MatchResult &Result)
override {
217 const auto *ED = Result.Nodes.getNodeAs<EnumDecl>(
"enum");
219 MoveDeclFromOldFileToNewFile(MoveTool, ED);
223 ClangMoveTool *MoveTool;
226class ClassDeclarationMatch :
public MatchFinder::MatchCallback {
228 explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
229 : MoveTool(MoveTool) {}
230 void run(
const MatchFinder::MatchResult &Result)
override {
231 SourceManager *SM = &Result.Context->getSourceManager();
232 if (
const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>(
"class_method"))
233 MatchClassMethod(CMD, SM);
234 else if (
const auto *VD =
235 Result.Nodes.getNodeAs<VarDecl>(
"class_static_var_decl"))
236 MatchClassStaticVariable(VD, SM);
237 else if (
const auto *CD =
238 Result.Nodes.getNodeAs<CXXRecordDecl>(
"moved_class"))
239 MatchClassDeclaration(CD, SM);
243 void MatchClassMethod(
const CXXMethodDecl *CMD, SourceManager *SM) {
246 if (!CMD->isInlined()) {
247 MoveTool->getMovedDecls().push_back(CMD);
248 MoveTool->addRemovedDecl(CMD);
251 if (
const auto *FTD = CMD->getDescribedFunctionTemplate())
252 MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
254 MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
258 void MatchClassStaticVariable(
const NamedDecl *VD, SourceManager *SM) {
259 MoveDeclFromOldFileToNewFile(MoveTool, VD);
262 void MatchClassDeclaration(
const CXXRecordDecl *CD, SourceManager *SM) {
265 if (
const auto *TC = CD->getDescribedClassTemplate())
266 MoveTool->getMovedDecls().push_back(TC);
268 MoveTool->getMovedDecls().push_back(CD);
269 MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
270 MoveTool->getUnremovedDeclsInOldHeader().erase(
271 MoveTool->getMovedDecls().back());
274 ClangMoveTool *MoveTool;
279SourceLocation getLocForEndOfDecl(
const Decl *D,
280 const LangOptions &LangOpts = LangOptions()) {
281 const auto &SM = D->getASTContext().getSourceManager();
285 auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
286 std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
288 bool InvalidTemp =
false;
289 llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
291 return SourceLocation();
293 const char *TokBegin = File.data() + LocInfo.second;
295 Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
296 TokBegin, File.end());
298 llvm::SmallVector<char, 16>
Line;
300 Lex.setParsingPreprocessorDirective(
true);
301 Lex.ReadToEndOfLine(&
Line);
302 SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(
Line.size());
306 return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
308 : EndLoc.getLocWithOffset(1);
312CharSourceRange getFullRange(
const Decl *D,
313 const LangOptions &options = LangOptions()) {
314 const auto &SM = D->getASTContext().getSourceManager();
315 SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
317 if (
const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
318 if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
319 Full.setEnd(Comment->getEndLoc());
322 if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
323 Full.setBegin(Comment->getBeginLoc());
326 return CharSourceRange::getCharRange(Full);
329std::string getDeclarationSourceText(
const Decl *D) {
330 const auto &SM = D->getASTContext().getSourceManager();
331 llvm::StringRef SourceText =
332 Lexer::getSourceText(getFullRange(D), SM, LangOptions());
333 return SourceText.str();
336bool isInHeaderFile(
const Decl *D, llvm::StringRef OriginalRunningDirectory,
337 llvm::StringRef OldHeader) {
338 const auto &SM = D->getASTContext().getSourceManager();
339 if (OldHeader.empty())
341 auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
342 if (ExpansionLoc.isInvalid())
345 if (
auto FE = SM.getFileEntryRefForID(SM.getFileID(ExpansionLoc))) {
346 return MakeAbsolutePath(SM, FE->getName()) ==
347 MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
353std::vector<std::string> getNamespaces(
const Decl *D) {
354 std::vector<std::string> Namespaces;
355 for (
const auto *Context = D->getDeclContext(); Context;
356 Context = Context->getParent()) {
357 if (llvm::isa<TranslationUnitDecl>(Context) ||
358 llvm::isa<LinkageSpecDecl>(Context))
361 if (
const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
362 Namespaces.push_back(ND->getName().str());
364 std::reverse(Namespaces.begin(), Namespaces.end());
369createInsertedReplacements(
const std::vector<std::string> &Includes,
370 const std::vector<const NamedDecl *> &Decls,
371 llvm::StringRef
FileName,
bool IsHeader =
false,
372 StringRef OldHeaderInclude =
"") {
376 for (
size_t i = 0; i < GuardName.size(); ++i) {
377 if (!isAlphanumeric(GuardName[i]))
380 GuardName = StringRef(GuardName).upper();
381 NewCode +=
"#ifndef " + GuardName +
"\n";
382 NewCode +=
"#define " + GuardName +
"\n\n";
385 NewCode += OldHeaderInclude;
387 for (
const auto &Include : Includes)
390 if (!Includes.empty())
397 std::vector<std::string> CurrentNamespaces;
398 for (
const auto *MovedDecl : Decls) {
400 std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
401 auto CurrentIt = CurrentNamespaces.begin();
402 auto DeclIt = DeclNamespaces.begin();
404 while (CurrentIt != CurrentNamespaces.end() &&
405 DeclIt != DeclNamespaces.end()) {
406 if (*CurrentIt != *DeclIt)
413 std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
415 NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
419 bool HasEndCurrentNamespace =
false;
420 auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
421 for (
auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
422 --RemainingSize, ++It) {
423 assert(It < CurrentNamespaces.rend());
424 NewCode +=
"} // namespace " + *It +
"\n";
425 HasEndCurrentNamespace =
true;
428 if (HasEndCurrentNamespace)
433 bool IsInNewNamespace =
false;
434 while (DeclIt != DeclNamespaces.end()) {
435 NewCode +=
"namespace " + *DeclIt +
" {\n";
436 IsInNewNamespace =
true;
442 if (!IsInNewNamespace)
444 NewCode += getDeclarationSourceText(MovedDecl);
445 CurrentNamespaces = std::move(NextNamespaces);
447 std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
448 for (
const auto &NS : CurrentNamespaces)
449 NewCode +=
"} // namespace " + NS +
"\n";
452 NewCode +=
"\n#endif // " + GuardName +
"\n";
453 return tooling::Replacements(tooling::Replacement(
FileName, 0, 0, NewCode));
459llvm::DenseSet<const Decl *>
460getUsedDecls(
const HelperDeclRefGraph *RG,
461 const std::vector<const NamedDecl *> &Decls) {
463 llvm::DenseSet<const CallGraphNode *> Nodes;
464 for (
const auto *D : Decls) {
465 auto Result = RG->getReachableNodes(
467 Nodes.insert(Result.begin(), Result.end());
469 llvm::DenseSet<const Decl *>
Results;
470 for (
const auto *
Node : Nodes)
477std::unique_ptr<ASTConsumer>
480 Compiler.getPreprocessor().addPPCallbacks(std::make_unique<FindAllIncludes>(
481 &Compiler.getSourceManager(), &MoveTool));
482 return MatchFinder.newASTConsumer();
487 : Context(Context), Reporter(Reporter) {
488 if (!Context->Spec.NewHeader.empty())
489 CCIncludes.push_back(
"#include \"" + Context->Spec.NewHeader +
"\"\n");
493 const auto &SM =
Decl->getASTContext().getSourceManager();
494 auto Loc =
Decl->getLocation();
495 StringRef FilePath = SM.getFilename(
Loc);
496 FilePathToFileID[FilePath] = SM.getFileID(
Loc);
497 RemovedDecls.push_back(
Decl);
502 isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldHeader));
503 auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->
Spec.
OldCC));
504 auto InOldFiles = anyOf(InOldHeader, InOldCC);
505 auto classTemplateForwardDecls =
506 classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
507 auto ForwardClassDecls = namedDecl(
508 anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
509 classTemplateForwardDecls));
511 hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
521 auto AllDeclsInHeader = namedDecl(
522 unless(ForwardClassDecls), unless(namespaceDecl()),
523 unless(usingDirectiveDecl()),
526 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
527 hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
528 Finder->addMatcher(AllDeclsInHeader.bind(
"decls_in_header"),
this);
535 Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind(
"fwd_decl"),
541 auto IsOldCCTopLevelDecl = allOf(
542 hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
546 Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
547 usingDirectiveDecl(unless(isImplicit()),
548 IsOldCCTopLevelDecl),
549 typeAliasDecl(IsOldCCTopLevelDecl)),
556 SmallVector<std::string, 4> QualNames;
557 QualNames.reserve(Context->
Spec.
Names.size());
558 for (StringRef SymbolName : Context->
Spec.
Names) {
559 QualNames.push_back((
"::" + SymbolName.trim().ltrim(
':')).str());
562 if (QualNames.empty()) {
563 llvm::errs() <<
"No symbols being moved.\n";
567 ast_matchers::internal::Matcher<NamedDecl> HasAnySymbolNames =
568 hasAnyName(SmallVector<StringRef, 4>(QualNames.begin(), QualNames.end()));
571 hasOutermostEnclosingClass(cxxRecordDecl(HasAnySymbolNames));
574 auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
575 auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
577 allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
586 auto HelperFuncOrVar =
587 namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
588 varDecl(isDefinition(), IsOldCCHelper)));
590 cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
593 namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind(
"helper_decls"),
603 declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind(
"dc")))
608 typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind(
"used_class")))),
609 hasAncestor(decl().bind(
"dc"))),
616 MatchCallbacks.push_back(std::make_unique<ClassDeclarationMatch>(
this));
619 cxxRecordDecl(InOldFiles, HasAnySymbolNames, isDefinition(), TopLevelDecl)
620 .bind(
"moved_class");
621 Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
624 Finder->addMatcher(cxxMethodDecl(InOldFiles,
625 ofOutermostEnclosingClass(HasAnySymbolNames),
627 .bind(
"class_method"),
628 MatchCallbacks.back().get());
631 varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
632 .bind(
"class_static_var_decl"),
633 MatchCallbacks.back().get());
635 MatchCallbacks.push_back(std::make_unique<FunctionDeclarationMatch>(
this));
636 Finder->addMatcher(functionDecl(InOldFiles, HasAnySymbolNames, TopLevelDecl)
638 MatchCallbacks.back().get());
640 MatchCallbacks.push_back(std::make_unique<VarDeclarationMatch>(
this));
642 varDecl(InOldFiles, HasAnySymbolNames, TopLevelDecl).bind(
"var"),
643 MatchCallbacks.back().get());
647 MatchCallbacks.push_back(std::make_unique<EnumDeclarationMatch>(
this));
649 enumDecl(InOldHeader, HasAnySymbolNames, isDefinition(), TopLevelDecl)
651 MatchCallbacks.back().get());
656 MatchCallbacks.push_back(std::make_unique<TypeAliasMatch>(
this));
657 Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind(
"typedef"),
658 typeAliasDecl().bind(
"type_alias")),
659 InOldHeader, HasAnySymbolNames, TopLevelDecl),
660 MatchCallbacks.back().get());
664 if (
const auto *D = Result.Nodes.getNodeAs<NamedDecl>(
"decls_in_header")) {
665 UnremovedDeclsInOldHeader.insert(D);
666 }
else if (
const auto *FWD =
667 Result.Nodes.getNodeAs<CXXRecordDecl>(
"fwd_decl")) {
669 if (RemovedDecls.empty()) {
670 if (
const auto *DCT = FWD->getDescribedClassTemplate())
671 MovedDecls.push_back(DCT);
673 MovedDecls.push_back(FWD);
675 }
else if (
const auto *ND =
676 Result.Nodes.getNodeAs<NamedDecl>(
"helper_decls")) {
677 MovedDecls.push_back(ND);
678 HelperDeclarations.push_back(ND);
679 LLVM_DEBUG(llvm::dbgs()
680 <<
"Add helper : " << ND->getDeclName() <<
" (" << ND <<
")\n");
681 }
else if (
const auto *UD = Result.Nodes.getNodeAs<NamedDecl>(
"using_decl")) {
682 MovedDecls.push_back(UD);
686std::string ClangMoveTool::makeAbsolutePath(StringRef
Path) {
691 llvm::StringRef SearchPath,
693 CharSourceRange IncludeFilenameRange,
694 const SourceManager &SM) {
695 SmallString<128> HeaderWithSearchPath;
696 llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
697 std::string AbsoluteIncludeHeader =
698 MakeAbsolutePath(SM, HeaderWithSearchPath);
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);
722void 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: " << D->getDeclName()
739 <<
" (" << D <<
")\n");
741 D->getCanonicalDecl()))) {
742 LLVM_DEBUG(llvm::dbgs() <<
"Helper removed in old.cc: "
743 << D->getDeclName() <<
" (" << 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();
758 llvm::errs() << llvm::toString(std::move(Err)) <<
"\n";
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));
776 llvm::errs() << llvm::toString(std::move(Err)) <<
"\n";
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,
786 llvm::errs() << llvm::toString(Style.takeError()) <<
"\n";
789 auto CleanReplacements = format::cleanupAroundReplacements(
792 if (!CleanReplacements) {
793 llvm::errs() << llvm::toString(CleanReplacements.takeError()) <<
"\n";
800void 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->getDeclName()
824 <<
" " << D <<
"\n");
825 ActualNewCCDecls.push_back(D);
829 std::string OldHeaderInclude =
834 createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
840 createInsertedReplacements(CCIncludes, ActualNewCCDecls,
845void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
847 auto FE = SM.getFileManager().getOptionalFileRef(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) {
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 (llvm::none_of(UnremovedDeclsInOldHeader, IsSupportedKind) &&
926 auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
932 moveDeclsToNewFiles();
933 removeDeclsInOldFiles();
const FunctionDecl * Decl
enum clang::clangd::@1062::Bracket::Direction Dir
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
::clang::DynTypedNode Node
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(Expr, isMacroID)
AST_MATCHER_P(UserDefinedLiteral, hasLiteral, clang::ast_matchers::internal::Matcher< Expr >, InnerMatcher)
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
std::map< std::string, tooling::Replacements > & FileToReplacements
std::string FallbackStyle
std::string OriginalRunningDirectory
SmallVector< std::string, 4 > Names