[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.
|
|
|
|
AST_MATCHER(VarDecl, isStaticDataMember) {
|
|
|
|
return Node.isStaticDataMember();
|
|
|
|
}
|
|
|
|
|
2016-10-13 18:31:00 +08:00
|
|
|
AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
|
|
|
|
ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
|
|
|
|
const auto* Context = Node.getDeclContext();
|
|
|
|
if (!Context) return false;
|
|
|
|
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();
|
|
|
|
if (!Parent) return false;
|
|
|
|
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))
|
|
|
|
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
|
|
|
|
<< '\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.
|
|
|
|
std::string MakeAbsolutePath(const SourceManager& SM, StringRef Path) {
|
|
|
|
llvm::SmallString<128> AbsolutePath(Path);
|
|
|
|
if (std::error_code EC =
|
|
|
|
SM.getFileManager().getVirtualFileSystem()->makeAbsolute(AbsolutePath))
|
|
|
|
llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
|
|
|
|
<< '\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(
|
|
|
|
llvm::sys::path::parent_path(AbsolutePath.str()));
|
|
|
|
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,
|
|
|
|
clang::CharSourceRange /*FilenameRange*/,
|
|
|
|
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,
|
|
|
|
FileEntry->getName(), 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-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);
|
|
|
|
SourceLocation EndLoc = D->getLocEnd().getLocWithOffset(Line.size());
|
|
|
|
// 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()) {
|
|
|
|
clang::SourceRange Full = D->getSourceRange();
|
|
|
|
Full.setEnd(getLocForEndOfDecl(D, SM));
|
|
|
|
// Expand to comments that are associated with the Decl.
|
|
|
|
if (const auto* Comment =
|
|
|
|
D->getASTContext().getRawCommentForDeclNoCache(D)) {
|
|
|
|
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.
|
|
|
|
if (SM->isBeforeInTranslationUnit(Comment->getLocStart(),
|
|
|
|
Full.getBegin()))
|
|
|
|
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-10-14 21:01:36 +08:00
|
|
|
llvm::StringRef FileName,
|
|
|
|
bool IsHeader = false) {
|
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";
|
|
|
|
NewCode += "#define " + GuardName + "\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
|
|
|
|
|
|
|
// 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.
|
|
|
|
std::vector<std::string> CurrentNamespaces;
|
|
|
|
for (const auto &MovedDecl : Decls) {
|
|
|
|
std::vector<std::string> DeclNamespaces = GetNamespaces(MovedDecl.Decl);
|
|
|
|
auto CurrentIt = CurrentNamespaces.begin();
|
|
|
|
auto DeclIt = DeclNamespaces.begin();
|
|
|
|
while (CurrentIt != CurrentNamespaces.end() &&
|
|
|
|
DeclIt != DeclNamespaces.end()) {
|
|
|
|
if (*CurrentIt != *DeclIt)
|
|
|
|
break;
|
|
|
|
++CurrentIt;
|
|
|
|
++DeclIt;
|
|
|
|
}
|
|
|
|
std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
|
|
|
|
CurrentIt);
|
|
|
|
NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
|
|
|
|
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";
|
[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";
|
[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-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)
|
|
|
|
NewCode += "#endif // " + GuardName + "\n";
|
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
|
|
|
ClangMoveTool::ClangMoveTool(
|
2016-10-06 16:29:32 +08:00
|
|
|
const MoveDefinitionSpec &MoveSpec,
|
|
|
|
std::map<std::string, tooling::Replacements> &FileToReplacements,
|
|
|
|
llvm::StringRef OriginalRunningDirectory, llvm::StringRef FallbackStyle)
|
|
|
|
: Spec(MoveSpec), FileToReplacements(FileToReplacements),
|
|
|
|
OriginalRunningDirectory(OriginalRunningDirectory),
|
|
|
|
FallbackStyle(FallbackStyle) {
|
2016-09-23 21:28:38 +08:00
|
|
|
if (!Spec.NewHeader.empty())
|
|
|
|
CCIncludes.push_back("#include \"" + 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
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
|
2016-10-13 16:48:42 +08:00
|
|
|
Optional<ast_matchers::internal::Matcher<NamedDecl>> InMovedClassNames;
|
2016-10-15 07:16:25 +08:00
|
|
|
for (StringRef ClassName : Spec.Names) {
|
2016-10-13 16:48:42 +08:00
|
|
|
llvm::StringRef GlobalClassName = ClassName.trim().ltrim(':');
|
|
|
|
const auto HasName = hasName(("::" + GlobalClassName).str());
|
|
|
|
InMovedClassNames =
|
|
|
|
InMovedClassNames ? anyOf(*InMovedClassNames, HasName) : HasName;
|
|
|
|
}
|
|
|
|
if (!InMovedClassNames) {
|
|
|
|
llvm::errs() << "No classes being moved.\n";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-04 17:05:31 +08:00
|
|
|
auto InOldHeader = isExpansionInFile(
|
|
|
|
MakeAbsolutePath(OriginalRunningDirectory, Spec.OldHeader));
|
|
|
|
auto InOldCC = isExpansionInFile(
|
|
|
|
MakeAbsolutePath(OriginalRunningDirectory, 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);
|
|
|
|
auto InMovedClass =
|
2016-10-13 18:31:00 +08:00
|
|
|
hasOutermostEnclosingClass(cxxRecordDecl(*InMovedClassNames));
|
[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
|
|
|
|
|
|
|
// Match moved class declarations.
|
|
|
|
auto MovedClass = cxxRecordDecl(
|
2016-10-13 16:48:42 +08:00
|
|
|
InOldFiles, *InMovedClassNames, isDefinition(),
|
[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
|
|
|
hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl())));
|
|
|
|
Finder->addMatcher(MovedClass.bind("moved_class"), this);
|
|
|
|
|
|
|
|
// Match moved class methods (static methods included) which are defined
|
|
|
|
// outside moved class declaration.
|
2016-10-13 18:31:00 +08:00
|
|
|
Finder->addMatcher(
|
|
|
|
cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*InMovedClassNames),
|
|
|
|
isDefinition())
|
|
|
|
.bind("class_method"),
|
|
|
|
this);
|
[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
|
|
|
|
|
|
|
// Match static member variable definition of the moved class.
|
2016-10-14 18:07:58 +08:00
|
|
|
Finder->addMatcher(varDecl(InMovedClass, InOldCC, isDefinition(),
|
|
|
|
isStaticDataMember())
|
[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
|
|
|
.bind("class_static_var_decl"),
|
|
|
|
this);
|
|
|
|
|
2016-10-19 22:13:21 +08:00
|
|
|
auto InOldCCNamedNamespace =
|
|
|
|
allOf(hasParent(namespaceDecl(unless(isAnonymous()))), InOldCC);
|
|
|
|
// Matching using decls/type alias decls which are in named 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-10-19 22:13:21 +08:00
|
|
|
namedDecl(
|
|
|
|
anyOf(usingDecl(InOldCCNamedNamespace),
|
|
|
|
usingDirectiveDecl(InOldCC, InOldCCNamedNamespace),
|
|
|
|
typeAliasDecl(InOldCC, InOldCCNamedNamespace)))
|
|
|
|
.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.
|
|
|
|
auto IsOldCCStaticDefinition =
|
|
|
|
allOf(isDefinition(), unless(InMovedClass), InOldCCNamedNamespace,
|
|
|
|
isStaticStorageClass());
|
[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-10-19 22:13:21 +08:00
|
|
|
namedDecl(anyOf(functionDecl(IsOldCCStaticDefinition),
|
|
|
|
varDecl(IsOldCCStaticDefinition)))
|
[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
|
|
|
.bind("static_decls"),
|
|
|
|
this);
|
|
|
|
|
|
|
|
// Match forward declarations in old header.
|
|
|
|
Finder->addMatcher(
|
|
|
|
cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition())), InOldHeader)
|
|
|
|
.bind("fwd_decl"),
|
|
|
|
this);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
|
|
|
|
if (const auto *CMD =
|
|
|
|
Result.Nodes.getNodeAs<clang::CXXMethodDecl>("class_method")) {
|
|
|
|
// Skip inline class methods. isInline() ast matcher doesn't ignore this
|
|
|
|
// case.
|
|
|
|
if (!CMD->isInlined()) {
|
|
|
|
MovedDecls.emplace_back(CMD, &Result.Context->getSourceManager());
|
|
|
|
RemovedDecls.push_back(MovedDecls.back());
|
|
|
|
}
|
|
|
|
} else if (const auto *VD = Result.Nodes.getNodeAs<clang::VarDecl>(
|
|
|
|
"class_static_var_decl")) {
|
|
|
|
MovedDecls.emplace_back(VD, &Result.Context->getSourceManager());
|
|
|
|
RemovedDecls.push_back(MovedDecls.back());
|
|
|
|
} else if (const auto *class_decl =
|
|
|
|
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("moved_class")) {
|
|
|
|
MovedDecls.emplace_back(class_decl, &Result.Context->getSourceManager());
|
|
|
|
RemovedDecls.push_back(MovedDecls.back());
|
|
|
|
} else if (const auto *FWD =
|
|
|
|
Result.Nodes.getNodeAs<clang::CXXRecordDecl>("fwd_decl")) {
|
|
|
|
// Skip all forwad declarations which appear after moved class declaration.
|
2016-10-22 03:26:43 +08:00
|
|
|
if (RemovedDecls.empty()) {
|
|
|
|
if (const auto *DCT = FWD->getDescribedClassTemplate()) {
|
|
|
|
MovedDecls.emplace_back(DCT, &Result.Context->getSourceManager());
|
|
|
|
} else {
|
|
|
|
MovedDecls.emplace_back(FWD, &Result.Context->getSourceManager());
|
|
|
|
}
|
|
|
|
}
|
2016-10-19 22:13:21 +08:00
|
|
|
} else if (const auto *ANS = Result.Nodes.getNodeAs<clang::NamespaceDecl>(
|
|
|
|
"anonymous_ns")) {
|
|
|
|
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-10-04 17:05:31 +08:00
|
|
|
void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader,
|
|
|
|
bool IsAngled,
|
|
|
|
llvm::StringRef SearchPath,
|
|
|
|
llvm::StringRef FileName,
|
|
|
|
const SourceManager& SM) {
|
2016-10-12 23:50:30 +08:00
|
|
|
SmallVector<char, 128> HeaderWithSearchPath;
|
|
|
|
llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
|
|
|
|
std::string AbsoluteOldHeader =
|
|
|
|
MakeAbsolutePath(OriginalRunningDirectory, 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(),
|
|
|
|
HeaderWithSearchPath.size())))
|
2016-09-23 21:28:38 +08:00
|
|
|
return;
|
|
|
|
|
|
|
|
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-10-04 17:05:31 +08:00
|
|
|
} else if (MakeAbsolutePath(OriginalRunningDirectory, Spec.OldCC) ==
|
2016-10-12 23:50:30 +08:00
|
|
|
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() {
|
|
|
|
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-10-06 16:59:24 +08:00
|
|
|
*MovedDecl.SM, 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-10-14 21:43:49 +08:00
|
|
|
auto Err = FileToReplacements[FilePath].add(RemoveReplacement);
|
|
|
|
if (Err) {
|
|
|
|
llvm::errs() << llvm::toString(std::move(Err)) << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-06 16:29:32 +08:00
|
|
|
|
|
|
|
llvm::StringRef Code =
|
|
|
|
SM.getBufferData(SM.getFileID(MovedDecl.Decl->getLocation()));
|
|
|
|
format::FormatStyle Style =
|
|
|
|
format::getStyle("file", FilePath, FallbackStyle);
|
|
|
|
auto CleanReplacements = format::cleanupAroundReplacements(
|
|
|
|
Code, FileToReplacements[FilePath], Style);
|
|
|
|
|
|
|
|
if (!CleanReplacements) {
|
|
|
|
llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
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-10-04 17:05:31 +08:00
|
|
|
if (isInHeaderFile(*MovedDecl.SM, MovedDecl.Decl, OriginalRunningDirectory,
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Spec.NewHeader.empty())
|
|
|
|
FileToReplacements[Spec.NewHeader] = createInsertedReplacements(
|
2016-10-14 21:01:36 +08:00
|
|
|
HeaderIncludes, NewHeaderDecls, Spec.NewHeader, /*IsHeader=*/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
|
|
|
if (!Spec.NewCC.empty())
|
|
|
|
FileToReplacements[Spec.NewCC] =
|
|
|
|
createInsertedReplacements(CCIncludes, NewCCDecls, Spec.NewCC);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ClangMoveTool::onEndOfTranslationUnit() {
|
|
|
|
if (RemovedDecls.empty())
|
|
|
|
return;
|
|
|
|
removeClassDefinitionInOldFiles();
|
|
|
|
moveClassDefinitionToNewFiles();
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace move
|
|
|
|
} // namespace clang
|