Skip to content

Commit ad38fbf

Browse files
committed
Recommit r315087 "[refactor] add support for refactoring options"
The recommit fixes a UB bug that occurred only on a small number of bots. Original message: 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: 315661
1 parent 5a2b02c commit ad38fbf

File tree

11 files changed

+423
-28
lines changed

11 files changed

+423
-28
lines changed

clang/include/clang/Tooling/Refactoring/RefactoringActionRule.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
namespace clang {
1717
namespace tooling {
1818

19+
class RefactoringOptionVisitor;
1920
class RefactoringResultConsumer;
2021
class RefactoringRuleContext;
2122

@@ -43,6 +44,14 @@ class RefactoringActionRule : public RefactoringActionRuleBase {
4344
/// Returns true when the rule has a source selection requirement that has
4445
/// to be fullfilled before refactoring can be performed.
4546
virtual bool hasSelectionRequirement() = 0;
47+
48+
/// Traverses each refactoring option used by the rule and invokes the
49+
/// \c visit callback in the consumer for each option.
50+
///
51+
/// Options are visited in the order of use, e.g. if a rule has two
52+
/// requirements that use options, the options from the first requirement
53+
/// are visited before the options in the second requirement.
54+
virtual void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) = 0;
4655
};
4756

4857
} // end namespace tooling

clang/include/clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_ACTION_RULE_REQUIREMENTS_H
1212

1313
#include "clang/Basic/LLVM.h"
14+
#include "clang/Tooling/Refactoring/RefactoringOption.h"
1415
#include "clang/Tooling/Refactoring/RefactoringRuleContext.h"
1516
#include "llvm/Support/Error.h"
1617
#include <type_traits>
@@ -53,6 +54,45 @@ class SourceRangeSelectionRequirement : public SourceSelectionRequirement {
5354
}
5455
};
5556

57+
/// A base class for any requirement that requires some refactoring options.
58+
class RefactoringOptionsRequirement : public RefactoringActionRuleRequirement {
59+
public:
60+
virtual ~RefactoringOptionsRequirement() {}
61+
62+
/// Returns the set of refactoring options that are used when evaluating this
63+
/// requirement.
64+
virtual ArrayRef<std::shared_ptr<RefactoringOption>>
65+
getRefactoringOptions() const = 0;
66+
};
67+
68+
/// A requirement that evaluates to the value of the given \c OptionType when
69+
/// the \c OptionType is a required option. When the \c OptionType is an
70+
/// optional option, the requirement will evaluate to \c None if the option is
71+
/// not specified or to an appropriate value otherwise.
72+
template <typename OptionType>
73+
class OptionRequirement : public RefactoringOptionsRequirement {
74+
public:
75+
OptionRequirement() : Opt(createRefactoringOption<OptionType>()) {}
76+
77+
ArrayRef<std::shared_ptr<RefactoringOption>>
78+
getRefactoringOptions() const final override {
79+
return Opt;
80+
}
81+
82+
Expected<typename OptionType::ValueType>
83+
evaluate(RefactoringRuleContext &) const {
84+
return static_cast<OptionType *>(Opt.get())->getValue();
85+
}
86+
87+
private:
88+
/// The partially-owned option.
89+
///
90+
/// The ownership of the option is shared among the different requirements
91+
/// because the same option can be used by multiple rules in one refactoring
92+
/// action.
93+
std::shared_ptr<RefactoringOption> Opt;
94+
};
95+
5696
} // end namespace tooling
5797
} // end namespace clang
5898

clang/include/clang/Tooling/Refactoring/RefactoringActionRulesInternal.h

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,23 @@ namespace internal {
2424

2525
inline llvm::Error findError() { return llvm::Error::success(); }
2626

27+
inline void ignoreError() {}
28+
29+
template <typename FirstT, typename... RestT>
30+
void ignoreError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
31+
if (!First)
32+
llvm::consumeError(First.takeError());
33+
ignoreError(Rest...);
34+
}
35+
2736
/// Scans the tuple and returns a valid \c Error if any of the values are
2837
/// invalid.
2938
template <typename FirstT, typename... RestT>
3039
llvm::Error findError(Expected<FirstT> &First, Expected<RestT> &... Rest) {
31-
if (!First)
40+
if (!First) {
41+
ignoreError(Rest...);
3242
return First.takeError();
43+
}
3344
return findError(Rest...);
3445
}
3546

@@ -49,6 +60,34 @@ void invokeRuleAfterValidatingRequirements(
4960
RuleType((*std::get<Is>(Values))...).invoke(Consumer, Context);
5061
}
5162

