Files
clang-p2996/clang-tools-extra/cpp11-migrate/Core/Transform.cpp
Edwin Vane 86142e02df cpp11-migrate: Fixes for r185811
Some changes to r185811 broke certain build configurations. These changes should
fix them.

Author: Guillaume Papin <guillaume.papin@epitech.eu>
llvm-svn: 185814
2013-07-08 12:49:04 +00:00

237 lines
7.8 KiB
C++

//===-- Core/Transform.cpp - Transform Base Class Def'n -------------------===//
//
// 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 the base Transform class from
/// which all transforms must subclass.
///
//===----------------------------------------------------------------------===//
#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"
using namespace clang;
llvm::cl::OptionCategory TransformsOptionsCategory("Transforms' options");
namespace {
using namespace tooling;
using namespace ast_matchers;
/// \brief Custom FrontendActionFactory to produce FrontendActions that simply
/// forward (Begin|End)SourceFileAction calls to a given Transform.
class ActionFactory : public clang::tooling::FrontendActionFactory {
public:
ActionFactory(MatchFinder &Finder, Transform &Owner)
: Finder(Finder), Owner(Owner) {}
virtual FrontendAction *create() LLVM_OVERRIDE {
return new FactoryAdaptor(Finder, Owner);
}
private:
class FactoryAdaptor : public ASTFrontendAction {
public:
FactoryAdaptor(MatchFinder &Finder, Transform &Owner)
: Finder(Finder), Owner(Owner) {}
ASTConsumer *CreateASTConsumer(CompilerInstance &, StringRef) {
return Finder.newASTConsumer();
}
virtual bool BeginSourceFileAction(CompilerInstance &CI,
StringRef Filename) LLVM_OVERRIDE {
if (!ASTFrontendAction::BeginSourceFileAction(CI, Filename))
return false;
return Owner.handleBeginSource(CI, Filename);
}
virtual void EndSourceFileAction() LLVM_OVERRIDE {
Owner.handleEndSource();
return ASTFrontendAction::EndSourceFileAction();
}
private:
MatchFinder &Finder;
Transform &Owner;
};
MatchFinder &Finder;
Transform &Owner;
};
} // namespace
/// \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 are (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 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) {
const FileEntry *Entry = Rewrite.getSourceMgr().getFileEntryForID(I->first);
assert(Entry != 0 && "Expected a FileEntry");
assert(Entry->getName() != 0 &&
"Unexpected NULL return from FileEntry::getName()");
std::string ResultBuf;
// Get a copy of the rewritten buffer from the Rewriter.
llvm::raw_string_ostream StringStream(ResultBuf);
I->second.write(StringStream);
// Cause results to be written to ResultBuf.
StringStream.str();
// FIXME: Use move semantics to avoid copies of the buffer contents if
// benchmarking shows the copies are expensive, especially for large source
// files.
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.
// Create HeaderOverride if not already existing
HeaderOverride &Header = Overrides.Headers[Entry->getName()];
if (Header.FileName.empty())
Header.FileName = Entry->getName();
Header.FileOverride = ResultBuf;
}
}
Transform::Transform(llvm::StringRef Name, const TransformOptions &Options)
: Name(Name), GlobalOptions(Options), Overrides(0),
RewriterOwner(new RewriterManager) {
Reset();
}
Transform::~Transform() {}
bool Transform::isFileModifiable(const SourceManager &SM,
const SourceLocation &Loc) const {
if (SM.isFromMainFile(Loc))
return true;
if (!GlobalOptions.EnableHeaderModifications)
return false;
const FileEntry *FE = SM.getFileEntryForID(SM.getFileID(Loc));
if (!FE)
return false;
return GlobalOptions.ModifiableHeaders.isFileIncluded(FE->getName());
}
bool Transform::handleBeginSource(CompilerInstance &CI, StringRef Filename) {
assert(Overrides != 0 && "Subclass transform didn't provide InputState");
CurrentSource = Filename.str();
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);
}
return true;
}
void Transform::handleEndSource() {
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);
}
if (Options().EnableTiming)
Timings.back().second += llvm::TimeRecord::getCurrentTime(false);
}
void Transform::addTiming(llvm::StringRef Label, llvm::TimeRecord Duration) {
Timings.push_back(std::make_pair(Label.str(), Duration));
}
FrontendActionFactory *
Transform::createActionFactory(MatchFinder &Finder) {
return new ActionFactory(Finder, /*Owner=*/ *this);
}