diff --git a/clang/examples/CMakeLists.txt b/clang/examples/CMakeLists.txt --- a/clang/examples/CMakeLists.txt +++ b/clang/examples/CMakeLists.txt @@ -8,3 +8,4 @@ add_subdirectory(AnnotateFunctions) add_subdirectory(Attribute) add_subdirectory(CallSuperAttribute) +add_subdirectory(PluginsOrder) diff --git a/clang/examples/PluginsOrder/CMakeLists.txt b/clang/examples/PluginsOrder/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/clang/examples/PluginsOrder/CMakeLists.txt @@ -0,0 +1,11 @@ +add_llvm_library(PluginsOrder MODULE PluginsOrder.cpp PLUGIN_TOOL clang) + +if(LLVM_ENABLE_PLUGINS AND (WIN32 OR CYGWIN)) + set(LLVM_LINK_COMPONENTS + Support + ) + clang_target_link_libraries(PluginsOrder PRIVATE + clangAST + clangFrontend + ) +endif() diff --git a/clang/examples/PluginsOrder/PluginsOrder.cpp b/clang/examples/PluginsOrder/PluginsOrder.cpp new file mode 100644 --- /dev/null +++ b/clang/examples/PluginsOrder/PluginsOrder.cpp @@ -0,0 +1,117 @@ +//===- PluginsOrder.cpp ---------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "clang/AST/AST.h" +#include "clang/AST/ASTConsumer.h" +#include "clang/Frontend/FrontendPluginRegistry.h" +using namespace clang; + +namespace { + +class AlwaysBeforeConsumer : public ASTConsumer { +public: + void HandleTranslationUnit(ASTContext &) override { + llvm::errs() << "always-before\n"; + } +}; + +class AlwaysBeforeAction : public PluginASTAction { +public: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef) override { + return std::make_unique(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &args) override { + return true; + } + + PluginASTAction::ActionType getActionType() override { + return AddBeforeMainAction; + } +}; + +class AlwaysAfterConsumer : public ASTConsumer { +public: + void HandleTranslationUnit(ASTContext &) override { + llvm::errs() << "always-after\n"; + } +}; + +class AlwaysAfterAction : public PluginASTAction { +public: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef) override { + return std::make_unique(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &args) override { + return true; + } + + PluginASTAction::ActionType getActionType() override { + return AddAfterMainAction; + } +}; + +class CmdAfterConsumer : public ASTConsumer { +public: + void HandleTranslationUnit(ASTContext &) override { + llvm::errs() << "cmd-after\n"; + } +}; + +class CmdAfterAction : public PluginASTAction { +public: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef) override { + return std::make_unique(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &args) override { + return true; + } + + PluginASTAction::ActionType getActionType() override { + return CmdlineAfterMainAction; + } +}; + +class CmdBeforeConsumer : public ASTConsumer { +public: + void HandleTranslationUnit(ASTContext &) override { + llvm::errs() << "cmd-before\n"; + } +}; + +class CmdBeforeAction : public PluginASTAction { +public: + std::unique_ptr CreateASTConsumer(CompilerInstance &CI, + llvm::StringRef) override { + return std::make_unique(); + } + + bool ParseArgs(const CompilerInstance &CI, + const std::vector &args) override { + return true; + } + + PluginASTAction::ActionType getActionType() override { + return CmdlineBeforeMainAction; + } +}; + +} // namespace + +static FrontendPluginRegistry::Add X1("cmd-before", ""); +static FrontendPluginRegistry::Add X2("cmd-after", ""); +static FrontendPluginRegistry::Add X3("always-before", ""); +static FrontendPluginRegistry::Add X4("always-after", ""); diff --git a/clang/include/clang/Frontend/FrontendAction.h b/clang/include/clang/Frontend/FrontendAction.h --- a/clang/include/clang/Frontend/FrontendAction.h +++ b/clang/include/clang/Frontend/FrontendAction.h @@ -270,17 +270,18 @@ const std::vector &arg) = 0; enum ActionType { - Cmdline, ///< Action is determined by the cc1 command-line - ReplaceAction, ///< Replace the main action - AddBeforeMainAction, ///< Execute the action before the main action - AddAfterMainAction ///< Execute the action after the main action + CmdlineBeforeMainAction, ///< Execute the action before the main action if + ///< on the command line + CmdlineAfterMainAction, ///< Execute the action after the main action if on + ///< the command line + ReplaceAction, ///< Replace the main action + AddBeforeMainAction, ///< Execute the action before the main action + AddAfterMainAction ///< Execute the action after the main action }; /// Get the action type for this plugin /// - /// \return The action type. If the type is Cmdline then by default the - /// plugin does nothing and what it does is determined by the cc1 - /// command-line. - virtual ActionType getActionType() { return Cmdline; } + /// \return The action type. By default we use CmdlineAfterMainAction. + virtual ActionType getActionType() { return CmdlineAfterMainAction; } }; /// Abstract base class to use for preprocessor-based frontend actions. diff --git a/clang/lib/Frontend/FrontendAction.cpp b/clang/lib/Frontend/FrontendAction.cpp --- a/clang/lib/Frontend/FrontendAction.cpp +++ b/clang/lib/Frontend/FrontendAction.cpp @@ -187,14 +187,19 @@ FrontendPluginRegistry::entries()) { std::unique_ptr P = Plugin.instantiate(); PluginASTAction::ActionType ActionType = P->getActionType(); - if (ActionType == PluginASTAction::Cmdline) { + if (ActionType == PluginASTAction::CmdlineAfterMainAction || + ActionType == PluginASTAction::CmdlineBeforeMainAction) { // This is O(|plugins| * |add_plugins|), but since both numbers are // way below 50 in practice, that's ok. if (llvm::any_of(CI.getFrontendOpts().AddPluginActions, [&](const std::string &PluginAction) { return PluginAction == Plugin.getName(); - })) - ActionType = PluginASTAction::AddAfterMainAction; + })) { + if (ActionType == PluginASTAction::CmdlineBeforeMainAction) + ActionType = PluginASTAction::AddBeforeMainAction; + else + ActionType = PluginASTAction::AddAfterMainAction; + } } if ((ActionType == PluginASTAction::AddBeforeMainAction || ActionType == PluginASTAction::AddAfterMainAction) && diff --git a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp --- a/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp +++ b/clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp @@ -79,7 +79,7 @@ if (Plugin.getName() == CI.getFrontendOpts().ActionName) { std::unique_ptr P(Plugin.instantiate()); if ((P->getActionType() != PluginASTAction::ReplaceAction && - P->getActionType() != PluginASTAction::Cmdline) || + P->getActionType() != PluginASTAction::CmdlineAfterMainAction) || !P->ParseArgs( CI, CI.getFrontendOpts().PluginArgs[std::string(Plugin.getName())])) diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -97,6 +97,7 @@ AnnotateFunctions CallSuperAttr clang-interpreter + PluginsOrder PrintFunctionNames ) endif () diff --git a/clang/test/Frontend/plugins-order.c b/clang/test/Frontend/plugins-order.c new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/plugins-order.c @@ -0,0 +1,12 @@ +// REQUIRES: plugins, examples + +// RUN: %clang_cc1 -load %llvmshlibdir/PluginsOrder%pluginext %s 2>&1 | FileCheck %s --check-prefix=ALWAYS +// ALWAYS: always-before +// ALWAYS-NEXT: always-after + +// RUN: %clang_cc1 -load %llvmshlibdir/PluginsOrder%pluginext %s -add-plugin cmd-after -add-plugin cmd-before 2>&1 | FileCheck %s --check-prefix=ALL +// RUN: %clang_cc1 -load %llvmshlibdir/PluginsOrder%pluginext %s -add-plugin cmd-before -add-plugin cmd-after 2>&1 | FileCheck %s --check-prefix=ALL +// ALL: cmd-before +// ALL-NEXT: always-before +// ALL-NEXT: cmd-after +// ALL-NEXT: always-after