[cfe-commits] r88772 - in /cfe/trunk: include/clang/Frontend/FrontendAction.h lib/Frontend/CMakeLists.txt lib/Frontend/FrontendAction.cpp

Daniel Dunbar daniel at zuster.org
Sat Nov 14 02:42:35 PST 2009


Author: ddunbar
Date: Sat Nov 14 04:42:35 2009
New Revision: 88772

URL: http://llvm.org/viewvc/llvm-project?rev=88772&view=rev
Log:
Add FrontendAction interface, for encapsulating a "clang-cc" style action.

Added:
    cfe/trunk/include/clang/Frontend/FrontendAction.h
    cfe/trunk/lib/Frontend/FrontendAction.cpp
Modified:
    cfe/trunk/lib/Frontend/CMakeLists.txt

Added: cfe/trunk/include/clang/Frontend/FrontendAction.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/FrontendAction.h?rev=88772&view=auto

==============================================================================
--- cfe/trunk/include/clang/Frontend/FrontendAction.h (added)
+++ cfe/trunk/include/clang/Frontend/FrontendAction.h Sat Nov 14 04:42:35 2009
@@ -0,0 +1,215 @@
+//===-- FrontendAction.h - Generic Frontend Action Interface ----*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_FRONTEND_FRONTENDACTION_H
+#define LLVM_CLANG_FRONTEND_FRONTENDACTION_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/OwningPtr.h"
+#include <string>
+
+namespace llvm {
+class Timer;
+}
+
+namespace clang {
+class ASTUnit;
+class ASTConsumer;
+class CompilerInstance;
+
+/// FrontendAction - Abstract base class for actions which can be performed by
+/// the frontend.
+class FrontendAction {
+  std::string CurrentFile;
+  llvm::OwningPtr<ASTUnit> CurrentASTUnit;
+  CompilerInstance *Instance;
+  llvm::Timer *CurrentTimer;
+
+protected:
+  /// @name Implementation Action Interface
+  /// @{
+
+  /// CreateASTConsumer - Create the AST consumer object for this action, if
+  /// supported.
+  ///
+  /// This routine is called as part of \see BeginSourceAction(), which will
+  /// fail if the AST consumer cannot be created. This will not be called if the
+  /// action has indicated that it only uses the preprocessor.
+  ///
+  /// \param CI - The current compiler instance, provided as a convenience, \see
+  /// getCompilerInstance().
+  ///
+  /// \param InFile - The current input file, provided as a convenience, \see
+  /// getCurrentFile().
+  ///
+  /// \return The new AST consumer, or 0 on failure.
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile) = 0;
+
+  /// BeginSourceFileAction - Callback at the start of processing a single
+  /// input.
+  ///
+  /// \return True on success; on failure \see ExecutionAction() and
+  /// EndSourceFileAction() will not be called.
+  virtual bool BeginSourceFileAction(CompilerInstance &CI,
+                                     llvm::StringRef Filename) {
+    return true;
+  }
+
+  /// ExecuteAction - Callback to run the program action, using the initialized
+  /// compiler instance.
+  ///
+  /// This routine is guaranteed to only be called between \see
+  /// BeginSourceFileAction() and \see EndSourceFileAction().
+  virtual void ExecuteAction() = 0;
+
+  /// EndSourceFileAction - Callback at the end of processing a single input;
+  /// this is guaranteed to only be called following a successful call to
+  /// BeginSourceFileAction (and BeingSourceFile).
+  virtual void EndSourceFileAction() {}
+
+  /// @}
+
+public:
+  FrontendAction();
+  virtual ~FrontendAction();
+
+  /// @name Compiler Instance Access
+  /// @{
+
+  CompilerInstance &getCompilerInstance() const {
+    assert(Instance && "Compiler instance not registered!");
+    return *Instance;
+  }
+
+  void setCompilerInstance(CompilerInstance *Value) { Instance = Value; }
+
+  /// @}
+  /// @name Current File Information
+  /// @{
+
+  bool isCurrentFileAST() const {
+    assert(!CurrentFile.empty() && "No current file!");
+    return CurrentASTUnit != 0;
+  }
+
+  const std::string &getCurrentFile() const {
+    assert(!CurrentFile.empty() && "No current file!");
+    return CurrentFile;
+  }
+
+  ASTUnit &getCurrentASTUnit() const {
+    assert(!CurrentASTUnit && "No current AST unit!");
+    return *CurrentASTUnit;
+  }
+
+  void setCurrentFile(llvm::StringRef Value, ASTUnit *AST = 0);
+
+  /// @}
+  /// @name Timing Utilities
+  /// @{
+
+  llvm::Timer *getCurrentTimer() const {
+    return CurrentTimer;
+  }
+
+  void setCurrentTimer(llvm::Timer *Value) {
+    CurrentTimer = Value;
+  }
+
+  /// @}
+  /// @name Supported Modes
+  /// @{
+
+  /// usesPreprocessorOnly - Does this action only use the preprocessor? If so
+  /// no AST context will be created and this action will be invalid with PCH
+  /// inputs.
+  virtual bool usesPreprocessorOnly() const = 0;
+
+  /// usesCompleteTranslationUnit - For AST based actions, should the
+  /// translation unit be completed?
+  virtual bool usesCompleteTranslationUnit() { return true; }
+
+  /// hasPCHSupport - Does this action support use with PCH?
+  virtual bool hasPCHSupport() const { return !usesPreprocessorOnly(); }
+
+  /// hasASTSupport - Does this action support use with AST files?
+  virtual bool hasASTSupport() const { return !usesPreprocessorOnly(); }
+
+  /// hasCodeCompletionSupport - Does this action support use with code
+  /// completion?
+  virtual bool hasCodeCompletionSupport() const { return false; }
+
+  /// @}
+  /// @name Public Action Interface
+  /// @{
+
+  /// BeginSourceFile - Prepare the action for processing the input file \arg
+  /// Filename; this is run after the options and frontend have been
+  /// initialized, but prior to executing any per-file processing.
+  ///
+  /// \param CI - The compiler instance this action is being run from. The
+  /// action may store and use this object up until the matching EndSourceFile
+  /// action.
+  ///
+  /// \param Filename - The input filename, which will be made available to
+  /// clients via \see getCurrentFile().
+  ///
+  /// \param IsAST - Indicates whether this is an AST input. AST inputs require
+  /// special handling, since the AST file itself contains several objects which
+  /// would normally be owned by the CompilerInstance. When processing AST input
+  /// files, these objects should generally not be initialized in the
+  /// CompilerInstance -- they will automatically be shared with the AST file in
+  /// between \see BeginSourceFile() and \see EndSourceFile().
+  ///
+  /// \return True on success; the compilation of this file should be aborted
+  /// and neither Execute nor EndSourceFile should be called.
+  bool BeginSourceFile(CompilerInstance &CI, llvm::StringRef Filename,
+                       bool IsAST = false);
+
+  /// Execute - Set the source managers main input file, and run the action.
+  void Execute();
+
+  /// EndSourceFile - Perform any per-file post processing, deallocate per-file
+  /// objects, and run statistics and output file cleanup code.
+  void EndSourceFile();
+
+  /// @}
+};
+
+/// ASTFrontendAction - Abstract base class to use for AST consumer based
+/// frontend actios.
+class ASTFrontendAction : public FrontendAction {
+  /// ExecuteAction - Implement the ExecuteAction interface by running Sema on
+  /// the already initialized AST consumer.
+  ///
+  /// This will also take care of instantiating a code completion consumer if
+  /// the user requested it and the action supports it.
+  virtual void ExecuteAction();
+
+public:
+  virtual bool usesPreprocessorOnly() const { return false; }
+};
+
+/// PreprocessorFrontendAction - Abstract base class to use for preprocessor
+/// based frontend actions.
+class PreprocessorFrontendAction : public FrontendAction {
+protected:
+  /// CreateASTConsumer - Provide a default implementation which returns aborts,
+  /// this method should never be called by FrontendAction clients.
+  virtual ASTConsumer *CreateASTConsumer(CompilerInstance &CI,
+                                         llvm::StringRef InFile);
+
+public:
+  virtual bool usesPreprocessorOnly() const { return true; }
+};
+
+}  // end namespace clang
+
+#endif

