Allow RefactoringTool to write to memory instead of always to disk
RefactoringTool::run() always writes the result of rewrites to disk. Instead, make this optional and provide a method for getting the refactoring results in a memory buffer instead. Also made ClangTool polymorphic so RefactoringTool could inherit from it to properly express the IS-A relationship. This change also provides access to ClangTool's public interface, e.g. mapVirtualFile() which is important once refactored buffers start living in memory instead of on disk. Reviewers: klimek llvm-svn: 172219
This commit is contained in:
parent
bfbd10b329
commit
5038ac0fb8
|
@ -52,7 +52,11 @@ public:
|
|||
iterator end() const { return Buffer.end(); }
|
||||
unsigned size() const { return Buffer.size(); }
|
||||
|
||||
raw_ostream &write(raw_ostream &) const;
|
||||
/// \brief Write to \p Stream the result of applying all changes to the
|
||||
/// original buffer.
|
||||
///
|
||||
/// The original buffer is not actually changed.
|
||||
raw_ostream &write(raw_ostream &Stream) const;
|
||||
|
||||
/// RemoveText - Remove the specified text.
|
||||
void RemoveText(unsigned OrigOffset, unsigned Size,
|
||||
|
|
|
@ -105,35 +105,48 @@ public:
|
|||
/// FIXME: Change to a vector and deduplicate in the RefactoringTool.
|
||||
typedef std::set<Replacement, Replacement::Less> Replacements;
|
||||
|
||||
/// \brief Apply all replacements on the Rewriter.
|
||||
/// \brief Apply all replacements in \p Replaces to the Rewriter \p Rewrite.
|
||||
///
|
||||
/// If at least one Apply returns false, ApplyAll returns false. Every
|
||||
/// Apply will be executed independently of the result of other
|
||||
/// Apply operations.
|
||||
/// Replacement applications happen independently of the success of
|
||||
/// other applications.
|
||||
///
|
||||
/// \returns true if all replacements apply. false otherwise.
|
||||
bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite);
|
||||
|
||||
/// \brief A tool to run refactorings.
|
||||
///
|
||||
/// This is a refactoring specific version of \see ClangTool.
|
||||
/// All text replacements added to getReplacements() during the run of the
|
||||
/// tool will be applied and saved after all translation units have been
|
||||
/// processed.
|
||||
class RefactoringTool {
|
||||
/// This is a refactoring specific version of \see ClangTool. FrontendActions
|
||||
/// passed to run() and runAndSave() should add replacements to
|
||||
/// getReplacements().
|
||||
class RefactoringTool : public ClangTool {
|
||||
public:
|
||||
/// \see ClangTool::ClangTool.
|
||||
RefactoringTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths);
|
||||
|
||||
/// \brief Returns a set of replacements. All replacements added during the
|
||||
/// run of the tool will be applied after all translation units have been
|
||||
/// processed.
|
||||
/// \brief Returns the set of replacements to which replacements should
|
||||
/// be added during the run of the tool.
|
||||
Replacements &getReplacements();
|
||||
|
||||
/// \see ClangTool::run.
|
||||
int run(FrontendActionFactory *ActionFactory);
|
||||
/// \brief Call run(), apply all generated replacements, and immediately save
|
||||
/// the results to disk.
|
||||
///
|
||||
/// \returns 0 upon success. Non-zero upon failure.
|
||||
int runAndSave(FrontendActionFactory *ActionFactory);
|
||||
|
||||
/// \brief Apply all stored replacements to the given Rewriter.
|
||||
///
|
||||
/// Replacement applications happen independently of the success of other
|
||||
/// applications.
|
||||
///
|
||||
/// \returns true if all replacements apply. false otherwise.
|
||||
bool applyAllReplacements(Rewriter &Rewrite);
|
||||
|
||||
private:
|
||||
/// \brief Write all refactored files to disk.
|
||||
int saveRewrittenFiles(Rewriter &Rewrite);
|
||||
|
||||
private:
|
||||
ClangTool Tool;
|
||||
Replacements Replace;
|
||||
};
|
||||
|
||||
|
@ -149,4 +162,3 @@ Replacement::Replacement(SourceManager &Sources, const Node &NodeToReplace,
|
|||
} // end namespace clang
|
||||
|
||||
#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H
|
||||
|
||||
|
|
|
@ -179,6 +179,8 @@ class ClangTool {
|
|||
ClangTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths);
|
||||
|
||||
virtual ~ClangTool() {}
|
||||
|
||||
/// \brief Map a virtual file to be used while running the tool.
|
||||
///
|
||||
/// \param FilePath The path at which the content will be mapped.
|
||||
|
@ -195,7 +197,7 @@ class ClangTool {
|
|||
/// \param ActionFactory Factory generating the frontend actions. The function
|
||||
/// takes ownership of this parameter. A new action is generated for every
|
||||
/// processed translation unit.
|
||||
int run(FrontendActionFactory *ActionFactory);
|
||||
virtual int run(FrontendActionFactory *ActionFactory);
|
||||
|
||||
/// \brief Returns the file manager used in the tool.
|
||||
///
|
||||
|
|
|
@ -135,7 +135,38 @@ bool applyAllReplacements(Replacements &Replaces, Rewriter &Rewrite) {
|
|||
return Result;
|
||||
}
|
||||
|
||||
bool saveRewrittenFiles(Rewriter &Rewrite) {
|
||||
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths)
|
||||
: ClangTool(Compilations, SourcePaths) {}
|
||||
|
||||
Replacements &RefactoringTool::getReplacements() { return Replace; }
|
||||
|
||||
int RefactoringTool::runAndSave(FrontendActionFactory *ActionFactory) {
|
||||
if (int Result = run(ActionFactory)) {
|
||||
return Result;
|
||||
}
|
||||
|
||||
LangOptions DefaultLangOptions;
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
DiagnosticsEngine Diagnostics(
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
|
||||
&*DiagOpts, &DiagnosticPrinter, false);
|
||||
SourceManager Sources(Diagnostics, getFiles());
|
||||
Rewriter Rewrite(Sources, DefaultLangOptions);
|
||||
|
||||
if (!applyAllReplacements(Rewrite)) {
|
||||
llvm::errs() << "Skipped some replacements.\n";
|
||||
}
|
||||
|
||||
return saveRewrittenFiles(Rewrite);
|
||||
}
|
||||
|
||||
bool RefactoringTool::applyAllReplacements(Rewriter &Rewrite) {
|
||||
return tooling::applyAllReplacements(Replace, Rewrite);
|
||||
}
|
||||
|
||||
int RefactoringTool::saveRewrittenFiles(Rewriter &Rewrite) {
|
||||
for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
|
||||
E = Rewrite.buffer_end();
|
||||
I != E; ++I) {
|
||||
|
@ -148,37 +179,11 @@ bool saveRewrittenFiles(Rewriter &Rewrite) {
|
|||
llvm::raw_fd_ostream FileStream(
|
||||
Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
|
||||
if (!ErrorInfo.empty())
|
||||
return false;
|
||||
return 1;
|
||||
I->second.write(FileStream);
|
||||
FileStream.flush();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
|
||||
ArrayRef<std::string> SourcePaths)
|
||||
: Tool(Compilations, SourcePaths) {}
|
||||
|
||||
Replacements &RefactoringTool::getReplacements() { return Replace; }
|
||||
|
||||
int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
|
||||
int Result = Tool.run(ActionFactory);
|
||||
LangOptions DefaultLangOptions;
|
||||
IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
|
||||
TextDiagnosticPrinter DiagnosticPrinter(llvm::errs(), &*DiagOpts);
|
||||
DiagnosticsEngine Diagnostics(
|
||||
llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()),
|
||||
&*DiagOpts, &DiagnosticPrinter, false);
|
||||
SourceManager Sources(Diagnostics, Tool.getFiles());
|
||||
Rewriter Rewrite(Sources, DefaultLangOptions);
|
||||
if (!applyAllReplacements(Replace, Rewrite)) {
|
||||
llvm::errs() << "Skipped some replacements.\n";
|
||||
}
|
||||
if (!saveRewrittenFiles(Rewrite)) {
|
||||
llvm::errs() << "Could not save rewritten files.\n";
|
||||
return 1;
|
||||
}
|
||||
return Result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // end namespace tooling
|
||||
|
|
Loading…
Reference in New Issue