1919#include " llvm/ADT/StringRef.h"
2020#include " llvm/Support/Errc.h"
2121#include " llvm/Support/Error.h"
22- #include < deque>
2322#include < string>
2423#include < utility>
2524#include < vector>
25+ #include < map>
2626
2727using namespace clang ;
2828using namespace tooling ;
@@ -80,52 +80,23 @@ void tooling::addInclude(RewriteRule &Rule, StringRef Header,
8080 Case.AddedIncludes .emplace_back (Header.str (), Format);
8181}
8282
83- // Determines whether A is a base type of B in the class hierarchy, including
84- // the implicit relationship of Type and QualType.
85- static bool isBaseOf (ASTNodeKind A, ASTNodeKind B) {
86- static auto TypeKind = ASTNodeKind::getFromNodeKind<Type>();
87- static auto QualKind = ASTNodeKind::getFromNodeKind<QualType>();
88- // / Mimic the implicit conversions of Matcher<>.
89- // / - From Matcher<Type> to Matcher<QualType>
90- // / - From Matcher<Base> to Matcher<Derived>
91- return (A.isSame (TypeKind) && B.isSame (QualKind)) || A.isBaseOf (B);
92- }
93-
94- // Try to find a common kind to which all of the rule's matchers can be
95- // converted.
96- static ASTNodeKind
97- findCommonKind (const SmallVectorImpl<RewriteRule::Case> &Cases) {
98- assert (!Cases.empty () && " Rule must have at least one case." );
99- ASTNodeKind JoinKind = Cases[0 ].Matcher .getSupportedKind ();
100- // Find a (least) Kind K, for which M.canConvertTo(K) holds, for all matchers
101- // M in Rules.
102- for (const auto &Case : Cases) {
103- auto K = Case.Matcher .getSupportedKind ();
104- if (isBaseOf (JoinKind, K)) {
105- JoinKind = K;
106- continue ;
107- }
108- if (K.isSame (JoinKind) || isBaseOf (K, JoinKind))
109- // JoinKind is already the lowest.
110- continue ;
111- // K and JoinKind are unrelated -- there is no least common kind.
112- return ASTNodeKind ();
113- }
114- return JoinKind;
83+ // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
84+ // (all node matcher types except for `QualType` and `Type`), rather than just
85+ // banning `QualType` and `Type`.
86+ static bool hasValidKind (const DynTypedMatcher &M) {
87+ return !M.canConvertTo <QualType>();
11588}
11689
11790// Binds each rule's matcher to a unique (and deterministic) tag based on
118- // `TagBase`.
119- static std::vector<DynTypedMatcher>
120- taggedMatchers ( StringRef TagBase,
121- const SmallVectorImpl<RewriteRule::Case> &Cases) {
91+ // `TagBase` and the id paired with the case .
92+ static std::vector<DynTypedMatcher> taggedMatchers (
93+ StringRef TagBase,
94+ const SmallVectorImpl<std::pair< size_t , RewriteRule::Case> > &Cases) {
12295 std::vector<DynTypedMatcher> Matchers;
12396 Matchers.reserve (Cases.size ());
124- size_t count = 0 ;
12597 for (const auto &Case : Cases) {
126- std::string Tag = (TagBase + Twine (count)).str ();
127- ++count;
128- auto M = Case.Matcher .tryBind (Tag);
98+ std::string Tag = (TagBase + Twine (Case.first )).str ();
99+ auto M = Case.second .Matcher .tryBind (Tag);
129100 assert (M && " RewriteRule matchers should be bindable." );
130101 Matchers.push_back (*std::move (M));
131102 }
@@ -142,22 +113,37 @@ RewriteRule tooling::applyFirst(ArrayRef<RewriteRule> Rules) {
142113 return R;
143114}
144115
145- static DynTypedMatcher joinCaseMatchers (const RewriteRule &Rule) {
146- assert (!Rule.Cases .empty () && " Rule must have at least one case." );
147- if (Rule.Cases .size () == 1 )
148- return Rule.Cases [0 ].Matcher ;
116+ std::vector<DynTypedMatcher>
117+ tooling::detail::buildMatchers (const RewriteRule &Rule) {
118+ // Map the cases into buckets of matchers -- one for each "root" AST kind,
119+ // which guarantees that they can be combined in a single anyOf matcher. Each
120+ // case is paired with an identifying number that is converted to a string id
121+ // in `taggedMatchers`.
122+ std::map<ASTNodeKind, SmallVector<std::pair<size_t , RewriteRule::Case>, 1 >>
123+ Buckets;
124+ const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases ;
125+ for (int I = 0 , N = Cases.size (); I < N; ++I) {
126+ assert (hasValidKind (Cases[I].Matcher ) &&
127+ " Matcher must be non-(Qual)Type node matcher" );
128+ Buckets[Cases[I].Matcher .getSupportedKind ()].emplace_back (I, Cases[I]);
129+ }
149130
150- auto CommonKind = findCommonKind (Rule.Cases );
151- assert (!CommonKind.isNone () && " Cases must have compatible matchers." );
152- return DynTypedMatcher::constructVariadic (
153- DynTypedMatcher::VO_AnyOf, CommonKind, taggedMatchers (" Tag" , Rule.Cases ));
131+ std::vector<DynTypedMatcher> Matchers;
132+ for (const auto &Bucket : Buckets) {
133+ DynTypedMatcher M = DynTypedMatcher::constructVariadic (
134+ DynTypedMatcher::VO_AnyOf, Bucket.first ,
135+ taggedMatchers (" Tag" , Bucket.second ));
136+ M.setAllowBind (true );
137+ // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
138+ Matchers.push_back (*M.tryBind (RewriteRule::RootID));
139+ }
140+ return Matchers;
154141}
155142
156143DynTypedMatcher tooling::detail::buildMatcher (const RewriteRule &Rule) {
157- DynTypedMatcher M = joinCaseMatchers (Rule);
158- M.setAllowBind (true );
159- // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
160- return *M.tryBind (RewriteRule::RootID);
144+ std::vector<DynTypedMatcher> Ms = buildMatchers (Rule);
145+ assert (Ms.size () == 1 && " Cases must have compatible matchers." );
146+ return Ms[0 ];
161147}
162148
163149// Finds the case that was "selected" -- that is, whose matcher triggered the
@@ -180,7 +166,8 @@ tooling::detail::findSelectedCase(const MatchResult &Result,
180166constexpr llvm::StringLiteral RewriteRule::RootID;
181167
182168void Transformer::registerMatchers (MatchFinder *MatchFinder) {
183- MatchFinder->addDynamicMatcher (tooling::detail::buildMatcher (Rule), this );
169+ for (auto &Matcher : tooling::detail::buildMatchers (Rule))
170+ MatchFinder->addDynamicMatcher (Matcher, this );
184171}
185172
186173void Transformer::run (const MatchResult &Result) {
@@ -222,12 +209,12 @@ void Transformer::run(const MatchResult &Result) {
222209 for (const auto &I : Case.AddedIncludes ) {
223210 auto &Header = I.first ;
224211 switch (I.second ) {
225- case IncludeFormat::Quoted:
226- AC.addHeader (Header);
227- break ;
228- case IncludeFormat::Angled:
229- AC.addHeader ((llvm::Twine (" <" ) + Header + " >" ).str ());
230- break ;
212+ case IncludeFormat::Quoted:
213+ AC.addHeader (Header);
214+ break ;
215+ case IncludeFormat::Angled:
216+ AC.addHeader ((llvm::Twine (" <" ) + Header + " >" ).str ());
217+ break ;
231218 }
232219 }
233220
0 commit comments