[cfe-commits] r88776 - /cfe/trunk/tools/clang-cc/clang-cc.cpp

Daniel Dunbar daniel at zuster.org
Sat Nov 14 02:53:49 PST 2009


Author: ddunbar
Date: Sat Nov 14 04:53:49 2009
New Revision: 88776

URL: http://llvm.org/viewvc/llvm-project?rev=88776&view=rev
Log:
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.

Modified:
    cfe/trunk/tools/clang-cc/clang-cc.cpp

Modified: cfe/trunk/tools/clang-cc/clang-cc.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/tools/clang-cc/clang-cc.cpp?rev=88776&r1=88775&r2=88776&view=diff

==============================================================================
--- cfe/trunk/tools/clang-cc/clang-cc.cpp (original)
+++ cfe/trunk/tools/clang-cc/clang-cc.cpp Sat Nov 14 04:53:49 2009
@@ -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 @@
 }
 
 //===----------------------------------------------------------------------===//
-// 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 @@
 /// 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 @@
   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;
+    // 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();
     }
 
-    // Reset the ID tables if we are reusing the SourceManager.
-    if (i)
-      Clang.getSourceManager().clearIDTables();
-
-    // 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)





More information about the cfe-commits mailing list