Fixes according to code review comments
[lldb.git] / clang-tools-extra / loop-convert / LoopConvert.cpp
1 //===-- loop-convert/LoopConvert.cpp - C++11 For loop migration -*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements a tool that migrates for loops to take advantage of the
11 // range-basead syntax new to C++11.
12 //
13 // Usage:
14 // loop-convert <cmake-output-dir> <file1> <file2> ...
15 //
16 // Where <cmake-output-dir> is a CMake build directory containing a file named
17 // compile_commands.json.
18 //
19 // <file1>... specify the pahs of files in the CMake source tree, with the same
20 // requirements as other tools built on LibTooling.
21 //
22 //===----------------------------------------------------------------------===//
23
24 #include "LoopActions.h"
25 #include "LoopMatchers.h"
26
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"
32
33 using clang::ast_matchers::MatchFinder;
34 namespace cl = llvm::cl;
35 using namespace clang::tooling;
36 using namespace clang::loop_migrate;
37
38 static cl::opt<std::string> BuildPath(
39     cl::Positional,
40     cl::desc("<build-path>"));
41
42 static cl::list<std::string> SourcePaths(
43     cl::Positional,
44     cl::desc("<source0> [... <sourceN>]"),
45     cl::OneOrMore);
46
47 // General options go here:
48 static cl::opt<bool> CountOnly(
49     "count-only", cl::desc("Do not apply transformations; only count them."));
50
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 "
56                          "(default)"),
57                clEnumValN(TCK_Risky, "A2",
58                           "Enable transformations that are likely "
59                           "to change semantics"),
60                clEnumValEnd),
61     cl::init(TCK_Reasonable));
62
63 int main(int argc, const char **argv) {
64   llvm::OwningPtr<CompilationDatabase> Compilations(
65       FixedCompilationDatabase::loadFromCommandLine(argc, argv));
66   cl::ParseCommandLineOptions(argc, argv);
67   if (!Compilations) {
68     std::string ErrorMessage;
69     Compilations.reset(
70         !BuildPath.empty() ?
71         CompilationDatabase::autoDetectFromDirectory(BuildPath, ErrorMessage) :
72         CompilationDatabase::autoDetectFromSource(SourcePaths[0],
73                                                   ErrorMessage));
74     if (!Compilations)
75       llvm::report_fatal_error(ErrorMessage);
76   }
77   ClangTool SyntaxTool(*Compilations, SourcePaths);
78
79   // First, let's check to make sure there were no errors.
80   if (int result =
81         SyntaxTool.run(newFrontendActionFactory<clang::SyntaxOnlyAction>())) {
82     llvm::errs() << "Error compiling files.\n";
83     return result;
84   }
85
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;
93
94   MatchFinder Finder;
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";
113     return result;
114   }
115
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";
125
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";
132       return result;
133     }
134   }
135
136   return 0;
137 }