63+
inline void visitRefactoringOptionsImpl(RefactoringOptionVisitor &) {}
64+
65+
/// Scans the list of requirements in a rule and visits all the refactoring
66+
/// options that are used by all the requirements.
67+
template <typename FirstT, typename... RestT>
68+
void visitRefactoringOptionsImpl(RefactoringOptionVisitor &Visitor,
69+
const FirstT &First, const RestT &... Rest) {
70+
struct OptionGatherer {
71+
RefactoringOptionVisitor &Visitor;
72+
73+
void operator()(const RefactoringOptionsRequirement &Requirement) {
74+
for (const auto &Option : Requirement.getRefactoringOptions())
75+
Option->passToVisitor(Visitor);
76+
}
77+
void operator()(const RefactoringActionRuleRequirement &) {}
78+
};
79+
(OptionGatherer{Visitor})(First);
80+
return visitRefactoringOptionsImpl(Visitor, Rest...);
81+
}
82+
83+
template <typename... RequirementTypes, size_t... Is>
84+
void visitRefactoringOptions(
85+
RefactoringOptionVisitor &Visitor,
86+
const std::tuple<RequirementTypes...> &Requirements,
87+
llvm::index_sequence<Is...>) {
88+
visitRefactoringOptionsImpl(Visitor, std::get<Is>(Requirements)...);
89+
}
90+
5291
/// A type trait that returns true when the given type list has at least one
5392
/// type whose base is the given base type.
5493
template <typename Base, typename First, typename... Rest>
@@ -97,6 +136,12 @@ createRefactoringActionRule(const RequirementTypes &... Requirements) {
97136
RequirementTypes...>::value;
98137
}
99138

