Hi klimek,
Instead of writing the result of each transform to disk for every
transform, write the results to buffers in memory and pass those buffers
to the next transform as input. Only write the buffers to disk if the
final syntax check passes.
http://llvm-reviews.chandlerc.com/D288
Files:
cpp11-migrate/CMakeLists.txt
cpp11-migrate/Cpp11Migrate.cpp
cpp11-migrate/LoopConvert/LoopConvert.cpp
cpp11-migrate/LoopConvert/LoopConvert.h
cpp11-migrate/Makefile
cpp11-migrate/RefactoringResults.cpp
cpp11-migrate/RefactoringResults.h
cpp11-migrate/Transform.h
Index: cpp11-migrate/CMakeLists.txt
===================================================================
--- cpp11-migrate/CMakeLists.txt
+++ cpp11-migrate/CMakeLists.txt
@@ -5,6 +5,7 @@
set (Cpp11MigrateSources
Cpp11Migrate.cpp
Transforms.cpp
+ RefactoringResults.cpp
)
# For each transform subdirectory.
Index: cpp11-migrate/Cpp11Migrate.cpp
===================================================================
--- cpp11-migrate/Cpp11Migrate.cpp
+++ cpp11-migrate/Cpp11Migrate.cpp
@@ -27,11 +27,12 @@
///
//===----------------------------------------------------------------------===//
+#include "Transforms.h"
+#include "Transform.h"
+#include "RefactoringResults.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
-#include "Transforms.h"
-#include "Transform.h"
namespace cl = llvm::cl;
using namespace clang::tooling;
@@ -74,23 +75,52 @@
return 1;
}
+ unsigned int NumFiles = OptionsParser.getSourcePathList().size();
+
+ RefactoringResults FileStates1(NumFiles), FileStates2(NumFiles),
+ *InputFileStates = &FileStates1,
+ *OutputFileStates = &FileStates2;
+
// Apply transforms.
for (Transforms::const_iterator I = TransformManager.begin(),
E = TransformManager.end(); I != E; ++I) {
- if ((*I)->apply(MaxRiskLevel, OptionsParser.getCompilations(),
- OptionsParser.getSourcePathList()) != 0) {
+ if ((*I)->apply(*InputFileStates,
+ MaxRiskLevel, OptionsParser.getCompilations(),
+ OptionsParser.getSourcePathList(),
+ *OutputFileStates) != 0) {
+ // FIXME: Improve ClangTool to not abort if just one file fails.
return 1;
}
+ std::swap(InputFileStates, OutputFileStates);
+ OutputFileStates->clear();
}
+ // Final state of files is pointed at by InputFileStates.
+
// Final Syntax check.
ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
+ for (RefactoringResults::const_iterator I = InputFileStates->begin(),
+ E = InputFileStates->end();
+ I != E; ++I) {
+ EndSyntaxTool.mapVirtualFile(I->first, I->second);
+ }
+
if (EndSyntaxTool.run(
newFrontendActionFactory<clang::SyntaxOnlyAction>()) != 0) {
- // FIXME: Revert changes made to files that fail the syntax test.
return 1;
}
+ // Syntax check passed, write results to file.
+ for (RefactoringResults::const_iterator I = InputFileStates->begin(),
+ E = InputFileStates->end();
+ I != E; ++I) {
+ std::string ErrorInfo;
+ llvm::raw_fd_ostream FileStream(I->first,
+ ErrorInfo,
+ llvm::raw_fd_ostream::F_Binary);
+ FileStream << I->second;
+ }
+
return 0;
}
Index: cpp11-migrate/LoopConvert/LoopConvert.cpp
===================================================================
--- cpp11-migrate/LoopConvert/LoopConvert.cpp
+++ cpp11-migrate/LoopConvert/LoopConvert.cpp
@@ -16,18 +16,29 @@
#include "LoopConvert.h"
#include "LoopActions.h"
#include "LoopMatchers.h"
+#include "RefactoringResults.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Tooling.h"
+#include "clang/Rewrite/Core/Rewriter.h"
using clang::ast_matchers::MatchFinder;
using namespace clang::tooling;
using namespace clang;
-int LoopConvertTransform::apply(RiskLevel MaxRisk,
+int LoopConvertTransform::apply(const RefactoringResults &InputStates,
+ RiskLevel MaxRisk,
const CompilationDatabase &Database,
- const std::vector<std::string> &SourcePaths) {
+ const std::vector<std::string> &SourcePaths,
+ RefactoringResults &ResultStates) {
RefactoringTool LoopTool(Database, SourcePaths);
+
+ for (RefactoringResults::const_iterator I = InputStates.begin(),
+ E = InputStates.end();
+ I != E; ++I) {
+ LoopTool.mapVirtualFile(I->first, I->second);
+ }
+
StmtAncestorASTVisitor ParentFinder;
StmtGeneratedVarNameMap GeneratedDecls;
ReplacedVarsMap ReplacedVars;
@@ -53,11 +64,20 @@
&RejectedChanges,
MaxRisk, LFK_PseudoArray);
Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
- if (int result = LoopTool.runAndSave(newFrontendActionFactory(&Finder))) {
+
+ if (int result = LoopTool.run(newFrontendActionFactory(&Finder))) {
llvm::errs() << "Error encountered during translation.\n";
return result;
}
+ OwningPtr<RewriterContainer>
+ Rewrite(new RewriterContainer(LoopTool.getFiles()));
+
+ // FIXME: Do something if some replacements didn't get applied?
+ LoopTool.applyAllReplacements(Rewrite->getRewriter());
+
+ ResultStates.collectResults(Rewrite->getRewriter());
+
if (AcceptedChanges > 0) {
setChangesMade();
}
Index: cpp11-migrate/LoopConvert/LoopConvert.h
===================================================================
--- cpp11-migrate/LoopConvert/LoopConvert.h
+++ cpp11-migrate/LoopConvert/LoopConvert.h
@@ -17,13 +17,16 @@
#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_LOOP_CONVERT_H
#include "Transform.h"
+#include "llvm/Support/Compiler.h" // For LLVM_OVERRIDE
class LoopConvertTransform : public Transform {
public:
- virtual int apply(RiskLevel MaxRiskLEvel,
+ virtual int apply(const RefactoringResults &InputStates,
+ RiskLevel MaxRiskLevel,
const clang::tooling::CompilationDatabase &Database,
- const std::vector<std::string> &SourcePaths) LLVM_OVERRIDE;
+ const std::vector<std::string> &SourcePaths,
+ RefactoringResults &ResultStates) LLVM_OVERRIDE;
};
#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_LOOP_CONVERT_H
Index: cpp11-migrate/Makefile
===================================================================
--- cpp11-migrate/Makefile
+++ cpp11-migrate/Makefile
@@ -17,7 +17,7 @@
include $(CLANG_LEVEL)/../../Makefile.config
-SOURCES = Cpp11Migrate.cpp Transforms.cpp
+SOURCES = Cpp11Migrate.cpp Transforms.cpp RefactoringResults.cpp
# For each Transform subdirectory add to SOURCES and BUILT_SOURCES.
# BUILT_SOURCES ensures a subdirectory is created to house object files from
Index: cpp11-migrate/RefactoringResults.cpp
===================================================================
--- /dev/null
+++ cpp11-migrate/RefactoringResults.cpp
@@ -0,0 +1,67 @@
+//===-- cpp11-migrate/RefactoringResults.cpp -- Class implementation ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the implementation of the RefactoringResults
+/// class.
+///
+//===----------------------------------------------------------------------===//
+
+#include "RefactoringResults.h"
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Basic/FileManager.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstring>
+
+using namespace clang;
+
+RefactoringResults::RefactoringResults(unsigned int NumResults) {
+ Data.reserve(NumResults);
+}
+
+RefactoringResults::~RefactoringResults() {
+ clear();
+}
+
+void RefactoringResults::clear() {
+ for (ResultVec::iterator I = Data.begin(),
+ E = Data.end();
+ I != E; ++I) {
+ delete [] I->first;
+ }
+ Data.clear();
+}
+
+void RefactoringResults::collectResults(Rewriter &Rewrite) {
+ // Default construct an extra item on the list.
+ for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(),
+ E = Rewrite.buffer_end();
+ I != E; ++I) {
+ const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
+ assert(Entry != 0 && "Expected a FileEntry");
+ assert(Entry->getName() != 0 &&
+ "Unexpected NULL return from FileEntry::getName()");
+ unsigned int FilenameLength = strlen(Entry->getName());
+
+ // This would be a little less wonky using move semantics. The goal is to
+ // avoid potentially expensive copies of ResultEntry.
+ Data.resize(Data.size() + 1);
+ ResultEntry &Result = Data.back();
+
+ // Copy the file name
+ Result.first = new char[FilenameLength + 1];
+ std::memcpy(Result.first, Entry->getName(), FilenameLength);
+ Result.first[FilenameLength] = 0;
+
+ // Get a copy of the rewritten buffer from the Rewriter.
+ llvm::raw_string_ostream StringStream(Result.second);
+ I->second.write(StringStream);
+ }
+}
Index: cpp11-migrate/RefactoringResults.h
===================================================================
--- /dev/null
+++ cpp11-migrate/RefactoringResults.h
@@ -0,0 +1,64 @@
+//===-- cpp11-migrate/RefactoringResults.h --- Class def'n ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// \brief This file provides the definition for RefactoringResults, a class
+/// for storing the results of running a RefactoringTool in memory.
+///
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_REFACTORING_RESULTS_H
+#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_REFACTORING_RESULTS_H
+
+#include <string>
+#include <vector>
+
+// Forward declarations.
+namespace clang {
+class Rewriter;
+} // namespace clang
+
+/// \brief Owns the result of refactoring one or more files.
+///
+/// Each refactoring result is represented by a pair: a filename for the
+/// original file, and a string buffer containing the result of refactoring on
+/// the original file. Both the filenames and the buffer contents become owned
+/// by this class.
+class RefactoringResults {
+public:
+ typedef std::pair<char*, std::string> ResultEntry;
+ typedef std::vector<ResultEntry> ResultVec;
+ typedef ResultVec::const_iterator const_iterator;
+
+public:
+ /// \brief Construct a container for holding \p NumResults refactoring
+ /// results.
+ RefactoringResults(unsigned int NumResults);
+ ~RefactoringResults();
+
+ /// \brief Get copies of the buffers resulting from applying all rewrites
+ /// represented by \p Rewrite.
+ void collectResults(clang::Rewriter &Rewrite);
+
+ /// \brief Free all refactoring results.
+ void clear();
+
+ /// \brief Iterator to the first refactoring result.
+ const_iterator begin() const { return Data.begin(); }
+
+ /// \brief Iterator to the end of the container.
+ const_iterator end() const { return Data.end(); }
+
+ /// \brief Return how many results are actually stored by this class.
+ ResultVec::size_type size() const { return Data.size(); }
+
+private:
+ ResultVec Data;
+};
+
+#endif // LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_REFACTORING_RESULTS_H
Index: cpp11-migrate/Transform.h
===================================================================
--- cpp11-migrate/Transform.h
+++ cpp11-migrate/Transform.h
@@ -15,8 +15,18 @@
#ifndef LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
#define LLVM_TOOLS_CLANG_TOOLS_EXTRA_CPP11_MIGRATE_TRANSFORM_H
-#include "clang/Tooling/CompilationDatabase.h"
#include <vector>
+#include <string>
+
+// For RewriterContainer
+#include "clang/Rewrite/Core/Rewriter.h"
+#include "clang/Basic/LangOptions.h"
+#include "clang/Basic/DiagnosticOptions.h"
+#include "clang/Frontend/TextDiagnosticPrinter.h"
+#include "clang/Basic/SourceManager.h"
+#include "llvm/Support/raw_ostream.h"
+////
+
/// \brief Description of the riskiness of actions that can be taken by
/// transforms.
@@ -31,12 +41,45 @@
RL_Risky
};
-// Forward Declarations
+// Forward declarations
namespace clang {
namespace tooling {
class CompilationDatabase;
} // namespace tooling
} // namespace clang
+class RefactoringResults;
+
+/// \brief Class for containing a Rewriter instance and all of
+/// its lifetime dependencies.
+///
+/// Subclasses of Transform using RefactoringTools will need to create
+/// Rewriters in order to apply Replacements and get the resulting buffer.
+/// Rewriter requires some objects to exist at least as long as it does so this
+/// class contains instances of those objects.
+///
+/// FIXME: These objects should really come from somewhere more global instead
+/// of being recreated for every Transform subclass, especially diagnostics.
+class RewriterContainer {
+public:
+ RewriterContainer(clang::FileManager &Files)
+ : DiagOpts(new clang::DiagnosticOptions()),
+ DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()),
+ Diagnostics(llvm::IntrusiveRefCntPtr<clang::DiagnosticIDs>(
+ new clang::DiagnosticIDs()),
+ DiagOpts.getPtr(), &DiagnosticPrinter, false),
+ Sources(Diagnostics, Files),
+ Rewrite(Sources, DefaultLangOptions) {}
+
+ clang::Rewriter &getRewriter() { return Rewrite; }
+
+private:
+ clang::LangOptions DefaultLangOptions;
+ llvm::IntrusiveRefCntPtr<clang::DiagnosticOptions> DiagOpts;
+ clang::TextDiagnosticPrinter DiagnosticPrinter;
+ clang::DiagnosticsEngine Diagnostics;
+ clang::SourceManager Sources;
+ clang::Rewriter Rewrite;
+};
/// \brief Abstract base class for all C++11 migration transforms.
class Transform {
@@ -51,9 +94,11 @@
///
/// \p Database must contain information for how to compile all files in
/// \p SourcePaths.
- virtual int apply(RiskLevel MaxRiskLevel,
+ virtual int apply(const RefactoringResults &InputStates,
+ RiskLevel MaxRiskLevel,
const clang::tooling::CompilationDatabase &Database,
- const std::vector<std::string> &SourcePaths) = 0;
+ const std::vector<std::string> &SourcePaths,
+ RefactoringResults &ResultStates) = 0;
/// \brief Query if changes were made during the last call to apply().
bool getChangesMade() const { return ChangesMade; }
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits