[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