1 //===-- loop-convert/LoopConvert.cpp - C++11 For loop migration -*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements a tool that migrates for loops to take advantage of the
11 // range-basead syntax new to C++11.
14 // loop-convert <cmake-output-dir> <file1> <file2> ...
16 // Where <cmake-output-dir> is a CMake build directory containing a file named
17 // compile_commands.json.
19 // <file1>... specify the pahs of files in the CMake source tree, with the same
20 // requirements as other tools built on LibTooling.
22 //===----------------------------------------------------------------------===//
24 #include "LoopActions.h"
25 #include "LoopMatchers.h"
27 #include "clang/Basic/FileManager.h"
28 #include "clang/Frontend/CompilerInstance.h"
29 #include "clang/Frontend/FrontendActions.h"
30 #include "clang/Tooling/Tooling.h"
31 #include "clang/Tooling/Refactoring.h"
33 using clang::ast_matchers::MatchFinder;
34 namespace cl = llvm::cl;
35 using namespace clang::tooling;
36 using namespace clang::loop_migrate;
38 static cl::opt<std::string> BuildPath(
40 cl::desc("<build-path>"));
42 static cl::list<std::string> SourcePaths(
44 cl::desc("<source0> [... <sourceN>]"),
47 // General options go here:
48 static cl::opt<bool> CountOnly(
49 "count-only", cl::desc("Do not apply transformations; only count them."));
51 static cl::opt<TranslationConfidenceKind> TransformationLevel(
52 cl::desc("Choose safety requirements for transformations:"),
53 cl::values(clEnumValN(TCK_Safe, "A0", "Enable safe transformations"),
54 clEnumValN(TCK_Reasonable, "A1",
55 "Enable transformations that might change semantics "
57 clEnumValN(TCK_Risky, "A2",
58 "Enable transformations that are likely "
59 "to change semantics"),
61 cl::init(TCK_Reasonable));
63 int main(int argc, const char **argv) {
64 llvm::OwningPtr<CompilationDatabase> Compilations(
65 FixedCompilationDatabase::loadFromCommandLine(argc, argv));
66 cl::ParseCommandLineOptions(argc, argv);
68 std::string ErrorMessage;
71 CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
72 CompilationDatabase::autoDetectFromSource(SourcePaths[0],
75 llvm::report_fatal_error(ErrorMessage);
77 ClangTool SyntaxTool(*Compilations, SourcePaths);
79 // First, let's check to make sure there were no errors.
81 SyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>())) {
82 llvm::errs() << "Error compiling files.\n";
86 RefactoringTool LoopTool(*Compilations, SourcePaths);
87 StmtAncestorASTVisitor ParentFinder;
88 StmtGeneratedVarNameMap GeneratedDecls;
89 ReplacedVarsMap ReplacedVars;
90 unsigned AcceptedChanges = 0;
91 unsigned DeferredChanges = 0;
92 unsigned RejectedChanges = 0;
95 LoopFixer ArrayLoopFixer(&ParentFinder, &LoopTool.getReplacements(),
96 &GeneratedDecls, &ReplacedVars, &AcceptedChanges,
97 &DeferredChanges, &RejectedChanges,
98 CountOnly, TransformationLevel, LFK_Array);
99 Finder.addMatcher(makeArrayLoopMatcher(), &ArrayLoopFixer);
100 LoopFixer IteratorLoopFixer(&ParentFinder, &LoopTool.getReplacements(),
101 &GeneratedDecls, &ReplacedVars, &AcceptedChanges,
102 &DeferredChanges, &RejectedChanges,
103 CountOnly, TransformationLevel, LFK_Iterator);
104 Finder.addMatcher(makeIteratorLoopMatcher(), &IteratorLoopFixer);
105 LoopFixer PseudoarrrayLoopFixer(&ParentFinder, &LoopTool.getReplacements(),
106 &GeneratedDecls, &ReplacedVars,
107 &AcceptedChanges, &DeferredChanges,
108 &RejectedChanges, CountOnly,
109 TransformationLevel, LFK_PseudoArray);
110 Finder.addMatcher(makePseudoArrayLoopMatcher(), &PseudoarrrayLoopFixer);
111 if (int result = LoopTool.run(newFrontendActionFactory(&Finder))) {
112 llvm::errs() << "Error encountered during translation.\n";
116 llvm::outs() << "\nFor Loop Conversion:\n\t" << AcceptedChanges
117 << " converted loop(s)\n\t" << DeferredChanges
118 << " potentially conflicting change(s) deferred.\n\t"
119 << RejectedChanges << " change(s) rejected.\n";
120 if (DeferredChanges > 0)
121 llvm::outs() << "Re-run this tool to attempt applying deferred changes.\n";
122 if (RejectedChanges > 0)
123 llvm::outs() << "Re-run this tool with a lower required confidence level "
124 "to apply rejected changes.\n";
126 if (AcceptedChanges > 0) {
127 // Check to see if the changes introduced any new errors.
128 ClangTool EndSyntaxTool(*Compilations, SourcePaths);
129 if (int result = EndSyntaxTool.run(
130 newFrontendActionFactory<clang::SyntaxOnlyAction>())) {
131 llvm::errs() << "Error compiling files after translation.\n";