diff options
author | Alex Lorenz <arphaman@gmail.com> | 2017-10-06 18:12:29 +0000 |
---|---|---|
committer | Alex Lorenz <arphaman@gmail.com> | 2017-10-06 18:12:29 +0000 |
commit | 15da33480b6b887360b5675ee7962d0ed15f3403 (patch) | |
tree | ff3d0365797db1317fe58b18b245f17e433d235b /clang/tools/clang-refactor/ClangRefactor.cpp | |
parent | 46a59fdab6d22fd701c875df31af9bc26eec24ef (diff) | |
download | bcm5719-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.cpp | 121 |
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 |