diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index 8d33a27fc090..75e6cbe4dd4d 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -28,6 +28,8 @@ def err_fe_no_fixit_and_codegen : Error< "FIX-ITs cannot be applied when generating code">; def err_fe_unable_to_find_fixit_file : Error< "FIX-IT could not find file '%0'">; +def err_fe_invalid_plugin_name : Error< + "unable to find plugin '%0'">; def err_verify_bogus_characters : Error< "bogus characters before '{{' in expected string">; diff --git a/clang/include/clang/Frontend/FrontendOptions.h b/clang/include/clang/Frontend/FrontendOptions.h index adb591ee0604..67656067fcea 100644 --- a/clang/include/clang/Frontend/FrontendOptions.h +++ b/clang/include/clang/Frontend/FrontendOptions.h @@ -39,6 +39,7 @@ namespace frontend { ParseNoop, ///< Parse with noop callbacks. ParsePrintCallbacks, ///< Parse and print each callback. ParseSyntaxOnly, ///< Parse and perform semantic analysis. + PluginAction, ///< Run a plugin action, \see ActionName. PrintDeclContext, ///< Print DeclContext and their Decls. PrintPreprocessedInput, ///< -E mode. RewriteBlocks, ///< ObjC->C Rewriter for Blocks. @@ -109,12 +110,16 @@ public: /// The frontend action to perform. frontend::ActionKind ProgramAction; + /// The name of the action to run when using a plugin action. + std::string ActionName; + public: FrontendOptions() { DebugCodeCompletionPrinter = 0; DisableFree = 0; EmptyInputOnly = 0; ProgramAction = frontend::ParseSyntaxOnly; + ActionName = ""; RelocatablePCH = 0; ShowMacrosInCodeCompletion = 0; ShowStats = 0; diff --git a/clang/include/clang/Frontend/FrontendPluginRegistry.h b/clang/include/clang/Frontend/FrontendPluginRegistry.h new file mode 100644 index 000000000000..8341492cfd23 --- /dev/null +++ b/clang/include/clang/Frontend/FrontendPluginRegistry.h @@ -0,0 +1,23 @@ +//===-- FrontendAction.h - Pluggable 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_PLUGINFRONTENDACTION_H +#define LLVM_CLANG_FRONTEND_PLUGINFRONTENDACTION_H + +#include "clang/Frontend/FrontendAction.h" +#include "llvm/Support/Registry.h" + +namespace clang { + +/// The frontend plugin registry. +typedef llvm::Registry FrontendPluginRegistry; + +} // end namespace clang + +#endif diff --git a/clang/tools/clang-cc/Options.cpp b/clang/tools/clang-cc/Options.cpp index 33b8d77d1583..3c57479b92a7 100644 --- a/clang/tools/clang-cc/Options.cpp +++ b/clang/tools/clang-cc/Options.cpp @@ -26,6 +26,7 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/CommandLine.h" +#include "llvm/Support/RegistryParser.h" #include using namespace clang; @@ -383,6 +384,11 @@ OutputFile("o", llvm::cl::value_desc("path"), llvm::cl::desc("Specify output file")); +static llvm::cl::opt +PluginActionName("plugin", + llvm::cl::desc("Use the named plugin action " + "(use \"help\" to list available options)")); + static llvm::cl::opt ProgAction(llvm::cl::desc("Choose output type:"), llvm::cl::ZeroOrMore, llvm::cl::init(ParseSyntaxOnly), @@ -885,12 +891,18 @@ void clang::InitializeDiagnosticOptions(DiagnosticOptions &Opts) { void clang::InitializeFrontendOptions(FrontendOptions &Opts) { using namespace frontendoptions; + // Select program action. + Opts.ProgramAction = ProgAction; + if (PluginActionName.getPosition()) { + Opts.ProgramAction = frontend::PluginAction; + Opts.ActionName = PluginActionName; + } + Opts.CodeCompletionAt = CodeCompletionAt; Opts.DebugCodeCompletionPrinter = CodeCompletionDebugPrinter; Opts.DisableFree = DisableFree; Opts.EmptyInputOnly = EmptyInputOnly; Opts.FixItLocations = FixItAtLocations; - Opts.ProgramAction = ProgAction; Opts.OutputFile = OutputFile; Opts.RelocatablePCH = RelocatablePCH; Opts.ShowMacrosInCodeCompletion = CodeCompletionWantsMacros; diff --git a/clang/tools/clang-cc/clang-cc.cpp b/clang/tools/clang-cc/clang-cc.cpp index 75640acfedb3..3df2edc4caeb 100644 --- a/clang/tools/clang-cc/clang-cc.cpp +++ b/clang/tools/clang-cc/clang-cc.cpp @@ -24,6 +24,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendActions.h" #include "clang/Frontend/FrontendDiagnostic.h" +#include "clang/Frontend/FrontendPluginRegistry.h" #include "clang/Frontend/PathDiagnosticClients.h" #include "clang/Frontend/PreprocessorOptions.h" #include "clang/Frontend/PreprocessorOutputOptions.h" @@ -36,6 +37,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/PluginLoader.h" #include "llvm/Support/PrettyStackTrace.h" +#include "llvm/Support/Registry.h" #include "llvm/Support/Timer.h" #include "llvm/Support/raw_ostream.h" #include "llvm/System/Host.h" @@ -81,11 +83,13 @@ std::string GetBuiltinIncludePath(const char *Argv0) { /// anything. llvm::Timer *ClangFrontendTimer = 0; -static FrontendAction *CreateFrontendAction(frontend::ActionKind AK) { +static FrontendAction *CreateFrontendAction(CompilerInstance &CI) { using namespace clang::frontend; - switch (AK) { - default: return 0; + switch (CI.getFrontendOpts().ProgramAction) { + default: + llvm::llvm_unreachable("Invalid program action!"); + case ASTDump: return new ASTDumpAction(); case ASTPrint: return new ASTPrintAction(); case ASTPrintXML: return new ASTPrintXMLAction(); @@ -105,6 +109,30 @@ static FrontendAction *CreateFrontendAction(frontend::ActionKind AK) { case ParseNoop: return new ParseOnlyAction(); case ParsePrintCallbacks: return new PrintParseAction(); case ParseSyntaxOnly: return new SyntaxOnlyAction(); + + case PluginAction: { + if (CI.getFrontendOpts().ActionName == "help") { + llvm::errs() << "clang-cc plugins:\n"; + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), + ie = FrontendPluginRegistry::end(); + it != ie; ++it) + llvm::errs() << " " << it->getName() << " - " << it->getDesc() << "\n"; + exit(1); + } + + for (FrontendPluginRegistry::iterator it = + FrontendPluginRegistry::begin(), ie = FrontendPluginRegistry::end(); + it != ie; ++it) { + if (it->getName() == CI.getFrontendOpts().ActionName) + return it->instantiate(); + } + + CI.getDiagnostics().Report(diag::err_fe_invalid_plugin_name) + << CI.getFrontendOpts().ActionName; + return 0; + } + case PrintDeclContext: return new DeclContextPrintAction(); case PrintPreprocessedInput: return new PrintPreprocessedAction(); case RewriteBlocks: return new RewriteBlocksAction(); @@ -279,9 +307,10 @@ int main(int argc, char **argv) { Clang.createPreprocessor(); } - llvm::OwningPtr Act( - CreateFrontendAction(Clang.getFrontendOpts().ProgramAction)); - assert(Act && "Invalid program action!"); + llvm::OwningPtr Act(CreateFrontendAction(Clang)); + if (!Act) + break; + Act->setCurrentTimer(ClangFrontendTimer); if (Act->BeginSourceFile(Clang, InFile, IsAST)) { Act->Execute(); @@ -315,3 +344,4 @@ int main(int argc, char **argv) { return (Clang.getDiagnostics().getNumErrors() != 0); } +