Imported Upstream version 6.10.0.49

Former-commit-id: 1d6753294b2993e1fbf92de9366bb9544db4189b
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2020-01-16 16:38:04 +00:00
parent d94e79959b
commit 468663ddbb
48518 changed files with 2789335 additions and 61176 deletions

View File

@@ -0,0 +1,21 @@
set(LLVM_LINK_COMPONENTS
support
)
add_clang_library(clangMove
ClangMove.cpp
HelperDeclRefGraph.cpp
LINK_LIBS
clangAnalysis
clangAST
clangASTMatchers
clangBasic
clangFormat
clangFrontend
clangLex
clangTooling
clangToolingCore
)
add_subdirectory(tool)

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,229 @@
//===-- ClangMove.h - Clang move -----------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#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 <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) {
DeclarationList.emplace_back(DeclarationName, Type);
};
// A <DeclarationName, DeclarationKind> pair.
// The DeclarationName is a fully qualified name for the declaration, like
// A::B::Foo. The DeclarationKind is a string represents the kind of the
// declaration, currently only "Function" and "Class" are supported.
typedef std::pair<std::string, std::string> DeclarationPair;
const std::vector<DeclarationPair> getDeclarationList() const {
return DeclarationList;
}
private:
std::vector<DeclarationPair> 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 OldHeaderIncludeRange;
/// 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

View File

@@ -0,0 +1,137 @@
//===-- UsedHelperDeclFinder.cpp - AST-based call graph for helper decls --===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "HelperDeclRefGraph.h"
#include "ClangMove.h"
#include "clang/AST/Decl.h"
#include "llvm/Support/Debug.h"
#include <vector>
#define DEBUG_TYPE "clang-move"
namespace clang {
namespace move {
void HelperDeclRefGraph::print(raw_ostream &OS) const {
OS << " --- Call graph Dump --- \n";
for (auto I = DeclMap.begin(); I != DeclMap.end(); ++I) {
const CallGraphNode *N = (I->second).get();
OS << " Declarations: ";
N->print(OS);
OS << " (" << N << ") ";
OS << " calls: ";
for (auto CI = N->begin(), CE = N->end(); CI != CE; ++CI) {
(*CI)->print(OS);
OS << " (" << CI << ") ";
}
OS << '\n';
}
OS.flush();
}
void HelperDeclRefGraph::addEdge(const Decl *Caller, const Decl *Callee) {
assert(Caller);
assert(Callee);
// Ignore the case where Caller equals Callee. This happens in the static
// class member definitions in global namespace like "int CLASS::static_var =
// 1;", its DC is a VarDel whose outmost enclosing declaration is the "CLASS"
// CXXRecordDecl.
if (Caller == Callee) return;
// Allocate a new node, mark it as root, and process it's calls.
CallGraphNode *CallerNode = getOrInsertNode(const_cast<Decl *>(Caller));
CallGraphNode *CalleeNode = getOrInsertNode(const_cast<Decl *>(Callee));
CallerNode->addCallee(CalleeNode);
}
void HelperDeclRefGraph::dump() const { print(llvm::errs()); }
CallGraphNode *HelperDeclRefGraph::getOrInsertNode(Decl *F) {
F = F->getCanonicalDecl();
std::unique_ptr<CallGraphNode> &Node = DeclMap[F];
if (Node)
return Node.get();
Node = llvm::make_unique<CallGraphNode>(F);
return Node.get();
}
CallGraphNode *HelperDeclRefGraph::getNode(const Decl *D) const {
auto I = DeclMap.find(D->getCanonicalDecl());
return I == DeclMap.end() ? nullptr : I->second.get();
}
llvm::DenseSet<const CallGraphNode *>
HelperDeclRefGraph::getReachableNodes(const Decl *Root) const {
const auto *RootNode = getNode(Root);
if (!RootNode)
return {};
llvm::DenseSet<const CallGraphNode *> ConnectedNodes;
std::function<void(const CallGraphNode *)> VisitNode =
[&](const CallGraphNode *Node) {
if (ConnectedNodes.count(Node))
return;
ConnectedNodes.insert(Node);
for (auto It = Node->begin(), End = Node->end(); It != End; ++It)
VisitNode(*It);
};
VisitNode(RootNode);
return ConnectedNodes;
}
const Decl *HelperDeclRGBuilder::getOutmostClassOrFunDecl(const Decl *D) {
const auto *DC = D->getDeclContext();
const auto *Result = D;
while (DC) {
if (const auto *RD = dyn_cast<CXXRecordDecl>(DC))
Result = RD;
else if (const auto *FD = dyn_cast<FunctionDecl>(DC))
Result = FD;
DC = DC->getParent();
}
return Result;
}
void HelperDeclRGBuilder::run(
const ast_matchers::MatchFinder::MatchResult &Result) {
// Construct the graph by adding a directed edge from caller to callee.
//
// "dc" is the closest ancestor declaration of "func_ref" or "used_class", it
// might be not the targetted Caller Decl, we always use the outmost enclosing
// FunctionDecl/CXXRecordDecl of "dc". For example,
//
// int MoveClass::F() { int a = helper(); return a; }
//
// The matched "dc" of "helper" DeclRefExpr is a VarDecl, we traverse up AST
// to find the outmost "MoveClass" CXXRecordDecl and use it as Caller.
if (const auto *FuncRef = Result.Nodes.getNodeAs<DeclRefExpr>("func_ref")) {
const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
assert(DC);
DEBUG(llvm::dbgs() << "Find helper function usage: "
<< FuncRef->getDecl()->getNameAsString() << " ("
<< FuncRef->getDecl() << ")\n");
RG->addEdge(
getOutmostClassOrFunDecl(DC->getCanonicalDecl()),
getOutmostClassOrFunDecl(FuncRef->getDecl()->getCanonicalDecl()));
} else if (const auto *UsedClass =
Result.Nodes.getNodeAs<CXXRecordDecl>("used_class")) {
const auto *DC = Result.Nodes.getNodeAs<Decl>("dc");
assert(DC);
DEBUG(llvm::dbgs() << "Find helper class usage: "
<< UsedClass->getNameAsString() << " (" << UsedClass
<< ")\n");
RG->addEdge(getOutmostClassOrFunDecl(DC->getCanonicalDecl()), UsedClass);
}
}
} // namespace move
} // namespace clang

