[clang-tools-extra] r356780 - Make clang-move use same file naming convention as other tools
Nico Weber via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 22 09:34:39 PDT 2019
Author: nico
Date: Fri Mar 22 09:34:39 2019
New Revision: 356780
URL: http://llvm.org/viewvc/llvm-project?rev=356780&view=rev
Log:
Make clang-move use same file naming convention as other tools
In all the other clang-foo tools, the main library file is called
Foo.cpp and the file in the tool/ folder is called ClangFoo.cpp.
Do this for clang-move too.
No intended behavior change.
Differential Revision: https://reviews.llvm.org/D59700
Added:
clang-tools-extra/trunk/clang-move/Move.cpp
clang-tools-extra/trunk/clang-move/Move.h
clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp
Removed:
clang-tools-extra/trunk/clang-move/ClangMove.cpp
clang-tools-extra/trunk/clang-move/ClangMove.h
clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
Modified:
clang-tools-extra/trunk/clang-move/CMakeLists.txt
clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt
Modified: clang-tools-extra/trunk/clang-move/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/CMakeLists.txt?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-move/CMakeLists.txt Fri Mar 22 09:34:39 2019
@@ -3,7 +3,7 @@ set(LLVM_LINK_COMPONENTS
)
add_clang_library(clangMove
- ClangMove.cpp
+ Move.cpp
HelperDeclRefGraph.cpp
LINK_LIBS
Removed: clang-tools-extra/trunk/clang-move/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.cpp?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.cpp (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.cpp (removed)
@@ -1,937 +0,0 @@
-//===-- ClangMove.cpp - Implement ClangMove functationalities ---*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangMove.h"
-#include "HelperDeclRefGraph.h"
-#include "clang/ASTMatchers/ASTMatchers.h"
-#include "clang/Basic/SourceManager.h"
-#include "clang/Format/Format.h"
-#include "clang/Frontend/CompilerInstance.h"
-#include "clang/Lex/Lexer.h"
-#include "clang/Lex/Preprocessor.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/Core/Replacement.h"
-#include "llvm/Support/Debug.h"
-#include "llvm/Support/Path.h"
-
-#define DEBUG_TYPE "clang-move"
-
-using namespace clang::ast_matchers;
-
-namespace clang {
-namespace move {
-namespace {
-
-// FIXME: Move to ASTMatchers.
-AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
-
-AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
-
-AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
- ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
- const auto *Context = Node.getDeclContext();
- if (!Context)
- return false;
- while (const auto *NextContext = Context->getParent()) {
- if (isa<NamespaceDecl>(NextContext) ||
- isa<TranslationUnitDecl>(NextContext))
- break;
- Context = NextContext;
- }
- return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
- Builder);
-}
-
-AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
- ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
- const CXXRecordDecl *Parent = Node.getParent();
- if (!Parent)
- return false;
- while (const auto *NextParent =
- dyn_cast<CXXRecordDecl>(Parent->getParent())) {
- Parent = NextParent;
- }
-
- return InnerMatcher.matches(*Parent, Finder, Builder);
-}
-
-std::string CleanPath(StringRef PathRef) {
- llvm::SmallString<128> Path(PathRef);
- llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
- // FIXME: figure out why this is necessary.
- llvm::sys::path::native(Path);
- return Path.str();
-}
-
-// 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);
- llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
- return CleanPath(std::move(AbsolutePath));
-}
-
-// Make the Path absolute using the current working directory of the given
-// SourceManager if the Path is not an absolute path.
-//
-// The Path can be a path relative to the build directory, or retrieved from
-// the SourceManager.
-std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
- llvm::SmallString<128> AbsolutePath(Path);
- if (std::error_code EC =
- SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
- AbsolutePath))
- llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
- << '\n';
- // Handle symbolic link path cases.
- // We are trying to get the real file path of the symlink.
- const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
- llvm::sys::path::parent_path(AbsolutePath.str()));
- if (Dir) {
- StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
- // FIXME: getCanonicalName might fail to get real path on VFS.
- if (llvm::sys::path::is_absolute(DirName)) {
- SmallString<128> AbsoluteFilename;
- llvm::sys::path::append(AbsoluteFilename, DirName,
- llvm::sys::path::filename(AbsolutePath.str()));
- return CleanPath(AbsoluteFilename);
- }
- }
- return CleanPath(AbsolutePath);
-}
-
-// Matches AST nodes that are expanded within the given AbsoluteFilePath.
-AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
- AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
- std::string, AbsoluteFilePath) {
- auto &SourceManager = Finder->getASTContext().getSourceManager();
- auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
- if (ExpansionLoc.isInvalid())
- return false;
- auto FileEntry =
- SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
- if (!FileEntry)
- return false;
- return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
- AbsoluteFilePath;
-}
-
-class FindAllIncludes : public PPCallbacks {
-public:
- explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
- : SM(*SM), MoveTool(MoveTool) {}
-
- void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
- StringRef FileName, bool IsAngled,
- CharSourceRange FilenameRange,
- const FileEntry * /*File*/, StringRef SearchPath,
- StringRef /*RelativePath*/,
- const Module * /*Imported*/,
- SrcMgr::CharacteristicKind /*FileType*/) override {
- if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
- MoveTool->addIncludes(FileName, IsAngled, SearchPath,
- FileEntry->getName(), FilenameRange, SM);
- }
-
-private:
- const SourceManager &SM;
- ClangMoveTool *const MoveTool;
-};
-
-/// 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);
-}
-
-class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
-public:
- explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
- : MoveTool(MoveTool) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
- assert(FD);
- const NamedDecl *D = FD;
- if (const auto *FTD = FD->getDescribedFunctionTemplate())
- D = FTD;
- MoveDeclFromOldFileToNewFile(MoveTool, D);
- }
-
-private:
- ClangMoveTool *MoveTool;
-};
-
-class VarDeclarationMatch : public MatchFinder::MatchCallback {
-public:
- explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
- : MoveTool(MoveTool) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
- assert(VD);
- MoveDeclFromOldFileToNewFile(MoveTool, VD);
- }
-
-private:
- ClangMoveTool *MoveTool;
-};
-
-class TypeAliasMatch : public MatchFinder::MatchCallback {
-public:
- explicit TypeAliasMatch(ClangMoveTool *MoveTool)
- : MoveTool(MoveTool) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
- MoveDeclFromOldFileToNewFile(MoveTool, TD);
- else if (const auto *TAD =
- Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
- const NamedDecl * D = TAD;
- if (const auto * TD = TAD->getDescribedAliasTemplate())
- D = TD;
- MoveDeclFromOldFileToNewFile(MoveTool, D);
- }
- }
-
-private:
- ClangMoveTool *MoveTool;
-};
-
-class EnumDeclarationMatch : public MatchFinder::MatchCallback {
-public:
- explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
- : MoveTool(MoveTool) {}
-
- void run(const MatchFinder::MatchResult &Result) override {
- const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
- assert(ED);
- MoveDeclFromOldFileToNewFile(MoveTool, ED);
- }
-
-private:
- ClangMoveTool *MoveTool;
-};
-
-class ClassDeclarationMatch : public MatchFinder::MatchCallback {
-public:
- explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
- : MoveTool(MoveTool) {}
- void run(const MatchFinder::MatchResult &Result) override {
- SourceManager *SM = &Result.Context->getSourceManager();
- if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
- MatchClassMethod(CMD, SM);
- else if (const auto *VD =
- Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
- MatchClassStaticVariable(VD, SM);
- else if (const auto *CD =
- Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
- MatchClassDeclaration(CD, SM);
- }
-
-private:
- void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
- // Skip inline class methods. isInline() ast matcher doesn't ignore this
- // case.
- if (!CMD->isInlined()) {
- MoveTool->getMovedDecls().push_back(CMD);
- MoveTool->addRemovedDecl(CMD);
- // Get template class method from its method declaration as
- // UnremovedDecls stores template class method.
- if (const auto *FTD = CMD->getDescribedFunctionTemplate())
- MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
- else
- MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
- }
- }
-
- void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
- MoveDeclFromOldFileToNewFile(MoveTool, VD);
- }
-
- void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
- // Get class template from its class declaration as UnremovedDecls stores
- // class template.
- if (const auto *TC = CD->getDescribedClassTemplate())
- MoveTool->getMovedDecls().push_back(TC);
- else
- MoveTool->getMovedDecls().push_back(CD);
- MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
- MoveTool->getUnremovedDeclsInOldHeader().erase(
- MoveTool->getMovedDecls().back());
- }
-
- ClangMoveTool *MoveTool;
-};
-
-// Expand to get the end location of the line where the EndLoc of the given
-// Decl.
-SourceLocation getLocForEndOfDecl(const Decl *D,
- const LangOptions &LangOpts = LangOptions()) {
- const auto &SM = D->getASTContext().getSourceManager();
- // 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.
- auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
- std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
- // Try to load the file buffer.
- bool InvalidTemp = false;
- llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
- if (InvalidTemp)
- return SourceLocation();
-
- const char *TokBegin = File.data() + LocInfo.second;
- // Lex from the start of the given location.
- Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
- TokBegin, File.end());
-
- llvm::SmallVector<char, 16> Line;
- // FIXME: this is a bit hacky to get ReadToEndOfLine work.
- Lex.setParsingPreprocessorDirective(true);
- Lex.ReadToEndOfLine(&Line);
- SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
- // If we already reach EOF, just return the EOF SourceLocation;
- // otherwise, move 1 offset ahead to include the trailing newline character
- // '\n'.
- return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
- ? EndLoc
- : EndLoc.getLocWithOffset(1);
-}
-
-// Get full range of a Decl including the comments associated with it.
-CharSourceRange getFullRange(const Decl *D,
- const LangOptions &options = LangOptions()) {
- const auto &SM = D->getASTContext().getSourceManager();
- SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
- // Expand to comments that are associated with the Decl.
- if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
- if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
- Full.setEnd(Comment->getEndLoc());
- // FIXME: Don't delete a preceding comment, if there are no other entities
- // it could refer to.
- if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
- Full.setBegin(Comment->getBeginLoc());
- }
-
- return CharSourceRange::getCharRange(Full);
-}
-
-std::string getDeclarationSourceText(const Decl *D) {
- const auto &SM = D->getASTContext().getSourceManager();
- llvm::StringRef SourceText =
- Lexer::getSourceText(getFullRange(D), SM, LangOptions());
- return SourceText.str();
-}
-
-bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
- llvm::StringRef OldHeader) {
- const auto &SM = D->getASTContext().getSourceManager();
- if (OldHeader.empty())
- return false;
- auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
- if (ExpansionLoc.isInvalid())
- return false;
-
- if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
- return MakeAbsolutePath(SM, FE->getName()) ==
- MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
- }
-
- return false;
-}
-
-std::vector<std::string> getNamespaces(const Decl *D) {
- std::vector<std::string> Namespaces;
- for (const auto *Context = D->getDeclContext(); Context;
- Context = Context->getParent()) {
- if (llvm::isa<TranslationUnitDecl>(Context) ||
- llvm::isa<LinkageSpecDecl>(Context))
- break;
-
- if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
- Namespaces.push_back(ND->getName().str());
- }
- std::reverse(Namespaces.begin(), Namespaces.end());
- return Namespaces;
-}
-
-tooling::Replacements
-createInsertedReplacements(const std::vector<std::string> &Includes,
- const std::vector<const NamedDecl *> &Decls,
- llvm::StringRef FileName, bool IsHeader = false,
- StringRef OldHeaderInclude = "") {
- std::string NewCode;
- std::string GuardName(FileName);
- if (IsHeader) {
- for (size_t i = 0; i < GuardName.size(); ++i) {
- if (!isAlphanumeric(GuardName[i]))
- GuardName[i] = '_';
- }
- GuardName = StringRef(GuardName).upper();
- NewCode += "#ifndef " + GuardName + "\n";
- NewCode += "#define " + GuardName + "\n\n";
- }
-
- NewCode += OldHeaderInclude;
- // Add #Includes.
- for (const auto &Include : Includes)
- NewCode += Include;
-
- if (!Includes.empty())
- NewCode += "\n";
-
- // Add moved class definition and its related declarations. All declarations
- // in same namespace are grouped together.
- //
- // Record namespaces where the current position is in.
- std::vector<std::string> CurrentNamespaces;
- for (const auto *MovedDecl : Decls) {
- // The namespaces of the declaration being moved.
- std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
- auto CurrentIt = CurrentNamespaces.begin();
- auto DeclIt = DeclNamespaces.begin();
- // Skip the common prefix.
- while (CurrentIt != CurrentNamespaces.end() &&
- DeclIt != DeclNamespaces.end()) {
- if (*CurrentIt != *DeclIt)
- break;
- ++CurrentIt;
- ++DeclIt;
- }
- // Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
- // which is used for next iteration of this loop.
- std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
- CurrentIt);
- NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
-
-
- // End with CurrentNamespace.
- bool HasEndCurrentNamespace = false;
- auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
- for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
- --RemainingSize, ++It) {
- assert(It < CurrentNamespaces.rend());
- NewCode += "} // namespace " + *It + "\n";
- HasEndCurrentNamespace = true;
- }
- // 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;
- while (DeclIt != DeclNamespaces.end()) {
- NewCode += "namespace " + *DeclIt + " {\n";
- IsInNewNamespace = true;
- ++DeclIt;
- }
- // If the moved declaration is in same namespace CurrentNamespace, add
- // a preceeding `\n' before the moved declaration.
- // FIXME: Don't add empty lines between using declarations.
- if (!IsInNewNamespace)
- NewCode += "\n";
- NewCode += getDeclarationSourceText(MovedDecl);
- CurrentNamespaces = std::move(NextNamespaces);
- }
- std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
- for (const auto &NS : CurrentNamespaces)
- NewCode += "} // namespace " + NS + "\n";
-
- if (IsHeader)
- NewCode += "\n#endif // " + GuardName + "\n";
- return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
-}
-
-// 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;
-}
-
-} // namespace
-
-std::unique_ptr<ASTConsumer>
-ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
- StringRef /*InFile*/) {
- Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
- &Compiler.getSourceManager(), &MoveTool));
- return MatchFinder.newASTConsumer();
-}
-
-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");
-}
-
-void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
- const auto &SM = Decl->getASTContext().getSourceManager();
- auto Loc = Decl->getLocation();
- StringRef FilePath = SM.getFilename(Loc);
- FilePathToFileID[FilePath] = SM.getFileID(Loc);
- RemovedDecls.push_back(Decl);
-}
-
-void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
- auto InOldHeader =
- isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
- auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
- auto InOldFiles = anyOf(InOldHeader, InOldCC);
- auto classTemplateForwardDecls =
- classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
- auto ForwardClassDecls = namedDecl(
- anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
- classTemplateForwardDecls));
- auto TopLevelDecl =
- hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
-
- //============================================================================
- // 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.
- //
- // We consider declarations inside a class belongs to the class. So these
- // declarations will be ignored.
- auto AllDeclsInHeader = namedDecl(
- unless(ForwardClassDecls), unless(namespaceDecl()),
- unless(usingDirectiveDecl()), // using namespace decl.
- notInMacro(),
- InOldHeader,
- hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
- hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
- Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
-
- // Don't register other matchers when dumping all declarations in header.
- if (Context->DumpDeclarations)
- return;
-
- // Match forward declarations in old header.
- Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
- this);
-
- //============================================================================
- // Matchers for old cc
- //============================================================================
- 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.
- Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
- usingDirectiveDecl(unless(isImplicit()),
- IsOldCCTopLevelDecl),
- typeAliasDecl(IsOldCCTopLevelDecl)),
- notInMacro())
- .bind("using_decl"),
- this);
-
- // Match static functions/variable definitions which are defined in named
- // namespaces.
- 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));
-
- // Matchers for helper declarations in old.cc.
- auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
- auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
- auto IsOldCCHelper =
- allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
- // Match helper classes separately with helper functions/variables since we
- // want to reuse these matchers in finding helpers usage below.
- //
- // 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)));
- auto HelperClasses =
- cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
- // 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);
-
- //============================================================================
- // Matchers for old files, including old.h/old.cc
- //============================================================================
- // Create a MatchCallback for class declarations.
- MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
- // Match moved class declarations.
- auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
- isDefinition(), TopLevelDecl)
- .bind("moved_class");
- Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
- // Match moved class methods (static methods included) which are defined
- // outside moved class declaration.
- Finder->addMatcher(
- cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
- 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());
-
- MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
- Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
- .bind("function"),
- MatchCallbacks.back().get());
-
- MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(this));
- Finder->addMatcher(
- varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
- MatchCallbacks.back().get());
-
- // Match enum definition in old.h. Enum helpers (which are defined in old.cc)
- // will not be moved for now no matter whether they are used or not.
- MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(this));
- Finder->addMatcher(
- enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
- .bind("enum"),
- MatchCallbacks.back().get());
-
- // 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.
- MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(this));
- Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
- typeAliasDecl().bind("type_alias")),
- InOldHeader, *HasAnySymbolNames, TopLevelDecl),
- MatchCallbacks.back().get());
-}
-
-void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
- if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
- UnremovedDeclsInOldHeader.insert(D);
- } else if (const auto *FWD =
- Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
- // Skip all forward declarations which appear after moved class declaration.
- if (RemovedDecls.empty()) {
- if (const auto *DCT = FWD->getDescribedClassTemplate())
- MovedDecls.push_back(DCT);
- else
- MovedDecls.push_back(FWD);
- }
- } else if (const auto *ND =
- Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
- MovedDecls.push_back(ND);
- HelperDeclarations.push_back(ND);
- LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
- << ND << ")\n");
- } else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
- MovedDecls.push_back(UD);
- }
-}
-
-std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
- return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
-}
-
-void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
- llvm::StringRef SearchPath,
- llvm::StringRef FileName,
- CharSourceRange IncludeFilenameRange,
- const SourceManager &SM) {
- SmallVector<char, 128> HeaderWithSearchPath;
- llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
- std::string AbsoluteIncludeHeader =
- MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
- HeaderWithSearchPath.size()));
- std::string IncludeLine =
- IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
- : ("#include \"" + IncludeHeader + "\"\n").str();
-
- std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
- std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
- if (AbsoluteOldHeader == AbsoluteCurrentFile) {
- // Find old.h includes "old.h".
- if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
- OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
- return;
- }
- HeaderIncludes.push_back(IncludeLine);
- } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
- // Find old.cc includes "old.h".
- if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
- OldHeaderIncludeRangeInCC = IncludeFilenameRange;
- return;
- }
- CCIncludes.push_back(IncludeLine);
- }
-}
-
-void ClangMoveTool::removeDeclsInOldFiles() {
- if (RemovedDecls.empty()) return;
-
- // 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) {
- LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
- << D->getNameAsString() << " (" << D << ")\n");
- if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
- D->getCanonicalDecl()))) {
- LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
- << D->getNameAsString() << " (" << D << ")\n");
- RemovedDecls.push_back(D);
- }
- }
- }
-
- for (const auto *RemovedDecl : RemovedDecls) {
- const auto &SM = RemovedDecl->getASTContext().getSourceManager();
- auto Range = getFullRange(RemovedDecl);
- tooling::Replacement RemoveReplacement(
- SM, CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
- "");
- std::string FilePath = RemoveReplacement.getFilePath().str();
- auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
- if (Err)
- llvm::errs() << llvm::toString(std::move(Err)) << "\n";
- }
- const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
-
- // Post process of cleanup around all the replacements.
- for (auto &FileAndReplacements : Context->FileToReplacements) {
- StringRef FilePath = FileAndReplacements.first;
- // Add #include of new header to old header.
- if (Context->Spec.OldDependOnNew &&
- MakeAbsolutePath(SM, FilePath) ==
- makeAbsolutePath(Context->Spec.OldHeader)) {
- // FIXME: Minimize the include path like include-fixer.
- std::string IncludeNewH =
- "#include \"" + Context->Spec.NewHeader + "\"\n";
- // 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";
- }
-
- auto SI = FilePathToFileID.find(FilePath);
- // Ignore replacements for new.h/cc.
- if (SI == FilePathToFileID.end()) continue;
- llvm::StringRef Code = SM.getBufferData(SI->second);
- auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
- Context->FallbackStyle);
- if (!Style) {
- llvm::errs() << llvm::toString(Style.takeError()) << "\n";
- continue;
- }
- auto CleanReplacements = format::cleanupAroundReplacements(
- Code, Context->FileToReplacements[FilePath], *Style);
-
- if (!CleanReplacements) {
- llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
- continue;
- }
- Context->FileToReplacements[FilePath] = *CleanReplacements;
- }
-}
-
-void ClangMoveTool::moveDeclsToNewFiles() {
- std::vector<const NamedDecl *> NewHeaderDecls;
- std::vector<const NamedDecl *> NewCCDecls;
- for (const auto *MovedDecl : MovedDecls) {
- if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
- Context->Spec.OldHeader))
- NewHeaderDecls.push_back(MovedDecl);
- else
- NewCCDecls.push_back(MovedDecl);
- }
-
- 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) &&
- !UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
- D->getCanonicalDecl())))
- continue;
-
- LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
- << " " << D << "\n");
- ActualNewCCDecls.push_back(D);
- }
-
- if (!Context->Spec.NewHeader.empty()) {
- std::string OldHeaderInclude =
- Context->Spec.NewDependOnOld
- ? "#include \"" + Context->Spec.OldHeader + "\"\n"
- : "";
- Context->FileToReplacements[Context->Spec.NewHeader] =
- createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
- Context->Spec.NewHeader, /*IsHeader=*/true,
- OldHeaderInclude);
- }
- if (!Context->Spec.NewCC.empty())
- Context->FileToReplacements[Context->Spec.NewCC] =
- createInsertedReplacements(CCIncludes, ActualNewCCDecls,
- Context->Spec.NewCC);
-}
-
-// Move all contents from OldFile to NewFile.
-void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
- StringRef NewFile) {
- const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
- if (!FE) {
- llvm::errs() << "Failed to get file: " << OldFile << "\n";
- return;
- }
- FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
- auto Begin = SM.getLocForStartOfFile(ID);
- auto End = SM.getLocForEndOfFile(ID);
- tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
- "");
- std::string FilePath = RemoveAll.getFilePath().str();
- Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
-
- StringRef Code = SM.getBufferData(ID);
- if (!NewFile.empty()) {
- 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 + '"')));
- };
- // 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);
- Context->FileToReplacements[NewFile] = std::move(AllCode);
- }
-}
-
-void ClangMoveTool::onEndOfTranslationUnit() {
- if (Context->DumpDeclarations) {
- assert(Reporter);
- for (const auto *Decl : UnremovedDeclsInOldHeader) {
- auto Kind = Decl->getKind();
- bool Templated = Decl->isTemplated();
- const std::string QualifiedName = Decl->getQualifiedNameAsString();
- if (Kind == Decl::Kind::Var)
- Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
- else if (Kind == Decl::Kind::Function ||
- Kind == Decl::Kind::FunctionTemplate)
- Reporter->reportDeclaration(QualifiedName, "Function", Templated);
- else if (Kind == Decl::Kind::ClassTemplate ||
- Kind == Decl::Kind::CXXRecord)
- Reporter->reportDeclaration(QualifiedName, "Class", Templated);
- else if (Kind == Decl::Kind::Enum)
- Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
- else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
- Kind == Decl::Kind::TypeAliasTemplate)
- Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
- }
- return;
- }
-
- if (RemovedDecls.empty())
- return;
- // 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.
- auto IsSupportedKind = [](const NamedDecl *Decl) {
- switch (Decl->getKind()) {
- case Decl::Kind::Function:
- case Decl::Kind::FunctionTemplate:
- case Decl::Kind::ClassTemplate:
- case Decl::Kind::CXXRecord:
- case Decl::Kind::Enum:
- case Decl::Kind::Typedef:
- case Decl::Kind::TypeAlias:
- case Decl::Kind::TypeAliasTemplate:
- case Decl::Kind::Var:
- return true;
- default:
- return false;
- }
- };
- if (std::none_of(UnremovedDeclsInOldHeader.begin(),
- UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
- !Context->Spec.OldHeader.empty()) {
- auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
- moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
- moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
- return;
- }
- LLVM_DEBUG(RGBuilder.getGraph()->dump());
- moveDeclsToNewFiles();
- removeDeclsInOldFiles();
-}
-
-} // namespace move
-} // namespace clang
Removed: clang-tools-extra/trunk/clang-move/ClangMove.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/ClangMove.h?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/ClangMove.h (original)
+++ clang-tools-extra/trunk/clang-move/ClangMove.h (removed)
@@ -1,240 +0,0 @@
-//===-- ClangMove.h - Clang move -----------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
-
-#include "HelperDeclRefGraph.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Frontend/FrontendAction.h"
-#include "clang/Tooling/Core/Replacement.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-#include <map>
-#include <memory>
-#include <string>
-#include <vector>
-
-namespace clang {
-namespace move {
-
-// A reporter which collects and reports declarations in old header.
-class DeclarationReporter {
-public:
- DeclarationReporter() = default;
- ~DeclarationReporter() = default;
-
- void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type,
- bool Templated) {
- DeclarationList.emplace_back(DeclarationName, Type, Templated);
- };
-
- struct Declaration {
- Declaration(llvm::StringRef QName, llvm::StringRef Kind, bool Templated)
- : QualifiedName(QName), Kind(Kind), Templated(Templated) {}
-
- friend bool operator==(const Declaration &LHS, const Declaration &RHS) {
- return std::tie(LHS.QualifiedName, LHS.Kind, LHS.Templated) ==
- std::tie(RHS.QualifiedName, RHS.Kind, RHS.Templated);
- }
- std::string QualifiedName; // E.g. A::B::Foo.
- std::string Kind; // E.g. Function, Class
- bool Templated = false; // Whether the declaration is templated.
- };
-
- const std::vector<Declaration> getDeclarationList() const {
- return DeclarationList;
- }
-
-private:
- std::vector<Declaration> DeclarationList;
-};
-
-// Specify declarations being moved. It contains all information of the moved
-// declarations.
-struct MoveDefinitionSpec {
- // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo.
- SmallVector<std::string, 4> Names;
- // The file path of old header, can be relative path and absolute path.
- std::string OldHeader;
- // The file path of old cc, can be relative path and absolute path.
- std::string OldCC;
- // The file path of new header, can be relative path and absolute path.
- std::string NewHeader;
- // The file path of new cc, can be relative path and absolute path.
- std::string NewCC;
- // Whether old.h depends on new.h. If true, #include "new.h" will be added
- // in old.h.
- bool OldDependOnNew = false;
- // Whether new.h depends on old.h. If true, #include "old.h" will be added
- // in new.h.
- bool NewDependOnOld = false;
-};
-
-// A Context which contains extra options which are used in ClangMoveTool.
-struct ClangMoveContext {
- MoveDefinitionSpec Spec;
- // The Key is file path, value is the replacements being applied to the file.
- std::map<std::string, tooling::Replacements> &FileToReplacements;
- // The original working directory where the local clang-move binary runs.
- //
- // clang-move will change its current working directory to the build
- // directory when analyzing the source file. We save the original working
- // directory in order to get the absolute file path for the fields in Spec.
- std::string OriginalRunningDirectory;
- // The name of a predefined code style.
- std::string FallbackStyle;
- // Whether dump all declarations in old header.
- bool DumpDeclarations;
-};
-
-// This tool is used to move class/function definitions from the given source
-// files (old.h/cc) to new files (new.h/cc).
-// The goal of this tool is to make the new/old files as compilable as possible.
-//
-// When moving a symbol,all used helper declarations (e.g. static
-// functions/variables definitions in global/named namespace,
-// functions/variables/classes definitions in anonymous namespace) used by the
-// moved symbol in old.cc are moved to the new.cc. In addition, all
-// using-declarations in old.cc are also moved to new.cc; forward class
-// declarations in old.h are also moved to new.h.
-//
-// The remaining helper declarations which are unused by non-moved symbols in
-// old.cc will be removed.
-//
-// Note: When all declarations in old header are being moved, all code in
-// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
-// that are not supported (e.g. typedef and enum) so that we always move old
-// files to new files when all symbols produced from dump_decls are moved.
-class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
-public:
- ClangMoveTool(ClangMoveContext *const Context,
- DeclarationReporter *const Reporter);
-
- void registerMatchers(ast_matchers::MatchFinder *Finder);
-
- void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
-
- void onEndOfTranslationUnit() override;
-
- /// Add #includes from old.h/cc files.
- ///
- /// \param IncludeHeader The name of the file being included, as written in
- /// the source code.
- /// \param IsAngled Whether the file name was enclosed in angle brackets.
- /// \param SearchPath The search path which was used to find the IncludeHeader
- /// in the file system. It can be a relative path or an absolute path.
- /// \param FileName The name of file where the IncludeHeader comes from.
- /// \param IncludeFilenameRange The source range for the written file name in
- /// #include (i.e. "old.h" for #include "old.h") in old.cc.
- /// \param SM The SourceManager.
- void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
- llvm::StringRef SearchPath, llvm::StringRef FileName,
- clang::CharSourceRange IncludeFilenameRange,
- const SourceManager &SM);
-
- std::vector<const NamedDecl *> &getMovedDecls() { return MovedDecls; }
-
- /// Add declarations being removed from old.h/cc. For each declarations, the
- /// method also records the mapping relationship between the corresponding
- /// FilePath and its FileID.
- void addRemovedDecl(const NamedDecl *Decl);
-
- llvm::SmallPtrSet<const NamedDecl *, 8> &getUnremovedDeclsInOldHeader() {
- return UnremovedDeclsInOldHeader;
- }
-
-private:
- // Make the Path absolute using the OrignalRunningDirectory if the Path is not
- // an absolute path. An empty Path will result in an empty string.
- std::string makeAbsolutePath(StringRef Path);
-
- void removeDeclsInOldFiles();
- void moveDeclsToNewFiles();
- void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile);
-
- // Stores all MatchCallbacks created by this tool.
- std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
- MatchCallbacks;
- // Store all potential declarations (decls being moved, forward decls) that
- // might need to move to new.h/cc. It includes all helper declarations
- // (include unused ones) by default. The unused ones will be filtered out in
- // the last stage. Saving in an AST-visited order.
- std::vector<const NamedDecl *> MovedDecls;
- // The declarations that needs to be removed in old.cc/h.
- std::vector<const NamedDecl *> RemovedDecls;
- // The #includes in old_header.h.
- std::vector<std::string> HeaderIncludes;
- // The #includes in old_cc.cc.
- std::vector<std::string> CCIncludes;
- // Records all helper declarations (function/variable/class definitions in
- // anonymous namespaces, static function/variable definitions in global/named
- // namespaces) in old.cc. saving in an AST-visited order.
- std::vector<const NamedDecl *> HelperDeclarations;
- // The unmoved named declarations in old header.
- llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
- /// The source range for the written file name in #include (i.e. "old.h" for
- /// #include "old.h") in old.cc, including the enclosing quotes or angle
- /// brackets.
- clang::CharSourceRange OldHeaderIncludeRangeInCC;
- /// The source range for the written file name in #include (i.e. "old.h" for
- /// #include "old.h") in old.h, including the enclosing quotes or angle
- /// brackets.
- clang::CharSourceRange OldHeaderIncludeRangeInHeader;
- /// Mapping from FilePath to FileID, which can be used in post processes like
- /// cleanup around replacements.
- llvm::StringMap<FileID> FilePathToFileID;
- /// A context contains all running options. It is not owned.
- ClangMoveContext *const Context;
- /// A reporter to report all declarations from old header. It is not owned.
- DeclarationReporter *const Reporter;
- /// Builder for helper declarations reference graph.
- HelperDeclRGBuilder RGBuilder;
-};
-
-class ClangMoveAction : public clang::ASTFrontendAction {
-public:
- ClangMoveAction(ClangMoveContext *const Context,
- DeclarationReporter *const Reporter)
- : MoveTool(Context, Reporter) {
- MoveTool.registerMatchers(&MatchFinder);
- }
-
- ~ClangMoveAction() override = default;
-
- std::unique_ptr<clang::ASTConsumer>
- CreateASTConsumer(clang::CompilerInstance &Compiler,
- llvm::StringRef InFile) override;
-
-private:
- ast_matchers::MatchFinder MatchFinder;
- ClangMoveTool MoveTool;
-};
-
-class ClangMoveActionFactory : public tooling::FrontendActionFactory {
-public:
- ClangMoveActionFactory(ClangMoveContext *const Context,
- DeclarationReporter *const Reporter = nullptr)
- : Context(Context), Reporter(Reporter) {}
-
- clang::FrontendAction *create() override {
- return new ClangMoveAction(Context, Reporter);
- }
-
-private:
- // Not owned.
- ClangMoveContext *const Context;
- DeclarationReporter *const Reporter;
-};
-
-} // namespace move
-} // namespace clang
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
Modified: clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp (original)
+++ clang-tools-extra/trunk/clang-move/HelperDeclRefGraph.cpp Fri Mar 22 09:34:39 2019
@@ -7,7 +7,7 @@
//===----------------------------------------------------------------------===//
#include "HelperDeclRefGraph.h"
-#include "ClangMove.h"
+#include "Move.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/Debug.h"
#include <vector>
Added: clang-tools-extra/trunk/clang-move/Move.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/Move.cpp?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/Move.cpp (added)
+++ clang-tools-extra/trunk/clang-move/Move.cpp Fri Mar 22 09:34:39 2019
@@ -0,0 +1,937 @@
+//===-- Move.cpp - Implement ClangMove functationalities --------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "Move.h"
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchers.h"
+#include "clang/Basic/SourceManager.h"
+#include "clang/Format/Format.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Lex/Lexer.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/Path.h"
+
+#define DEBUG_TYPE "clang-move"
+
+using namespace clang::ast_matchers;
+
+namespace clang {
+namespace move {
+namespace {
+
+// FIXME: Move to ASTMatchers.
+AST_MATCHER(VarDecl, isStaticDataMember) { return Node.isStaticDataMember(); }
+
+AST_MATCHER(NamedDecl, notInMacro) { return !Node.getLocation().isMacroID(); }
+
+AST_MATCHER_P(Decl, hasOutermostEnclosingClass,
+ ast_matchers::internal::Matcher<Decl>, InnerMatcher) {
+ const auto *Context = Node.getDeclContext();
+ if (!Context)
+ return false;
+ while (const auto *NextContext = Context->getParent()) {
+ if (isa<NamespaceDecl>(NextContext) ||
+ isa<TranslationUnitDecl>(NextContext))
+ break;
+ Context = NextContext;
+ }
+ return InnerMatcher.matches(*Decl::castFromDeclContext(Context), Finder,
+ Builder);
+}
+
+AST_MATCHER_P(CXXMethodDecl, ofOutermostEnclosingClass,
+ ast_matchers::internal::Matcher<CXXRecordDecl>, InnerMatcher) {
+ const CXXRecordDecl *Parent = Node.getParent();
+ if (!Parent)
+ return false;
+ while (const auto *NextParent =
+ dyn_cast<CXXRecordDecl>(Parent->getParent())) {
+ Parent = NextParent;
+ }
+
+ return InnerMatcher.matches(*Parent, Finder, Builder);
+}
+
+std::string CleanPath(StringRef PathRef) {
+ llvm::SmallString<128> Path(PathRef);
+ llvm::sys::path::remove_dots(Path, /*remove_dot_dot=*/true);
+ // FIXME: figure out why this is necessary.
+ llvm::sys::path::native(Path);
+ return Path.str();
+}
+
+// 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);
+ llvm::sys::fs::make_absolute(InitialDirectory, AbsolutePath);
+ return CleanPath(std::move(AbsolutePath));
+}
+
+// Make the Path absolute using the current working directory of the given
+// SourceManager if the Path is not an absolute path.
+//
+// The Path can be a path relative to the build directory, or retrieved from
+// the SourceManager.
+std::string MakeAbsolutePath(const SourceManager &SM, StringRef Path) {
+ llvm::SmallString<128> AbsolutePath(Path);
+ if (std::error_code EC =
+ SM.getFileManager().getVirtualFileSystem()->makeAbsolute(
+ AbsolutePath))
+ llvm::errs() << "Warning: could not make absolute file: '" << EC.message()
+ << '\n';
+ // Handle symbolic link path cases.
+ // We are trying to get the real file path of the symlink.
+ const DirectoryEntry *Dir = SM.getFileManager().getDirectory(
+ llvm::sys::path::parent_path(AbsolutePath.str()));
+ if (Dir) {
+ StringRef DirName = SM.getFileManager().getCanonicalName(Dir);
+ // FIXME: getCanonicalName might fail to get real path on VFS.
+ if (llvm::sys::path::is_absolute(DirName)) {
+ SmallString<128> AbsoluteFilename;
+ llvm::sys::path::append(AbsoluteFilename, DirName,
+ llvm::sys::path::filename(AbsolutePath.str()));
+ return CleanPath(AbsoluteFilename);
+ }
+ }
+ return CleanPath(AbsolutePath);
+}
+
+// Matches AST nodes that are expanded within the given AbsoluteFilePath.
+AST_POLYMORPHIC_MATCHER_P(isExpansionInFile,
+ AST_POLYMORPHIC_SUPPORTED_TYPES(Decl, Stmt, TypeLoc),
+ std::string, AbsoluteFilePath) {
+ auto &SourceManager = Finder->getASTContext().getSourceManager();
+ auto ExpansionLoc = SourceManager.getExpansionLoc(Node.getBeginLoc());
+ if (ExpansionLoc.isInvalid())
+ return false;
+ auto FileEntry =
+ SourceManager.getFileEntryForID(SourceManager.getFileID(ExpansionLoc));
+ if (!FileEntry)
+ return false;
+ return MakeAbsolutePath(SourceManager, FileEntry->getName()) ==
+ AbsoluteFilePath;
+}
+
+class FindAllIncludes : public PPCallbacks {
+public:
+ explicit FindAllIncludes(SourceManager *SM, ClangMoveTool *const MoveTool)
+ : SM(*SM), MoveTool(MoveTool) {}
+
+ void InclusionDirective(SourceLocation HashLoc, const Token & /*IncludeTok*/,
+ StringRef FileName, bool IsAngled,
+ CharSourceRange FilenameRange,
+ const FileEntry * /*File*/, StringRef SearchPath,
+ StringRef /*RelativePath*/,
+ const Module * /*Imported*/,
+ SrcMgr::CharacteristicKind /*FileType*/) override {
+ if (const auto *FileEntry = SM.getFileEntryForID(SM.getFileID(HashLoc)))
+ MoveTool->addIncludes(FileName, IsAngled, SearchPath,
+ FileEntry->getName(), FilenameRange, SM);
+ }
+
+private:
+ const SourceManager &SM;
+ ClangMoveTool *const MoveTool;
+};
+
+/// 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);
+}
+
+class FunctionDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit FunctionDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *FD = Result.Nodes.getNodeAs<FunctionDecl>("function");
+ assert(FD);
+ const NamedDecl *D = FD;
+ if (const auto *FTD = FD->getDescribedFunctionTemplate())
+ D = FTD;
+ MoveDeclFromOldFileToNewFile(MoveTool, D);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class VarDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit VarDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *VD = Result.Nodes.getNodeAs<VarDecl>("var");
+ assert(VD);
+ MoveDeclFromOldFileToNewFile(MoveTool, VD);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class TypeAliasMatch : public MatchFinder::MatchCallback {
+public:
+ explicit TypeAliasMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ if (const auto *TD = Result.Nodes.getNodeAs<TypedefDecl>("typedef"))
+ MoveDeclFromOldFileToNewFile(MoveTool, TD);
+ else if (const auto *TAD =
+ Result.Nodes.getNodeAs<TypeAliasDecl>("type_alias")) {
+ const NamedDecl * D = TAD;
+ if (const auto * TD = TAD->getDescribedAliasTemplate())
+ D = TD;
+ MoveDeclFromOldFileToNewFile(MoveTool, D);
+ }
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class EnumDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit EnumDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+
+ void run(const MatchFinder::MatchResult &Result) override {
+ const auto *ED = Result.Nodes.getNodeAs<EnumDecl>("enum");
+ assert(ED);
+ MoveDeclFromOldFileToNewFile(MoveTool, ED);
+ }
+
+private:
+ ClangMoveTool *MoveTool;
+};
+
+class ClassDeclarationMatch : public MatchFinder::MatchCallback {
+public:
+ explicit ClassDeclarationMatch(ClangMoveTool *MoveTool)
+ : MoveTool(MoveTool) {}
+ void run(const MatchFinder::MatchResult &Result) override {
+ SourceManager *SM = &Result.Context->getSourceManager();
+ if (const auto *CMD = Result.Nodes.getNodeAs<CXXMethodDecl>("class_method"))
+ MatchClassMethod(CMD, SM);
+ else if (const auto *VD =
+ Result.Nodes.getNodeAs<VarDecl>("class_static_var_decl"))
+ MatchClassStaticVariable(VD, SM);
+ else if (const auto *CD =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("moved_class"))
+ MatchClassDeclaration(CD, SM);
+ }
+
+private:
+ void MatchClassMethod(const CXXMethodDecl *CMD, SourceManager *SM) {
+ // Skip inline class methods. isInline() ast matcher doesn't ignore this
+ // case.
+ if (!CMD->isInlined()) {
+ MoveTool->getMovedDecls().push_back(CMD);
+ MoveTool->addRemovedDecl(CMD);
+ // Get template class method from its method declaration as
+ // UnremovedDecls stores template class method.
+ if (const auto *FTD = CMD->getDescribedFunctionTemplate())
+ MoveTool->getUnremovedDeclsInOldHeader().erase(FTD);
+ else
+ MoveTool->getUnremovedDeclsInOldHeader().erase(CMD);
+ }
+ }
+
+ void MatchClassStaticVariable(const NamedDecl *VD, SourceManager *SM) {
+ MoveDeclFromOldFileToNewFile(MoveTool, VD);
+ }
+
+ void MatchClassDeclaration(const CXXRecordDecl *CD, SourceManager *SM) {
+ // Get class template from its class declaration as UnremovedDecls stores
+ // class template.
+ if (const auto *TC = CD->getDescribedClassTemplate())
+ MoveTool->getMovedDecls().push_back(TC);
+ else
+ MoveTool->getMovedDecls().push_back(CD);
+ MoveTool->addRemovedDecl(MoveTool->getMovedDecls().back());
+ MoveTool->getUnremovedDeclsInOldHeader().erase(
+ MoveTool->getMovedDecls().back());
+ }
+
+ ClangMoveTool *MoveTool;
+};
+
+// Expand to get the end location of the line where the EndLoc of the given
+// Decl.
+SourceLocation getLocForEndOfDecl(const Decl *D,
+ const LangOptions &LangOpts = LangOptions()) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ // 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.
+ auto EndExpansionLoc = SM.getExpansionRange(D->getEndLoc()).getEnd();
+ std::pair<FileID, unsigned> LocInfo = SM.getDecomposedLoc(EndExpansionLoc);
+ // Try to load the file buffer.
+ bool InvalidTemp = false;
+ llvm::StringRef File = SM.getBufferData(LocInfo.first, &InvalidTemp);
+ if (InvalidTemp)
+ return SourceLocation();
+
+ const char *TokBegin = File.data() + LocInfo.second;
+ // Lex from the start of the given location.
+ Lexer Lex(SM.getLocForStartOfFile(LocInfo.first), LangOpts, File.begin(),
+ TokBegin, File.end());
+
+ llvm::SmallVector<char, 16> Line;
+ // FIXME: this is a bit hacky to get ReadToEndOfLine work.
+ Lex.setParsingPreprocessorDirective(true);
+ Lex.ReadToEndOfLine(&Line);
+ SourceLocation EndLoc = EndExpansionLoc.getLocWithOffset(Line.size());
+ // If we already reach EOF, just return the EOF SourceLocation;
+ // otherwise, move 1 offset ahead to include the trailing newline character
+ // '\n'.
+ return SM.getLocForEndOfFile(LocInfo.first) == EndLoc
+ ? EndLoc
+ : EndLoc.getLocWithOffset(1);
+}
+
+// Get full range of a Decl including the comments associated with it.
+CharSourceRange getFullRange(const Decl *D,
+ const LangOptions &options = LangOptions()) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ SourceRange Full(SM.getExpansionLoc(D->getBeginLoc()), getLocForEndOfDecl(D));
+ // Expand to comments that are associated with the Decl.
+ if (const auto *Comment = D->getASTContext().getRawCommentForDeclNoCache(D)) {
+ if (SM.isBeforeInTranslationUnit(Full.getEnd(), Comment->getEndLoc()))
+ Full.setEnd(Comment->getEndLoc());
+ // FIXME: Don't delete a preceding comment, if there are no other entities
+ // it could refer to.
+ if (SM.isBeforeInTranslationUnit(Comment->getBeginLoc(), Full.getBegin()))
+ Full.setBegin(Comment->getBeginLoc());
+ }
+
+ return CharSourceRange::getCharRange(Full);
+}
+
+std::string getDeclarationSourceText(const Decl *D) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ llvm::StringRef SourceText =
+ Lexer::getSourceText(getFullRange(D), SM, LangOptions());
+ return SourceText.str();
+}
+
+bool isInHeaderFile(const Decl *D, llvm::StringRef OriginalRunningDirectory,
+ llvm::StringRef OldHeader) {
+ const auto &SM = D->getASTContext().getSourceManager();
+ if (OldHeader.empty())
+ return false;
+ auto ExpansionLoc = SM.getExpansionLoc(D->getBeginLoc());
+ if (ExpansionLoc.isInvalid())
+ return false;
+
+ if (const auto *FE = SM.getFileEntryForID(SM.getFileID(ExpansionLoc))) {
+ return MakeAbsolutePath(SM, FE->getName()) ==
+ MakeAbsolutePath(OriginalRunningDirectory, OldHeader);
+ }
+
+ return false;
+}
+
+std::vector<std::string> getNamespaces(const Decl *D) {
+ std::vector<std::string> Namespaces;
+ for (const auto *Context = D->getDeclContext(); Context;
+ Context = Context->getParent()) {
+ if (llvm::isa<TranslationUnitDecl>(Context) ||
+ llvm::isa<LinkageSpecDecl>(Context))
+ break;
+
+ if (const auto *ND = llvm::dyn_cast<NamespaceDecl>(Context))
+ Namespaces.push_back(ND->getName().str());
+ }
+ std::reverse(Namespaces.begin(), Namespaces.end());
+ return Namespaces;
+}
+
+tooling::Replacements
+createInsertedReplacements(const std::vector<std::string> &Includes,
+ const std::vector<const NamedDecl *> &Decls,
+ llvm::StringRef FileName, bool IsHeader = false,
+ StringRef OldHeaderInclude = "") {
+ std::string NewCode;
+ std::string GuardName(FileName);
+ if (IsHeader) {
+ for (size_t i = 0; i < GuardName.size(); ++i) {
+ if (!isAlphanumeric(GuardName[i]))
+ GuardName[i] = '_';
+ }
+ GuardName = StringRef(GuardName).upper();
+ NewCode += "#ifndef " + GuardName + "\n";
+ NewCode += "#define " + GuardName + "\n\n";
+ }
+
+ NewCode += OldHeaderInclude;
+ // Add #Includes.
+ for (const auto &Include : Includes)
+ NewCode += Include;
+
+ if (!Includes.empty())
+ NewCode += "\n";
+
+ // Add moved class definition and its related declarations. All declarations
+ // in same namespace are grouped together.
+ //
+ // Record namespaces where the current position is in.
+ std::vector<std::string> CurrentNamespaces;
+ for (const auto *MovedDecl : Decls) {
+ // The namespaces of the declaration being moved.
+ std::vector<std::string> DeclNamespaces = getNamespaces(MovedDecl);
+ auto CurrentIt = CurrentNamespaces.begin();
+ auto DeclIt = DeclNamespaces.begin();
+ // Skip the common prefix.
+ while (CurrentIt != CurrentNamespaces.end() &&
+ DeclIt != DeclNamespaces.end()) {
+ if (*CurrentIt != *DeclIt)
+ break;
+ ++CurrentIt;
+ ++DeclIt;
+ }
+ // Calculate the new namespaces after adding MovedDecl in CurrentNamespace,
+ // which is used for next iteration of this loop.
+ std::vector<std::string> NextNamespaces(CurrentNamespaces.begin(),
+ CurrentIt);
+ NextNamespaces.insert(NextNamespaces.end(), DeclIt, DeclNamespaces.end());
+
+
+ // End with CurrentNamespace.
+ bool HasEndCurrentNamespace = false;
+ auto RemainingSize = CurrentNamespaces.end() - CurrentIt;
+ for (auto It = CurrentNamespaces.rbegin(); RemainingSize > 0;
+ --RemainingSize, ++It) {
+ assert(It < CurrentNamespaces.rend());
+ NewCode += "} // namespace " + *It + "\n";
+ HasEndCurrentNamespace = true;
+ }
+ // 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;
+ while (DeclIt != DeclNamespaces.end()) {
+ NewCode += "namespace " + *DeclIt + " {\n";
+ IsInNewNamespace = true;
+ ++DeclIt;
+ }
+ // If the moved declaration is in same namespace CurrentNamespace, add
+ // a preceeding `\n' before the moved declaration.
+ // FIXME: Don't add empty lines between using declarations.
+ if (!IsInNewNamespace)
+ NewCode += "\n";
+ NewCode += getDeclarationSourceText(MovedDecl);
+ CurrentNamespaces = std::move(NextNamespaces);
+ }
+ std::reverse(CurrentNamespaces.begin(), CurrentNamespaces.end());
+ for (const auto &NS : CurrentNamespaces)
+ NewCode += "} // namespace " + NS + "\n";
+
+ if (IsHeader)
+ NewCode += "\n#endif // " + GuardName + "\n";
+ return tooling::Replacements(tooling::Replacement(FileName, 0, 0, NewCode));
+}
+
+// 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;
+}
+
+} // namespace
+
+std::unique_ptr<ASTConsumer>
+ClangMoveAction::CreateASTConsumer(CompilerInstance &Compiler,
+ StringRef /*InFile*/) {
+ Compiler.getPreprocessor().addPPCallbacks(llvm::make_unique<FindAllIncludes>(
+ &Compiler.getSourceManager(), &MoveTool));
+ return MatchFinder.newASTConsumer();
+}
+
+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");
+}
+
+void ClangMoveTool::addRemovedDecl(const NamedDecl *Decl) {
+ const auto &SM = Decl->getASTContext().getSourceManager();
+ auto Loc = Decl->getLocation();
+ StringRef FilePath = SM.getFilename(Loc);
+ FilePathToFileID[FilePath] = SM.getFileID(Loc);
+ RemovedDecls.push_back(Decl);
+}
+
+void ClangMoveTool::registerMatchers(ast_matchers::MatchFinder *Finder) {
+ auto InOldHeader =
+ isExpansionInFile(makeAbsolutePath(Context->Spec.OldHeader));
+ auto InOldCC = isExpansionInFile(makeAbsolutePath(Context->Spec.OldCC));
+ auto InOldFiles = anyOf(InOldHeader, InOldCC);
+ auto classTemplateForwardDecls =
+ classTemplateDecl(unless(has(cxxRecordDecl(isDefinition()))));
+ auto ForwardClassDecls = namedDecl(
+ anyOf(cxxRecordDecl(unless(anyOf(isImplicit(), isDefinition()))),
+ classTemplateForwardDecls));
+ auto TopLevelDecl =
+ hasDeclContext(anyOf(namespaceDecl(), translationUnitDecl()));
+
+ //============================================================================
+ // 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.
+ //
+ // We consider declarations inside a class belongs to the class. So these
+ // declarations will be ignored.
+ auto AllDeclsInHeader = namedDecl(
+ unless(ForwardClassDecls), unless(namespaceDecl()),
+ unless(usingDirectiveDecl()), // using namespace decl.
+ notInMacro(),
+ InOldHeader,
+ hasParent(decl(anyOf(namespaceDecl(), translationUnitDecl()))),
+ hasDeclContext(decl(anyOf(namespaceDecl(), translationUnitDecl()))));
+ Finder->addMatcher(AllDeclsInHeader.bind("decls_in_header"), this);
+
+ // Don't register other matchers when dumping all declarations in header.
+ if (Context->DumpDeclarations)
+ return;
+
+ // Match forward declarations in old header.
+ Finder->addMatcher(namedDecl(ForwardClassDecls, InOldHeader).bind("fwd_decl"),
+ this);
+
+ //============================================================================
+ // Matchers for old cc
+ //============================================================================
+ 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.
+ Finder->addMatcher(namedDecl(anyOf(usingDecl(IsOldCCTopLevelDecl),
+ usingDirectiveDecl(unless(isImplicit()),
+ IsOldCCTopLevelDecl),
+ typeAliasDecl(IsOldCCTopLevelDecl)),
+ notInMacro())
+ .bind("using_decl"),
+ this);
+
+ // Match static functions/variable definitions which are defined in named
+ // namespaces.
+ 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));
+
+ // Matchers for helper declarations in old.cc.
+ auto InAnonymousNS = hasParent(namespaceDecl(isAnonymous()));
+ auto NotInMovedClass= allOf(unless(InMovedClass), InOldCC);
+ auto IsOldCCHelper =
+ allOf(NotInMovedClass, anyOf(isStaticStorageClass(), InAnonymousNS));
+ // Match helper classes separately with helper functions/variables since we
+ // want to reuse these matchers in finding helpers usage below.
+ //
+ // 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)));
+ auto HelperClasses =
+ cxxRecordDecl(notInMacro(), NotInMovedClass, InAnonymousNS);
+ // 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);
+
+ //============================================================================
+ // Matchers for old files, including old.h/old.cc
+ //============================================================================
+ // Create a MatchCallback for class declarations.
+ MatchCallbacks.push_back(llvm::make_unique<ClassDeclarationMatch>(this));
+ // Match moved class declarations.
+ auto MovedClass = cxxRecordDecl(InOldFiles, *HasAnySymbolNames,
+ isDefinition(), TopLevelDecl)
+ .bind("moved_class");
+ Finder->addMatcher(MovedClass, MatchCallbacks.back().get());
+ // Match moved class methods (static methods included) which are defined
+ // outside moved class declaration.
+ Finder->addMatcher(
+ cxxMethodDecl(InOldFiles, ofOutermostEnclosingClass(*HasAnySymbolNames),
+ 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());
+
+ MatchCallbacks.push_back(llvm::make_unique<FunctionDeclarationMatch>(this));
+ Finder->addMatcher(functionDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl)
+ .bind("function"),
+ MatchCallbacks.back().get());
+
+ MatchCallbacks.push_back(llvm::make_unique<VarDeclarationMatch>(this));
+ Finder->addMatcher(
+ varDecl(InOldFiles, *HasAnySymbolNames, TopLevelDecl).bind("var"),
+ MatchCallbacks.back().get());
+
+ // Match enum definition in old.h. Enum helpers (which are defined in old.cc)
+ // will not be moved for now no matter whether they are used or not.
+ MatchCallbacks.push_back(llvm::make_unique<EnumDeclarationMatch>(this));
+ Finder->addMatcher(
+ enumDecl(InOldHeader, *HasAnySymbolNames, isDefinition(), TopLevelDecl)
+ .bind("enum"),
+ MatchCallbacks.back().get());
+
+ // 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.
+ MatchCallbacks.push_back(llvm::make_unique<TypeAliasMatch>(this));
+ Finder->addMatcher(namedDecl(anyOf(typedefDecl().bind("typedef"),
+ typeAliasDecl().bind("type_alias")),
+ InOldHeader, *HasAnySymbolNames, TopLevelDecl),
+ MatchCallbacks.back().get());
+}
+
+void ClangMoveTool::run(const ast_matchers::MatchFinder::MatchResult &Result) {
+ if (const auto *D = Result.Nodes.getNodeAs<NamedDecl>("decls_in_header")) {
+ UnremovedDeclsInOldHeader.insert(D);
+ } else if (const auto *FWD =
+ Result.Nodes.getNodeAs<CXXRecordDecl>("fwd_decl")) {
+ // Skip all forward declarations which appear after moved class declaration.
+ if (RemovedDecls.empty()) {
+ if (const auto *DCT = FWD->getDescribedClassTemplate())
+ MovedDecls.push_back(DCT);
+ else
+ MovedDecls.push_back(FWD);
+ }
+ } else if (const auto *ND =
+ Result.Nodes.getNodeAs<NamedDecl>("helper_decls")) {
+ MovedDecls.push_back(ND);
+ HelperDeclarations.push_back(ND);
+ LLVM_DEBUG(llvm::dbgs() << "Add helper : " << ND->getNameAsString() << " ("
+ << ND << ")\n");
+ } else if (const auto *UD = Result.Nodes.getNodeAs<NamedDecl>("using_decl")) {
+ MovedDecls.push_back(UD);
+ }
+}
+
+std::string ClangMoveTool::makeAbsolutePath(StringRef Path) {
+ return MakeAbsolutePath(Context->OriginalRunningDirectory, Path);
+}
+
+void ClangMoveTool::addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+ llvm::StringRef SearchPath,
+ llvm::StringRef FileName,
+ CharSourceRange IncludeFilenameRange,
+ const SourceManager &SM) {
+ SmallVector<char, 128> HeaderWithSearchPath;
+ llvm::sys::path::append(HeaderWithSearchPath, SearchPath, IncludeHeader);
+ std::string AbsoluteIncludeHeader =
+ MakeAbsolutePath(SM, llvm::StringRef(HeaderWithSearchPath.data(),
+ HeaderWithSearchPath.size()));
+ std::string IncludeLine =
+ IsAngled ? ("#include <" + IncludeHeader + ">\n").str()
+ : ("#include \"" + IncludeHeader + "\"\n").str();
+
+ std::string AbsoluteOldHeader = makeAbsolutePath(Context->Spec.OldHeader);
+ std::string AbsoluteCurrentFile = MakeAbsolutePath(SM, FileName);
+ if (AbsoluteOldHeader == AbsoluteCurrentFile) {
+ // Find old.h includes "old.h".
+ if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+ OldHeaderIncludeRangeInHeader = IncludeFilenameRange;
+ return;
+ }
+ HeaderIncludes.push_back(IncludeLine);
+ } else if (makeAbsolutePath(Context->Spec.OldCC) == AbsoluteCurrentFile) {
+ // Find old.cc includes "old.h".
+ if (AbsoluteOldHeader == AbsoluteIncludeHeader) {
+ OldHeaderIncludeRangeInCC = IncludeFilenameRange;
+ return;
+ }
+ CCIncludes.push_back(IncludeLine);
+ }
+}
+
+void ClangMoveTool::removeDeclsInOldFiles() {
+ if (RemovedDecls.empty()) return;
+
+ // 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) {
+ LLVM_DEBUG(llvm::dbgs() << "Check helper is used: "
+ << D->getNameAsString() << " (" << D << ")\n");
+ if (!UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+ D->getCanonicalDecl()))) {
+ LLVM_DEBUG(llvm::dbgs() << "Helper removed in old.cc: "
+ << D->getNameAsString() << " (" << D << ")\n");
+ RemovedDecls.push_back(D);
+ }
+ }
+ }
+
+ for (const auto *RemovedDecl : RemovedDecls) {
+ const auto &SM = RemovedDecl->getASTContext().getSourceManager();
+ auto Range = getFullRange(RemovedDecl);
+ tooling::Replacement RemoveReplacement(
+ SM, CharSourceRange::getCharRange(Range.getBegin(), Range.getEnd()),
+ "");
+ std::string FilePath = RemoveReplacement.getFilePath().str();
+ auto Err = Context->FileToReplacements[FilePath].add(RemoveReplacement);
+ if (Err)
+ llvm::errs() << llvm::toString(std::move(Err)) << "\n";
+ }
+ const auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+
+ // Post process of cleanup around all the replacements.
+ for (auto &FileAndReplacements : Context->FileToReplacements) {
+ StringRef FilePath = FileAndReplacements.first;
+ // Add #include of new header to old header.
+ if (Context->Spec.OldDependOnNew &&
+ MakeAbsolutePath(SM, FilePath) ==
+ makeAbsolutePath(Context->Spec.OldHeader)) {
+ // FIXME: Minimize the include path like include-fixer.
+ std::string IncludeNewH =
+ "#include \"" + Context->Spec.NewHeader + "\"\n";
+ // 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";
+ }
+
+ auto SI = FilePathToFileID.find(FilePath);
+ // Ignore replacements for new.h/cc.
+ if (SI == FilePathToFileID.end()) continue;
+ llvm::StringRef Code = SM.getBufferData(SI->second);
+ auto Style = format::getStyle(format::DefaultFormatStyle, FilePath,
+ Context->FallbackStyle);
+ if (!Style) {
+ llvm::errs() << llvm::toString(Style.takeError()) << "\n";
+ continue;
+ }
+ auto CleanReplacements = format::cleanupAroundReplacements(
+ Code, Context->FileToReplacements[FilePath], *Style);
+
+ if (!CleanReplacements) {
+ llvm::errs() << llvm::toString(CleanReplacements.takeError()) << "\n";
+ continue;
+ }
+ Context->FileToReplacements[FilePath] = *CleanReplacements;
+ }
+}
+
+void ClangMoveTool::moveDeclsToNewFiles() {
+ std::vector<const NamedDecl *> NewHeaderDecls;
+ std::vector<const NamedDecl *> NewCCDecls;
+ for (const auto *MovedDecl : MovedDecls) {
+ if (isInHeaderFile(MovedDecl, Context->OriginalRunningDirectory,
+ Context->Spec.OldHeader))
+ NewHeaderDecls.push_back(MovedDecl);
+ else
+ NewCCDecls.push_back(MovedDecl);
+ }
+
+ 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) &&
+ !UsedDecls.count(HelperDeclRGBuilder::getOutmostClassOrFunDecl(
+ D->getCanonicalDecl())))
+ continue;
+
+ LLVM_DEBUG(llvm::dbgs() << "Helper used in new.cc: " << D->getNameAsString()
+ << " " << D << "\n");
+ ActualNewCCDecls.push_back(D);
+ }
+
+ if (!Context->Spec.NewHeader.empty()) {
+ std::string OldHeaderInclude =
+ Context->Spec.NewDependOnOld
+ ? "#include \"" + Context->Spec.OldHeader + "\"\n"
+ : "";
+ Context->FileToReplacements[Context->Spec.NewHeader] =
+ createInsertedReplacements(HeaderIncludes, NewHeaderDecls,
+ Context->Spec.NewHeader, /*IsHeader=*/true,
+ OldHeaderInclude);
+ }
+ if (!Context->Spec.NewCC.empty())
+ Context->FileToReplacements[Context->Spec.NewCC] =
+ createInsertedReplacements(CCIncludes, ActualNewCCDecls,
+ Context->Spec.NewCC);
+}
+
+// Move all contents from OldFile to NewFile.
+void ClangMoveTool::moveAll(SourceManager &SM, StringRef OldFile,
+ StringRef NewFile) {
+ const FileEntry *FE = SM.getFileManager().getFile(makeAbsolutePath(OldFile));
+ if (!FE) {
+ llvm::errs() << "Failed to get file: " << OldFile << "\n";
+ return;
+ }
+ FileID ID = SM.getOrCreateFileID(FE, SrcMgr::C_User);
+ auto Begin = SM.getLocForStartOfFile(ID);
+ auto End = SM.getLocForEndOfFile(ID);
+ tooling::Replacement RemoveAll(SM, CharSourceRange::getCharRange(Begin, End),
+ "");
+ std::string FilePath = RemoveAll.getFilePath().str();
+ Context->FileToReplacements[FilePath] = tooling::Replacements(RemoveAll);
+
+ StringRef Code = SM.getBufferData(ID);
+ if (!NewFile.empty()) {
+ 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 + '"')));
+ };
+ // 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);
+ Context->FileToReplacements[NewFile] = std::move(AllCode);
+ }
+}
+
+void ClangMoveTool::onEndOfTranslationUnit() {
+ if (Context->DumpDeclarations) {
+ assert(Reporter);
+ for (const auto *Decl : UnremovedDeclsInOldHeader) {
+ auto Kind = Decl->getKind();
+ bool Templated = Decl->isTemplated();
+ const std::string QualifiedName = Decl->getQualifiedNameAsString();
+ if (Kind == Decl::Kind::Var)
+ Reporter->reportDeclaration(QualifiedName, "Variable", Templated);
+ else if (Kind == Decl::Kind::Function ||
+ Kind == Decl::Kind::FunctionTemplate)
+ Reporter->reportDeclaration(QualifiedName, "Function", Templated);
+ else if (Kind == Decl::Kind::ClassTemplate ||
+ Kind == Decl::Kind::CXXRecord)
+ Reporter->reportDeclaration(QualifiedName, "Class", Templated);
+ else if (Kind == Decl::Kind::Enum)
+ Reporter->reportDeclaration(QualifiedName, "Enum", Templated);
+ else if (Kind == Decl::Kind::Typedef || Kind == Decl::Kind::TypeAlias ||
+ Kind == Decl::Kind::TypeAliasTemplate)
+ Reporter->reportDeclaration(QualifiedName, "TypeAlias", Templated);
+ }
+ return;
+ }
+
+ if (RemovedDecls.empty())
+ return;
+ // 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.
+ auto IsSupportedKind = [](const NamedDecl *Decl) {
+ switch (Decl->getKind()) {
+ case Decl::Kind::Function:
+ case Decl::Kind::FunctionTemplate:
+ case Decl::Kind::ClassTemplate:
+ case Decl::Kind::CXXRecord:
+ case Decl::Kind::Enum:
+ case Decl::Kind::Typedef:
+ case Decl::Kind::TypeAlias:
+ case Decl::Kind::TypeAliasTemplate:
+ case Decl::Kind::Var:
+ return true;
+ default:
+ return false;
+ }
+ };
+ if (std::none_of(UnremovedDeclsInOldHeader.begin(),
+ UnremovedDeclsInOldHeader.end(), IsSupportedKind) &&
+ !Context->Spec.OldHeader.empty()) {
+ auto &SM = RemovedDecls[0]->getASTContext().getSourceManager();
+ moveAll(SM, Context->Spec.OldHeader, Context->Spec.NewHeader);
+ moveAll(SM, Context->Spec.OldCC, Context->Spec.NewCC);
+ return;
+ }
+ LLVM_DEBUG(RGBuilder.getGraph()->dump());
+ moveDeclsToNewFiles();
+ removeDeclsInOldFiles();
+}
+
+} // namespace move
+} // namespace clang
Added: clang-tools-extra/trunk/clang-move/Move.h
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/Move.h?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/Move.h (added)
+++ clang-tools-extra/trunk/clang-move/Move.h Fri Mar 22 09:34:39 2019
@@ -0,0 +1,240 @@
+//===-- Move.h - Clang move ----------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
+
+#include "HelperDeclRefGraph.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/Tooling/Core/Replacement.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace clang {
+namespace move {
+
+// A reporter which collects and reports declarations in old header.
+class DeclarationReporter {
+public:
+ DeclarationReporter() = default;
+ ~DeclarationReporter() = default;
+
+ void reportDeclaration(llvm::StringRef DeclarationName, llvm::StringRef Type,
+ bool Templated) {
+ DeclarationList.emplace_back(DeclarationName, Type, Templated);
+ };
+
+ struct Declaration {
+ Declaration(llvm::StringRef QName, llvm::StringRef Kind, bool Templated)
+ : QualifiedName(QName), Kind(Kind), Templated(Templated) {}
+
+ friend bool operator==(const Declaration &LHS, const Declaration &RHS) {
+ return std::tie(LHS.QualifiedName, LHS.Kind, LHS.Templated) ==
+ std::tie(RHS.QualifiedName, RHS.Kind, RHS.Templated);
+ }
+ std::string QualifiedName; // E.g. A::B::Foo.
+ std::string Kind; // E.g. Function, Class
+ bool Templated = false; // Whether the declaration is templated.
+ };
+
+ const std::vector<Declaration> getDeclarationList() const {
+ return DeclarationList;
+ }
+
+private:
+ std::vector<Declaration> DeclarationList;
+};
+
+// Specify declarations being moved. It contains all information of the moved
+// declarations.
+struct MoveDefinitionSpec {
+ // The list of fully qualified names, e.g. Foo, a::Foo, b::Foo.
+ SmallVector<std::string, 4> Names;
+ // The file path of old header, can be relative path and absolute path.
+ std::string OldHeader;
+ // The file path of old cc, can be relative path and absolute path.
+ std::string OldCC;
+ // The file path of new header, can be relative path and absolute path.
+ std::string NewHeader;
+ // The file path of new cc, can be relative path and absolute path.
+ std::string NewCC;
+ // Whether old.h depends on new.h. If true, #include "new.h" will be added
+ // in old.h.
+ bool OldDependOnNew = false;
+ // Whether new.h depends on old.h. If true, #include "old.h" will be added
+ // in new.h.
+ bool NewDependOnOld = false;
+};
+
+// A Context which contains extra options which are used in ClangMoveTool.
+struct ClangMoveContext {
+ MoveDefinitionSpec Spec;
+ // The Key is file path, value is the replacements being applied to the file.
+ std::map<std::string, tooling::Replacements> &FileToReplacements;
+ // The original working directory where the local clang-move binary runs.
+ //
+ // clang-move will change its current working directory to the build
+ // directory when analyzing the source file. We save the original working
+ // directory in order to get the absolute file path for the fields in Spec.
+ std::string OriginalRunningDirectory;
+ // The name of a predefined code style.
+ std::string FallbackStyle;
+ // Whether dump all declarations in old header.
+ bool DumpDeclarations;
+};
+
+// This tool is used to move class/function definitions from the given source
+// files (old.h/cc) to new files (new.h/cc).
+// The goal of this tool is to make the new/old files as compilable as possible.
+//
+// When moving a symbol,all used helper declarations (e.g. static
+// functions/variables definitions in global/named namespace,
+// functions/variables/classes definitions in anonymous namespace) used by the
+// moved symbol in old.cc are moved to the new.cc. In addition, all
+// using-declarations in old.cc are also moved to new.cc; forward class
+// declarations in old.h are also moved to new.h.
+//
+// The remaining helper declarations which are unused by non-moved symbols in
+// old.cc will be removed.
+//
+// Note: When all declarations in old header are being moved, all code in
+// old.h/cc will be moved, which means old.h/cc are empty. This ignores symbols
+// that are not supported (e.g. typedef and enum) so that we always move old
+// files to new files when all symbols produced from dump_decls are moved.
+class ClangMoveTool : public ast_matchers::MatchFinder::MatchCallback {
+public:
+ ClangMoveTool(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter);
+
+ void registerMatchers(ast_matchers::MatchFinder *Finder);
+
+ void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+ void onEndOfTranslationUnit() override;
+
+ /// Add #includes from old.h/cc files.
+ ///
+ /// \param IncludeHeader The name of the file being included, as written in
+ /// the source code.
+ /// \param IsAngled Whether the file name was enclosed in angle brackets.
+ /// \param SearchPath The search path which was used to find the IncludeHeader
+ /// in the file system. It can be a relative path or an absolute path.
+ /// \param FileName The name of file where the IncludeHeader comes from.
+ /// \param IncludeFilenameRange The source range for the written file name in
+ /// #include (i.e. "old.h" for #include "old.h") in old.cc.
+ /// \param SM The SourceManager.
+ void addIncludes(llvm::StringRef IncludeHeader, bool IsAngled,
+ llvm::StringRef SearchPath, llvm::StringRef FileName,
+ clang::CharSourceRange IncludeFilenameRange,
+ const SourceManager &SM);
+
+ std::vector<const NamedDecl *> &getMovedDecls() { return MovedDecls; }
+
+ /// Add declarations being removed from old.h/cc. For each declarations, the
+ /// method also records the mapping relationship between the corresponding
+ /// FilePath and its FileID.
+ void addRemovedDecl(const NamedDecl *Decl);
+
+ llvm::SmallPtrSet<const NamedDecl *, 8> &getUnremovedDeclsInOldHeader() {
+ return UnremovedDeclsInOldHeader;
+ }
+
+private:
+ // Make the Path absolute using the OrignalRunningDirectory if the Path is not
+ // an absolute path. An empty Path will result in an empty string.
+ std::string makeAbsolutePath(StringRef Path);
+
+ void removeDeclsInOldFiles();
+ void moveDeclsToNewFiles();
+ void moveAll(SourceManager& SM, StringRef OldFile, StringRef NewFile);
+
+ // Stores all MatchCallbacks created by this tool.
+ std::vector<std::unique_ptr<ast_matchers::MatchFinder::MatchCallback>>
+ MatchCallbacks;
+ // Store all potential declarations (decls being moved, forward decls) that
+ // might need to move to new.h/cc. It includes all helper declarations
+ // (include unused ones) by default. The unused ones will be filtered out in
+ // the last stage. Saving in an AST-visited order.
+ std::vector<const NamedDecl *> MovedDecls;
+ // The declarations that needs to be removed in old.cc/h.
+ std::vector<const NamedDecl *> RemovedDecls;
+ // The #includes in old_header.h.
+ std::vector<std::string> HeaderIncludes;
+ // The #includes in old_cc.cc.
+ std::vector<std::string> CCIncludes;
+ // Records all helper declarations (function/variable/class definitions in
+ // anonymous namespaces, static function/variable definitions in global/named
+ // namespaces) in old.cc. saving in an AST-visited order.
+ std::vector<const NamedDecl *> HelperDeclarations;
+ // The unmoved named declarations in old header.
+ llvm::SmallPtrSet<const NamedDecl*, 8> UnremovedDeclsInOldHeader;
+ /// The source range for the written file name in #include (i.e. "old.h" for
+ /// #include "old.h") in old.cc, including the enclosing quotes or angle
+ /// brackets.
+ clang::CharSourceRange OldHeaderIncludeRangeInCC;
+ /// The source range for the written file name in #include (i.e. "old.h" for
+ /// #include "old.h") in old.h, including the enclosing quotes or angle
+ /// brackets.
+ clang::CharSourceRange OldHeaderIncludeRangeInHeader;
+ /// Mapping from FilePath to FileID, which can be used in post processes like
+ /// cleanup around replacements.
+ llvm::StringMap<FileID> FilePathToFileID;
+ /// A context contains all running options. It is not owned.
+ ClangMoveContext *const Context;
+ /// A reporter to report all declarations from old header. It is not owned.
+ DeclarationReporter *const Reporter;
+ /// Builder for helper declarations reference graph.
+ HelperDeclRGBuilder RGBuilder;
+};
+
+class ClangMoveAction : public clang::ASTFrontendAction {
+public:
+ ClangMoveAction(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter)
+ : MoveTool(Context, Reporter) {
+ MoveTool.registerMatchers(&MatchFinder);
+ }
+
+ ~ClangMoveAction() override = default;
+
+ std::unique_ptr<clang::ASTConsumer>
+ CreateASTConsumer(clang::CompilerInstance &Compiler,
+ llvm::StringRef InFile) override;
+
+private:
+ ast_matchers::MatchFinder MatchFinder;
+ ClangMoveTool MoveTool;
+};
+
+class ClangMoveActionFactory : public tooling::FrontendActionFactory {
+public:
+ ClangMoveActionFactory(ClangMoveContext *const Context,
+ DeclarationReporter *const Reporter = nullptr)
+ : Context(Context), Reporter(Reporter) {}
+
+ clang::FrontendAction *create() override {
+ return new ClangMoveAction(Context, Reporter);
+ }
+
+private:
+ // Not owned.
+ ClangMoveContext *const Context;
+ DeclarationReporter *const Reporter;
+};
+
+} // namespace move
+} // namespace clang
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_CLANGMOVE_H
Modified: clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt?rev=356780&r1=356779&r2=356780&view=diff
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt (original)
+++ clang-tools-extra/trunk/clang-move/tool/CMakeLists.txt Fri Mar 22 09:34:39 2019
@@ -1,7 +1,7 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_clang_executable(clang-move
- ClangMoveMain.cpp
+ ClangMove.cpp
)
target_link_libraries(clang-move
Added: clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp?rev=356780&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp (added)
+++ clang-tools-extra/trunk/clang-move/tool/ClangMove.cpp Fri Mar 22 09:34:39 2019
@@ -0,0 +1,212 @@
+//===-- ClangMove.cpp - move defintion to new file --------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "Move.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Tooling/ArgumentsAdjusters.h"
+#include "clang/Tooling/CommonOptionsParser.h"
+#include "clang/Tooling/Refactoring.h"
+#include "clang/Tooling/Tooling.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/Process.h"
+#include "llvm/Support/Signals.h"
+#include "llvm/Support/YAMLTraits.h"
+#include <set>
+#include <string>
+
+using namespace clang;
+using namespace llvm;
+
+namespace {
+
+std::error_code CreateNewFile(const llvm::Twine &path) {
+ int fd = 0;
+ if (std::error_code ec = llvm::sys::fs::openFileForWrite(
+ path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
+ return ec;
+
+ return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
+}
+
+cl::OptionCategory ClangMoveCategory("clang-move options");
+
+cl::list<std::string> Names("names", cl::CommaSeparated,
+ cl::desc("The list of the names of classes being "
+ "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ OldHeader("old_header",
+ cl::desc("The relative/absolute file path of old header."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ NewHeader("new_header",
+ cl::desc("The relative/absolute file path of new header."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+ OldDependOnNew("old_depend_on_new",
+ cl::desc("Whether old header will depend on new header. If "
+ "true, clang-move will "
+ "add #include of new header to old header."),
+ cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<bool>
+ NewDependOnOld("new_depend_on_old",
+ cl::desc("Whether new header will depend on old header. If "
+ "true, clang-move will "
+ "add #include of old header to new header."),
+ cl::init(false), cl::cat(ClangMoveCategory));
+
+cl::opt<std::string>
+ Style("style",
+ cl::desc("The style name used for reformatting. Default is \"llvm\""),
+ cl::init("llvm"), cl::cat(ClangMoveCategory));
+
+cl::opt<bool> Dump("dump_result",
+ cl::desc("Dump results in JSON format to stdout."),
+ cl::cat(ClangMoveCategory));
+
+cl::opt<bool> DumpDecls(
+ "dump_decls",
+ cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
+ "the option is specified, other command options will be ignored. "
+ "An empty JSON will be returned if old header isn't specified."),
+ cl::cat(ClangMoveCategory));
+
+} // namespace
+
+int main(int argc, const char **argv) {
+ llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
+ tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
+
+ if (OldDependOnNew && NewDependOnOld) {
+ llvm::errs() << "Provide either --old_depend_on_new or "
+ "--new_depend_on_old. clang-move doesn't support these two "
+ "options at same time (It will introduce include cycle).\n";
+ return 1;
+ }
+
+ tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList());
+ // Add "-fparse-all-comments" compile option to make clang parse all comments.
+ Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
+ "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
+ move::MoveDefinitionSpec Spec;
+ Spec.Names = {Names.begin(), Names.end()};
+ Spec.OldHeader = OldHeader;
+ Spec.NewHeader = NewHeader;
+ Spec.OldCC = OldCC;
+ Spec.NewCC = NewCC;
+ Spec.OldDependOnNew = OldDependOnNew;
+ Spec.NewDependOnOld = NewDependOnOld;
+
+ llvm::SmallString<128> InitialDirectory;
+ if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
+ llvm::report_fatal_error("Cannot detect current path: " +
+ Twine(EC.message()));
+
+ move::ClangMoveContext Context{Spec, Tool.getReplacements(),
+ InitialDirectory.str(), Style, DumpDecls};
+ move::DeclarationReporter Reporter;
+ move::ClangMoveActionFactory Factory(&Context, &Reporter);
+
+ int CodeStatus = Tool.run(&Factory);
+ if (CodeStatus)
+ return CodeStatus;
+
+ if (DumpDecls) {
+ llvm::outs() << "[\n";
+ const auto &Declarations = Reporter.getDeclarationList();
+ for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
+ llvm::outs() << " {\n";
+ llvm::outs() << " \"DeclarationName\": \"" << I->QualifiedName
+ << "\",\n";
+ llvm::outs() << " \"DeclarationType\": \"" << I->Kind << "\",\n";
+ llvm::outs() << " \"Templated\": " << (I->Templated ? "true" : "false")
+ << "\n";
+ llvm::outs() << " }";
+ // Don't print trailing "," at the end of last element.
+ if (I != std::prev(E))
+ llvm::outs() << ",\n";
+ }
+ llvm::outs() << "\n]\n";
+ return 0;
+ }
+
+ if (!NewCC.empty()) {
+ std::error_code EC = CreateNewFile(NewCC);
+ if (EC) {
+ llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
+ << "\n";
+ return EC.value();
+ }
+ }
+ if (!NewHeader.empty()) {
+ std::error_code EC = CreateNewFile(NewHeader);
+ if (EC) {
+ llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
+ << "\n";
+ return EC.value();
+ }
+ }
+
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
+ clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
+ DiagnosticsEngine Diagnostics(
+ IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
+ &DiagnosticPrinter, false);
+ auto &FileMgr = Tool.getFiles();
+ SourceManager SM(Diagnostics, FileMgr);
+ Rewriter Rewrite(SM, LangOptions());
+
+ if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
+ llvm::errs() << "Failed applying all replacements.\n";
+ return 1;
+ }
+
+ if (Dump) {
+ std::set<llvm::StringRef> Files;
+ for (const auto &it : Tool.getReplacements())
+ Files.insert(it.first);
+ auto WriteToJson = [&](llvm::raw_ostream &OS) {
+ OS << "[\n";
+ for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
+ OS << " {\n";
+ OS << " \"FilePath\": \"" << *I << "\",\n";
+ const auto *Entry = FileMgr.getFile(*I);
+ auto ID = SM.translateFile(Entry);
+ std::string Content;
+ llvm::raw_string_ostream ContentStream(Content);
+ Rewrite.getEditBuffer(ID).write(ContentStream);
+ OS << " \"SourceText\": \""
+ << llvm::yaml::escape(ContentStream.str()) << "\"\n";
+ OS << " }";
+ if (I != std::prev(E))
+ OS << ",\n";
+ }
+ OS << "\n]\n";
+ };
+ WriteToJson(llvm::outs());
+ return 0;
+ }
+
+ return Rewrite.overwriteChangedFiles();
+}
Removed: clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp
URL: http://llvm.org/viewvc/llvm-project/clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp?rev=356779&view=auto
==============================================================================
--- clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp (original)
+++ clang-tools-extra/trunk/clang-move/tool/ClangMoveMain.cpp (removed)
@@ -1,212 +0,0 @@
-//===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "ClangMove.h"
-#include "clang/Frontend/TextDiagnosticPrinter.h"
-#include "clang/Rewrite/Core/Rewriter.h"
-#include "clang/Tooling/ArgumentsAdjusters.h"
-#include "clang/Tooling/CommonOptionsParser.h"
-#include "clang/Tooling/Refactoring.h"
-#include "clang/Tooling/Tooling.h"
-#include "llvm/ADT/StringRef.h"
-#include "llvm/Support/CommandLine.h"
-#include "llvm/Support/Path.h"
-#include "llvm/Support/Process.h"
-#include "llvm/Support/Signals.h"
-#include "llvm/Support/YAMLTraits.h"
-#include <set>
-#include <string>
-
-using namespace clang;
-using namespace llvm;
-
-namespace {
-
-std::error_code CreateNewFile(const llvm::Twine &path) {
- int fd = 0;
- if (std::error_code ec = llvm::sys::fs::openFileForWrite(
- path, fd, llvm::sys::fs::CD_CreateAlways, llvm::sys::fs::F_Text))
- return ec;
-
- return llvm::sys::Process::SafelyCloseFileDescriptor(fd);
-}
-
-cl::OptionCategory ClangMoveCategory("clang-move options");
-
-cl::list<std::string> Names("names", cl::CommaSeparated,
- cl::desc("The list of the names of classes being "
- "moved, e.g. \"Foo,a::Foo,b::Foo\"."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
- OldHeader("old_header",
- cl::desc("The relative/absolute file path of old header."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
- OldCC("old_cc", cl::desc("The relative/absolute file path of old cc."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
- NewHeader("new_header",
- cl::desc("The relative/absolute file path of new header."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
- NewCC("new_cc", cl::desc("The relative/absolute file path of new cc."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<bool>
- OldDependOnNew("old_depend_on_new",
- cl::desc("Whether old header will depend on new header. If "
- "true, clang-move will "
- "add #include of new header to old header."),
- cl::init(false), cl::cat(ClangMoveCategory));
-
-cl::opt<bool>
- NewDependOnOld("new_depend_on_old",
- cl::desc("Whether new header will depend on old header. If "
- "true, clang-move will "
- "add #include of old header to new header."),
- cl::init(false), cl::cat(ClangMoveCategory));
-
-cl::opt<std::string>
- Style("style",
- cl::desc("The style name used for reformatting. Default is \"llvm\""),
- cl::init("llvm"), cl::cat(ClangMoveCategory));
-
-cl::opt<bool> Dump("dump_result",
- cl::desc("Dump results in JSON format to stdout."),
- cl::cat(ClangMoveCategory));
-
-cl::opt<bool> DumpDecls(
- "dump_decls",
- cl::desc("Dump all declarations in old header (JSON format) to stdout. If "
- "the option is specified, other command options will be ignored. "
- "An empty JSON will be returned if old header isn't specified."),
- cl::cat(ClangMoveCategory));
-
-} // namespace
-
-int main(int argc, const char **argv) {
- llvm::sys::PrintStackTraceOnErrorSignal(argv[0]);
- tooling::CommonOptionsParser OptionsParser(argc, argv, ClangMoveCategory);
-
- if (OldDependOnNew && NewDependOnOld) {
- llvm::errs() << "Provide either --old_depend_on_new or "
- "--new_depend_on_old. clang-move doesn't support these two "
- "options at same time (It will introduce include cycle).\n";
- return 1;
- }
-
- tooling::RefactoringTool Tool(OptionsParser.getCompilations(),
- OptionsParser.getSourcePathList());
- // Add "-fparse-all-comments" compile option to make clang parse all comments.
- Tool.appendArgumentsAdjuster(tooling::getInsertArgumentAdjuster(
- "-fparse-all-comments", tooling::ArgumentInsertPosition::BEGIN));
- move::MoveDefinitionSpec Spec;
- Spec.Names = {Names.begin(), Names.end()};
- Spec.OldHeader = OldHeader;
- Spec.NewHeader = NewHeader;
- Spec.OldCC = OldCC;
- Spec.NewCC = NewCC;
- Spec.OldDependOnNew = OldDependOnNew;
- Spec.NewDependOnOld = NewDependOnOld;
-
- llvm::SmallString<128> InitialDirectory;
- if (std::error_code EC = llvm::sys::fs::current_path(InitialDirectory))
- llvm::report_fatal_error("Cannot detect current path: " +
- Twine(EC.message()));
-
- move::ClangMoveContext Context{Spec, Tool.getReplacements(),
- InitialDirectory.str(), Style, DumpDecls};
- move::DeclarationReporter Reporter;
- move::ClangMoveActionFactory Factory(&Context, &Reporter);
-
- int CodeStatus = Tool.run(&Factory);
- if (CodeStatus)
- return CodeStatus;
-
- if (DumpDecls) {
- llvm::outs() << "[\n";
- const auto &Declarations = Reporter.getDeclarationList();
- for (auto I = Declarations.begin(), E = Declarations.end(); I != E; ++I) {
- llvm::outs() << " {\n";
- llvm::outs() << " \"DeclarationName\": \"" << I->QualifiedName
- << "\",\n";
- llvm::outs() << " \"DeclarationType\": \"" << I->Kind << "\",\n";
- llvm::outs() << " \"Templated\": " << (I->Templated ? "true" : "false")
- << "\n";
- llvm::outs() << " }";
- // Don't print trailing "," at the end of last element.
- if (I != std::prev(E))
- llvm::outs() << ",\n";
- }
- llvm::outs() << "\n]\n";
- return 0;
- }
-
- if (!NewCC.empty()) {
- std::error_code EC = CreateNewFile(NewCC);
- if (EC) {
- llvm::errs() << "Failed to create " << NewCC << ": " << EC.message()
- << "\n";
- return EC.value();
- }
- }
- if (!NewHeader.empty()) {
- std::error_code EC = CreateNewFile(NewHeader);
- if (EC) {
- llvm::errs() << "Failed to create " << NewHeader << ": " << EC.message()
- << "\n";
- return EC.value();
- }
- }
-
- IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions());
- clang::TextDiagnosticPrinter DiagnosticPrinter(errs(), &*DiagOpts);
- DiagnosticsEngine Diagnostics(
- IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), &*DiagOpts,
- &DiagnosticPrinter, false);
- auto &FileMgr = Tool.getFiles();
- SourceManager SM(Diagnostics, FileMgr);
- Rewriter Rewrite(SM, LangOptions());
-
- if (!formatAndApplyAllReplacements(Tool.getReplacements(), Rewrite, Style)) {
- llvm::errs() << "Failed applying all replacements.\n";
- return 1;
- }
-
- if (Dump) {
- std::set<llvm::StringRef> Files;
- for (const auto &it : Tool.getReplacements())
- Files.insert(it.first);
- auto WriteToJson = [&](llvm::raw_ostream &OS) {
- OS << "[\n";
- for (auto I = Files.begin(), E = Files.end(); I != E; ++I) {
- OS << " {\n";
- OS << " \"FilePath\": \"" << *I << "\",\n";
- const auto *Entry = FileMgr.getFile(*I);
- auto ID = SM.translateFile(Entry);
- std::string Content;
- llvm::raw_string_ostream ContentStream(Content);
- Rewrite.getEditBuffer(ID).write(ContentStream);
- OS << " \"SourceText\": \""
- << llvm::yaml::escape(ContentStream.str()) << "\"\n";
- OS << " }";
- if (I != std::prev(E))
- OS << ",\n";
- }
- OS << "\n]\n";
- };
- WriteToJson(llvm::outs());
- return 0;
- }
-
- return Rewrite.overwriteChangedFiles();
-}
More information about the cfe-commits
mailing list