xref: /minix3/external/bsd/llvm/dist/clang/tools/arcmt-test/arcmt-test.cpp (revision f4a2713ac843a11c696ec80c0a5e3e5d80b4d338)
1*f4a2713aSLionel Sambuc //===-- arcmt-test.cpp - ARC Migration Tool testbed -----------------------===//
2*f4a2713aSLionel Sambuc //
3*f4a2713aSLionel Sambuc //                     The LLVM Compiler Infrastructure
4*f4a2713aSLionel Sambuc //
5*f4a2713aSLionel Sambuc // This file is distributed under the University of Illinois Open Source
6*f4a2713aSLionel Sambuc // License. See LICENSE.TXT for details.
7*f4a2713aSLionel Sambuc //
8*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
9*f4a2713aSLionel Sambuc 
10*f4a2713aSLionel Sambuc #include "clang/ARCMigrate/ARCMT.h"
11*f4a2713aSLionel Sambuc #include "clang/Frontend/ASTUnit.h"
12*f4a2713aSLionel Sambuc #include "clang/Frontend/TextDiagnosticPrinter.h"
13*f4a2713aSLionel Sambuc #include "clang/Frontend/Utils.h"
14*f4a2713aSLionel Sambuc #include "clang/Frontend/VerifyDiagnosticConsumer.h"
15*f4a2713aSLionel Sambuc #include "clang/Lex/Preprocessor.h"
16*f4a2713aSLionel Sambuc #include "llvm/Support/FileSystem.h"
17*f4a2713aSLionel Sambuc #include "llvm/Support/MemoryBuffer.h"
18*f4a2713aSLionel Sambuc #include "llvm/Support/Signals.h"
19*f4a2713aSLionel Sambuc #include "llvm/Support/system_error.h"
20*f4a2713aSLionel Sambuc 
21*f4a2713aSLionel Sambuc using namespace clang;
22*f4a2713aSLionel Sambuc using namespace arcmt;
23*f4a2713aSLionel Sambuc 
24*f4a2713aSLionel Sambuc static llvm::cl::opt<bool>
25*f4a2713aSLionel Sambuc CheckOnly("check-only",
26*f4a2713aSLionel Sambuc       llvm::cl::desc("Just check for issues that need to be handled manually"));
27*f4a2713aSLionel Sambuc 
28*f4a2713aSLionel Sambuc //static llvm::cl::opt<bool>
29*f4a2713aSLionel Sambuc //TestResultForARC("test-result",
30*f4a2713aSLionel Sambuc //llvm::cl::desc("Test the result of transformations by parsing it in ARC mode"));
31*f4a2713aSLionel Sambuc 
32*f4a2713aSLionel Sambuc static llvm::cl::opt<bool>
33*f4a2713aSLionel Sambuc OutputTransformations("output-transformations",
34*f4a2713aSLionel Sambuc                       llvm::cl::desc("Print the source transformations"));
35*f4a2713aSLionel Sambuc 
36*f4a2713aSLionel Sambuc static llvm::cl::opt<bool>
37*f4a2713aSLionel Sambuc VerifyDiags("verify",llvm::cl::desc("Verify emitted diagnostics and warnings"));
38*f4a2713aSLionel Sambuc 
39*f4a2713aSLionel Sambuc static llvm::cl::opt<bool>
40*f4a2713aSLionel Sambuc VerboseOpt("v", llvm::cl::desc("Enable verbose output"));
41*f4a2713aSLionel Sambuc 
42*f4a2713aSLionel Sambuc static llvm::cl::opt<bool>
43*f4a2713aSLionel Sambuc VerifyTransformedFiles("verify-transformed-files",
44*f4a2713aSLionel Sambuc llvm::cl::desc("Read pairs of file mappings (typically the output of "
45*f4a2713aSLionel Sambuc                "c-arcmt-test) and compare their contents with the filenames "
46*f4a2713aSLionel Sambuc                "provided in command-line"));
47*f4a2713aSLionel Sambuc 
48*f4a2713aSLionel Sambuc static llvm::cl::opt<std::string>
49*f4a2713aSLionel Sambuc RemappingsFile("remappings-file",
50*f4a2713aSLionel Sambuc                llvm::cl::desc("Pairs of file mappings (typically the output of "
51*f4a2713aSLionel Sambuc                "c-arcmt-test)"));
52*f4a2713aSLionel Sambuc 
53*f4a2713aSLionel Sambuc static llvm::cl::list<std::string>
54*f4a2713aSLionel Sambuc ResultFiles(llvm::cl::Positional, llvm::cl::desc("<filename>..."));
55*f4a2713aSLionel Sambuc 
56*f4a2713aSLionel Sambuc static llvm::cl::extrahelp extraHelp(
57*f4a2713aSLionel Sambuc   "\nusage with compiler args: arcmt-test [options] --args [compiler flags]\n");
58*f4a2713aSLionel Sambuc 
59*f4a2713aSLionel Sambuc // This function isn't referenced outside its translation unit, but it
60*f4a2713aSLionel Sambuc // can't use the "static" keyword because its address is used for
61*f4a2713aSLionel Sambuc // GetMainExecutable (since some platforms don't support taking the
62*f4a2713aSLionel Sambuc // address of main, and some platforms can't implement GetMainExecutable
63*f4a2713aSLionel Sambuc // without being given the address of a function in the main executable).
64*f4a2713aSLionel Sambuc std::string GetExecutablePath(const char *Argv0) {
65*f4a2713aSLionel Sambuc   // This just needs to be some symbol in the binary; C++ doesn't
66*f4a2713aSLionel Sambuc   // allow taking the address of ::main however.
67*f4a2713aSLionel Sambuc   void *MainAddr = (void*) (intptr_t) GetExecutablePath;
68*f4a2713aSLionel Sambuc   return llvm::sys::fs::getMainExecutable(Argv0, MainAddr);
69*f4a2713aSLionel Sambuc }
70*f4a2713aSLionel Sambuc 
71*f4a2713aSLionel Sambuc static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
72*f4a2713aSLionel Sambuc                                 raw_ostream &OS);
73*f4a2713aSLionel Sambuc static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
74*f4a2713aSLionel Sambuc                              raw_ostream &OS);
75*f4a2713aSLionel Sambuc 
76*f4a2713aSLionel Sambuc namespace {
77*f4a2713aSLionel Sambuc 
78*f4a2713aSLionel Sambuc class PrintTransforms : public MigrationProcess::RewriteListener {
79*f4a2713aSLionel Sambuc   ASTContext *Ctx;
80*f4a2713aSLionel Sambuc   raw_ostream &OS;
81*f4a2713aSLionel Sambuc 
82*f4a2713aSLionel Sambuc public:
83*f4a2713aSLionel Sambuc   PrintTransforms(raw_ostream &OS)
84*f4a2713aSLionel Sambuc     : Ctx(0), OS(OS) { }
85*f4a2713aSLionel Sambuc 
86*f4a2713aSLionel Sambuc   virtual void start(ASTContext &ctx) { Ctx = &ctx; }
87*f4a2713aSLionel Sambuc   virtual void finish() { Ctx = 0; }
88*f4a2713aSLionel Sambuc 
89*f4a2713aSLionel Sambuc   virtual void insert(SourceLocation loc, StringRef text) {
90*f4a2713aSLionel Sambuc     assert(Ctx);
91*f4a2713aSLionel Sambuc     OS << "Insert: ";
92*f4a2713aSLionel Sambuc     printSourceLocation(loc, *Ctx, OS);
93*f4a2713aSLionel Sambuc     OS << " \"" << text << "\"\n";
94*f4a2713aSLionel Sambuc   }
95*f4a2713aSLionel Sambuc 
96*f4a2713aSLionel Sambuc   virtual void remove(CharSourceRange range) {
97*f4a2713aSLionel Sambuc     assert(Ctx);
98*f4a2713aSLionel Sambuc     OS << "Remove: ";
99*f4a2713aSLionel Sambuc     printSourceRange(range, *Ctx, OS);
100*f4a2713aSLionel Sambuc     OS << '\n';
101*f4a2713aSLionel Sambuc   }
102*f4a2713aSLionel Sambuc };
103*f4a2713aSLionel Sambuc 
104*f4a2713aSLionel Sambuc } // anonymous namespace
105*f4a2713aSLionel Sambuc 
106*f4a2713aSLionel Sambuc static bool checkForMigration(StringRef resourcesPath,
107*f4a2713aSLionel Sambuc                               ArrayRef<const char *> Args) {
108*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
109*f4a2713aSLionel Sambuc   DiagnosticConsumer *DiagClient =
110*f4a2713aSLionel Sambuc     new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
111*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
112*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticsEngine> Diags(
113*f4a2713aSLionel Sambuc       new DiagnosticsEngine(DiagID, &*DiagOpts, DiagClient));
114*f4a2713aSLionel Sambuc   // Chain in -verify checker, if requested.
115*f4a2713aSLionel Sambuc   VerifyDiagnosticConsumer *verifyDiag = 0;
116*f4a2713aSLionel Sambuc   if (VerifyDiags) {
117*f4a2713aSLionel Sambuc     verifyDiag = new VerifyDiagnosticConsumer(*Diags);
118*f4a2713aSLionel Sambuc     Diags->setClient(verifyDiag);
119*f4a2713aSLionel Sambuc   }
120*f4a2713aSLionel Sambuc 
121*f4a2713aSLionel Sambuc   CompilerInvocation CI;
122*f4a2713aSLionel Sambuc   if (!CompilerInvocation::CreateFromArgs(CI, Args.begin(), Args.end(), *Diags))
123*f4a2713aSLionel Sambuc     return true;
124*f4a2713aSLionel Sambuc 
125*f4a2713aSLionel Sambuc   if (CI.getFrontendOpts().Inputs.empty()) {
126*f4a2713aSLionel Sambuc     llvm::errs() << "error: no input files\n";
127*f4a2713aSLionel Sambuc     return true;
128*f4a2713aSLionel Sambuc   }
129*f4a2713aSLionel Sambuc 
130*f4a2713aSLionel Sambuc   if (!CI.getLangOpts()->ObjC1)
131*f4a2713aSLionel Sambuc     return false;
132*f4a2713aSLionel Sambuc 
133*f4a2713aSLionel Sambuc   arcmt::checkForManualIssues(CI, CI.getFrontendOpts().Inputs[0],
134*f4a2713aSLionel Sambuc                               Diags->getClient());
135*f4a2713aSLionel Sambuc   return Diags->getClient()->getNumErrors() > 0;
136*f4a2713aSLionel Sambuc }
137*f4a2713aSLionel Sambuc 
138*f4a2713aSLionel Sambuc static void printResult(FileRemapper &remapper, raw_ostream &OS) {
139*f4a2713aSLionel Sambuc   PreprocessorOptions PPOpts;
140*f4a2713aSLionel Sambuc   remapper.applyMappings(PPOpts);
141*f4a2713aSLionel Sambuc   // The changed files will be in memory buffers, print them.
142*f4a2713aSLionel Sambuc   for (unsigned i = 0, e = PPOpts.RemappedFileBuffers.size(); i != e; ++i) {
143*f4a2713aSLionel Sambuc     const llvm::MemoryBuffer *mem = PPOpts.RemappedFileBuffers[i].second;
144*f4a2713aSLionel Sambuc     OS << mem->getBuffer();
145*f4a2713aSLionel Sambuc   }
146*f4a2713aSLionel Sambuc }
147*f4a2713aSLionel Sambuc 
148*f4a2713aSLionel Sambuc static bool performTransformations(StringRef resourcesPath,
149*f4a2713aSLionel Sambuc                                    ArrayRef<const char *> Args) {
150*f4a2713aSLionel Sambuc   // Check first.
151*f4a2713aSLionel Sambuc   if (checkForMigration(resourcesPath, Args))
152*f4a2713aSLionel Sambuc     return true;
153*f4a2713aSLionel Sambuc 
154*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
155*f4a2713aSLionel Sambuc   DiagnosticConsumer *DiagClient =
156*f4a2713aSLionel Sambuc     new TextDiagnosticPrinter(llvm::errs(), &*DiagOpts);
157*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
158*f4a2713aSLionel Sambuc   IntrusiveRefCntPtr<DiagnosticsEngine> TopDiags(
159*f4a2713aSLionel Sambuc       new DiagnosticsEngine(DiagID, &*DiagOpts, &*DiagClient));
160*f4a2713aSLionel Sambuc 
161*f4a2713aSLionel Sambuc   CompilerInvocation origCI;
162*f4a2713aSLionel Sambuc   if (!CompilerInvocation::CreateFromArgs(origCI, Args.begin(), Args.end(),
163*f4a2713aSLionel Sambuc                                      *TopDiags))
164*f4a2713aSLionel Sambuc     return true;
165*f4a2713aSLionel Sambuc 
166*f4a2713aSLionel Sambuc   if (origCI.getFrontendOpts().Inputs.empty()) {
167*f4a2713aSLionel Sambuc     llvm::errs() << "error: no input files\n";
168*f4a2713aSLionel Sambuc     return true;
169*f4a2713aSLionel Sambuc   }
170*f4a2713aSLionel Sambuc 
171*f4a2713aSLionel Sambuc   if (!origCI.getLangOpts()->ObjC1)
172*f4a2713aSLionel Sambuc     return false;
173*f4a2713aSLionel Sambuc 
174*f4a2713aSLionel Sambuc   MigrationProcess migration(origCI, DiagClient);
175*f4a2713aSLionel Sambuc 
176*f4a2713aSLionel Sambuc   std::vector<TransformFn>
177*f4a2713aSLionel Sambuc     transforms = arcmt::getAllTransformations(origCI.getLangOpts()->getGC(),
178*f4a2713aSLionel Sambuc                                  origCI.getMigratorOpts().NoFinalizeRemoval);
179*f4a2713aSLionel Sambuc   assert(!transforms.empty());
180*f4a2713aSLionel Sambuc 
181*f4a2713aSLionel Sambuc   OwningPtr<PrintTransforms> transformPrinter;
182*f4a2713aSLionel Sambuc   if (OutputTransformations)
183*f4a2713aSLionel Sambuc     transformPrinter.reset(new PrintTransforms(llvm::outs()));
184*f4a2713aSLionel Sambuc 
185*f4a2713aSLionel Sambuc   for (unsigned i=0, e = transforms.size(); i != e; ++i) {
186*f4a2713aSLionel Sambuc     bool err = migration.applyTransform(transforms[i], transformPrinter.get());
187*f4a2713aSLionel Sambuc     if (err) return true;
188*f4a2713aSLionel Sambuc 
189*f4a2713aSLionel Sambuc     if (VerboseOpt) {
190*f4a2713aSLionel Sambuc       if (i == e-1)
191*f4a2713aSLionel Sambuc         llvm::errs() << "\n##### FINAL RESULT #####\n";
192*f4a2713aSLionel Sambuc       else
193*f4a2713aSLionel Sambuc         llvm::errs() << "\n##### OUTPUT AFTER "<< i+1 <<". TRANSFORMATION #####\n";
194*f4a2713aSLionel Sambuc       printResult(migration.getRemapper(), llvm::errs());
195*f4a2713aSLionel Sambuc       llvm::errs() << "\n##########################\n\n";
196*f4a2713aSLionel Sambuc     }
197*f4a2713aSLionel Sambuc   }
198*f4a2713aSLionel Sambuc 
199*f4a2713aSLionel Sambuc   if (!OutputTransformations)
200*f4a2713aSLionel Sambuc     printResult(migration.getRemapper(), llvm::outs());
201*f4a2713aSLionel Sambuc 
202*f4a2713aSLionel Sambuc   // FIXME: TestResultForARC
203*f4a2713aSLionel Sambuc 
204*f4a2713aSLionel Sambuc   return false;
205*f4a2713aSLionel Sambuc }
206*f4a2713aSLionel Sambuc 
207*f4a2713aSLionel Sambuc static bool filesCompareEqual(StringRef fname1, StringRef fname2) {
208*f4a2713aSLionel Sambuc   using namespace llvm;
209*f4a2713aSLionel Sambuc 
210*f4a2713aSLionel Sambuc   OwningPtr<MemoryBuffer> file1;
211*f4a2713aSLionel Sambuc   MemoryBuffer::getFile(fname1, file1);
212*f4a2713aSLionel Sambuc   if (!file1)
213*f4a2713aSLionel Sambuc     return false;
214*f4a2713aSLionel Sambuc 
215*f4a2713aSLionel Sambuc   OwningPtr<MemoryBuffer> file2;
216*f4a2713aSLionel Sambuc   MemoryBuffer::getFile(fname2, file2);
217*f4a2713aSLionel Sambuc   if (!file2)
218*f4a2713aSLionel Sambuc     return false;
219*f4a2713aSLionel Sambuc 
220*f4a2713aSLionel Sambuc   return file1->getBuffer() == file2->getBuffer();
221*f4a2713aSLionel Sambuc }
222*f4a2713aSLionel Sambuc 
223*f4a2713aSLionel Sambuc static bool verifyTransformedFiles(ArrayRef<std::string> resultFiles) {
224*f4a2713aSLionel Sambuc   using namespace llvm;
225*f4a2713aSLionel Sambuc 
226*f4a2713aSLionel Sambuc   assert(!resultFiles.empty());
227*f4a2713aSLionel Sambuc 
228*f4a2713aSLionel Sambuc   std::map<StringRef, StringRef> resultMap;
229*f4a2713aSLionel Sambuc 
230*f4a2713aSLionel Sambuc   for (ArrayRef<std::string>::iterator
231*f4a2713aSLionel Sambuc          I = resultFiles.begin(), E = resultFiles.end(); I != E; ++I) {
232*f4a2713aSLionel Sambuc     StringRef fname(*I);
233*f4a2713aSLionel Sambuc     if (!fname.endswith(".result")) {
234*f4a2713aSLionel Sambuc       errs() << "error: filename '" << fname
235*f4a2713aSLionel Sambuc                    << "' does not have '.result' extension\n";
236*f4a2713aSLionel Sambuc       return true;
237*f4a2713aSLionel Sambuc     }
238*f4a2713aSLionel Sambuc     resultMap[sys::path::stem(fname)] = fname;
239*f4a2713aSLionel Sambuc   }
240*f4a2713aSLionel Sambuc 
241*f4a2713aSLionel Sambuc   OwningPtr<MemoryBuffer> inputBuf;
242*f4a2713aSLionel Sambuc   if (RemappingsFile.empty())
243*f4a2713aSLionel Sambuc     MemoryBuffer::getSTDIN(inputBuf);
244*f4a2713aSLionel Sambuc   else
245*f4a2713aSLionel Sambuc     MemoryBuffer::getFile(RemappingsFile, inputBuf);
246*f4a2713aSLionel Sambuc   if (!inputBuf) {
247*f4a2713aSLionel Sambuc     errs() << "error: could not read remappings input\n";
248*f4a2713aSLionel Sambuc     return true;
249*f4a2713aSLionel Sambuc   }
250*f4a2713aSLionel Sambuc 
251*f4a2713aSLionel Sambuc   SmallVector<StringRef, 8> strs;
252*f4a2713aSLionel Sambuc   inputBuf->getBuffer().split(strs, "\n", /*MaxSplit=*/-1, /*KeepEmpty=*/false);
253*f4a2713aSLionel Sambuc 
254*f4a2713aSLionel Sambuc   if (strs.empty()) {
255*f4a2713aSLionel Sambuc     errs() << "error: no files to verify from stdin\n";
256*f4a2713aSLionel Sambuc     return true;
257*f4a2713aSLionel Sambuc   }
258*f4a2713aSLionel Sambuc   if (strs.size() % 2 != 0) {
259*f4a2713aSLionel Sambuc     errs() << "error: files to verify are not original/result pairs\n";
260*f4a2713aSLionel Sambuc     return true;
261*f4a2713aSLionel Sambuc   }
262*f4a2713aSLionel Sambuc 
263*f4a2713aSLionel Sambuc   for (unsigned i = 0, e = strs.size(); i != e; i += 2) {
264*f4a2713aSLionel Sambuc     StringRef inputOrigFname = strs[i];
265*f4a2713aSLionel Sambuc     StringRef inputResultFname = strs[i+1];
266*f4a2713aSLionel Sambuc 
267*f4a2713aSLionel Sambuc     std::map<StringRef, StringRef>::iterator It;
268*f4a2713aSLionel Sambuc     It = resultMap.find(sys::path::filename(inputOrigFname));
269*f4a2713aSLionel Sambuc     if (It == resultMap.end()) {
270*f4a2713aSLionel Sambuc       errs() << "error: '" << inputOrigFname << "' is not in the list of "
271*f4a2713aSLionel Sambuc              << "transformed files to verify\n";
272*f4a2713aSLionel Sambuc       return true;
273*f4a2713aSLionel Sambuc     }
274*f4a2713aSLionel Sambuc 
275*f4a2713aSLionel Sambuc     bool exists = false;
276*f4a2713aSLionel Sambuc     sys::fs::exists(It->second, exists);
277*f4a2713aSLionel Sambuc     if (!exists) {
278*f4a2713aSLionel Sambuc       errs() << "error: '" << It->second << "' does not exist\n";
279*f4a2713aSLionel Sambuc       return true;
280*f4a2713aSLionel Sambuc     }
281*f4a2713aSLionel Sambuc     sys::fs::exists(inputResultFname, exists);
282*f4a2713aSLionel Sambuc     if (!exists) {
283*f4a2713aSLionel Sambuc       errs() << "error: '" << inputResultFname << "' does not exist\n";
284*f4a2713aSLionel Sambuc       return true;
285*f4a2713aSLionel Sambuc     }
286*f4a2713aSLionel Sambuc 
287*f4a2713aSLionel Sambuc     if (!filesCompareEqual(It->second, inputResultFname)) {
288*f4a2713aSLionel Sambuc       errs() << "error: '" << It->second << "' is different than "
289*f4a2713aSLionel Sambuc              << "'" << inputResultFname << "'\n";
290*f4a2713aSLionel Sambuc       return true;
291*f4a2713aSLionel Sambuc     }
292*f4a2713aSLionel Sambuc 
293*f4a2713aSLionel Sambuc     resultMap.erase(It);
294*f4a2713aSLionel Sambuc   }
295*f4a2713aSLionel Sambuc 
296*f4a2713aSLionel Sambuc   if (!resultMap.empty()) {
297*f4a2713aSLionel Sambuc     for (std::map<StringRef, StringRef>::iterator
298*f4a2713aSLionel Sambuc            I = resultMap.begin(), E = resultMap.end(); I != E; ++I)
299*f4a2713aSLionel Sambuc       errs() << "error: '" << I->second << "' was not verified!\n";
300*f4a2713aSLionel Sambuc     return true;
301*f4a2713aSLionel Sambuc   }
302*f4a2713aSLionel Sambuc 
303*f4a2713aSLionel Sambuc   return false;
304*f4a2713aSLionel Sambuc }
305*f4a2713aSLionel Sambuc 
306*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
307*f4a2713aSLionel Sambuc // Misc. functions.
308*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
309*f4a2713aSLionel Sambuc 
310*f4a2713aSLionel Sambuc static void printSourceLocation(SourceLocation loc, ASTContext &Ctx,
311*f4a2713aSLionel Sambuc                                 raw_ostream &OS) {
312*f4a2713aSLionel Sambuc   SourceManager &SM = Ctx.getSourceManager();
313*f4a2713aSLionel Sambuc   PresumedLoc PL = SM.getPresumedLoc(loc);
314*f4a2713aSLionel Sambuc 
315*f4a2713aSLionel Sambuc   OS << llvm::sys::path::filename(PL.getFilename());
316*f4a2713aSLionel Sambuc   OS << ":" << PL.getLine() << ":"
317*f4a2713aSLionel Sambuc             << PL.getColumn();
318*f4a2713aSLionel Sambuc }
319*f4a2713aSLionel Sambuc 
320*f4a2713aSLionel Sambuc static void printSourceRange(CharSourceRange range, ASTContext &Ctx,
321*f4a2713aSLionel Sambuc                              raw_ostream &OS) {
322*f4a2713aSLionel Sambuc   SourceManager &SM = Ctx.getSourceManager();
323*f4a2713aSLionel Sambuc   const LangOptions &langOpts = Ctx.getLangOpts();
324*f4a2713aSLionel Sambuc 
325*f4a2713aSLionel Sambuc   PresumedLoc PL = SM.getPresumedLoc(range.getBegin());
326*f4a2713aSLionel Sambuc 
327*f4a2713aSLionel Sambuc   OS << llvm::sys::path::filename(PL.getFilename());
328*f4a2713aSLionel Sambuc   OS << " [" << PL.getLine() << ":"
329*f4a2713aSLionel Sambuc              << PL.getColumn();
330*f4a2713aSLionel Sambuc   OS << " - ";
331*f4a2713aSLionel Sambuc 
332*f4a2713aSLionel Sambuc   SourceLocation end = range.getEnd();
333*f4a2713aSLionel Sambuc   PL = SM.getPresumedLoc(end);
334*f4a2713aSLionel Sambuc 
335*f4a2713aSLionel Sambuc   unsigned endCol = PL.getColumn() - 1;
336*f4a2713aSLionel Sambuc   if (!range.isTokenRange())
337*f4a2713aSLionel Sambuc     endCol += Lexer::MeasureTokenLength(end, SM, langOpts);
338*f4a2713aSLionel Sambuc   OS << PL.getLine() << ":" << endCol << "]";
339*f4a2713aSLionel Sambuc }
340*f4a2713aSLionel Sambuc 
341*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
342*f4a2713aSLionel Sambuc // Command line processing.
343*f4a2713aSLionel Sambuc //===----------------------------------------------------------------------===//
344*f4a2713aSLionel Sambuc 
345*f4a2713aSLionel Sambuc int main(int argc, const char **argv) {
346*f4a2713aSLionel Sambuc   void *MainAddr = (void*) (intptr_t) GetExecutablePath;
347*f4a2713aSLionel Sambuc   llvm::sys::PrintStackTraceOnErrorSignal();
348*f4a2713aSLionel Sambuc 
349*f4a2713aSLionel Sambuc   std::string
350*f4a2713aSLionel Sambuc     resourcesPath = CompilerInvocation::GetResourcesPath(argv[0], MainAddr);
351*f4a2713aSLionel Sambuc 
352*f4a2713aSLionel Sambuc   int optargc = 0;
353*f4a2713aSLionel Sambuc   for (; optargc != argc; ++optargc) {
354*f4a2713aSLionel Sambuc     if (StringRef(argv[optargc]) == "--args")
355*f4a2713aSLionel Sambuc       break;
356*f4a2713aSLionel Sambuc   }
357*f4a2713aSLionel Sambuc   llvm::cl::ParseCommandLineOptions(optargc, argv, "arcmt-test");
358*f4a2713aSLionel Sambuc 
359*f4a2713aSLionel Sambuc   if (VerifyTransformedFiles) {
360*f4a2713aSLionel Sambuc     if (ResultFiles.empty()) {
361*f4a2713aSLionel Sambuc       llvm::cl::PrintHelpMessage();
362*f4a2713aSLionel Sambuc       return 1;
363*f4a2713aSLionel Sambuc     }
364*f4a2713aSLionel Sambuc     return verifyTransformedFiles(ResultFiles);
365*f4a2713aSLionel Sambuc   }
366*f4a2713aSLionel Sambuc 
367*f4a2713aSLionel Sambuc   if (optargc == argc) {
368*f4a2713aSLionel Sambuc     llvm::cl::PrintHelpMessage();
369*f4a2713aSLionel Sambuc     return 1;
370*f4a2713aSLionel Sambuc   }
371*f4a2713aSLionel Sambuc 
372*f4a2713aSLionel Sambuc   ArrayRef<const char*> Args(argv+optargc+1, argc-optargc-1);
373*f4a2713aSLionel Sambuc 
374*f4a2713aSLionel Sambuc   if (CheckOnly)
375*f4a2713aSLionel Sambuc     return checkForMigration(resourcesPath, Args);
376*f4a2713aSLionel Sambuc 
377*f4a2713aSLionel Sambuc   return performTransformations(resourcesPath, Args);
378*f4a2713aSLionel Sambuc }
379