Modified: cfe/trunk/lib/Frontend/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CMakeLists.txt?rev=88772&r1=88771&r2=88772&view=diff

==============================================================================
--- cfe/trunk/lib/Frontend/CMakeLists.txt (original)
+++ cfe/trunk/lib/Frontend/CMakeLists.txt Sat Nov 14 04:42:35 2009
@@ -12,6 +12,7 @@
   DiagChecker.cpp
   DocumentXML.cpp
   FixItRewriter.cpp
+  FrontendAction.cpp
   FrontendOptions.cpp
   GeneratePCH.cpp
   HTMLDiagnostics.cpp

Added: cfe/trunk/lib/Frontend/FrontendAction.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/FrontendAction.cpp?rev=88772&view=auto

==============================================================================
--- cfe/trunk/lib/Frontend/FrontendAction.cpp (added)
+++ cfe/trunk/lib/Frontend/FrontendAction.cpp Sat Nov 14 04:42:35 2009
@@ -0,0 +1,225 @@
+//===--- FrontendAction.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/FrontendAction.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/Lex/HeaderSearch.h"
+#include "clang/Lex/Preprocessor.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendDiagnostic.h"
+#include "clang/Sema/ParseAST.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Timer.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace clang;
+
+FrontendAction::FrontendAction() : Instance(0), CurrentTimer(0) {}
+
+FrontendAction::~FrontendAction() {}
+
+void FrontendAction::setCurrentFile(llvm::StringRef Value, ASTUnit *AST) {
+  CurrentFile = Value;
+  CurrentASTUnit.reset(AST);
+}
+
+bool FrontendAction::BeginSourceFile(CompilerInstance &CI,
+                                     llvm::StringRef Filename,
+                                     bool IsAST) {
+  assert(!Instance && "Already processing a source file!");
+  assert(!Filename.empty() && "Unexpected empty filename!");
+  setCurrentFile(Filename);
+  setCompilerInstance(&CI);
+
+  // AST files follow a very different path, since they share objects via the
+  // AST unit.
+  if (IsAST) {
+    assert(!usesPreprocessorOnly() &&
+           "Attempt to pass AST file to preprocessor only action!");
+    assert(hasASTSupport() && "This action does not have AST support!");
+
+    std::string Error;
+    ASTUnit *AST = ASTUnit::LoadFromPCHFile(Filename, &Error);
+    if (!AST) {
+      CI.getDiagnostics().Report(diag::err_fe_invalid_ast_file) << Error;
+      goto failure;
+    }
+
+    setCurrentFile(Filename, AST);
+
+    // Set the shared objects, these are reset when we finish processing the
+    // file, otherwise the CompilerInstance will happily destroy them.
+    CI.setFileManager(&AST->getFileManager());
+    CI.setSourceManager(&AST->getSourceManager());
+    CI.setPreprocessor(&AST->getPreprocessor());
+    CI.setASTContext(&AST->getASTContext());
+
+    // Initialize the action.
+    if (!BeginSourceFileAction(CI, Filename))
+      goto failure;
+
+    /// Create the AST consumer.
+    CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+    if (!CI.hasASTConsumer())
+      goto failure;
+
+    return true;
+  }
+
+  // Inform the diagnostic client we are processing a source file.
+  CI.getDiagnosticClient().BeginSourceFile(CI.getLangOpts(),
+                                           &CI.getPreprocessor());
+
+  // Initialize the action.
+  if (!BeginSourceFileAction(CI, Filename))
+    goto failure;
+
+  /// Create the AST context and consumer unless this is a preprocessor only
+  /// action.
+  if (!usesPreprocessorOnly()) {
+    CI.createASTContext();
+    CI.setASTConsumer(CreateASTConsumer(CI, Filename));
+    if (!CI.hasASTConsumer())
+      goto failure;
+
+    /// Use PCH?
+    if (!CI.getPreprocessorOpts().getImplicitPCHInclude().empty()) {
+      assert(hasPCHSupport() && "This action does not have PCH support!");
+      CI.createPCHExternalASTSource(
+        CI.getPreprocessorOpts().getImplicitPCHInclude());
+      if (!CI.getASTContext().getExternalSource())
+        goto failure;
+    }
+  }
+
+  // Initialize builtin info as long as we aren't using an external AST
+  // source.
+  if (!CI.hasASTContext() || !CI.getASTContext().getExternalSource()) {
+    Preprocessor &PP = CI.getPreprocessor();
+    PP.getBuiltinInfo().InitializeBuiltins(PP.getIdentifierTable(),
+                                           PP.getLangOptions().NoBuiltin);
+  }
+
+  return true;
+
+  // If we failed, reset state since the client will not end up calling the
+  // matching EndSourceFile().
+  failure:
+  if (isCurrentFileAST()) {
+    CI.takeASTContext();
+    CI.takePreprocessor();
+    CI.takeSourceManager();
+    CI.takeFileManager();
+  }
+
+  CI.getDiagnosticClient().EndSourceFile();
+  setCurrentFile("");
+  setCompilerInstance(0);
+  return false;
+}
+
+void FrontendAction::Execute() {
+  CompilerInstance &CI = getCompilerInstance();
+
+  // Initialize the main file entry. This needs to be delayed until after PCH
+  // has loaded.
+  if (isCurrentFileAST()) {
+    // 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>");
+    CI.getSourceManager().createMainFileIDForMemBuffer(SB);
+  } else {
+    if (!CI.InitializeSourceManager(getCurrentFile()))
+      return;
+  }
+
+  llvm::TimeRegion Timer(CurrentTimer);
+  ExecuteAction();
+}
+
+void FrontendAction::EndSourceFile() {
+  CompilerInstance &CI = getCompilerInstance();
+
+  // Finalize the action.
+  EndSourceFileAction();
+
+  // Release the consumer and the AST, in that order since the consumer may
+  // perform actions in its destructor which require the context.
+  //
+  // FIXME: There is more per-file stuff we could just drop here?
+  if (CI.getFrontendOpts().DisableFree) {
+    CI.takeASTConsumer();
+    if (!isCurrentFileAST())
+      CI.takeASTContext();
+  } else {
+    CI.setASTConsumer(0);
+    if (!isCurrentFileAST())
+      CI.setASTContext(0);
+  }
+
+  if (CI.getFrontendOpts().ShowStats) {
+    llvm::errs() << "\nSTATISTICS FOR '" << getCurrentFile() << "':\n";
+    CI.getPreprocessor().PrintStats();
+    CI.getPreprocessor().getIdentifierTable().PrintStats();
+    CI.getPreprocessor().getHeaderSearchInfo().PrintStats();
+    CI.getSourceManager().PrintStats();
+    llvm::errs() << "\n";
+  }
+
+  // Cleanup the output streams, and erase the output files if we encountered
+  // an error.
+  CI.ClearOutputFiles(/*EraseFiles=*/CI.getDiagnostics().getNumErrors());
+
+  // Inform the diagnostic client we are done with this source file.
+  CI.getDiagnosticClient().EndSourceFile();
+
+  if (isCurrentFileAST()) {
+    CI.takeASTContext();
+    CI.takePreprocessor();
+    CI.takeSourceManager();
+    CI.takeFileManager();
+  }
+
+  setCompilerInstance(0);
+  setCurrentFile("");
+}
+
+//===----------------------------------------------------------------------===//
+// Utility Actions
+//===----------------------------------------------------------------------===//
+
+void ASTFrontendAction::ExecuteAction() {
+  CompilerInstance &CI = getCompilerInstance();
+
+  // FIXME: Move the truncation aspect of this into Sema, we delayed this till
+  // here so the source manager would be initialized.
+  if (hasCodeCompletionSupport() &&
+      !CI.getFrontendOpts().CodeCompletionAt.FileName.empty())
+    CI.createCodeCompletionConsumer();
+
+  // Use a code completion consumer?
+  CodeCompleteConsumer *CompletionConsumer = 0;
+  if (CI.hasCodeCompletionConsumer())
+    CompletionConsumer = &CI.getCodeCompletionConsumer();
+
+  ParseAST(CI.getPreprocessor(), &CI.getASTConsumer(), CI.getASTContext(),
+           CI.getFrontendOpts().ShowStats,
+           usesCompleteTranslationUnit(), CompletionConsumer);
+}
+
+ASTConsumer *
+PreprocessorFrontendAction::CreateASTConsumer(CompilerInstance &CI,
+                                              llvm::StringRef InFile) {
+  llvm::llvm_unreachable("Invalid CreateASTConsumer on preprocessor action!");
+}





More information about the cfe-commits mailing list