[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
//===-- ClangMove.cpp - Implement ClangMove functationalities ---*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "ClangMove.h"
|
|
|
|
#include "clang/ASTMatchers/ASTMatchers.h"
|
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Format/Format.h"
|
|
|
|
#include "clang/Frontend/CompilerInstance.h"
|
|
|
|
#include "clang/Lex/Lexer.h"
|
|
|
|
#include "clang/Lex/Preprocessor.h"
|
|
|
|
#include "clang/Rewrite/Core/Rewriter.h"
|
|
|
|
#include "clang/Tooling/Core/Replacement.h"
|
2016-10-04 17:05:31 +08:00
|
|
|
#include "llvm/Support/Path.h"
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
|
|
|
|
using namespace clang::ast_matchers;
|
|
|
|
|
|
|
|
namespace clang {
|
|
|
|
namespace move {
|
|
|
|
namespace {
|
|
|
|
|
2016-10-14 18:07:58 +08:00
|
|
|
// FIXME: Move to ASTMatchers.
|
2016-11-08 15:50:19 +08:00
|
|
|
AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
|
2016-10-14 18:07:58 +08:00
|
|
|
|
2016-10-13 18:31:00 +08:00
|
|
|
AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
|
|
|
|
ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
|
2016-11-08 15:50:19 +08:00
|
|
|
const auto *Context = Node.getDeclContext();
|
|
|
|
if (!Context)
|
|
|
|
return false;
|
2016-10-13 18:31:00 +08:00
|
|
|
while (const auto *NextContext = Context->getParent()) {
|
|
|
|
if (isa<NamespaceDecl>(NextContext) ||
|
|
|
|
isa<TranslationUnitDecl>(NextContext))
|
|
|
|
break;
|
|
|
|
Context = NextContext;
|
|
|
|
}
|
|
|
|
return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
|
|
|
|
Builder);
|
|
|
|
}
|
|
|
|
|
|
|
|
AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
|
|
|
|
ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
|
|
|
|
const CXXRecordDecl *Parent = Node.getParent();
|
2016-11-08 15:50:19 +08:00
|
|
|
if (!Parent)
|
|
|
|
return false;
|
2016-10-13 18:31:00 +08:00
|
|
|
while (const auto *NextParent =
|
|
|
|
dyn_cast<CXXRecordDecl>(Parent->getParent())) {
|
|
|
|
Parent = NextParent;
|
|
|
|
}
|
|
|
|
|
|
|
|
return InnerMatcher.matches(*Parent, Finder, Builder);
|
|
|
|
}
|
|
|
|
|
2016-10-04 17:05:31 +08:00
|
|
|
// Make the Path absolute using the CurrentDir if the Path is not an absolute
|
|
|
|
// path. An empty Path will result in an empty string.
|
|
|
|
std::string MakeAbsolutePath(StringRef CurrentDir, StringRef Path) {
|
|
|
|
if (Path.empty())
|
|
|
|
return "";
|
|
|
|
llvm::SmallString<128> InitialDirectory(CurrentDir);
|
|
|
|
llvm::SmallString<128> AbsolutePath(Path);
|
|
|
|
if (std::error_code EC =
|
|
|
|
llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath))
|
2016-11-08 15:50:19 +08:00
|
|
|
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
|
2016-10-04 17:05:31 +08:00
|
|
|
<< '\n';
|
|
|
|
llvm::sys::path::remove_dots(AbsolutePath, /*remove_dot_dot=*/true);
|
2016-10-04 17:49:20 +08:00
|
|
|
llvm::sys::path::native(AbsolutePath);
|
2016-10-04 17:05:31 +08:00
|
|
|
return AbsolutePath.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make the Path absolute using the current working directory of the given
|
|
|
|
// SourceManager if the Path is not an absolute path.
|
|
|
|
//
|
|
|
|
// The Path can be a path relative to the build directory, or retrieved from
|
|
|
|
// the SourceManager.
|
2016-11-08 15:50:19 +08:00
|
|
|
std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
|
2016-10-04 17:05:31 +08:00
|
|
|
llvm::SmallString<128> AbsolutePath(Path);
|
|
|
|
if (std::error_code EC =
|
2016-11-08 15:50:19 +08:00
|
|
|
SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
|
|
|
|
AbsolutePath))
|
|
|
|
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
|
2016-10-04 17:05:31 +08:00
|
|
|
<< '\n';
|
2016-10-12 23:50:30 +08:00
|
|
|
// Handle symbolic link path cases.
|
|
|
|
// We are trying to get the real file path of the symlink.
|
|
|
|
const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
|
2016-11-08 15:50:19 +08:00
|
|
|
llvm::sys::path::parent_path(AbsolutePath.str()));
|
2016-10-12 23:50:30 +08:00
|
|
|
if (Dir) {
|
|
|
|
StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
|
|
|
|
SmallVector<char, 128> AbsoluteFilename;
|
|
|
|
llvm::sys::path::append(AbsoluteFilename, DirName,
|
|
|
|
llvm::sys::path::filename(AbsolutePath.str()));
|
|
|
|
return llvm::StringRef(AbsoluteFilename.data(), AbsoluteFilename.size())
|
|
|
|
.str();
|
|
|
|
}
|
2016-10-04 17:05:31 +08:00
|
|
|
return AbsolutePath.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Matches AST nodes that are expanded within the given AbsoluteFilePath.
|
|
|
|
AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
|
|
|
|
AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
|
|
|
|
std::string, AbsoluteFilePath) {
|
|
|
|
auto &SourceManager = Finder->getASTContext().getSourceManager();
|
|
|
|
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getLocStart());
|
|
|
|
if (ExpansionLoc.isInvalid())
|
|
|
|
return false;
|
|
|
|
auto FileEntry =
|
|
|
|
SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
|
|
|
|
if (!FileEntry)
|
|
|
|
return false;
|
|
|
|
return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
|
|
|
|
AbsoluteFilePath;
|
|
|
|
}
|
|
|
|
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
class FindAllIncludes : public clang::PPCallbacks {
|
|
|
|
public:
|
|
|
|
explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
|
|
|
|
: SM(*SM), MoveTool(MoveTool) {}
|
|
|
|
|
|
|
|
void InclusionDirective(clang::SourceLocation HashLoc,
|
|
|
|
const clang::Token & /*IncludeTok*/,
|
|
|
|
StringRef FileName, bool IsAngled,
|
2016-11-09 03:55:13 +08:00
|
|
|
clang::CharSourceRange FilenameRange,
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
const clang::FileEntry * /*File*/,
|
2016-10-04 17:05:31 +08:00
|
|
|
StringRef SearchPath, StringRef /*RelativePath*/,
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
const clang::Module * /*Imported*/) override {
|
2016-09-23 21:28:38 +08:00
|
|
|
if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
|
2016-10-04 17:05:31 +08:00
|
|
|
MoveTool->addIncludes(FileName, IsAngled, SearchPath,
|
2016-11-09 03:55:13 +08:00
|
|
|
FileEntry->getName(), FilenameRange, SM);
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
const SourceManager &SM;
|
|
|
|
ClangMoveTool *const MoveTool;
|
|
|
|
};
|
|
|
|
|
2016-11-16 21:05:19 +08:00
|
|
|
class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
|
|
|
|
public:
|
|
|
|
explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
|
|
|
|
: MoveTool(MoveTool) {}
|
|
|
|
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
|
|
|
const auto *FD = Result.Nodes.getNodeAs<clang::FunctionDecl>("function");
|
|
|
|
assert(FD);
|
|
|
|
const clang::NamedDecl *D = FD;
|
|
|
|
if (const auto *FTD = FD->getDescribedFunctionTemplate())
|
|
|
|
D = FTD;
|
|
|
|
MoveTool->getMovedDecls().emplace_back(D,
|
|
|
|
&Result.Context->getSourceManager());
|
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(D);
|
2016-11-23 18:04:19 +08:00
|
|
|
MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
|
2016-11-16 21:05:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ClangMoveTool *MoveTool;
|
|
|
|
};
|
|
|
|
|
2016-11-14 22:15:44 +08:00
|
|
|
class ClassDeclarationMatch : public MatchFinder::MatchCallback {
|
|
|
|
public:
|
|
|
|
explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
|
|
|
|
: MoveTool(MoveTool) {}
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
|
|
|
clang::SourceManager* SM = &Result.Context->getSourceManager();
|
|
|
|
if (const auto *CMD =
|
|
|
|
Result.Nodes.getNodeAs<clang::CXXMethodDecl>("class_method"))
|
|
|
|
MatchClassMethod(CMD, SM);
|
|
|
|
else if (const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
|
|
|
|
"class_static_var_decl"))
|
|
|
|
MatchClassStaticVariable(VD, SM);
|
|
|
|
else if (const auto *CD = Result.Nodes.getNodeAs<clang::CXXRecordDecl>(
|
|
|
|
"moved_class"))
|
|
|
|
MatchClassDeclaration(CD, SM);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
void MatchClassMethod(const clang::CXXMethodDecl* CMD,
|
|
|
|
clang::SourceManager* SM) {
|
|
|
|
// Skip inline class methods. isInline() ast matcher doesn't ignore this
|
|
|
|
// case.
|
|
|
|
if (!CMD->isInlined()) {
|
|
|
|
MoveTool->getMovedDecls().emplace_back(CMD, SM);
|
2016-11-23 18:04:19 +08:00
|
|
|
MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
|
2016-11-14 22:15:44 +08:00
|
|
|
// Get template class method from its method declaration as
|
|
|
|
// UnremovedDecls stores template class method.
|
|
|
|
if (const auto *FTD = CMD->getDescribedFunctionTemplate())
|
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
|
|
|
|
else
|
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void MatchClassStaticVariable(const clang::NamedDecl *VD,
|
|
|
|
clang::SourceManager* SM) {
|
|
|
|
MoveTool->getMovedDecls().emplace_back(VD, SM);
|
2016-11-23 18:04:19 +08:00
|
|
|
MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
|
2016-11-14 22:15:44 +08:00
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(VD);
|
|
|
|
}
|
|
|
|
|
|
|
|
void MatchClassDeclaration(const clang::CXXRecordDecl *CD,
|
|
|
|
clang::SourceManager* SM) {
|
|
|
|
// Get class template from its class declaration as UnremovedDecls stores
|
|
|
|
// class template.
|
|
|
|
if (const auto *TC = CD->getDescribedClassTemplate())
|
|
|
|
MoveTool->getMovedDecls().emplace_back(TC, SM);
|
|
|
|
else
|
|
|
|
MoveTool->getMovedDecls().emplace_back(CD, SM);
|
2016-11-23 18:04:19 +08:00
|
|
|
MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
|
2016-11-14 22:15:44 +08:00
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(
|
|
|
|
MoveTool->getMovedDecls().back().Decl);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClangMoveTool *MoveTool;
|
|
|
|
};
|
|
|
|
|
2016-10-06 16:59:24 +08:00
|
|
|
// Expand to get the end location of the line where the EndLoc of the given
|
|
|
|
// Decl.
|
|
|
|
SourceLocation
|
|
|
|
getLocForEndOfDecl(const clang::Decl *D, const SourceManager *SM,
|
|
|
|
const LangOptions &LangOpts = clang::LangOptions()) {
|
|
|
|
std::pair<FileID, unsigned> LocInfo = SM->getDecomposedLoc(D->getLocEnd());
|
|
|
|
// Try to load the file buffer.
|
|
|
|
bool InvalidTemp = false;
|
|
|
|
llvm::StringRef File = SM->getBufferData(LocInfo.first, &InvalidTemp);
|
|
|
|
if (InvalidTemp)
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
const char *TokBegin = File.data() + LocInfo.second;
|
|
|
|
// Lex from the start of the given location.
|
|
|
|
Lexer Lex(SM->getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
|
|
|
|
TokBegin, File.end());
|
|
|
|
|
|
|
|
llvm::SmallVector<char, 16> Line;
|
|
|
|
// FIXME: this is a bit hacky to get ReadToEndOfLine work.
|
|
|
|
Lex.setParsingPreprocessorDirective(true);
|
|
|
|
Lex.ReadToEndOfLine(&Line);
|
2016-11-08 15:50:19 +08:00
|
|
|
SourceLocation EndLoc = D->getLocEnd().getLocWithOffset(Line.size());
|
2016-10-06 16:59:24 +08:00
|
|
|
// If we already reach EOF, just return the EOF SourceLocation;
|
|
|
|
// otherwise, move 1 offset ahead to include the trailing newline character
|
|
|
|
// '\n'.
|
|
|
|
return SM->getLocForEndOfFile(LocInfo.first) == EndLoc
|
|
|
|
? EndLoc
|
|
|
|
: EndLoc.getLocWithOffset(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get full range of a Decl including the comments associated with it.
|
|
|
|
clang::CharSourceRange
|
|
|
|
GetFullRange(const clang::SourceManager *SM, const clang::Decl *D,
|
|
|
|
const clang::LangOptions &options = clang::LangOptions()) {
|
2016-11-14 22:46:48 +08:00
|
|
|
clang::SourceRange Full(SM->getExpansionLoc(D->getLocStart()),
|
|
|
|
getLocForEndOfDecl(D, SM));
|
2016-10-06 16:59:24 +08:00
|
|
|
// Expand to comments that are associated with the Decl.
|
2016-11-08 15:50:19 +08:00
|
|
|
if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
|
2016-10-06 16:59:24 +08:00
|
|
|
if (SM->isBeforeInTranslationUnit(Full.getEnd(), Comment->getLocEnd()))
|
|
|
|
Full.setEnd(Comment->getLocEnd());
|
|
|
|
// FIXME: Don't delete a preceding comment, if there are no other entities
|
|
|
|
// it could refer to.
|
2016-11-08 15:50:19 +08:00
|
|
|
if (SM->isBeforeInTranslationUnit(Comment->getLocStart(), Full.getBegin()))
|
2016-10-06 16:59:24 +08:00
|
|
|
Full.setBegin(Comment->getLocStart());
|
|
|
|
}
|
|
|
|
|
|
|
|
return clang::CharSourceRange::getCharRange(Full);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string getDeclarationSourceText(const clang::Decl *D,
|
|
|
|
const clang::SourceManager *SM) {
|
|
|
|
llvm::StringRef SourceText = clang::Lexer::getSourceText(
|
|
|
|
GetFullRange(SM, D), *SM, clang::LangOptions());
|
|
|
|
return SourceText.str();
|
|
|
|
}
|
|
|
|
|
2016-10-04 17:05:31 +08:00
|
|
|
bool isInHeaderFile(const clang::SourceManager &SM, const clang::Decl *D,
|
|
|
|
llvm::StringRef OriginalRunningDirectory,
|
|
|
|
llvm::StringRef OldHeader) {
|
|
|
|
if (OldHeader.empty())
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
return false;
|
|
|
|
auto ExpansionLoc = SM.getExpansionLoc(D->getLocStart());
|
|
|
|
if (ExpansionLoc.isInvalid())
|
|
|
|
return false;
|
|
|
|
|
2016-10-04 17:05:31 +08:00
|
|
|
if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
|
|
|
|
return MakeAbsolutePath(SM, FE->getName()) ==
|
|
|
|
MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
|
|
|
|
}
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::vector<std::string> GetNamespaces(const clang::Decl *D) {
|
|
|
|
std::vector<std::string> Namespaces;
|
|
|
|
for (const auto *Context = D->getDeclContext(); Context;
|
|
|
|
Context = Context->getParent()) {
|
|
|
|
if (llvm::isa<clang::TranslationUnitDecl>(Context) ||
|
|
|
|
llvm::isa<clang::LinkageSpecDecl>(Context))
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (const auto *ND = llvm::dyn_cast<clang::NamespaceDecl>(Context))
|
|
|
|
Namespaces.push_back(ND->getName().str());
|
|
|
|
}
|
|
|
|
std::reverse(Namespaces.begin(), Namespaces.end());
|
|
|
|
return Namespaces;
|
|
|
|
}
|
|
|
|
|
|
|
|
clang::tooling::Replacements
|
|
|
|
createInsertedReplacements(const std::vector<std::string> &Includes,
|
|
|
|
const std::vector<ClangMoveTool::MovedDecl> &Decls,
|
2016-11-23 18:04:19 +08:00
|
|
|
llvm::StringRef FileName, bool IsHeader = false,
|
|
|
|
StringRef OldHeaderInclude = "") {
|
2016-10-14 21:43:49 +08:00
|
|
|
std::string NewCode;
|
2016-10-14 21:01:36 +08:00
|
|
|
std::string GuardName(FileName);
|
|
|
|
if (IsHeader) {
|
2016-10-17 23:26:34 +08:00
|
|
|
for (size_t i = 0; i < GuardName.size(); ++i) {
|
|
|
|
if (!isAlphanumeric(GuardName[i]))
|
|
|
|
GuardName[i] = '_';
|
|
|
|
}
|
2016-10-14 21:01:36 +08:00
|
|
|
GuardName = StringRef(GuardName).upper();
|
2016-10-14 21:43:49 +08:00
|
|
|
NewCode += "#ifndef " + GuardName + "\n";
|
2016-11-15 17:06:59 +08:00
|
|
|
NewCode += "#define " + GuardName + "\n\n";
|
2016-10-14 21:01:36 +08:00
|
|
|
}
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
|
2016-11-23 18:04:19 +08:00
|
|
|
NewCode += OldHeaderInclude;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
// Add #Includes.
|
|
|
|
for (const auto &Include : Includes)
|
2016-10-14 21:43:49 +08:00
|
|
|
NewCode += Include;
|
2016-10-06 16:59:24 +08:00
|
|
|
|
2016-10-14 21:43:49 +08:00
|
|
|
if (!Includes.empty())
|
|
|
|
NewCode += "\n";
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
|
|
|
|
// Add moved class definition and its related declarations. All declarations
|
|
|
|
// in same namespace are grouped together.
|
2016-11-15 17:06:59 +08:00
|
|
|
//
|
|
|
|
// Record namespaces where the current position is in.
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
std::vector<std::string> CurrentNamespaces;
|
|
|
|
for (const auto &MovedDecl : Decls) {
|
2016-11-15 17:06:59 +08:00
|
|
|
// The namespaces of the declaration being moved.
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
std::vector<std::string> DeclNamespaces = GetNamespaces(MovedDecl.Decl);
|
|
|
|
auto CurrentIt = CurrentNamespaces.begin();
|
|
|
|
auto DeclIt = DeclNamespaces.begin();
|
2016-11-15 17:06:59 +08:00
|
|
|
// Skip the common prefix.
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
while (CurrentIt != CurrentNamespaces.end() &&
|
|
|
|
DeclIt != DeclNamespaces.end()) {
|
|
|
|
if (*CurrentIt != *DeclIt)
|
|
|
|
break;
|
|
|
|
++CurrentIt;
|
|
|
|
++DeclIt;
|
|
|
|
}
|
2016-11-15 17:06:59 +08:00
|
|
|
// Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
|
|
|
|
// which is used for next iteration of this loop.
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
|
|
|
|
CurrentIt);
|
|
|
|
NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
|
2016-11-15 17:06:59 +08:00
|
|
|
|
|
|
|
|
|
|
|
// End with CurrentNamespace.
|
|
|
|
bool HasEndCurrentNamespace = false;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
|
|
|
|
for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
|
|
|
|
--RemainingSize, ++It) {
|
|
|
|
assert(It < CurrentNamespaces.rend());
|
2016-10-14 21:43:49 +08:00
|
|
|
NewCode += "} // namespace " + *It + "\n";
|
2016-11-15 17:06:59 +08:00
|
|
|
HasEndCurrentNamespace = true;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
2016-11-15 17:06:59 +08:00
|
|
|
// Add trailing '\n' after the nested namespace definition.
|
|
|
|
if (HasEndCurrentNamespace)
|
|
|
|
NewCode += "\n";
|
|
|
|
|
|
|
|
// If the moved declaration is not in CurrentNamespace, add extra namespace
|
|
|
|
// definitions.
|
|
|
|
bool IsInNewNamespace = false;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
while (DeclIt != DeclNamespaces.end()) {
|
2016-10-14 21:43:49 +08:00
|
|
|
NewCode += "namespace " + *DeclIt + " {\n";
|
2016-11-15 17:06:59 +08:00
|
|
|
IsInNewNamespace = true;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
++DeclIt;
|
|
|
|
}
|
2016-11-15 17:06:59 +08:00
|
|
|
// If the moved declaration is in same namespace CurrentNamespace, add
|
|
|
|
// a preceeding `\n' before the moved declaration.
|
2016-11-18 18:51:16 +08:00
|
|
|
// FIXME: Don't add empty lines between using declarations.
|
2016-11-15 17:06:59 +08:00
|
|
|
if (!IsInNewNamespace)
|
|
|
|
NewCode += "\n";
|
2016-10-14 21:43:49 +08:00
|
|
|
NewCode += getDeclarationSourceText(MovedDecl.Decl, MovedDecl.SM);
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
CurrentNamespaces = std::move(NextNamespaces);
|
|
|
|
}
|
|
|
|
std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
|
2016-10-14 21:43:49 +08:00
|
|
|
for (const auto &NS : CurrentNamespaces)
|
|
|
|
NewCode += "} // namespace " + NS + "\n";
|
2016-10-14 21:01:36 +08:00
|
|
|
|
2016-10-14 21:43:49 +08:00
|
|
|
if (IsHeader)
|
2016-11-15 17:06:59 +08:00
|
|
|
NewCode += "\n#endif // " + GuardName + "\n";
|
2016-10-14 21:43:49 +08:00
|
|
|
return clang::tooling::Replacements(
|
|
|
|
clang::tooling::Replacement(FileName, 0, 0, NewCode));
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace
|
|
|
|
|
|
|
|
std::unique_ptr<clang::ASTConsumer>
|
|
|
|
ClangMoveAction::CreateASTConsumer(clang::CompilerInstance &Compiler,
|
|
|
|
StringRef /*InFile*/) {
|
|
|
|
Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
|
|
|
|
&Compiler.getSourceManager(), &MoveTool));
|
|
|
|
return MatchFinder.newASTConsumer();
|
|
|
|
}
|
|
|
|
|
2016-11-24 18:17:17 +08:00
|
|
|
ClangMoveTool::ClangMoveTool(ClangMoveContext *const Context,
|
|
|
|
DeclarationReporter *const Reporter)
|
|
|
|
: Context(Context), Reporter(Reporter) {
|
|
|
|
if (!Context->Spec.NewHeader.empty())
|
|
|
|
CCIncludes.push_back("#include \"" + Context->Spec.NewHeader + "\"\n");
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
2016-11-23 18:04:19 +08:00
|
|
|
void ClangMoveTool::addRemovedDecl(const MovedDecl &Decl) {
|
|
|
|
const auto &SM = *Decl.SM;
|
|
|
|
auto Loc = Decl.Decl->getLocation();
|
|
|
|
StringRef FilePath = SM.getFilename(Loc);
|
|
|
|
FilePathToFileID[FilePath] = SM.getFileID(Loc);
|
|
|
|
RemovedDecls.push_back(Decl);
|
|
|
|
}
|
|
|
|
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
2016-11-24 18:17:17 +08:00
|
|
|
auto InOldHeader =
|
|
|
|
isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
|
|
|
|
auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
auto InOldFiles = anyOf(InOldHeader, InOldCC);
|
2016-11-09 03:55:13 +08:00
|
|
|
auto ForwardDecls =
|
|
|
|
cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())));
|
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// Matchers for old header
|
|
|
|
//============================================================================
|
|
|
|
// Match all top-level named declarations (e.g. function, variable, enum) in
|
|
|
|
// old header, exclude forward class declarations and namespace declarations.
|
|
|
|
//
|
2016-11-24 18:17:17 +08:00
|
|
|
// We consider declarations inside a class belongs to the class. So these
|
|
|
|
// declarations will be ignored.
|
2016-11-09 03:55:13 +08:00
|
|
|
auto AllDeclsInHeader = namedDecl(
|
|
|
|
unless(ForwardDecls), unless(namespaceDecl()),
|
2016-11-24 18:17:17 +08:00
|
|
|
unless(usingDirectiveDecl()), // using namespace decl.
|
2016-11-09 03:55:13 +08:00
|
|
|
unless(classTemplateDecl(has(ForwardDecls))), // template forward decl.
|
|
|
|
InOldHeader,
|
2016-11-24 18:17:17 +08:00
|
|
|
hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
|
|
|
|
hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
|
2016-11-09 03:55:13 +08:00
|
|
|
Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
|
2016-11-24 18:17:17 +08:00
|
|
|
|
|
|
|
// Don't register other matchers when dumping all declarations in header.
|
|
|
|
if (Context->DumpDeclarations)
|
|
|
|
return;
|
|
|
|
|
2016-11-09 03:55:13 +08:00
|
|
|
// Match forward declarations in old header.
|
|
|
|
Finder->addMatcher(namedDecl(ForwardDecls, InOldHeader).bind("fwd_decl"),
|
|
|
|
this);
|
|
|
|
|
2016-11-10 13:33:26 +08:00
|
|
|
//============================================================================
|
|
|
|
// Matchers for old cc
|
|
|
|
//============================================================================
|
2016-11-18 18:51:16 +08:00
|
|
|
auto InOldCCNamedOrGlobalNamespace =
|
|
|
|
allOf(hasParent(decl(anyOf(namespaceDecl(unless(isAnonymous())),
|
|
|
|
translationUnitDecl()))),
|
|
|
|
InOldCC);
|
|
|
|
// Matching using decls/type alias decls which are in named namespace or
|
|
|
|
// global namespace. Those in classes, functions and anonymous namespaces are
|
|
|
|
// covered in other matchers.
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
Finder->addMatcher(
|
2016-11-18 18:51:16 +08:00
|
|
|
namedDecl(anyOf(usingDecl(InOldCCNamedOrGlobalNamespace),
|
|
|
|
usingDirectiveDecl(InOldCCNamedOrGlobalNamespace),
|
|
|
|
typeAliasDecl( InOldCCNamedOrGlobalNamespace)))
|
2016-10-19 22:13:21 +08:00
|
|
|
.bind("using_decl"),
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
this);
|
|
|
|
|
2016-10-19 22:13:21 +08:00
|
|
|
// Match anonymous namespace decl in old cc.
|
|
|
|
Finder->addMatcher(namespaceDecl(isAnonymous(), InOldCC).bind("anonymous_ns"),
|
|
|
|
this);
|
|
|
|
|
|
|
|
// Match static functions/variable definitions which are defined in named
|
|
|
|
// namespaces.
|
2016-11-24 18:17:17 +08:00
|
|
|
Optional<ast_matchers::internal::Matcher<NamedDecl>> HasAnySymbolNames;
|
|
|
|
for (StringRef SymbolName : Context->Spec.Names) {
|
|
|
|
llvm::StringRef GlobalSymbolName = SymbolName.trim().ltrim(':');
|
|
|
|
const auto HasName = hasName(("::" + GlobalSymbolName).str());
|
|
|
|
HasAnySymbolNames =
|
|
|
|
HasAnySymbolNames ? anyOf(*HasAnySymbolNames, HasName) : HasName;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!HasAnySymbolNames) {
|
|
|
|
llvm::errs() << "No symbols being moved.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto InMovedClass =
|
|
|
|
hasOutermostEnclosingClass(cxxRecordDecl(*HasAnySymbolNames));
|
2016-10-19 22:13:21 +08:00
|
|
|
auto IsOldCCStaticDefinition =
|
2016-11-18 18:51:16 +08:00
|
|
|
allOf(isDefinition(), unless(InMovedClass), InOldCCNamedOrGlobalNamespace,
|
2016-10-19 22:13:21 +08:00
|
|
|
isStaticStorageClass());
|
2016-11-08 15:50:19 +08:00
|
|
|
Finder->addMatcher(namedDecl(anyOf(functionDecl(IsOldCCStaticDefinition),
|
|
|
|
varDecl(IsOldCCStaticDefinition)))
|
|
|
|
.bind("static_decls"),
|
|
|
|
this);
|
2016-11-14 22:15:44 +08:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// Matchers for old files, including old.h/old.cc
|
|
|
|
//============================================================================
|
|
|
|
// Create a MatchCallback for class declarations.
|
|
|
|
MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
|
|
|
|
// Match moved class declarations.
|
|
|
|
auto MovedClass =
|
|
|
|
cxxRecordDecl(
|
2016-11-16 21:05:19 +08:00
|
|
|
InOldFiles, *HasAnySymbolNames, isDefinition(),
|
2016-11-14 22:15:44 +08:00
|
|
|
hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())))
|
|
|
|
.bind("moved_class");
|
|
|
|
Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
|
|
|
|
// Match moved class methods (static methods included) which are defined
|
|
|
|
// outside moved class declaration.
|
|
|
|
Finder->addMatcher(
|
2016-11-16 21:05:19 +08:00
|
|
|
cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
|
2016-11-14 22:15:44 +08:00
|
|
|
isDefinition())
|
|
|
|
.bind("class_method"),
|
|
|
|
MatchCallbacks.back().get());
|
|
|
|
// Match static member variable definition of the moved class.
|
|
|
|
Finder->addMatcher(
|
|
|
|
varDecl(InMovedClass, InOldFiles, isDefinition(), isStaticDataMember())
|
|
|
|
.bind("class_static_var_decl"),
|
|
|
|
MatchCallbacks.back().get());
|
|
|
|
|
2016-11-16 21:05:19 +08:00
|
|
|
MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
|
|
|
|
Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames,
|
|
|
|
anyOf(hasDeclContext(namespaceDecl()),
|
|
|
|
hasDeclContext(translationUnitDecl())))
|
|
|
|
.bind("function"),
|
|
|
|
MatchCallbacks.back().get());
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
|
2016-11-09 03:55:13 +08:00
|
|
|
if (const auto *D =
|
|
|
|
Result.Nodes.getNodeAs<clang::NamedDecl>("decls_in_header")) {
|
|
|
|
UnremovedDeclsInOldHeader.insert(D);
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
} else if (const auto *FWD =
|
|
|
|
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("fwd_decl")) {
|
2016-11-24 18:17:17 +08:00
|
|
|
// Skip all forward declarations which appear after moved class declaration.
|
2016-10-22 03:26:43 +08:00
|
|
|
if (RemovedDecls.empty()) {
|
2016-11-10 13:33:26 +08:00
|
|
|
if (const auto *DCT = FWD->getDescribedClassTemplate())
|
2016-10-22 03:26:43 +08:00
|
|
|
MovedDecls.emplace_back(DCT, &Result.Context->getSourceManager());
|
2016-11-10 13:33:26 +08:00
|
|
|
else
|
2016-10-22 03:26:43 +08:00
|
|
|
MovedDecls.emplace_back(FWD, &Result.Context->getSourceManager());
|
|
|
|
}
|
2016-11-08 15:50:19 +08:00
|
|
|
} else if (const auto *ANS =
|
|
|
|
Result.Nodes.getNodeAs<clang::NamespaceDecl>("anonymous_ns")) {
|
2016-10-19 22:13:21 +08:00
|
|
|
MovedDecls.emplace_back(ANS, &Result.Context->getSourceManager());
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
} else if (const auto *ND =
|
|
|
|
Result.Nodes.getNodeAs<clang::NamedDecl>("static_decls")) {
|
|
|
|
MovedDecls.emplace_back(ND, &Result.Context->getSourceManager());
|
2016-10-19 22:13:21 +08:00
|
|
|
} else if (const auto *UD =
|
|
|
|
Result.Nodes.getNodeAs<clang::NamedDecl>("using_decl")) {
|
|
|
|
MovedDecls.emplace_back(UD, &Result.Context->getSourceManager());
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-11-09 03:55:13 +08:00
|
|
|
std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
|
2016-11-24 18:17:17 +08:00
|
|
|
return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
|
2016-11-09 03:55:13 +08:00
|
|
|
}
|
|
|
|
|
2016-11-08 15:50:19 +08:00
|
|
|
void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
|
2016-10-04 17:05:31 +08:00
|
|
|
llvm::StringRef SearchPath,
|
|
|
|
llvm::StringRef FileName,
|
2016-11-09 03:55:13 +08:00
|
|
|
clang::CharSourceRange IncludeFilenameRange,
|
2016-11-08 15:50:19 +08:00
|
|
|
const SourceManager &SM) {
|
2016-10-12 23:50:30 +08:00
|
|
|
SmallVector<char, 128> HeaderWithSearchPath;
|
|
|
|
llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
|
2016-11-24 18:17:17 +08:00
|
|
|
std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
|
2016-09-23 21:28:38 +08:00
|
|
|
// FIXME: Add old.h to the new.cc/h when the new target has dependencies on
|
|
|
|
// old.h/c. For instance, when moved class uses another class defined in
|
|
|
|
// old.h, the old.h should be added in new.h.
|
2016-10-12 23:50:30 +08:00
|
|
|
if (AbsoluteOldHeader ==
|
|
|
|
MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
|
2016-11-09 03:55:13 +08:00
|
|
|
HeaderWithSearchPath.size()))) {
|
|
|
|
OldHeaderIncludeRange = IncludeFilenameRange;
|
2016-09-23 21:28:38 +08:00
|
|
|
return;
|
2016-11-09 03:55:13 +08:00
|
|
|
}
|
2016-09-23 21:28:38 +08:00
|
|
|
|
|
|
|
std::string IncludeLine =
|
|
|
|
IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
|
|
|
|
: ("#include \"" + IncludeHeader + "\"\n").str();
|
2016-10-04 17:05:31 +08:00
|
|
|
|
2016-10-12 23:50:30 +08:00
|
|
|
std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
|
|
|
|
if (AbsoluteOldHeader == AbsoluteCurrentFile) {
|
2016-09-23 21:28:38 +08:00
|
|
|
HeaderIncludes.push_back(IncludeLine);
|
2016-11-24 18:17:17 +08:00
|
|
|
} else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
|
2016-09-23 21:28:38 +08:00
|
|
|
CCIncludes.push_back(IncludeLine);
|
2016-10-04 17:05:31 +08:00
|
|
|
}
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::removeClassDefinitionInOldFiles() {
|
2016-11-23 18:04:19 +08:00
|
|
|
if (RemovedDecls.empty()) return;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
for (const auto &MovedDecl : RemovedDecls) {
|
2016-10-06 16:29:32 +08:00
|
|
|
const auto &SM = *MovedDecl.SM;
|
2016-10-06 16:59:24 +08:00
|
|
|
auto Range = GetFullRange(&SM, MovedDecl.Decl);
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
clang::tooling::Replacement RemoveReplacement(
|
2016-11-23 18:04:19 +08:00
|
|
|
SM,
|
2016-11-08 15:50:19 +08:00
|
|
|
clang::CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
"");
|
|
|
|
std::string FilePath = RemoveReplacement.getFilePath().str();
|
2016-11-24 18:17:17 +08:00
|
|
|
auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
|
2016-11-23 18:04:19 +08:00
|
|
|
if (Err)
|
2016-10-14 21:43:49 +08:00
|
|
|
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
|
2016-11-23 18:04:19 +08:00
|
|
|
}
|
|
|
|
const SourceManager* SM = RemovedDecls[0].SM;
|
|
|
|
|
|
|
|
// Post process of cleanup around all the replacements.
|
2016-11-24 18:17:17 +08:00
|
|
|
for (auto &FileAndReplacements : Context->FileToReplacements) {
|
2016-11-23 18:04:19 +08:00
|
|
|
StringRef FilePath = FileAndReplacements.first;
|
|
|
|
// Add #include of new header to old header.
|
2016-11-24 18:17:17 +08:00
|
|
|
if (Context->Spec.OldDependOnNew &&
|
|
|
|
MakeAbsolutePath(*SM, FilePath) ==
|
|
|
|
makeAbsolutePath(Context->Spec.OldHeader)) {
|
2016-11-23 18:04:19 +08:00
|
|
|
// FIXME: Minimize the include path like include-fixer.
|
2016-11-24 18:17:17 +08:00
|
|
|
std::string IncludeNewH =
|
|
|
|
"#include \"" + Context->Spec.NewHeader + "\"\n";
|
2016-11-23 18:04:19 +08:00
|
|
|
// This replacment for inserting header will be cleaned up at the end.
|
|
|
|
auto Err = FileAndReplacements.second.add(
|
|
|
|
tooling::Replacement(FilePath, UINT_MAX, 0, IncludeNewH));
|
|
|
|
if (Err)
|
|
|
|
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
|
2016-10-14 21:43:49 +08:00
|
|
|
}
|
2016-10-06 16:29:32 +08:00
|
|
|
|
2016-11-23 18:04:19 +08:00
|
|
|
auto SI = FilePathToFileID.find(FilePath);
|
|
|
|
// Ignore replacements for new.h/cc.
|
|
|
|
if (SI == FilePathToFileID.end()) continue;
|
|
|
|
llvm::StringRef Code = SM->getBufferData(SI->second);
|
2016-10-06 16:29:32 +08:00
|
|
|
format::FormatStyle Style =
|
2016-11-24 18:17:17 +08:00
|
|
|
format::getStyle("file", FilePath, Context->FallbackStyle);
|
2016-10-06 16:29:32 +08:00
|
|
|
auto CleanReplacements = format::cleanupAroundReplacements(
|
2016-11-24 18:17:17 +08:00
|
|
|
Code, Context->FileToReplacements[FilePath], Style);
|
2016-10-06 16:29:32 +08:00
|
|
|
|
|
|
|
if (!CleanReplacements) {
|
|
|
|
llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
2016-11-24 18:17:17 +08:00
|
|
|
Context->FileToReplacements[FilePath] = *CleanReplacements;
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::moveClassDefinitionToNewFiles() {
|
|
|
|
std::vector<MovedDecl> NewHeaderDecls;
|
|
|
|
std::vector<MovedDecl> NewCCDecls;
|
|
|
|
for (const auto &MovedDecl : MovedDecls) {
|
2016-11-24 18:17:17 +08:00
|
|
|
if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl,
|
|
|
|
Context->OriginalRunningDirectory,
|
|
|
|
Context->Spec.OldHeader))
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
NewHeaderDecls.push_back(MovedDecl);
|
|
|
|
else
|
|
|
|
NewCCDecls.push_back(MovedDecl);
|
|
|
|
}
|
|
|
|
|
2016-11-24 18:17:17 +08:00
|
|
|
if (!Context->Spec.NewHeader.empty()) {
|
2016-11-23 18:04:19 +08:00
|
|
|
std::string OldHeaderInclude =
|
2016-11-24 18:17:17 +08:00
|
|
|
Context->Spec.NewDependOnOld
|
|
|
|
? "#include \"" + Context->Spec.OldHeader + "\"\n"
|
|
|
|
: "";
|
|
|
|
Context->FileToReplacements[Context->Spec.NewHeader] =
|
|
|
|
createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
|
|
|
|
Context->Spec.NewHeader, /*IsHeader=*/true,
|
|
|
|
OldHeaderInclude);
|
2016-11-23 18:04:19 +08:00
|
|
|
}
|
2016-11-24 18:17:17 +08:00
|
|
|
if (!Context->Spec.NewCC.empty())
|
|
|
|
Context->FileToReplacements[Context->Spec.NewCC] =
|
|
|
|
createInsertedReplacements(CCIncludes, NewCCDecls, Context->Spec.NewCC);
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
}
|
|
|
|
|
2016-11-09 03:55:13 +08:00
|
|
|
// Move all contents from OldFile to NewFile.
|
|
|
|
void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
|
|
|
|
StringRef NewFile) {
|
|
|
|
const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
|
|
|
|
if (!FE) {
|
|
|
|
llvm::errs() << "Failed to get file: " << OldFile << "\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
|
|
|
|
auto Begin = SM.getLocForStartOfFile(ID);
|
|
|
|
auto End = SM.getLocForEndOfFile(ID);
|
|
|
|
clang::tooling::Replacement RemoveAll (
|
|
|
|
SM, clang::CharSourceRange::getCharRange(Begin, End), "");
|
|
|
|
std::string FilePath = RemoveAll.getFilePath().str();
|
2016-11-24 18:17:17 +08:00
|
|
|
Context->FileToReplacements[FilePath] =
|
|
|
|
clang::tooling::Replacements(RemoveAll);
|
2016-11-09 03:55:13 +08:00
|
|
|
|
|
|
|
StringRef Code = SM.getBufferData(ID);
|
|
|
|
if (!NewFile.empty()) {
|
|
|
|
auto AllCode = clang::tooling::Replacements(
|
|
|
|
clang::tooling::Replacement(NewFile, 0, 0, Code));
|
|
|
|
// If we are moving from old.cc, an extra step is required: excluding
|
|
|
|
// the #include of "old.h", instead, we replace it with #include of "new.h".
|
2016-11-24 18:17:17 +08:00
|
|
|
if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRange.isValid()) {
|
2016-11-09 03:55:13 +08:00
|
|
|
AllCode = AllCode.merge(
|
|
|
|
clang::tooling::Replacements(clang::tooling::Replacement(
|
2016-11-24 18:17:17 +08:00
|
|
|
SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
|
2016-11-09 03:55:13 +08:00
|
|
|
}
|
2016-11-24 18:17:17 +08:00
|
|
|
Context->FileToReplacements[NewFile] = std::move(AllCode);
|
2016-11-09 03:55:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
void ClangMoveTool::onEndOfTranslationUnit() {
|
2016-11-24 18:17:17 +08:00
|
|
|
if (Context->DumpDeclarations) {
|
|
|
|
assert(Reporter);
|
|
|
|
for (const auto *Decl : UnremovedDeclsInOldHeader) {
|
|
|
|
auto Kind = Decl->getKind();
|
|
|
|
const std::string QualifiedName = Decl->getQualifiedNameAsString();
|
|
|
|
if (Kind == Decl::Kind::Function || Kind == Decl::Kind::FunctionTemplate)
|
|
|
|
Reporter->reportDeclaration(QualifiedName, "Function");
|
|
|
|
else if (Kind == Decl::Kind::ClassTemplate ||
|
|
|
|
Kind == Decl::Kind::CXXRecord)
|
|
|
|
Reporter->reportDeclaration(QualifiedName, "Class");
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
if (RemovedDecls.empty())
|
|
|
|
return;
|
2016-11-24 18:17:17 +08:00
|
|
|
if (UnremovedDeclsInOldHeader.empty() && !Context->Spec.OldHeader.empty()) {
|
2016-11-09 03:55:13 +08:00
|
|
|
auto &SM = *RemovedDecls[0].SM;
|
2016-11-24 18:17:17 +08:00
|
|
|
moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
|
|
|
|
moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
|
2016-11-09 03:55:13 +08:00
|
|
|
return;
|
|
|
|
}
|
[clang-move] A prototype tool for moving class definition to new file.
Summary:
This patch introduces a new tool which moves a specific class definition
from files (.h, .cc) to new files (.h, .cc), which mostly acts like
"Extract class defintion". In the long term, this tool should be
merged in to clang-refactoring as a subtool.
clang-move not only moves class definition, but also moves all the
forward declarations, functions defined in anonymous namespace and #include
headers to new files, to make sure the new files are compliable as much
as possible.
To move `Foo` from old.[h/cc] to new.[h/cc], use:
```
clang-move -name=Foo -old_header=old.h -old_cc=old.cc -new_header=new.h
-new_cc=new.cc old.cc
```
To move `Foo` from old.h to new.h, use:
```
clang-move -name=Foo -old_header=old.h -new_header=new.h old.cc
```
Reviewers: klimek, djasper, ioeric
Subscribers: mgorny, beanz, Eugene.Zelenko, bkramer, omtcyfz, cfe-commits
Differential Revision: https://reviews.llvm.org/D24243
llvm-svn: 282070
2016-09-21 21:18:19 +08:00
|
|
|
removeClassDefinitionInOldFiles();
|
|
|
|
moveClassDefinitionToNewFiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace move
|
|
|
|
} // namespace clang
|