diff options
author | Edwin Vane <edwin.vane@intel.com> | 2013-06-18 15:31:01 +0000 |
---|---|---|
committer | Edwin Vane <edwin.vane@intel.com> | 2013-06-18 15:31:01 +0000 |
commit | 62c013db6ce8dabac58a313c5e4ca05e75e45881 (patch) | |
tree | bb79b5905ac9a479c6f8b9b7c38bdb3a859fcfc3 /clang-tools-extra/cpp11-migrate/Core/Transform.cpp | |
parent | 302c0da6f138d1475b497a6e987787e94f15046f (diff) | |
download | bcm5719-llvm-62c013db6ce8dabac58a313c5e4ca05e75e45881.tar.gz bcm5719-llvm-62c013db6ce8dabac58a313c5e4ca05e75e45881.zip |
cpp11-migrate: Transform now responsible for applying replacements
To make it possible for replacements made to headers as part of transforming
one translation unit to not be visible to the transform of other translation
units, Transform now handles replacement application as part of its
end-of-source handling. Several things were simplified as a result:
- The duplicated code in every transform for applying replacements is now gone
and replaced with one location in Transform.
- RefactoringTool is no longer used since Transform houses the Replacements
structure.
- RewriterContainer is now a private implementation detail of Transform (also
renamed to RewriterManager since its behaviour is slightly different now with
respect to lifetime of objects).
- There's now no distinction between input and output file state.
Misc notes:
- Interface changes reflected in unit tests.
- Replacements for files other than the main file are assumed to be for headers
and stored as such.
llvm-svn: 184194
Diffstat (limited to 'clang-tools-extra/cpp11-migrate/Core/Transform.cpp')
-rw-r--r-- | clang-tools-extra/cpp11-migrate/Core/Transform.cpp | 132 |
1 files changed, 99 insertions, 33 deletions
diff --git a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp index adc6e6dc718..5fd73ad0380 100644 --- a/clang-tools-extra/cpp11-migrate/Core/Transform.cpp +++ b/clang-tools-extra/cpp11-migrate/Core/Transform.cpp @@ -1,6 +1,10 @@ #include "Core/Transform.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Basic/LangOptions.h" +#include "clang/Basic/DiagnosticOptions.h" +#include "clang/Basic/SourceManager.h" #include "clang/Frontend/CompilerInstance.h" +#include "clang/Frontend/TextDiagnosticPrinter.h" #include "clang/Rewrite/Core/Rewriter.h" #include "clang/Tooling/Tooling.h" #include "llvm/Support/raw_ostream.h" @@ -54,29 +58,55 @@ private: MatchFinder &Finder; Transform &Owner; }; - } // namespace -RewriterContainer::RewriterContainer(clang::FileManager &Files, - const FileOverrides &InputStates) - : 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) { - for (FileOverrides::const_iterator I = InputStates.begin(), - E = InputStates.end(); - I != E; ++I) - I->second.applyOverrides(Sources, Files); -} +/// \brief Class for creating Rewriter objects and housing Rewriter +/// dependencies. +/// +/// A Rewriter depends on a SourceManager which in turn depends on a +/// FileManager and a DiagnosticsEngine. Transform uses this class to create a +/// new Rewriter and SourceManager for every translation unit it transforms. A +/// DiagnosticsEngine doesn't need to be re-created so it's constructed once. A +/// SourceManager and Rewriter and (re)created as required. +/// +/// FIXME: The DiagnosticsEngine should really come from somewhere more global. +/// It shouldn't be re-created once for every transform. +/// +/// NOTE: SourceManagers cannot be shared. Therefore the one used to parse the +/// translation unit cannot be used to create a Rewriter. This is why both a +/// SourceManager and Rewriter need to be created for each translation unit. +class RewriterManager { +public: + RewriterManager() + : DiagOpts(new DiagnosticOptions()), + DiagnosticPrinter(llvm::errs(), DiagOpts.getPtr()), + Diagnostics( + llvm::IntrusiveRefCntPtr<DiagnosticIDs>(new DiagnosticIDs()), + DiagOpts.getPtr(), &DiagnosticPrinter, false) {} + + void prepare(FileManager &Files) { + Sources.reset(new SourceManager(Diagnostics, Files)); + Rewrite.reset(new Rewriter(*Sources, DefaultLangOptions)); + } -void collectResults(clang::Rewriter &Rewrite, - const FileOverrides &InputStates, - FileOverrides &Results) { - // Copy the contents of InputStates to be modified. - Results = InputStates; + void applyOverrides(const SourceOverrides &Overrides) { + Overrides.applyOverrides(*Sources); + } + + Rewriter &getRewriter() { return *Rewrite; } +private: + LangOptions DefaultLangOptions; + llvm::IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts; + TextDiagnosticPrinter DiagnosticPrinter; + DiagnosticsEngine Diagnostics; + llvm::OwningPtr<SourceManager> Sources; + llvm::OwningPtr<Rewriter> Rewrite; +}; + +/// \brief Flatten the Rewriter buffers of \p Rewrite and store results as +/// file content overrides in \p Overrides. +void collectResults(clang::Rewriter &Rewrite, SourceOverrides &Overrides) { for (Rewriter::buffer_iterator I = Rewrite.buffer_begin(), E = Rewrite.buffer_end(); I != E; ++I) { @@ -85,12 +115,6 @@ void collectResults(clang::Rewriter &Rewrite, assert(Entry->getName() != 0 && "Unexpected NULL return from FileEntry::getName()"); - FileOverrides::iterator OverrideI = Results.find(Entry->getName()); - if (OverrideI == Results.end()) { - OverrideI = Results.insert(FileOverrides::value_type( - Entry->getName(), Entry->getName())).first; - } - std::string ResultBuf; // Get a copy of the rewritten buffer from the Rewriter. @@ -103,18 +127,49 @@ void collectResults(clang::Rewriter &Rewrite, // FIXME: Use move semantics to avoid copies of the buffer contents if // benchmarking shows the copies are expensive, especially for large source // files. - OverrideI->second.MainFileOverride = ResultBuf; + + if (Overrides.MainFileName == Entry->getName()) { + Overrides.MainFileOverride = ResultBuf; + continue; + } + + // Header overrides are treated differently. Eventually, raw replacements + // will be stored as well for later output to disk. Applying replacements + // in memory will always be necessary as the source goes down the transform + // pipeline. + + HeaderOverrides &Headers = Overrides.Headers; + HeaderOverrides::iterator HeaderI = Headers.find(Entry->getName()); + if (HeaderI == Headers.end()) + HeaderI = Headers.insert(HeaderOverrides::value_type( + Entry->getName(), Entry->getName())).first; + + HeaderI->second.FileOverride = ResultBuf; } } +Transform::Transform(llvm::StringRef Name, const TransformOptions &Options) + : Name(Name), GlobalOptions(Options), Overrides(0), + RewriterOwner(new RewriterManager) { + Reset(); +} + +Transform::~Transform() {} + bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { - assert(InputState != 0 && "Subclass transform didn't provide InputState"); + assert(Overrides != 0 && "Subclass transform didn't provide InputState"); + + CurrentSource = Filename.str(); - FileOverrides::const_iterator I = InputState->find(Filename.str()); - if (I != InputState->end()) { - I->second.applyOverrides(CI.getSourceManager(), CI.getFileManager()); + RewriterOwner->prepare(CI.getFileManager()); + FileOverrides::const_iterator I = Overrides->find(CurrentSource); + if (I != Overrides->end()) { + I->second.applyOverrides(CI.getSourceManager()); + RewriterOwner->applyOverrides(I->second); } + Replace.clear(); + if (Options().EnableTiming) { Timings.push_back(std::make_pair(Filename.str(), llvm::TimeRecord())); Timings.back().second -= llvm::TimeRecord::getCurrentTime(true); @@ -123,10 +178,21 @@ bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) { } void Transform::handleEndSource() { - if (!Options().EnableTiming) - return; + if (!getReplacements().empty()) { + // FIXME: applyAllReplacements will indicate if it couldn't apply all + // replacements. Handle that case. + applyAllReplacements(getReplacements(), RewriterOwner->getRewriter()); + + FileOverrides::iterator I = Overrides->find(CurrentSource); + if (I == Overrides->end()) + I = Overrides + ->insert(FileOverrides::value_type(CurrentSource, CurrentSource)).first; + + collectResults(RewriterOwner->getRewriter(), I->second); + } - Timings.back().second += llvm::TimeRecord::getCurrentTime(false); + if (Options().EnableTiming) + Timings.back().second += llvm::TimeRecord::getCurrentTime(false); } void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) { |