FrontendActions.cpp revision e127a0d80155b45dafe77f2b4380e5fa111a3345
1//===--- FrontendActions.cpp ----------------------------------------------===//
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#include "clang/Frontend/FrontendActions.h"
11#include "clang/AST/ASTConsumer.h"
12#include "clang/Lex/Preprocessor.h"
13#include "clang/Parse/Parser.h"
14#include "clang/Basic/FileManager.h"
15#include "clang/Frontend/AnalysisConsumer.h"
16#include "clang/Frontend/ASTConsumers.h"
17#include "clang/Frontend/ASTUnit.h"
18#include "clang/Frontend/CompilerInstance.h"
19#include "clang/Frontend/FixItRewriter.h"
20#include "clang/Frontend/FrontendDiagnostic.h"
21#include "clang/Frontend/Utils.h"
22#include "llvm/Support/raw_ostream.h"
23using namespace clang;
24
25//===----------------------------------------------------------------------===//
26// Custom Actions
27//===----------------------------------------------------------------------===//
28
29ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
30                                               llvm::StringRef InFile) {
31  return new ASTConsumer();
32}
33
34void InitOnlyAction::ExecuteAction() {
35}
36
37//===----------------------------------------------------------------------===//
38// AST Consumer Actions
39//===----------------------------------------------------------------------===//
40
41ASTConsumer *AnalysisAction::CreateASTConsumer(CompilerInstance &CI,
42                                               llvm::StringRef InFile) {
43  return CreateAnalysisConsumer(CI.getPreprocessor(),
44                                CI.getFrontendOpts().OutputFile,
45                                CI.getAnalyzerOpts());
46}
47
48ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
49                                               llvm::StringRef InFile) {
50  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
51    return CreateASTPrinter(OS);
52  return 0;
53}
54
55ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
56                                                  llvm::StringRef InFile) {
57  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
58    return CreateASTPrinterXML(OS);
59  return 0;
60}
61
62ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
63                                              llvm::StringRef InFile) {
64  return CreateASTDumper();
65}
66
67ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
68                                              llvm::StringRef InFile) {
69  return CreateASTViewer();
70}
71
72ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
73                                                       llvm::StringRef InFile) {
74  return CreateDeclContextPrinter();
75}
76
77ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
78                                                  llvm::StringRef InFile) {
79  const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
80  if (CI.getFrontendOpts().RelocatablePCH &&
81      Sysroot.empty()) {
82    CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
83    return 0;
84  }
85
86  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
87  if (!OS)
88    return 0;
89
90  if (CI.getFrontendOpts().RelocatablePCH)
91    return CreatePCHGenerator(CI.getPreprocessor(), OS, Sysroot.c_str());
92
93  return CreatePCHGenerator(CI.getPreprocessor(), OS);
94}
95
96ASTConsumer *HTMLPrintAction::CreateASTConsumer(CompilerInstance &CI,
97                                                llvm::StringRef InFile) {
98  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
99    return CreateHTMLPrinter(OS, CI.getPreprocessor());
100  return 0;
101}
102
103ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
104                                                      llvm::StringRef InFile) {
105  return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
106}
107
108FixItAction::FixItAction() {}
109FixItAction::~FixItAction() {}
110
111ASTConsumer *FixItAction::CreateASTConsumer(CompilerInstance &CI,
112                                            llvm::StringRef InFile) {
113  return new ASTConsumer();
114}
115
116/// AddFixItLocations - Add any individual user specified "fix-it" locations,
117/// and return true on success.
118static bool AddFixItLocations(CompilerInstance &CI,
119                              FixItRewriter &FixItRewrite) {
120  const std::vector<ParsedSourceLocation> &Locs =
121    CI.getFrontendOpts().FixItLocations;
122  for (unsigned i = 0, e = Locs.size(); i != e; ++i) {
123    const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName);
124    if (!File) {
125      CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file)
126        << Locs[i].FileName;
127      return false;
128    }
129
130    RequestedSourceLocation Requested;
131    Requested.File = File;
132    Requested.Line = Locs[i].Line;
133    Requested.Column = Locs[i].Column;
134    FixItRewrite.addFixItLocation(Requested);
135  }
136
137  const std::string &OutputFile = CI.getFrontendOpts().OutputFile;
138  if (Locs.empty() && !OutputFile.empty()) {
139    // FIXME: we will issue "FIX-IT applied suggested code changes" for every
140    // input, but only the main file will actually be rewritten.
141    const std::vector<std::pair<FrontendOptions::InputKind, std::string> > &Inputs =
142      CI.getFrontendOpts().Inputs;
143    for (unsigned i = 0, e = Inputs.size(); i != e; ++i) {
144      const FileEntry *File = CI.getFileManager().getFile(Inputs[i].second);
145      assert(File && "Input file not found in FileManager");
146      RequestedSourceLocation Requested;
147      Requested.File = File;
148      Requested.Line = 0;
149      Requested.Column = 0;
150      FixItRewrite.addFixItLocation(Requested);
151    }
152  }
153
154  return true;
155}
156
157bool FixItAction::BeginSourceFileAction(CompilerInstance &CI,
158                                        llvm::StringRef Filename) {
159  Rewriter.reset(new FixItRewriter(CI.getDiagnostics(), CI.getSourceManager(),
160                                   CI.getLangOpts()));
161  if (!AddFixItLocations(CI, *Rewriter))
162    return false;
163
164  return true;
165}
166
167void FixItAction::EndSourceFileAction() {
168  const FrontendOptions &FEOpts = getCompilerInstance().getFrontendOpts();
169  if (!FEOpts.OutputFile.empty()) {
170    // When called with 'clang -fixit -o filename' output only the main file.
171
172    const SourceManager &SM = getCompilerInstance().getSourceManager();
173    FileID MainFileID = SM.getMainFileID();
174    if (!Rewriter->IsModified(MainFileID)) {
175      getCompilerInstance().getDiagnostics().Report(
176          diag::note_fixit_main_file_unchanged);
177      return;
178    }
179
180    llvm::OwningPtr<llvm::raw_ostream> OwnedStream;
181    llvm::raw_ostream *OutFile;
182    if (FEOpts.OutputFile == "-") {
183      OutFile = &llvm::outs();
184    } else {
185      std::string Err;
186      OutFile = new llvm::raw_fd_ostream(FEOpts.OutputFile.c_str(), Err,
187                                         llvm::raw_fd_ostream::F_Binary);
188      OwnedStream.reset(OutFile);
189    }
190
191    Rewriter->WriteFixedFile(MainFileID, *OutFile);
192    return;
193  }
194
195  // Otherwise rewrite all files.
196  Rewriter->WriteFixedFiles();
197}
198
199ASTConsumer *RewriteObjCAction::CreateASTConsumer(CompilerInstance &CI,
200                                                  llvm::StringRef InFile) {
201  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "cpp"))
202    return CreateObjCRewriter(InFile, OS,
203                              CI.getDiagnostics(), CI.getLangOpts(),
204                              CI.getDiagnosticOpts().NoRewriteMacros);
205  return 0;
206}
207
208ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
209                                                 llvm::StringRef InFile) {
210  return new ASTConsumer();
211}
212
213//===----------------------------------------------------------------------===//
214// Preprocessor Actions
215//===----------------------------------------------------------------------===//
216
217void DumpRawTokensAction::ExecuteAction() {
218  Preprocessor &PP = getCompilerInstance().getPreprocessor();
219  SourceManager &SM = PP.getSourceManager();
220
221  // Start lexing the specified input file.
222  const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
223  Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
224  RawLex.SetKeepWhitespaceMode(true);
225
226  Token RawTok;
227  RawLex.LexFromRawLexer(RawTok);
228  while (RawTok.isNot(tok::eof)) {
229    PP.DumpToken(RawTok, true);
230    llvm::errs() << "\n";
231    RawLex.LexFromRawLexer(RawTok);
232  }
233}
234
235void DumpTokensAction::ExecuteAction() {
236  Preprocessor &PP = getCompilerInstance().getPreprocessor();
237  // Start preprocessing the specified input file.
238  Token Tok;
239  PP.EnterMainSourceFile();
240  do {
241    PP.Lex(Tok);
242    PP.DumpToken(Tok, true);
243    llvm::errs() << "\n";
244  } while (Tok.isNot(tok::eof));
245}
246
247void GeneratePTHAction::ExecuteAction() {
248  CompilerInstance &CI = getCompilerInstance();
249  if (CI.getFrontendOpts().OutputFile.empty() ||
250      CI.getFrontendOpts().OutputFile == "-") {
251    // FIXME: Don't fail this way.
252    // FIXME: Verify that we can actually seek in the given file.
253    llvm::report_fatal_error("PTH requires a seekable file for output!");
254  }
255  llvm::raw_fd_ostream *OS =
256    CI.createDefaultOutputFile(true, getCurrentFile());
257  if (!OS) return;
258
259  CacheTokens(CI.getPreprocessor(), OS);
260}
261
262void ParseOnlyAction::ExecuteAction() {
263  Preprocessor &PP = getCompilerInstance().getPreprocessor();
264  llvm::OwningPtr<Action> PA(new MinimalAction(PP));
265
266  Parser P(PP, *PA);
267  PP.EnterMainSourceFile();
268  P.ParseTranslationUnit();
269}
270
271void PreprocessOnlyAction::ExecuteAction() {
272  Preprocessor &PP = getCompilerInstance().getPreprocessor();
273
274  Token Tok;
275  // Start parsing the specified input file.
276  PP.EnterMainSourceFile();
277  do {
278    PP.Lex(Tok);
279  } while (Tok.isNot(tok::eof));
280}
281
282void PrintParseAction::ExecuteAction() {
283  CompilerInstance &CI = getCompilerInstance();
284  Preprocessor &PP = getCompilerInstance().getPreprocessor();
285  llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
286  if (!OS) return;
287
288  llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));
289
290  Parser P(PP, *PA);
291  PP.EnterMainSourceFile();
292  P.ParseTranslationUnit();
293}
294
295void PrintPreprocessedAction::ExecuteAction() {
296  CompilerInstance &CI = getCompilerInstance();
297  // Output file needs to be set to 'Binary', to avoid converting Unix style
298  // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
299  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
300  if (!OS) return;
301
302  DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
303                           CI.getPreprocessorOutputOpts());
304}
305
306void RewriteMacrosAction::ExecuteAction() {
307  CompilerInstance &CI = getCompilerInstance();
308  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
309  if (!OS) return;
310
311  RewriteMacrosInInput(CI.getPreprocessor(), OS);
312}
313
314void RewriteTestAction::ExecuteAction() {
315  CompilerInstance &CI = getCompilerInstance();
316  llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
317  if (!OS) return;
318
319  DoRewriteTest(CI.getPreprocessor(), OS);
320}
321