139+
void visitRefactoringOptions(RefactoringOptionVisitor &Visitor) override {
140+
internal::visitRefactoringOptions(
141+
Visitor, Requirements,
142+
llvm::index_sequence_for<RequirementTypes...>());
143+
}
144+
100145
private:
101146
std::tuple<RequirementTypes...> Requirements;
102147
};
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
//===--- RefactoringOption.h - Clang refactoring library ------------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
11+
#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
12+
13+
#include "clang/Basic/LLVM.h"
14+
#include <memory>
15+
#include <type_traits>
16+
17+
namespace clang {
18+
namespace tooling {
19+
20+
class RefactoringOptionVisitor;
21+
22+
/// A refactoring option is an interface that describes a value that
23+
/// has an impact on the outcome of a refactoring.
24+
///
25+
/// Refactoring options can be specified using command-line arguments when
26+
/// the clang-refactor tool is used.
27+
class RefactoringOption {
28+
public:
29+
virtual ~RefactoringOption() {}
30+
31+
/// Returns the name of the refactoring option.
32+
///
33+
/// Each refactoring option must have a unique name.
34+
virtual StringRef getName() const = 0;
35+
36+
virtual StringRef getDescription() const = 0;
37+
38+
/// True when this option must be specified before invoking the refactoring
39+
/// action.
40+
virtual bool isRequired() const = 0;
41+
42+
/// Invokes the \c visit method in the option consumer that's appropriate
43+
/// for the option's value type.
44+
///
45+
/// For example, if the option stores a string value, this method will
46+
/// invoke the \c visit method with a reference to an std::string value.
47+
virtual void passToVisitor(RefactoringOptionVisitor &Visitor) = 0;
48+
};
49+
50+
/// Constructs a refactoring option of the given type.
51+
///
52+
/// The ownership of options is shared among requirements that use it because
53+
/// one option can be used by multiple rules in a refactoring action.
54+
template <typename OptionType>
55+
std::shared_ptr<OptionType> createRefactoringOption() {
56+
static_assert(std::is_base_of<RefactoringOption, OptionType>::value,
57+
"invalid option type");
58+
return std::make_shared<OptionType>();
59+
}
60+
61+
} // end namespace tooling
62+
} // end namespace clang
63+
64+
#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_H
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===--- RefactoringOptionVisitor.h - Clang refactoring library -----------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
11+
#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
12+
13+
#include "clang/Basic/LLVM.h"
14+
#include <type_traits>
15+
16+
namespace clang {
17+
namespace tooling {
18+
19+
class RefactoringOption;
20+
21+
/// An interface that declares functions that handle different refactoring
22+
/// option types.
23+
///
24+
/// A valid refactoring option type must have a corresponding \c visit
25+
/// declaration in this interface.
26+
class RefactoringOptionVisitor {
27+
public:
28+
virtual ~RefactoringOptionVisitor() {}
29+
30+
virtual void visit(const RefactoringOption &Opt,
31+
Optional<std::string> &Value) = 0;
32+
};
33+
34+
namespace traits {
35+
namespace internal {
36+
37+
template <typename T> struct HasHandle {
38+
private:
39+
template <typename ClassT>
40+
static auto check(ClassT *) -> typename std::is_same<
41+
decltype(std::declval<RefactoringOptionVisitor>().visit(
42+
std::declval<RefactoringOption>(), *std::declval<Optional<T> *>())),
43+
void>::type;
44+
45+
template <typename> static std::false_type check(...);
46+
47+
public:
48+
using Type = decltype(check<RefactoringOptionVisitor>(nullptr));
49+
};
50+
51+
} // end namespace internal
52+
53+
/// A type trait that returns true iff the given type is a type that can be
54+
/// stored in a refactoring option.
55+
template <typename T>
56+
struct IsValidOptionType : internal::HasHandle<T>::Type {};
57+
58+
} // end namespace traits
59+
} // end namespace tooling
60+
} // end namespace clang
61+
62+
#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTION_VISITOR_H
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
//===--- RefactoringOptions.h - Clang refactoring library -----------------===//
2+
//
3+
// The LLVM Compiler Infrastructure
4+
//
5+
// This file is distributed under the University of Illinois Open Source
6+
// License. See LICENSE.TXT for details.
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H
11+
#define LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H
12+
13+
#include "clang/Basic/LLVM.h"
14+
#include "clang/Tooling/Refactoring/RefactoringActionRuleRequirements.h"
15+
#include "clang/Tooling/Refactoring/RefactoringOption.h"
16+
#include "clang/Tooling/Refactoring/RefactoringOptionVisitor.h"
17+
#include "llvm/Support/Error.h"
18+
#include <type_traits>
19+
20+
namespace clang {
21+
namespace tooling {
22+
23+
/// A refactoring option that stores a value of type \c T.
24+
template <typename T, typename = typename std::enable_if<
25+
traits::IsValidOptionType<T>::value>::type>
26+
class OptionalRefactoringOption : public RefactoringOption {
27+
public:
28+
void passToVisitor(RefactoringOptionVisitor &Visitor) final override {
29+
Visitor.visit(*this, Value);
30+
}
31+
32+
bool isRequired() const override { return false; }
33+
34+
using ValueType = Optional<T>;
35+
36+
const ValueType &getValue() const { return Value; }
37+
38+
protected:
39+
Optional<T> Value;
40+
};
41+
42+
/// A required refactoring option that stores a value of type \c T.
43+
template <typename T, typename = typename std::enable_if<
44+
traits::IsValidOptionType<T>::value>::type>
45+
class RequiredRefactoringOption : public OptionalRefactoringOption<T> {
46+
public:
47+
using ValueType = T;
48+
49+
const ValueType &getValue() const {
50+
return *OptionalRefactoringOption<T>::Value;
51+
}
52+
bool isRequired() const final override { return true; }
53+
};
54+
55+
} // end namespace tooling
56+
} // end namespace clang
57+
58+
#endif // LLVM_CLANG_TOOLING_REFACTOR_REFACTORING_OPTIONS_H

clang/include/clang/Tooling/Refactoring/Rename/RenamingAction.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
#include "clang/Tooling/Refactoring.h"
1919
#include "clang/Tooling/Refactoring/AtomicChange.h"
20+
#include "clang/Tooling/Refactoring/RefactoringOptions.h"
2021
#include "clang/Tooling/Refactoring/Rename/SymbolOccurrences.h"
2122
#include "llvm/Support/Error.h"
2223

@@ -45,12 +46,19 @@ class RenamingAction {
4546
bool PrintLocations;
4647
};
4748

49+
class NewNameOption : public RequiredRefactoringOption<std::string> {
50+
public:
51+
StringRef getName() const override { return "new-name"; }
52+
StringRef getDescription() const override {
53+
return "The new name to change the symbol to";
54+
}
55+
};
56+
4857
/// Returns source replacements that correspond to the rename of the given
4958
/// symbol occurrences.
5059
llvm::Expected<std::vector<AtomicChange>>
5160
createRenameReplacements(const SymbolOccurrences &Occurrences,
52-
const SourceManager &SM,
53-
ArrayRef<StringRef> NewNameStrings);
61+
const SourceManager &SM, const SymbolName &NewName);
5462

5563
/// Rename all symbols identified by the given USRs.
5664
class QualifiedRenamingAction {

0 commit comments

Comments
 (0)