summaryrefslogtreecommitdiffstats
path: root/clang/tools/clang-refactor/ClangRefactor.cpp
diff options
context:
space:
mode:
authorAlex Lorenz <arphaman@gmail.com>2017-10-06 18:12:29 +0000
committerAlex Lorenz <arphaman@gmail.com>2017-10-06 18:12:29 +0000
commit15da33480b6b887360b5675ee7962d0ed15f3403 (patch)
treeff3d0365797db1317fe58b18b245f17e433d235b /clang/tools/clang-refactor/ClangRefactor.cpp
parent46a59fdab6d22fd701c875df31af9bc26eec24ef (diff)
downloadbcm5719-llvm-15da33480b6b887360b5675ee7962d0ed15f3403.tar.gz
bcm5719-llvm-15da33480b6b887360b5675ee7962d0ed15f3403.zip
[refactor] add support for refactoring options
This commit adds initial support for refactoring options. One can now use optional and required std::string options. This commit also adds a NewNameOption for the local-rename refactoring action to allow rename to work with custom names. Differential Revision: https://reviews.llvm.org/D37856 llvm-svn: 315087
Diffstat (limited to 'clang/tools/clang-refactor/ClangRefactor.cpp')
-rw-r--r--clang/tools/clang-refactor/ClangRefactor.cpp121
1 files changed, 114 insertions, 7 deletions
diff --git a/clang/tools/clang-refactor/ClangRefactor.cpp b/clang/tools/clang-refactor/ClangRefactor.cpp
index ff13773072e..47e09e7050b 100644
--- a/clang/tools/clang-refactor/ClangRefactor.cpp
+++ b/clang/tools/clang-refactor/ClangRefactor.cpp
@@ -18,6 +18,7 @@
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Refactoring.h"
#include "clang/Tooling/Refactoring/RefactoringAction.h"
+#include "clang/Tooling/Refactoring/RefactoringOptions.h"
#include "clang/Tooling/Refactoring/Rename/RenamingAction.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"
@@ -32,10 +33,10 @@ namespace cl = llvm::cl;
namespace opts {
-static cl::OptionCategory CommonRefactorOptions("Common refactoring options");
+static cl::OptionCategory CommonRefactorOptions("Refactoring options");
static cl::opt<bool> Verbose("v", cl::desc("Use verbose output"),
- cl::cat(CommonRefactorOptions),
+ cl::cat(cl::GeneralCategory),
cl::sub(*cl::AllSubCommands));
} // end namespace opts
@@ -116,6 +117,92 @@ SourceSelectionArgument::fromString(StringRef Value) {
return nullptr;
}
+/// A container that stores the command-line options used by a single
+/// refactoring option.
+class RefactoringActionCommandLineOptions {
+public:
+ void addStringOption(const RefactoringOption &Option,
+ std::unique_ptr<cl::opt<std::string>> CLOption) {
+ StringOptions[&Option] = std::move(CLOption);
+ }
+
+ const cl::opt<std::string> &
+ getStringOption(const RefactoringOption &Opt) const {
+ auto It = StringOptions.find(&Opt);
+ return *It->second;
+ }
+
+private:
+ llvm::DenseMap<const RefactoringOption *,
+ std::unique_ptr<cl::opt<std::string>>>
+ StringOptions;
+};
+
+/// Passes the command-line option values to the options used by a single
+/// refactoring action rule.
+class CommandLineRefactoringOptionVisitor final
+ : public RefactoringOptionVisitor {
+public:
+ CommandLineRefactoringOptionVisitor(
+ const RefactoringActionCommandLineOptions &Options)
+ : Options(Options) {}
+
+ void visit(const RefactoringOption &Opt,
+ Optional<std::string> &Value) override {
+ const cl::opt<std::string> &CLOpt = Options.getStringOption(Opt);
+ if (!CLOpt.getValue().empty()) {
+ Value = CLOpt.getValue();
+ return;
+ }
+ Value = None;
+ if (Opt.isRequired())
+ MissingRequiredOptions.push_back(&Opt);
+ }
+
+ ArrayRef<const RefactoringOption *> getMissingRequiredOptions() const {
+ return MissingRequiredOptions;
+ }
+
+private:
+ llvm::SmallVector<const RefactoringOption *, 4> MissingRequiredOptions;
+ const RefactoringActionCommandLineOptions &Options;
+};
+
+/// Creates the refactoring options used by all the rules in a single
+/// refactoring action.
+class CommandLineRefactoringOptionCreator final
+ : public RefactoringOptionVisitor {
+public:
+ CommandLineRefactoringOptionCreator(
+ cl::OptionCategory &Category, cl::SubCommand &Subcommand,
+ RefactoringActionCommandLineOptions &Options)
+ : Category(Category), Subcommand(Subcommand), Options(Options) {}
+
+ void visit(const RefactoringOption &Opt, Optional<std::string> &) override {
+ if (Visited.insert(&Opt).second)
+ Options.addStringOption(Opt, create<std::string>(Opt));
+ }
+
+private:
+ template <typename T>
+ std::unique_ptr<cl::opt<T>> create(const RefactoringOption &Opt) {
+ if (!OptionNames.insert(Opt.getName()).second)
+ llvm::report_fatal_error("Multiple identical refactoring options "
+ "specified for one refactoring action");
+ // FIXME: cl::Required can be specified when this option is present
+ // in all rules in an action.
+ return llvm::make_unique<cl::opt<T>>(
+ Opt.getName(), cl::desc(Opt.getDescription()), cl::Optional,
+ cl::cat(Category), cl::sub(Subcommand));
+ }
+
+ llvm::SmallPtrSet<const RefactoringOption *, 8> Visited;
+ llvm::StringSet<> OptionNames;
+ cl::OptionCategory &Category;
+ cl::SubCommand &Subcommand;
+ RefactoringActionCommandLineOptions &Options;
+};
+
/// A subcommand that corresponds to individual refactoring action.
class RefactoringActionSubcommand : public cl::SubCommand {
public:
@@ -138,6 +225,12 @@ public:
"<file>:<line>:<column>)"),
cl::cat(Category), cl::sub(*this));
}
+ // Create the refactoring options.
+ for (const auto &Rule : this->ActionRules) {
+ CommandLineRefactoringOptionCreator OptionCreator(Category, *this,
+ Options);
+ Rule->visitRefactoringOptions(OptionCreator);
+ }
}
~RefactoringActionSubcommand() { unregisterSubCommand(); }
@@ -160,11 +253,17 @@ public:
assert(Selection && "selection not supported!");
return ParsedSelection.get();
}
+
+ const RefactoringActionCommandLineOptions &getOptions() const {
+ return Options;
+ }
+
private:
std::unique_ptr<RefactoringAction> Action;
RefactoringActionRules ActionRules;
std::unique_ptr<cl::opt<std::string>> Selection;
std::unique_ptr<SourceSelectionArgument> ParsedSelection;
+ RefactoringActionCommandLineOptions Options;
};
class ClangRefactorConsumer : public RefactoringResultConsumer {
@@ -262,14 +361,22 @@ public:
bool HasSelection = false;
for (const auto &Rule : Subcommand.getActionRules()) {
+ bool SelectionMatches = true;
if (Rule->hasSelectionRequirement()) {
HasSelection = true;
- if (Subcommand.getSelection())
- MatchingRules.push_back(Rule.get());
- else
+ if (!Subcommand.getSelection()) {
MissingOptions.insert("selection");
+ SelectionMatches = false;
+ }
+ }
+ CommandLineRefactoringOptionVisitor Visitor(Subcommand.getOptions());
+ Rule->visitRefactoringOptions(Visitor);
+ if (SelectionMatches && Visitor.getMissingRequiredOptions().empty()) {
+ MatchingRules.push_back(Rule.get());
+ continue;
}
- // FIXME (Alex L): Support custom options.
+ for (const RefactoringOption *Opt : Visitor.getMissingRequiredOptions())
+ MissingOptions.insert(Opt->getName());
}
if (MatchingRules.empty()) {
llvm::errs() << "error: '" << Subcommand.getName()
@@ -326,7 +433,7 @@ int main(int argc, const char **argv) {
ClangRefactorTool Tool;
CommonOptionsParser Options(
- argc, argv, opts::CommonRefactorOptions, cl::ZeroOrMore,
+ argc, argv, cl::GeneralCategory, cl::ZeroOrMore,
"Clang-based refactoring tool for C, C++ and Objective-C");
// Figure out which action is specified by the user. The user must specify
OpenPOWER on IntegriCloud