2019-03-23 00:34:39 +08:00
|
|
|
//===-- Move.cpp - Implement ClangMove functationalities --------*- C++ -*-===//
|
[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
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
[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
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2019-03-23 00:34:39 +08:00
|
|
|
#include "Move.h"
|
2017-01-03 17:00:51 +08:00
|
|
|
#include "HelperDeclRefGraph.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
|
|
|
#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"
|
2017-01-03 17:00:51 +08:00
|
|
|
#include "llvm/Support/Debug.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
|
|
|
|
2017-01-03 17:00:51 +08:00
|
|
|
#define DEBUG_TYPE "clang-move"
|
|
|
|
|
[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
|
|
|
|
2017-01-17 18:08:11 +08:00
|
|
|
AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2018-05-17 20:40:50 +08:00
|
|
|
std::string CleanPath(StringRef PathRef) {
|
|
|
|
llvm::SmallString<128> Path(PathRef);
|
|
|
|
llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
|
2018-05-17 22:59:15 +08:00
|
|
|
// FIXME: figure out why this is necessary.
|
|
|
|
llvm::sys::path::native(Path);
|
2018-05-17 20:40:50 +08:00
|
|
|
return Path.str();
|
|
|
|
}
|
|
|
|
|
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);
|
2019-01-16 18:26:52 +08:00
|
|
|
llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
|
2018-05-17 20:40:50 +08:00
|
|
|
return CleanPath(std::move(AbsolutePath));
|
2016-10-04 17:05:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 =
|
2019-03-27 06:32:06 +08:00
|
|
|
SM.getFileManager().getVirtualFileSystem().makeAbsolute(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';
|
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.
|
2019-08-02 05:32:01 +08:00
|
|
|
auto 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) {
|
2019-08-02 05:32:01 +08:00
|
|
|
StringRef DirName = SM.getFileManager().getCanonicalName(*Dir);
|
2018-05-17 04:10:10 +08:00
|
|
|
// FIXME: getCanonicalName might fail to get real path on VFS.
|
|
|
|
if (llvm::sys::path::is_absolute(DirName)) {
|
2018-05-17 20:40:50 +08:00
|
|
|
SmallString<128> AbsoluteFilename;
|
2018-05-17 04:10:10 +08:00
|
|
|
llvm::sys::path::append(AbsoluteFilename, DirName,
|
|
|
|
llvm::sys::path::filename(AbsolutePath.str()));
|
2018-05-17 20:40:50 +08:00
|
|
|
return CleanPath(AbsoluteFilename);
|
2018-05-17 04:10:10 +08:00
|
|
|
}
|
2016-10-12 23:50:30 +08:00
|
|
|
}
|
2018-05-17 20:40:50 +08:00
|
|
|
return CleanPath(AbsolutePath);
|
2016-10-04 17:05:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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();
|
2018-08-10 06:42:26 +08:00
|
|
|
auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
|
2016-10-04 17:05:31 +08:00
|
|
|
if (ExpansionLoc.isInvalid())
|
|
|
|
return false;
|
2019-08-02 05:32:01 +08:00
|
|
|
auto *FileEntry =
|
2016-10-04 17:05:31 +08:00
|
|
|
SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
|
|
|
|
if (!FileEntry)
|
|
|
|
return false;
|
|
|
|
return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
|
|
|
|
AbsoluteFilePath;
|
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
class FindAllIncludes : public PPCallbacks {
|
[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
|
|
|
public:
|
|
|
|
explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
|
|
|
|
: SM(*SM), MoveTool(MoveTool) {}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
|
[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
|
|
|
StringRef FileName, bool IsAngled,
|
2018-10-12 00:09:26 +08:00
|
|
|
CharSourceRange FilenameRange,
|
|
|
|
const FileEntry * /*File*/, StringRef SearchPath,
|
|
|
|
StringRef /*RelativePath*/,
|
|
|
|
const Module * /*Imported*/,
|
2018-05-11 03:13:14 +08:00
|
|
|
SrcMgr::CharacteristicKind /*FileType*/) 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;
|
|
|
|
};
|
|
|
|
|
2017-01-03 22:22:25 +08:00
|
|
|
/// Add a declatration being moved to new.h/cc. Note that the declaration will
|
|
|
|
/// also be deleted in old.h/cc.
|
|
|
|
void MoveDeclFromOldFileToNewFile(ClangMoveTool *MoveTool, const NamedDecl *D) {
|
|
|
|
MoveTool->getMovedDecls().push_back(D);
|
|
|
|
MoveTool->addRemovedDecl(D);
|
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(D);
|
|
|
|
}
|
|
|
|
|
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 {
|
2018-10-12 00:09:26 +08:00
|
|
|
const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
|
2016-11-16 21:05:19 +08:00
|
|
|
assert(FD);
|
2018-10-12 00:09:26 +08:00
|
|
|
const NamedDecl *D = FD;
|
2016-11-16 21:05:19 +08:00
|
|
|
if (const auto *FTD = FD->getDescribedFunctionTemplate())
|
|
|
|
D = FTD;
|
2017-01-03 22:22:25 +08:00
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, D);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ClangMoveTool *MoveTool;
|
|
|
|
};
|
|
|
|
|
2017-02-27 21:19:13 +08:00
|
|
|
class VarDeclarationMatch : public MatchFinder::MatchCallback {
|
|
|
|
public:
|
|
|
|
explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
|
|
|
|
: MoveTool(MoveTool) {}
|
|
|
|
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
2018-10-12 00:09:26 +08:00
|
|
|
const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
|
2017-02-27 21:19:13 +08:00
|
|
|
assert(VD);
|
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, VD);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ClangMoveTool *MoveTool;
|
|
|
|
};
|
|
|
|
|
2017-01-04 22:50:49 +08:00
|
|
|
class TypeAliasMatch : public MatchFinder::MatchCallback {
|
|
|
|
public:
|
|
|
|
explicit TypeAliasMatch(ClangMoveTool *MoveTool)
|
|
|
|
: MoveTool(MoveTool) {}
|
|
|
|
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
2018-10-12 00:09:26 +08:00
|
|
|
if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
|
2017-01-04 22:50:49 +08:00
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, TD);
|
|
|
|
else if (const auto *TAD =
|
2018-10-12 00:09:26 +08:00
|
|
|
Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
|
2017-01-04 22:50:49 +08:00
|
|
|
const NamedDecl * D = TAD;
|
|
|
|
if (const auto * TD = TAD->getDescribedAliasTemplate())
|
|
|
|
D = TD;
|
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
ClangMoveTool *MoveTool;
|
|
|
|
};
|
|
|
|
|
2017-01-03 22:22:25 +08:00
|
|
|
class EnumDeclarationMatch : public MatchFinder::MatchCallback {
|
|
|
|
public:
|
|
|
|
explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
|
|
|
|
: MoveTool(MoveTool) {}
|
|
|
|
|
|
|
|
void run(const MatchFinder::MatchResult &Result) override {
|
2018-10-12 00:09:26 +08:00
|
|
|
const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
|
2017-01-03 22:22:25 +08:00
|
|
|
assert(ED);
|
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, ED);
|
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 {
|
2018-10-12 00:09:26 +08:00
|
|
|
SourceManager *SM = &Result.Context->getSourceManager();
|
|
|
|
if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
|
2016-11-14 22:15:44 +08:00
|
|
|
MatchClassMethod(CMD, SM);
|
2018-10-12 00:09:26 +08:00
|
|
|
else if (const auto *VD =
|
|
|
|
Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
|
2016-11-14 22:15:44 +08:00
|
|
|
MatchClassStaticVariable(VD, SM);
|
2018-10-12 00:09:26 +08:00
|
|
|
else if (const auto *CD =
|
|
|
|
Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
|
2016-11-14 22:15:44 +08:00
|
|
|
MatchClassDeclaration(CD, SM);
|
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
2018-10-12 00:09:26 +08:00
|
|
|
void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
|
2016-11-14 22:15:44 +08:00
|
|
|
// Skip inline class methods. isInline() ast matcher doesn't ignore this
|
|
|
|
// case.
|
|
|
|
if (!CMD->isInlined()) {
|
2016-12-02 20:39:39 +08:00
|
|
|
MoveTool->getMovedDecls().push_back(CMD);
|
|
|
|
MoveTool->addRemovedDecl(CMD);
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
|
2017-01-03 22:22:25 +08:00
|
|
|
MoveDeclFromOldFileToNewFile(MoveTool, VD);
|
2016-11-14 22:15:44 +08:00
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
|
2016-11-14 22:15:44 +08:00
|
|
|
// Get class template from its class declaration as UnremovedDecls stores
|
|
|
|
// class template.
|
|
|
|
if (const auto *TC = CD->getDescribedClassTemplate())
|
2016-12-02 20:39:39 +08:00
|
|
|
MoveTool->getMovedDecls().push_back(TC);
|
2016-11-14 22:15:44 +08:00
|
|
|
else
|
2016-12-02 20:39:39 +08:00
|
|
|
MoveTool->getMovedDecls().push_back(CD);
|
2016-11-23 18:04:19 +08:00
|
|
|
MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
|
2016-11-14 22:15:44 +08:00
|
|
|
MoveTool->getUnremovedDeclsInOldHeader().erase(
|
2016-12-02 20:39:39 +08:00
|
|
|
MoveTool->getMovedDecls().back());
|
2016-11-14 22:15:44 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
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.
|
2018-10-12 00:09:26 +08:00
|
|
|
SourceLocation getLocForEndOfDecl(const Decl *D,
|
|
|
|
const LangOptions &LangOpts = LangOptions()) {
|
2016-12-02 20:39:39 +08:00
|
|
|
const auto &SM = D->getASTContext().getSourceManager();
|
2018-04-30 13:26:07 +08:00
|
|
|
// If the expansion range is a character range, this is the location of
|
|
|
|
// the first character past the end. Otherwise it's the location of the
|
|
|
|
// first character in the final token in the range.
|
2018-08-10 06:43:02 +08:00
|
|
|
auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
|
2016-12-13 23:35:47 +08:00
|
|
|
std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
|
2016-10-06 16:59:24 +08:00
|
|
|
// Try to load the file buffer.
|
|
|
|
bool InvalidTemp = false;
|
2016-12-02 20:39:39 +08:00
|
|
|
llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
|
2016-10-06 16:59:24 +08:00
|
|
|
if (InvalidTemp)
|
|
|
|
return SourceLocation();
|
|
|
|
|
|
|
|
const char *TokBegin = File.data() + LocInfo.second;
|
|
|
|
// Lex from the start of the given location.
|
2016-12-02 20:39:39 +08:00
|
|
|
Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
|
2016-10-06 16:59:24 +08:00
|
|
|
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-12-13 23:35:47 +08:00
|
|
|
SourceLocation EndLoc = EndExpansionLoc.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'.
|
2016-12-02 20:39:39 +08:00
|
|
|
return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
|
2016-10-06 16:59:24 +08:00
|
|
|
? EndLoc
|
|
|
|
: EndLoc.getLocWithOffset(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get full range of a Decl including the comments associated with it.
|
2018-10-12 00:09:26 +08:00
|
|
|
CharSourceRange getFullRange(const Decl *D,
|
|
|
|
const LangOptions &options = LangOptions()) {
|
2016-12-02 20:39:39 +08:00
|
|
|
const auto &SM = D->getASTContext().getSourceManager();
|
2018-10-12 00:09:26 +08:00
|
|
|
SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
|
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)) {
|
2018-08-10 06:43:02 +08:00
|
|
|
if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
|
|
|
|
Full.setEnd(Comment->getEndLoc());
|
2016-10-06 16:59:24 +08:00
|
|
|
// FIXME: Don't delete a preceding comment, if there are no other entities
|
|
|
|
// it could refer to.
|
2018-08-10 06:42:26 +08:00
|
|
|
if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
|
|
|
|
Full.setBegin(Comment->getBeginLoc());
|
2016-10-06 16:59:24 +08:00
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
return CharSourceRange::getCharRange(Full);
|
2016-10-06 16:59:24 +08:00
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
std::string getDeclarationSourceText(const Decl *D) {
|
2016-12-02 20:39:39 +08:00
|
|
|
const auto &SM = D->getASTContext().getSourceManager();
|
|
|
|
llvm::StringRef SourceText =
|
2018-10-12 00:09:26 +08:00
|
|
|
Lexer::getSourceText(getFullRange(D), SM, LangOptions());
|
2016-10-06 16:59:24 +08:00
|
|
|
return SourceText.str();
|
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
|
2016-10-04 17:05:31 +08:00
|
|
|
llvm::StringRef OldHeader) {
|
2016-12-02 20:39:39 +08:00
|
|
|
const auto &SM = D->getASTContext().getSourceManager();
|
2016-10-04 17:05:31 +08:00
|
|
|
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;
|
2018-08-10 06:42:26 +08:00
|
|
|
auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
|
[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 (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;
|
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
std::vector<std::string> getNamespaces(const Decl *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
|
|
|
std::vector<std::string> Namespaces;
|
|
|
|
for (const auto *Context = D->getDeclContext(); Context;
|
|
|
|
Context = Context->getParent()) {
|
2018-10-12 00:09:26 +08:00
|
|
|
if (llvm::isa<TranslationUnitDecl>(Context) ||
|
|
|
|
llvm::isa<LinkageSpecDecl>(Context))
|
[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
|
|
|
break;
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
|
[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
|
|
|
Namespaces.push_back(ND->getName().str());
|
|
|
|
}
|
|
|
|
std::reverse(Namespaces.begin(), Namespaces.end());
|
|
|
|
return Namespaces;
|
|
|
|
}
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
tooling::Replacements
|
[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
|
|
|
createInsertedReplacements(const std::vector<std::string> &Includes,
|
2016-12-02 20:39:39 +08:00
|
|
|
const std::vector<const NamedDecl *> &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;
|
2016-12-02 20:39:39 +08:00
|
|
|
for (const auto *MovedDecl : Decls) {
|
2016-11-15 17:06:59 +08:00
|
|
|
// The namespaces of the declaration being moved.
|
2016-12-02 20:39:39 +08:00
|
|
|
std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
|
[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 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-12-02 20:39:39 +08:00
|
|
|
NewCode += getDeclarationSourceText(MovedDecl);
|
[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";
|
2018-10-12 00:09:26 +08:00
|
|
|
return tooling::Replacements(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
|
|
|
}
|
|
|
|
|
2017-01-03 17:00:51 +08:00
|
|
|
// Return a set of all decls which are used/referenced by the given Decls.
|
|
|
|
// Specically, given a class member declaration, this method will return all
|
|
|
|
// decls which are used by the whole class.
|
|
|
|
llvm::DenseSet<const Decl *>
|
|
|
|
getUsedDecls(const HelperDeclRefGraph *RG,
|
|
|
|
const std::vector<const NamedDecl *> &Decls) {
|
|
|
|
assert(RG);
|
|
|
|
llvm::DenseSet<const CallGraphNode *> Nodes;
|
|
|
|
for (const auto *D : Decls) {
|
|
|
|
auto Result = RG->getReachableNodes(
|
|
|
|
HelperDeclRGBuilder::getOutmostClassOrFunDecl(D));
|
|
|
|
Nodes.insert(Result.begin(), Result.end());
|
|
|
|
}
|
|
|
|
llvm::DenseSet<const Decl *> Results;
|
|
|
|
for (const auto *Node : Nodes)
|
|
|
|
Results.insert(Node->getDecl());
|
|
|
|
return Results;
|
|
|
|
}
|
|
|
|
|
[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
|
|
|
|
|
2018-10-12 00:09:26 +08:00
|
|
|
std::unique_ptr<ASTConsumer>
|
|
|
|
ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
|
[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
|
|
|
StringRef /*InFile*/) {
|
2019-08-15 07:52:23 +08:00
|
|
|
Compiler.getPreprocessor().addPPCallbacks(std::make_unique<FindAllIncludes>(
|
[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
|
|
|
&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-12-02 20:39:39 +08:00
|
|
|
void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
|
|
|
|
const auto &SM = Decl->getASTContext().getSourceManager();
|
|
|
|
auto Loc = Decl->getLocation();
|
2016-11-23 18:04:19 +08:00
|
|
|
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);
|
2017-05-02 20:15:11 +08:00
|
|
|
auto classTemplateForwardDecls =
|
|
|
|
classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
|
|
|
|
auto ForwardClassDecls = namedDecl(
|
|
|
|
anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
|
|
|
|
classTemplateForwardDecls));
|
2017-01-03 22:22:25 +08:00
|
|
|
auto TopLevelDecl =
|
|
|
|
hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
|
2016-11-09 03:55:13 +08:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// 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(
|
2017-05-02 20:15:11 +08:00
|
|
|
unless(ForwardClassDecls), unless(namespaceDecl()),
|
|
|
|
unless(usingDirectiveDecl()), // using namespace decl.
|
2018-02-09 23:57:30 +08:00
|
|
|
notInMacro(),
|
2016-11-09 03:55:13 +08:00
|
|
|
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.
|
2017-05-02 20:15:11 +08:00
|
|
|
Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
|
2016-11-09 03:55:13 +08:00
|
|
|
this);
|
|
|
|
|
2016-11-10 13:33:26 +08:00
|
|
|
//============================================================================
|
|
|
|
// Matchers for old cc
|
|
|
|
//============================================================================
|
2017-01-03 17:00:51 +08:00
|
|
|
auto IsOldCCTopLevelDecl = allOf(
|
|
|
|
hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))), InOldCC);
|
|
|
|
// Matching using decls/type alias decls which are in named/anonymous/global
|
|
|
|
// namespace, these decls are always copied to new.h/cc. Those in classes,
|
|
|
|
// functions are covered in other matchers.
|
2017-01-17 18:08:11 +08:00
|
|
|
Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
|
2018-08-31 11:51:33 +08:00
|
|
|
usingDirectiveDecl(unless(isImplicit()),
|
|
|
|
IsOldCCTopLevelDecl),
|
2017-01-17 18:08:11 +08:00
|
|
|
typeAliasDecl(IsOldCCTopLevelDecl)),
|
|
|
|
notInMacro())
|
|
|
|
.bind("using_decl"),
|
|
|
|
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
|
|
|
|
2016-10-19 22:13:21 +08:00
|
|
|
// 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));
|
2017-01-03 17:00:51 +08:00
|
|
|
|
|
|
|
// Matchers for helper declarations in old.cc.
|
|
|
|
auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
|
2017-01-17 21:22:37 +08:00
|
|
|
auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
|
|
|
|
auto IsOldCCHelper =
|
|
|
|
allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
|
2017-01-03 17:00:51 +08:00
|
|
|
// Match helper classes separately with helper functions/variables since we
|
|
|
|
// want to reuse these matchers in finding helpers usage below.
|
2017-01-17 21:22:37 +08:00
|
|
|
//
|
|
|
|
// There could be forward declarations usage for helpers, especially for
|
|
|
|
// classes and functions. We need include these forward declarations.
|
|
|
|
//
|
|
|
|
// Forward declarations for variable helpers will be excluded as these
|
|
|
|
// declarations (with "extern") are not supposed in cpp file.
|
|
|
|
auto HelperFuncOrVar =
|
|
|
|
namedDecl(notInMacro(), anyOf(functionDecl(IsOldCCHelper),
|
|
|
|
varDecl(isDefinition(), IsOldCCHelper)));
|
2017-01-17 18:08:11 +08:00
|
|
|
auto HelperClasses =
|
2017-01-17 21:22:37 +08:00
|
|
|
cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
|
2017-01-03 17:00:51 +08:00
|
|
|
// Save all helper declarations in old.cc.
|
|
|
|
Finder->addMatcher(
|
|
|
|
namedDecl(anyOf(HelperFuncOrVar, HelperClasses)).bind("helper_decls"),
|
|
|
|
this);
|
|
|
|
|
|
|
|
// Construct an AST-based call graph of helper declarations in old.cc.
|
|
|
|
// In the following matcheres, "dc" is a caller while "helper_decls" and
|
|
|
|
// "used_class" is a callee, so a new edge starting from caller to callee will
|
|
|
|
// be add in the graph.
|
|
|
|
//
|
|
|
|
// Find helper function/variable usages.
|
|
|
|
Finder->addMatcher(
|
|
|
|
declRefExpr(to(HelperFuncOrVar), hasAncestor(decl().bind("dc")))
|
|
|
|
.bind("func_ref"),
|
|
|
|
&RGBuilder);
|
|
|
|
// Find helper class usages.
|
|
|
|
Finder->addMatcher(
|
|
|
|
typeLoc(loc(recordType(hasDeclaration(HelperClasses.bind("used_class")))),
|
|
|
|
hasAncestor(decl().bind("dc"))),
|
|
|
|
&RGBuilder);
|
2016-11-14 22:15:44 +08:00
|
|
|
|
|
|
|
//============================================================================
|
|
|
|
// Matchers for old files, including old.h/old.cc
|
|
|
|
//============================================================================
|
|
|
|
// Create a MatchCallback for class declarations.
|
2019-08-15 07:52:23 +08:00
|
|
|
MatchCallbacks.push_back(std::make_unique<ClassDeclarationMatch>(this));
|
2016-11-14 22:15:44 +08:00
|
|
|
// Match moved class declarations.
|
2017-01-03 22:22:25 +08:00
|
|
|
auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
|
|
|
|
isDefinition(), TopLevelDecl)
|
|
|
|
.bind("moved_class");
|
2016-11-14 22:15:44 +08:00
|
|
|
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());
|
|
|
|
|
2019-08-15 07:52:23 +08:00
|
|
|
MatchCallbacks.push_back(std::make_unique<FunctionDeclarationMatch>(this));
|
2017-01-03 22:22:25 +08:00
|
|
|
Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
|
2016-11-16 21:05:19 +08:00
|
|
|
.bind("function"),
|
|
|
|
MatchCallbacks.back().get());
|
2017-01-03 22:22:25 +08:00
|
|
|
|
2019-08-15 07:52:23 +08:00
|
|
|
MatchCallbacks.push_back(std::make_unique<VarDeclarationMatch>(this));
|
2017-02-27 21:19:13 +08:00
|
|
|
Finder->addMatcher(
|
|
|
|
varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
|
|
|
|
MatchCallbacks.back().get());
|
|
|
|
|
2017-01-04 22:50:49 +08:00
|
|
|
// Match enum definition in old.h. Enum helpers (which are defined in old.cc)
|
2017-01-03 22:22:25 +08:00
|
|
|
// will not be moved for now no matter whether they are used or not.
|
2019-08-15 07:52:23 +08:00
|
|
|
MatchCallbacks.push_back(std::make_unique<EnumDeclarationMatch>(this));
|
2017-01-03 22:22:25 +08:00
|
|
|
Finder->addMatcher(
|
|
|
|
enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
|
|
|
|
.bind("enum"),
|
|
|
|
MatchCallbacks.back().get());
|
2017-01-04 22:50:49 +08:00
|
|
|
|
|
|
|
// Match type alias in old.h, this includes "typedef" and "using" type alias
|
|
|
|
// declarations. Type alias helpers (which are defined in old.cc) will not be
|
|
|
|
// moved for now no matter whether they are used or not.
|
2019-08-15 07:52:23 +08:00
|
|
|
MatchCallbacks.push_back(std::make_unique<TypeAliasMatch>(this));
|
2017-01-04 22:50:49 +08:00
|
|
|
Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
|
|
|
|
typeAliasDecl().bind("type_alias")),
|
|
|
|
InOldHeader, *HasAnySymbolNames, TopLevelDecl),
|
|
|
|
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) {
|
2018-10-12 00:09:26 +08:00
|
|
|
if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
|
2016-11-09 03:55:13 +08:00
|
|
|
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 =
|
2018-10-12 00:09:26 +08:00
|
|
|
Result.Nodes.getNodeAs<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-12-02 20:39:39 +08:00
|
|
|
MovedDecls.push_back(DCT);
|
2016-11-10 13:33:26 +08:00
|
|
|
else
|
2016-12-02 20:39:39 +08:00
|
|
|
MovedDecls.push_back(FWD);
|
2016-10-22 03:26:43 +08:00
|
|
|
}
|
2017-01-03 17:00:51 +08:00
|
|
|
} else if (const auto *ND =
|
2018-10-12 00:09:26 +08:00
|
|
|
Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
|
2017-01-03 17:00:51 +08:00
|
|
|
MovedDecls.push_back(ND);
|
|
|
|
HelperDeclarations.push_back(ND);
|
2018-05-16 00:37:45 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
|
|
|
|
<< ND << ")\n");
|
2018-10-12 00:09:26 +08:00
|
|
|
} else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
|
2016-12-02 20:39:39 +08:00
|
|
|
MovedDecls.push_back(UD);
|
[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,
|
2018-10-12 00:09:26 +08:00
|
|
|
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);
|
2018-01-31 20:12:29 +08:00
|
|
|
std::string AbsoluteIncludeHeader =
|
2016-10-12 23:50:30 +08:00
|
|
|
MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
|
2018-01-31 20:12:29 +08:00
|
|
|
HeaderWithSearchPath.size()));
|
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
|
|
|
|
2018-01-31 20:12:29 +08:00
|
|
|
std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
|
2016-10-12 23:50:30 +08:00
|
|
|
std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
|
|
|
|
if (AbsoluteOldHeader == AbsoluteCurrentFile) {
|
2018-01-31 20:12:29 +08:00
|
|
|
// Find old.h includes "old.h".
|
|
|
|
if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
|
|
|
|
OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
|
|
|
|
return;
|
|
|
|
}
|
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) {
|
2018-01-31 20:12:29 +08:00
|
|
|
// Find old.cc includes "old.h".
|
|
|
|
if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
|
|
|
|
OldHeaderIncludeRangeInCC = IncludeFilenameRange;
|
|
|
|
return;
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
2016-12-02 20:39:39 +08:00
|
|
|
void ClangMoveTool::removeDeclsInOldFiles() {
|
2016-11-23 18:04:19 +08:00
|
|
|
if (RemovedDecls.empty()) return;
|
2017-01-03 17:00:51 +08:00
|
|
|
|
|
|
|
// If old_header is not specified (only move declarations from old.cc), remain
|
|
|
|
// all the helper function declarations in old.cc as UnremovedDeclsInOldHeader
|
|
|
|
// is empty in this case, there is no way to verify unused/used helpers.
|
|
|
|
if (!Context->Spec.OldHeader.empty()) {
|
|
|
|
std::vector<const NamedDecl *> UnremovedDecls;
|
|
|
|
for (const auto *D : UnremovedDeclsInOldHeader)
|
|
|
|
UnremovedDecls.push_back(D);
|
|
|
|
|
|
|
|
auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), UnremovedDecls);
|
|
|
|
|
|
|
|
// We remove the helper declarations which are not used in the old.cc after
|
|
|
|
// moving the given declarations.
|
|
|
|
for (const auto *D : HelperDeclarations) {
|
2018-05-16 00:37:45 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
|
|
|
|
<< D->getNameAsString() << " (" << D << ")\n");
|
2017-01-17 21:22:37 +08:00
|
|
|
if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
|
|
|
|
D->getCanonicalDecl()))) {
|
2018-05-16 00:37:45 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
|
|
|
|
<< D->getNameAsString() << " (" << D << ")\n");
|
2017-01-03 17:00:51 +08:00
|
|
|
RemovedDecls.push_back(D);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 20:39:39 +08:00
|
|
|
for (const auto *RemovedDecl : RemovedDecls) {
|
|
|
|
const auto &SM = RemovedDecl->getASTContext().getSourceManager();
|
|
|
|
auto Range = getFullRange(RemovedDecl);
|
2018-10-12 00:09:26 +08:00
|
|
|
tooling::Replacement RemoveReplacement(
|
|
|
|
SM, 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
|
|
|
}
|
2016-12-02 20:39:39 +08:00
|
|
|
const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
|
2016-11-23 18:04:19 +08:00
|
|
|
|
|
|
|
// 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 &&
|
2016-12-02 20:39:39 +08:00
|
|
|
MakeAbsolutePath(SM, FilePath) ==
|
2016-11-24 18:17:17 +08:00
|
|
|
makeAbsolutePath(Context->Spec.OldHeader)) {
|
2019-03-25 22:09:10 +08:00
|
|
|
// FIXME: Minimize the include path like clang-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;
|
2016-12-02 20:39:39 +08:00
|
|
|
llvm::StringRef Code = SM.getBufferData(SI->second);
|
2018-08-02 18:30:56 +08:00
|
|
|
auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
|
|
|
|
Context->FallbackStyle);
|
2017-01-17 08:13:32 +08:00
|
|
|
if (!Style) {
|
|
|
|
llvm::errs() << llvm::toString(Style.takeError()) << "\n";
|
|
|
|
continue;
|
|
|
|
}
|
2016-10-06 16:29:32 +08:00
|
|
|
auto CleanReplacements = format::cleanupAroundReplacements(
|
2017-01-17 08:13:32 +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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-02 20:39:39 +08:00
|
|
|
void ClangMoveTool::moveDeclsToNewFiles() {
|
|
|
|
std::vector<const NamedDecl *> NewHeaderDecls;
|
|
|
|
std::vector<const NamedDecl *> NewCCDecls;
|
|
|
|
for (const auto *MovedDecl : MovedDecls) {
|
|
|
|
if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
|
2016-11-24 18:17:17 +08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2017-01-03 17:00:51 +08:00
|
|
|
auto UsedDecls = getUsedDecls(RGBuilder.getGraph(), RemovedDecls);
|
|
|
|
std::vector<const NamedDecl *> ActualNewCCDecls;
|
|
|
|
|
|
|
|
// Filter out all unused helpers in NewCCDecls.
|
|
|
|
// We only move the used helpers (including transively used helpers) and the
|
|
|
|
// given symbols being moved.
|
|
|
|
for (const auto *D : NewCCDecls) {
|
|
|
|
if (llvm::is_contained(HelperDeclarations, D) &&
|
2017-01-17 21:22:37 +08:00
|
|
|
!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
|
|
|
|
D->getCanonicalDecl())))
|
2017-01-03 17:00:51 +08:00
|
|
|
continue;
|
|
|
|
|
2018-05-16 00:37:45 +08:00
|
|
|
LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
|
|
|
|
<< " " << D << "\n");
|
2017-01-03 17:00:51 +08:00
|
|
|
ActualNewCCDecls.push_back(D);
|
|
|
|
}
|
|
|
|
|
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] =
|
2017-01-03 17:00:51 +08:00
|
|
|
createInsertedReplacements(CCIncludes, ActualNewCCDecls,
|
|
|
|
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) {
|
2019-08-02 05:32:01 +08:00
|
|
|
auto FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
|
2016-11-09 03:55:13 +08:00
|
|
|
if (!FE) {
|
|
|
|
llvm::errs() << "Failed to get file: " << OldFile << "\n";
|
|
|
|
return;
|
|
|
|
}
|
2019-08-02 05:32:01 +08:00
|
|
|
FileID ID = SM.getOrCreateFileID(*FE, SrcMgr::C_User);
|
2016-11-09 03:55:13 +08:00
|
|
|
auto Begin = SM.getLocForStartOfFile(ID);
|
|
|
|
auto End = SM.getLocForEndOfFile(ID);
|
2018-10-12 00:09:26 +08:00
|
|
|
tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
|
|
|
|
"");
|
2016-11-09 03:55:13 +08:00
|
|
|
std::string FilePath = RemoveAll.getFilePath().str();
|
2018-10-12 00:09:26 +08:00
|
|
|
Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
|
2016-11-09 03:55:13 +08:00
|
|
|
|
|
|
|
StringRef Code = SM.getBufferData(ID);
|
|
|
|
if (!NewFile.empty()) {
|
2018-10-12 00:09:26 +08:00
|
|
|
auto AllCode =
|
|
|
|
tooling::Replacements(tooling::Replacement(NewFile, 0, 0, Code));
|
|
|
|
auto ReplaceOldInclude = [&](CharSourceRange OldHeaderIncludeRange) {
|
|
|
|
AllCode = AllCode.merge(tooling::Replacements(tooling::Replacement(
|
|
|
|
SM, OldHeaderIncludeRange, '"' + Context->Spec.NewHeader + '"')));
|
2018-01-31 20:12:29 +08:00
|
|
|
};
|
|
|
|
// Fix the case where old.h/old.cc includes "old.h", we replace the
|
|
|
|
// `#include "old.h"` with `#include "new.h"`.
|
|
|
|
if (Context->Spec.NewCC == NewFile && OldHeaderIncludeRangeInCC.isValid())
|
|
|
|
ReplaceOldInclude(OldHeaderIncludeRangeInCC);
|
|
|
|
else if (Context->Spec.NewHeader == NewFile &&
|
|
|
|
OldHeaderIncludeRangeInHeader.isValid())
|
|
|
|
ReplaceOldInclude(OldHeaderIncludeRangeInHeader);
|
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();
|
2018-10-09 01:22:50 +08:00
|
|
|
bool Templated = Decl->isTemplated();
|
2016-11-24 18:17:17 +08:00
|
|
|
const std::string QualifiedName = Decl->getQualifiedNameAsString();
|
2017-02-27 21:19:13 +08:00
|
|
|
if (Kind == Decl::Kind::Var)
|
2018-10-09 01:22:50 +08:00
|
|
|
Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
|
2017-02-27 21:19:13 +08:00
|
|
|
else if (Kind == Decl::Kind::Function ||
|
|
|
|
Kind == Decl::Kind::FunctionTemplate)
|
2018-10-09 01:22:50 +08:00
|
|
|
Reporter->reportDeclaration(QualifiedName, "Function", Templated);
|
2016-11-24 18:17:17 +08:00
|
|
|
else if (Kind == Decl::Kind::ClassTemplate ||
|
|
|
|
Kind == Decl::Kind::CXXRecord)
|
2018-10-09 01:22:50 +08:00
|
|
|
Reporter->reportDeclaration(QualifiedName, "Class", Templated);
|
2017-01-16 17:34:07 +08:00
|
|
|
else if (Kind == Decl::Kind::Enum)
|
2018-10-09 01:22:50 +08:00
|
|
|
Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
|
|
|
|
else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
|
2017-01-16 17:34:07 +08:00
|
|
|
Kind == Decl::Kind::TypeAliasTemplate)
|
2018-10-09 01:22:50 +08:00
|
|
|
Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
|
2016-11-24 18:17:17 +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
|
|
|
if (RemovedDecls.empty())
|
|
|
|
return;
|
2018-02-09 23:57:30 +08:00
|
|
|
// Ignore symbols that are not supported when checking if there is unremoved
|
|
|
|
// symbol in old header. This makes sure that we always move old files to new
|
|
|
|
// files when all symbols produced from dump_decls are moved.
|
2018-10-12 00:09:26 +08:00
|
|
|
auto IsSupportedKind = [](const NamedDecl *Decl) {
|
2016-12-06 18:12:23 +08:00
|
|
|
switch (Decl->getKind()) {
|
|
|
|
case Decl::Kind::Function:
|
|
|
|
case Decl::Kind::FunctionTemplate:
|
|
|
|
case Decl::Kind::ClassTemplate:
|
|
|
|
case Decl::Kind::CXXRecord:
|
2017-01-03 22:22:25 +08:00
|
|
|
case Decl::Kind::Enum:
|
2017-01-04 22:50:49 +08:00
|
|
|
case Decl::Kind::Typedef:
|
|
|
|
case Decl::Kind::TypeAlias:
|
|
|
|
case Decl::Kind::TypeAliasTemplate:
|
2017-02-27 21:19:13 +08:00
|
|
|
case Decl::Kind::Var:
|
2016-12-06 18:12:23 +08:00
|
|
|
return true;
|
|
|
|
default:
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
if (std::none_of(UnremovedDeclsInOldHeader.begin(),
|
|
|
|
UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
|
|
|
|
!Context->Spec.OldHeader.empty()) {
|
2016-12-02 20:39:39 +08:00
|
|
|
auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
|
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;
|
|
|
|
}
|
2018-05-16 00:37:45 +08:00
|
|
|
LLVM_DEBUG(RGBuilder.getGraph()->dump());
|
2016-12-02 20:39:39 +08:00
|
|
|
moveDeclsToNewFiles();
|
2017-01-03 17:00:51 +08:00
|
|
|
removeDeclsInOldFiles();
|
[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 move
|
|
|
|
} // namespace clang
|