| //===--- FrontendActions.cpp ----------------------------------------------===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "clang/Frontend/FrontendActions.h" |
| #include "clang/AST/ASTConsumer.h" |
| #include "clang/Lex/Pragma.h" |
| #include "clang/Lex/Preprocessor.h" |
| #include "clang/Parse/Parser.h" |
| #include "clang/Basic/FileManager.h" |
| #include "clang/Frontend/ASTConsumers.h" |
| #include "clang/Frontend/ASTUnit.h" |
| #include "clang/Frontend/CompilerInstance.h" |
| #include "clang/Frontend/FrontendDiagnostic.h" |
| #include "clang/Frontend/Utils.h" |
| #include "clang/Serialization/ASTWriter.h" |
| #include "llvm/ADT/OwningPtr.h" |
| #include "llvm/Support/MemoryBuffer.h" |
| #include "llvm/Support/raw_ostream.h" |
| using namespace clang; |
| |
| //===----------------------------------------------------------------------===// |
| // Custom Actions |
| //===----------------------------------------------------------------------===// |
| |
| ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| return new ASTConsumer(); |
| } |
| |
| void InitOnlyAction::ExecuteAction() { |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // AST Consumer Actions |
| //===----------------------------------------------------------------------===// |
| |
| ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| if (raw_ostream *OS = CI.createDefaultOutputFile(false, InFile)) |
| return CreateASTPrinter(OS); |
| return 0; |
| } |
| |
| ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| return CreateASTDumper(); |
| } |
| |
| ASTConsumer *ASTDumpXMLAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| raw_ostream *OS; |
| if (CI.getFrontendOpts().OutputFile.empty()) |
| OS = &llvm::outs(); |
| else |
| OS = CI.createDefaultOutputFile(false, InFile); |
| if (!OS) return 0; |
| return CreateASTDumperXML(*OS); |
| } |
| |
| ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| return CreateASTViewer(); |
| } |
| |
| ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| return CreateDeclContextPrinter(); |
| } |
| |
| ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| std::string Sysroot; |
| std::string OutputFile; |
| raw_ostream *OS = 0; |
| bool Chaining; |
| if (ComputeASTConsumerArguments(CI, InFile, Sysroot, OutputFile, OS, Chaining)) |
| return 0; |
| |
| if (!CI.getFrontendOpts().RelocatablePCH) |
| Sysroot.clear(); |
| return new PCHGenerator(CI.getPreprocessor(), OutputFile, Chaining, Sysroot, |
| OS); |
| } |
| |
| bool GeneratePCHAction::ComputeASTConsumerArguments(CompilerInstance &CI, |
| StringRef InFile, |
| std::string &Sysroot, |
| std::string &OutputFile, |
| raw_ostream *&OS, |
| bool &Chaining) { |
| Sysroot = CI.getHeaderSearchOpts().Sysroot; |
| if (CI.getFrontendOpts().RelocatablePCH && Sysroot.empty()) { |
| CI.getDiagnostics().Report(diag::err_relocatable_without_isysroot); |
| return true; |
| } |
| |
| // We use createOutputFile here because this is exposed via libclang, and we |
| // must disable the RemoveFileOnSignal behavior. |
| OS = CI.createOutputFile(CI.getFrontendOpts().OutputFile, /*Binary=*/true, |
| /*RemoveFileOnSignal=*/false, InFile); |
| if (!OS) |
| return true; |
| |
| OutputFile = CI.getFrontendOpts().OutputFile; |
| Chaining = CI.getInvocation().getFrontendOpts().ChainedPCH && |
| !CI.getPreprocessorOpts().ImplicitPCHInclude.empty(); |
| return false; |
| } |
| |
| ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI, |
| StringRef InFile) { |
| return new ASTConsumer(); |
| } |
| |
| //===----------------------------------------------------------------------===// |
| // Preprocessor Actions |
| //===----------------------------------------------------------------------===// |
| |
| void DumpRawTokensAction::ExecuteAction() { |
| Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
| SourceManager &SM = PP.getSourceManager(); |
| |
| // Start lexing the specified input file. |
| const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID()); |
| Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions()); |
| RawLex.SetKeepWhitespaceMode(true); |
| |
| Token RawTok; |
| RawLex.LexFromRawLexer(RawTok); |
| while (RawTok.isNot(tok::eof)) { |
| PP.DumpToken(RawTok, true); |
| llvm::errs() << "\n"; |
| RawLex.LexFromRawLexer(RawTok); |
| } |
| } |
| |
| void DumpTokensAction::ExecuteAction() { |
| Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
| // Start preprocessing the specified input file. |
| Token Tok; |
| PP.EnterMainSourceFile(); |
| do { |
| PP.Lex(Tok); |
| PP.DumpToken(Tok, true); |
| llvm::errs() << "\n"; |
| } while (Tok.isNot(tok::eof)); |
| } |
| |
| void GeneratePTHAction::ExecuteAction() { |
| CompilerInstance &CI = getCompilerInstance(); |
| if (CI.getFrontendOpts().OutputFile.empty() || |
| CI.getFrontendOpts().OutputFile == "-") { |
| // FIXME: Don't fail this way. |
| // FIXME: Verify that we can actually seek in the given file. |
| llvm::report_fatal_error("PTH requires a seekable file for output!"); |
| } |
| llvm::raw_fd_ostream *OS = |
| CI.createDefaultOutputFile(true, getCurrentFile()); |
| if (!OS) return; |
| |
| CacheTokens(CI.getPreprocessor(), OS); |
| } |
| |
| void PreprocessOnlyAction::ExecuteAction() { |
| Preprocessor &PP = getCompilerInstance().getPreprocessor(); |
| |
| // Ignore unknown pragmas. |
| PP.AddPragmaHandler(new EmptyPragmaHandler()); |
| |
| Token Tok; |
| // Start parsing the specified input file. |
| PP.EnterMainSourceFile(); |
| do { |
| PP.Lex(Tok); |
| } while (Tok.isNot(tok::eof)); |
| } |
| |
| void PrintPreprocessedAction::ExecuteAction() { |
| CompilerInstance &CI = getCompilerInstance(); |
| // Output file needs to be set to 'Binary', to avoid converting Unix style |
| // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>). |
| raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile()); |
| if (!OS) return; |
| |
| DoPrintPreprocessedInput(CI.getPreprocessor(), OS, |
| CI.getPreprocessorOutputOpts()); |
| } |
| |
| void PrintPreambleAction::ExecuteAction() { |
| switch (getCurrentFileKind()) { |
| case IK_C: |
| case IK_CXX: |
| case IK_ObjC: |
| case IK_ObjCXX: |
| case IK_OpenCL: |
| case IK_CUDA: |
| break; |
| |
| case IK_None: |
| case IK_Asm: |
| case IK_PreprocessedC: |
| case IK_PreprocessedCXX: |
| case IK_PreprocessedObjC: |
| case IK_PreprocessedObjCXX: |
| case IK_AST: |
| case IK_LLVM_IR: |
| // We can't do anything with these. |
| return; |
| } |
| |
| CompilerInstance &CI = getCompilerInstance(); |
| llvm::MemoryBuffer *Buffer |
| = CI.getFileManager().getBufferForFile(getCurrentFile()); |
| if (Buffer) { |
| unsigned Preamble = Lexer::ComputePreamble(Buffer).first; |
| llvm::outs().write(Buffer->getBufferStart(), Preamble); |
| delete Buffer; |
| } |
| } |