diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-11-14 10:53:49 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-11-14 10:53:49 +0000 |
commit | 4fdba99ccce46d577ea1bcd5081843ef95ff5c11 (patch) | |
tree | dc70170424d2a1ecdf73dc7400891de17618f1e3 | |
parent | 5f3b997e28899972e2ba23ec25e830d4066fa59a (diff) |
clang-cc: Switch to using FrontendAction. Whee.
Please report any discrepancies you see in clang-cc, I'm not confident that our regression tests cover all the fun ways one can use clang-cc.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@88776 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | tools/clang-cc/clang-cc.cpp | 469 |
1 files changed, 59 insertions, 410 deletions
diff --git a/tools/clang-cc/clang-cc.cpp b/tools/clang-cc/clang-cc.cpp index 51a0084562..35ae4b0234 100644 --- a/tools/clang-cc/clang-cc.cpp +++ b/tools/clang-cc/clang-cc.cpp @@ -8,50 +8,32 @@ //===----------------------------------------------------------------------===// // // This utility may be invoked in the following manner: -// clang --help - Output help info. -// clang [options] - Read from stdin. -// clang [options] file - Read from "file". -// clang [options] file1 file2 - Read these files. +// clang-cc --help - Output help info. +// clang-cc [options] - Read from stdin. +// clang-cc [options] file - Read from "file". +// clang-cc [options] file1 file2 - Read these files. // //===----------------------------------------------------------------------===// #include "Options.h" -#include "clang/AST/ASTConsumer.h" -#include "clang/AST/ASTContext.h" -#include "clang/Analysis/PathDiagnostic.h" #include "clang/Basic/FileManager.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" #include "clang/Basic/Version.h" -#include "clang/CodeGen/ModuleBuilder.h" -#include "clang/Frontend/ASTConsumers.h" -#include "clang/Frontend/ASTUnit.h" -#include "clang/Frontend/AnalysisConsumer.h" -#include "clang/Frontend/CommandLineSourceLoc.h" #include "clang/Frontend/CompilerInstance.h" #include "clang/Frontend/CompilerInvocation.h" -#include "clang/Frontend/DependencyOutputOptions.h" -#include "clang/Frontend/FixItRewriter.h" +#include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" #include "clang/Frontend/PathDiagnosticClients.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Frontend/PreprocessorOutputOptions.h" -#include "clang/Frontend/Utils.h" #include "clang/Frontend/VerifyDiagnosticsClient.h" -#include "clang/Lex/HeaderSearch.h" -#include "clang/Lex/LexDiagnostic.h" -#include "clang/Parse/Parser.h" -#include "clang/Sema/CodeCompleteConsumer.h" -#include "clang/Sema/ParseAST.h" -#include "clang/Sema/SemaDiagnostic.h" -#include "llvm/LLVMContext.h" #include "llvm/ADT/OwningPtr.h" -#include "llvm/ADT/StringExtras.h" #include "llvm/Config/config.h" +#include "llvm/LLVMContext.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ManagedStatic.h" -#include "llvm/Support/MemoryBuffer.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" #include "llvm/Support/Timer.h" @@ -184,19 +166,6 @@ std::string GetBuiltinIncludePath(const char *Argv0) { } //===----------------------------------------------------------------------===// -// Basic Parser driver -//===----------------------------------------------------------------------===// - -static void ParseFile(Preprocessor &PP, MinimalAction *PA) { - Parser P(PP, *PA); - PP.EnterMainSourceFile(); - - // Parsing the specified input file. - P.ParseTranslationUnit(); - delete PA; -} - -//===----------------------------------------------------------------------===// // Main driver //===----------------------------------------------------------------------===// @@ -205,361 +174,39 @@ static void ParseFile(Preprocessor &PP, MinimalAction *PA) { /// anything. llvm::Timer *ClangFrontendTimer = 0; -/// AddFixItLocations - Add any individual user specified "fix-it" locations, -/// and return true on success. -static bool AddFixItLocations(CompilerInstance &CI, - FixItRewriter &FixItRewrite) { - const std::vector<ParsedSourceLocation> &Locs = - CI.getFrontendOpts().FixItLocations; - for (unsigned i = 0, e = Locs.size(); i != e; ++i) { - const FileEntry *File = CI.getFileManager().getFile(Locs[i].FileName); - if (!File) { - CI.getDiagnostics().Report(diag::err_fe_unable_to_find_fixit_file) - << Locs[i].FileName; - return false; - } - - RequestedSourceLocation Requested; - Requested.File = File; - Requested.Line = Locs[i].Line; - Requested.Column = Locs[i].Column; - FixItRewrite.addFixItLocation(Requested); - } - - return true; -} - -static ASTConsumer *CreateConsumerAction(CompilerInstance &CI, - Preprocessor &PP, - const std::string &InFile, - ProgActions PA) { - const FrontendOptions &FEOpts = CI.getFrontendOpts(); - +static FrontendAction *CreateFrontendAction(ProgActions PA) { switch (PA) { - default: - return 0; - - case ASTPrint: - return CreateASTPrinter(CI.createDefaultOutputFile(false, InFile)); - - case ASTPrintXML: - return CreateASTPrinterXML(CI.createDefaultOutputFile(false, InFile, - "xml")); - - case ASTDump: - return CreateASTDumper(); - - case ASTView: - return CreateASTViewer(); - - case DumpRecordLayouts: - return CreateRecordLayoutDumper(); - - case InheritanceView: - return CreateInheritanceViewer(FEOpts.ViewClassInheritance); - - case EmitAssembly: - case EmitLLVM: - case EmitBC: - case EmitLLVMOnly: { - BackendAction Act; - llvm::OwningPtr<llvm::raw_ostream> OS; - if (ProgAction == EmitAssembly) { - Act = Backend_EmitAssembly; - OS.reset(CI.createDefaultOutputFile(false, InFile, "s")); - } else if (ProgAction == EmitLLVM) { - Act = Backend_EmitLL; - OS.reset(CI.createDefaultOutputFile(false, InFile, "ll")); - } else if (ProgAction == EmitLLVMOnly) { - Act = Backend_EmitNothing; - } else { - Act = Backend_EmitBC; - OS.reset(CI.createDefaultOutputFile(true, InFile, "bc")); - } - - return CreateBackendConsumer(Act, PP.getDiagnostics(), PP.getLangOptions(), - CI.getCodeGenOpts(), InFile, OS.take(), - CI.getLLVMContext()); - } - - case RewriteObjC: - return CreateObjCRewriter(InFile, - CI.createDefaultOutputFile(true, InFile, "cpp"), - PP.getDiagnostics(), PP.getLangOptions(), - CI.getDiagnosticOpts().NoRewriteMacros); - - case RewriteBlocks: - return CreateBlockRewriter(InFile, PP.getDiagnostics(), - PP.getLangOptions()); - - case FixIt: - return new ASTConsumer(); - - case ParseSyntaxOnly: - return new ASTConsumer(); - - case PrintDeclContext: - return CreateDeclContextPrinter(); + default: return 0; + case ASTDump: return new ASTDumpAction(); + case ASTPrint: return new ASTPrintAction(); + case ASTPrintXML: return new ASTPrintXMLAction(); + case ASTView: return new ASTViewAction(); + case DumpRawTokens: return new DumpRawTokensAction(); + case DumpRecordLayouts: return new DumpRecordAction(); + case DumpTokens: return new DumpTokensAction(); + case EmitAssembly: return new EmitAssemblyAction(); + case EmitBC: return new EmitBCAction(); + case EmitHTML: return new HTMLPrintAction(); + case EmitLLVM: return new EmitLLVMAction(); + case EmitLLVMOnly: return new EmitLLVMOnlyAction(); + case FixIt: return new FixItAction(); + case GeneratePCH: return new GeneratePCHAction(); + case GeneratePTH: return new GeneratePTHAction(); + case InheritanceView: return new InheritanceViewAction(); + case ParseNoop: return new ParseOnlyAction(); + case ParsePrintCallbacks: return new PrintParseAction(); + case ParseSyntaxOnly: return new SyntaxOnlyAction(); + case PrintDeclContext: return new DeclContextPrintAction(); + case PrintPreprocessedInput: return new PrintPreprocessedAction(); + case RewriteBlocks: return new RewriteBlocksAction(); + case RewriteMacros: return new RewriteMacrosAction(); + case RewriteObjC: return new RewriteObjCAction(); + case RewriteTest: return new RewriteTestAction(); + case RunAnalysis: return new AnalysisAction(); + case RunPreprocessorOnly: return new PreprocessOnlyAction(); } } -/// ProcessInputFile - Process a single input file with the specified state. -static void ProcessInputFile(CompilerInstance &CI, const std::string &InFile, - ProgActions PA) { - Preprocessor &PP = CI.getPreprocessor(); - const FrontendOptions &FEOpts = CI.getFrontendOpts(); - llvm::OwningPtr<ASTConsumer> Consumer; - llvm::OwningPtr<FixItRewriter> FixItRewrite; - bool CompleteTranslationUnit = true; - - switch (PA) { - default: - Consumer.reset(CreateConsumerAction(CI, PP, InFile, PA)); - if (!Consumer.get()) { - PP.getDiagnostics().Report(diag::err_fe_invalid_ast_action); - return; - } - break; - - case EmitHTML: - Consumer.reset(CreateHTMLPrinter(CI.createDefaultOutputFile(false, InFile), - PP)); - break; - - case RunAnalysis: - Consumer.reset(CreateAnalysisConsumer(PP, FEOpts.OutputFile, - CI.getAnalyzerOpts())); - break; - - case GeneratePCH: { - const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot; - bool Relocatable = FEOpts.RelocatablePCH; - if (Relocatable && Sysroot.empty()) { - PP.Diag(SourceLocation(), diag::err_relocatable_without_without_isysroot); - Relocatable = false; - } - - llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile); - if (Relocatable) - Consumer.reset(CreatePCHGenerator(PP, OS, Sysroot.c_str())); - else - Consumer.reset(CreatePCHGenerator(PP, OS)); - CompleteTranslationUnit = false; - break; - } - - // Do any necessary set up for non-consumer actions. - case DumpRawTokens: - case DumpTokens: - case RunPreprocessorOnly: - case ParseNoop: - case GeneratePTH: - case PrintPreprocessedInput: - case ParsePrintCallbacks: - case RewriteMacros: - case RewriteTest: - break; // No setup. - } - - // Check if we want a fix-it rewriter. - if (PA == FixIt) { - FixItRewrite.reset(new FixItRewriter(PP.getDiagnostics(), - PP.getSourceManager(), - PP.getLangOptions())); - if (!AddFixItLocations(CI, *FixItRewrite)) - return; - } - - if (Consumer) { - // Create the ASTContext. - CI.createASTContext(); - - // Create the external AST source when using PCH. - const std::string &ImplicitPCHInclude = - CI.getPreprocessorOpts().getImplicitPCHInclude(); - if (!ImplicitPCHInclude.empty()) { - CI.createPCHExternalASTSource(ImplicitPCHInclude); - if (!CI.getASTContext().getExternalSource()) - return; - } - } - - // Initialize builtin info as long as we aren't using an external AST - // source. - if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) - PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(), - PP.getLangOptions().NoBuiltin); - - // Initialize the main file entry. This needs to be delayed until after PCH - // has loaded. - if (!CI.InitializeSourceManager(InFile)) - return; - - if (Consumer) { - // FIXME: Move the truncation aspect of this into Sema. - if (!FEOpts.CodeCompletionAt.FileName.empty()) - CI.createCodeCompletionConsumer(); - - // Run the AST consumer action. - CodeCompleteConsumer *CompletionConsumer = - CI.hasCodeCompletionConsumer() ? &CI.getCodeCompletionConsumer() : 0; - ParseAST(PP, Consumer.get(), CI.getASTContext(), FEOpts.ShowStats, - CompleteTranslationUnit, CompletionConsumer); - } else { - // Run the preprocessor actions. - llvm::TimeRegion Timer(ClangFrontendTimer); - switch (PA) { - default: - assert(0 && "unexpected program action"); - - case DumpRawTokens: { - SourceManager &SM = PP.getSourceManager(); - // Start lexing the specified input file. - Lexer RawLex(SM.getMainFileID(), SM, PP.getLangOptions()); - RawLex.SetKeepWhitespaceMode(true); - - Token RawTok; - RawLex.LexFromRawLexer(RawTok); - while (RawTok.isNot(tok::eof)) { - PP.DumpToken(RawTok, true); - fprintf(stderr, "\n"); - RawLex.LexFromRawLexer(RawTok); - } - break; - } - - case DumpTokens: { - Token Tok; - // Start preprocessing the specified input file. - PP.EnterMainSourceFile(); - do { - PP.Lex(Tok); - PP.DumpToken(Tok, true); - fprintf(stderr, "\n"); - } while (Tok.isNot(tok::eof)); - break; - } - - case GeneratePTH: - if (FEOpts.OutputFile.empty() || FEOpts.OutputFile == "-") { - // FIXME: Don't fail this way. - // FIXME: Verify that we can actually seek in the given file. - llvm::errs() << "ERROR: PTH requires an seekable file for output!\n"; - ::exit(1); - } - CacheTokens(PP, CI.createDefaultOutputFile(true, InFile)); - break; - - case ParseNoop: - ParseFile(PP, new MinimalAction(PP)); - break; - - case ParsePrintCallbacks: { - llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile); - ParseFile(PP, CreatePrintParserActionsAction(PP, OS)); - break; - } - case PrintPreprocessedInput: - DoPrintPreprocessedInput(PP, CI.createDefaultOutputFile(false, InFile), - CI.getPreprocessorOutputOpts()); - break; - - case RewriteMacros: - RewriteMacrosInInput(PP, CI.createDefaultOutputFile(true, InFile)); - break; - - case RewriteTest: - DoRewriteTest(PP, CI.createDefaultOutputFile(false, InFile)); - break; - - case RunPreprocessorOnly: { // Just lex as fast as we can, no output. - Token Tok; - // Start parsing the specified input file. - PP.EnterMainSourceFile(); - do { - PP.Lex(Tok); - } while (Tok.isNot(tok::eof)); - break; - } - } - } - - if (FixItRewrite) - FixItRewrite->WriteFixedFile(InFile, FEOpts.OutputFile); - - // Release the consumer and the AST, in that order since the consumer may - // perform actions in its destructor which require the context. - if (FEOpts.DisableFree) { - Consumer.take(); - CI.takeASTContext(); - } else { - Consumer.reset(); - CI.setASTContext(0); - } - - if (FEOpts.ShowStats) { - fprintf(stderr, "\nSTATISTICS FOR '%s':\n", InFile.c_str()); - PP.PrintStats(); - PP.getIdentifierTable().PrintStats(); - PP.getHeaderSearchInfo().PrintStats(); - PP.getSourceManager().PrintStats(); - fprintf(stderr, "\n"); - } - - // Cleanup the output streams, and erase the output files if we encountered an - // error. - CI.ClearOutputFiles(/*EraseFiles=*/PP.getDiagnostics().getNumErrors()); -} - -/// ProcessASTInputFile - Process a single AST input file with the specified -/// state. -static void ProcessASTInputFile(CompilerInstance &CI, const std::string &InFile, - ProgActions PA) { - std::string Error; - llvm::OwningPtr<ASTUnit> AST(ASTUnit::LoadFromPCHFile(InFile, &Error)); - if (!AST) { - CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error; - return; - } - - Preprocessor &PP = AST->getPreprocessor(); - llvm::OwningPtr<ASTConsumer> Consumer(CreateConsumerAction(CI, PP, - InFile, PA)); - if (!Consumer.get()) { - CI.getDiagnostics().Report(diag::err_fe_invalid_ast_action); - return; - } - - // Set the main file ID to an empty file. - // - // FIXME: We probably shouldn't need this, but for now this is the simplest - // way to reuse the logic in ParseAST. - const char *EmptyStr = ""; - llvm::MemoryBuffer *SB = - llvm::MemoryBuffer::getMemBuffer(EmptyStr, EmptyStr, "<dummy input>"); - AST->getSourceManager().createMainFileIDForMemBuffer(SB); - - // Stream the input AST to the consumer. - CI.getDiagnostics().getClient()->BeginSourceFile(PP.getLangOptions(), &PP); - ParseAST(PP, Consumer.get(), AST->getASTContext(), - CI.getFrontendOpts().ShowStats); - CI.getDiagnostics().getClient()->EndSourceFile(); - - // Release the consumer and the AST, in that order since the consumer may - // perform actions in its destructor which require the context. - if (CI.getFrontendOpts().DisableFree) { - Consumer.take(); - AST.take(); - } else { - Consumer.reset(); - AST.reset(); - } - - // Cleanup the output streams, and erase the output files if we encountered an - // error. - CI.ClearOutputFiles(/*EraseFiles=*/PP.getDiagnostics().getNumErrors()); -} - static void LLVMErrorHandler(void *UserData, const std::string &Message) { Diagnostic &Diags = *static_cast<Diagnostic*>(UserData); @@ -701,33 +348,35 @@ int main(int argc, char **argv) { if (!Clang.getFrontendOpts().FixItLocations.empty()) ProgAction = FixIt; - // Create the source manager. - Clang.createSourceManager(); - - // Create a file manager object to provide access to and cache the filesystem. - Clang.createFileManager(); - for (unsigned i = 0, e = Clang.getFrontendOpts().Inputs.size(); i != e; ++i) { const std::string &InFile = Clang.getFrontendOpts().Inputs[i].second; - // AST inputs are handled specially. - if (IsAST) { - ProcessASTInputFile(Clang, InFile, ProgAction); - continue; - } - - // Reset the ID tables if we are reusing the SourceManager. - if (i) - Clang.getSourceManager().clearIDTables(); + // If we aren't using an AST file, setup the file and source managers and + // the preprocessor. + if (!IsAST) { + if (!i) { + // Create a file manager object to provide access to and cache the + // filesystem. + Clang.createFileManager(); + + // Create the source manager. + Clang.createSourceManager(); + } else { + // Reset the ID tables if we are reusing the SourceManager. + Clang.getSourceManager().clearIDTables(); + } - // Create the preprocessor. - Clang.createPreprocessor(); + // Create the preprocessor. + Clang.createPreprocessor(); + } - // Process the source file. - Clang.getDiagnostics().getClient()->BeginSourceFile(Clang.getLangOpts(), - &Clang.getPreprocessor()); - ProcessInputFile(Clang, InFile, ProgAction); - Clang.getDiagnostics().getClient()->EndSourceFile(); + llvm::OwningPtr<FrontendAction> Act(CreateFrontendAction(ProgAction)); + assert(Act && "Invalid program action!"); + Act->setCurrentTimer(ClangFrontendTimer); + if (Act->BeginSourceFile(Clang, InFile, IsAST)) { + Act->Execute(); + Act->EndSourceFile(); + } } if (Clang.getDiagnosticOpts().ShowCarets) |