View File

@@ -0,0 +1,99 @@
//===-- UsedHelperDeclFinder.h - AST-based call graph for helper decls ----===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Analysis/CallGraph.h"
#include "llvm/ADT/DenseSet.h"
#include <memory>
#include <vector>
namespace clang {
namespace move {
// A reference graph for finding used/unused helper declarations in a single
// translation unit (e.g. old.cc). We don't reuse CallGraph in clang/Analysis
// because that CallGraph only supports function declarations.
//
// Helper declarations include following types:
// * function/variable/class definitions in an anonymous namespace.
// * static function/variable definitions in a global/named namespace.
//
// The reference graph is a directed graph. Each node in the graph represents a
// helper declaration in old.cc or a non-moved/moved declaration (e.g. class,
// function) in old.h, which means each node is associated with a Decl.
//
// To construct the graph, we use AST matcher to find interesting Decls (usually
// a pair of Caller and Callee), and add an edge from the Caller node to the
// Callee node.
//
// Specially, for a class, it might have multiple declarations such methods
// and member variables. We only use a single node to present this class, and
// this node is associated with the class declaration (CXXRecordDecl).
//
// The graph has 3 types of edges:
// 1. moved_decl => helper_decl
// 2. non_moved_decl => helper_decl
// 3. helper_decl => helper_decl
class HelperDeclRefGraph {
public:
HelperDeclRefGraph() = default;
~HelperDeclRefGraph() = default;
// Add a directed edge from the caller node to the callee node.
// A new node will be created if the node for Caller/Callee doesn't exist.
//
// Note that, all class member declarations are represented by a single node
// in the graph. The corresponding Decl of this node is the class declaration.
void addEdge(const Decl *Caller, const Decl *Callee);
CallGraphNode *getNode(const Decl *D) const;
// Get all reachable nodes in the graph from the given declaration D's node,
// including D.
llvm::DenseSet<const CallGraphNode *> getReachableNodes(const Decl *D) const;
// Dump the call graph for debug purpose.
void dump() const;
private:
void print(raw_ostream &OS) const;
// Lookup a node for the given declaration D. If not found, insert a new
// node into the graph.
CallGraphNode *getOrInsertNode(Decl *D);
typedef llvm::DenseMap<const Decl *, std::unique_ptr<CallGraphNode>>
DeclMapTy;
// DeclMap owns all CallGraphNodes.
DeclMapTy DeclMap;
};
// A builder helps to construct a call graph of helper declarations.
class HelperDeclRGBuilder : public ast_matchers::MatchFinder::MatchCallback {
public:
HelperDeclRGBuilder() : RG(new HelperDeclRefGraph) {}
void run(const ast_matchers::MatchFinder::MatchResult &Result) override;
const HelperDeclRefGraph *getGraph() const { return RG.get(); }
// Find out the outmost enclosing class/function declaration of a given D.
// For a CXXMethodDecl, get its CXXRecordDecl; For a VarDecl/FunctionDecl, get
// its outmost enclosing FunctionDecl or CXXRecordDecl.
// Return D if not found.
static const Decl *getOutmostClassOrFunDecl(const Decl *D);
private:
std::unique_ptr<HelperDeclRefGraph> RG;
};
} // namespace move
} // namespace clang
#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_MOVE_USED_HELPER_DECL_FINDER_H

View File

@@ -0,0 +1,18 @@
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
add_clang_executable(clang-move
ClangMoveMain.cpp
)
target_link_libraries(clang-move
PRIVATE
clangAST
clangASTMatchers
clangBasic
clangFormat
clangFrontend
clangMove
clangRewrite
clangTooling
clangToolingCore
)

View File

@@ -0,0 +1,210 @@
//===-- ClangMoveMain.cpp - move defintion to new file ----------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "ClangMove.h"
#include "clang/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::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->first << "\",\n";
llvm::outs() << " \"DeclarationType\": \"" << I->second << "\"\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();
}