blob: d71626ce8281128169588b829f5219937749d9d5 [file] [log] [blame]
//===-- cpp11-migrate/Cpp11Migrate.cpp - Main file C++11 migration tool ---===//
//
// 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 implements the C++11 feature migration tool main function
/// and transformation framework.
///
/// See user documentation for usage instructions.
///
//===----------------------------------------------------------------------===//
#include "Core/Transforms.h"
#include "Core/Transform.h"
#include "LoopConvert/LoopConvert.h"
#include "UseNullptr/UseNullptr.h"
#include "UseAuto/UseAuto.h"
#include "AddOverride/AddOverride.h"
#include "clang/Frontend/FrontendActions.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/Signals.h"
namespace cl = llvm::cl;
using namespace clang::tooling;
static cl::opt<RiskLevel> MaxRiskLevel(
"risk", cl::desc("Select a maximum risk level:"),
cl::values(clEnumValN(RL_Safe, "safe", "Only safe transformations"),
clEnumValN(RL_Reasonable, "reasonable",
"Enable transformations that might change "
"semantics (default)"),
clEnumValN(RL_Risky, "risky",
"Enable transformations that are likely to "
"change semantics"),
clEnumValEnd),
cl::init(RL_Reasonable));
static cl::opt<bool> FinalSyntaxCheck(
"final-syntax-check",
cl::desc("Check for correct syntax after applying transformations"),
cl::init(false));
static cl::opt<bool>
SummaryMode("summary", cl::desc("Print transform summary"),
cl::init(false));
// TODO: Remove cl::Hidden when functionality for acknowledging include/exclude
// options are implemented in the tool.
static cl::opt<std::string>
IncludePaths("include", cl::Hidden,
cl::desc("Comma seperated list of paths to consider to be "
"transformed"));
static cl::opt<std::string>
ExcludePaths("exclude", cl::Hidden,
cl::desc("Comma seperated list of paths that can not "
"be transformed"));
static cl::opt<std::string>
IncludeFromFile("include-from", cl::Hidden, cl::value_desc("filename"),
cl::desc("File containing a list of paths to consider to "
"be transformed"));
static cl::opt<std::string>
ExcludeFromFile("exclude-from", cl::Hidden, cl::value_desc("filename"),
cl::desc("File containing a list of paths that can not be "
"transforms"));
class EndSyntaxArgumentsAdjuster : public ArgumentsAdjuster {
CommandLineArguments Adjust(const CommandLineArguments &Args) {
CommandLineArguments AdjustedArgs = Args;
AdjustedArgs.push_back("-fsyntax-only");
AdjustedArgs.push_back("-std=c++11");
return AdjustedArgs;
}
};
int main(int argc, const char **argv) {
llvm::sys::PrintStackTraceOnErrorSignal();
Transforms TransformManager;
TransformManager.registerTransform(
"loop-convert", "Make use of range-based for loops where possible",
&ConstructTransform<LoopConvertTransform>);
TransformManager.registerTransform(
"use-nullptr", "Make use of nullptr keyword where possible",
&ConstructTransform<UseNullptrTransform>);
TransformManager.registerTransform(
"use-auto", "Use of 'auto' type specifier",
&ConstructTransform<UseAutoTransform>);
TransformManager.registerTransform(
"add-override", "Make use of override specifier where possible",
&ConstructTransform<AddOverrideTransform>);
// Add more transform options here.
// This causes options to be parsed.
CommonOptionsParser OptionsParser(argc, argv);
TransformManager.createSelectedTransforms();
if (TransformManager.begin() == TransformManager.end()) {
llvm::errs() << "No selected transforms\n";
return 1;
}
FileContentsByPath FileStates1, FileStates2,
*InputFileStates = &FileStates1, *OutputFileStates = &FileStates2;
// Apply transforms.
for (Transforms::const_iterator I = TransformManager.begin(),
E = TransformManager.end();
I != E; ++I) {
if ((*I)->apply(*InputFileStates, MaxRiskLevel,
OptionsParser.getCompilations(),
OptionsParser.getSourcePathList(), *OutputFileStates) !=
0) {
// FIXME: Improve ClangTool to not abort if just one file fails.
return 1;
}
if (SummaryMode) {
llvm::outs() << "Transform: " << (*I)->getName()
<< " - Accepted: "
<< (*I)->getAcceptedChanges();
if ((*I)->getChangesNotMade()) {
llvm::outs() << " - Rejected: "
<< (*I)->getRejectedChanges()
<< " - Deferred: "
<< (*I)->getDeferredChanges();
}
llvm::outs() << "\n";
}
std::swap(InputFileStates, OutputFileStates);
OutputFileStates->clear();
}
// Final state of files is pointed at by InputFileStates.
if (FinalSyntaxCheck) {
ClangTool EndSyntaxTool(OptionsParser.getCompilations(),
OptionsParser.getSourcePathList());
// Add c++11 support to clang.
EndSyntaxTool.setArgumentsAdjuster(new EndSyntaxArgumentsAdjuster);
for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
E = InputFileStates->end();
I != E; ++I) {
EndSyntaxTool.mapVirtualFile(I->first, I->second);
}
if (EndSyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>())
!= 0) {
return 1;
}
}
// Write results to file.
for (FileContentsByPath::const_iterator I = InputFileStates->begin(),
E = InputFileStates->end();
I != E; ++I) {
std::string ErrorInfo;
llvm::raw_fd_ostream FileStream(I->first.c_str(), ErrorInfo,
llvm::raw_fd_ostream::F_Binary);
FileStream << I->second;
}
return 0;
}