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,
/// 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;
};
} // end namespace clang
#endif // end namespace LLVM_CLANG_TOOLING_REFACTORING_H
-
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.
/// \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.
///
return Result;
}
-bool saveRewrittenFiles(Rewriter &Rewrite) {
- for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
- E = Rewrite.buffer_end();
- I != E; ++I) {
- // FIXME: This code is copied from the FixItRewriter.cpp - I think it should
- // go into directly into Rewriter (there we also have the Diagnostics to
- // handle the error cases better).
- const FileEntry *Entry =
- Rewrite.getSourceMgr().getFileEntryForID(I->first);
- std::string ErrorInfo;
- llvm::raw_fd_ostream FileStream(
- Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
- if (!ErrorInfo.empty())
- return false;
- I->second.write(FileStream);
- FileStream.flush();
- }
- return true;
-}
-
RefactoringTool::RefactoringTool(const CompilationDatabase &Compilations,
ArrayRef<std::string> SourcePaths)
- : Tool(Compilations, SourcePaths) {}
+ : ClangTool(Compilations, SourcePaths) {}
Replacements &RefactoringTool::getReplacements() { return Replace; }
-int RefactoringTool::run(FrontendActionFactory *ActionFactory) {
- int Result = Tool.run(ActionFactory);
+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, Tool.getFiles());
+ SourceManager Sources(Diagnostics, getFiles());
Rewriter Rewrite(Sources, DefaultLangOptions);
- if (!applyAllReplacements(Replace, Rewrite)) {
+
+ if (!applyAllReplacements(Rewrite)) {
llvm::errs() << "Skipped some replacements.\n";
}
- if (!saveRewrittenFiles(Rewrite)) {
- llvm::errs() << "Could not save rewritten files.\n";
- return 1;
+
+ 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) {
+ // FIXME: This code is copied from the FixItRewriter.cpp - I think it should
+ // go into directly into Rewriter (there we also have the Diagnostics to
+ // handle the error cases better).
+ const FileEntry *Entry =
+ Rewrite.getSourceMgr().getFileEntryForID(I->first);
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream FileStream(
+ Entry->getName(), ErrorInfo, llvm::raw_fd_ostream::F_Binary);
+ if (!ErrorInfo.empty())
+ return 1;
+ I->second.write(FileStream);
+ FileStream.flush();
}
- return Result;
+ return 0;
}
} // end namespace tooling