[clang] Add plugin ActionType to run command line plugin before main action

Currently we have a way to run a plugin if specified on the command line
after the main action, and ways to unconditionally run the plugin before
or after the main action, but no way to run a plugin if specified on the
command line before the main action.

This introduces the missing option.

This is helpful because -clear-ast-before-backend clears the AST before
codegen, while some plugins may want access to the AST.

Reviewed By: dblaikie

Differential Revision: https://reviews.llvm.org/D112096
This commit is contained in:
Arthur Eubanks 2021-10-19 14:50:44 -07:00
parent eabf11f9ea
commit fe66433fe1
8 changed files with 160 additions and 12 deletions

View File

@ -8,3 +8,4 @@ add_subdirectory(PrintFunctionNames)
add_subdirectory(AnnotateFunctions)
add_subdirectory(Attribute)
add_subdirectory(CallSuperAttribute)
add_subdirectory(PluginsOrder)

View File

@ -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()

View File

@ -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<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef) override {
return std::make_unique<AlwaysBeforeConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string> &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<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef) override {
return std::make_unique<AlwaysAfterConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string> &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<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef) override {
return std::make_unique<CmdAfterConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string> &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<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
llvm::StringRef) override {
return std::make_unique<CmdBeforeConsumer>();
}
bool ParseArgs(const CompilerInstance &CI,
const std::vector<std::string> &args) override {
return true;
}
PluginASTAction::ActionType getActionType() override {
return CmdlineBeforeMainAction;
}
};
} // namespace
static FrontendPluginRegistry::Add<CmdBeforeAction> X1("cmd-before", "");
static FrontendPluginRegistry::Add<CmdAfterAction> X2("cmd-after", "");
static FrontendPluginRegistry::Add<AlwaysBeforeAction> X3("always-before", "");
static FrontendPluginRegistry::Add<AlwaysAfterAction> X4("always-after", "");

View File

@ -270,17 +270,18 @@ public:
const std::vector<std::string> &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.

View File

@ -187,14 +187,19 @@ FrontendAction::CreateWrappedASTConsumer(CompilerInstance &CI,
FrontendPluginRegistry::entries()) {
std::unique_ptr<PluginASTAction> 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) &&

View File

@ -79,7 +79,7 @@ CreateFrontendBaseAction(CompilerInstance &CI) {
if (Plugin.getName() == CI.getFrontendOpts().ActionName) {
std::unique_ptr<PluginASTAction> 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())]))

View File

@ -97,6 +97,7 @@ if (CLANG_BUILD_EXAMPLES)
AnnotateFunctions
CallSuperAttr
clang-interpreter
PluginsOrder
PrintFunctionNames
)
endif ()

View File

@ -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