clang  10.0.0svn
RewriteRule.cpp
Go to the documentation of this file.
1 //===--- Transformer.cpp - Transformer library implementation ---*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
14 #include "llvm/ADT/Optional.h"
15 #include "llvm/ADT/StringRef.h"
16 #include "llvm/Support/Errc.h"
17 #include "llvm/Support/Error.h"
18 #include <map>
19 #include <string>
20 #include <utility>
21 #include <vector>
22 
23 using namespace clang;
24 using namespace transformer;
25 
27 using ast_matchers::internal::DynTypedMatcher;
29 
31 
36  for (const auto &Edit : Edits) {
37  Expected<CharSourceRange> Range = Edit.TargetRange(Result);
38  if (!Range)
39  return Range.takeError();
41  tooling::getRangeForEdit(*Range, *Result.Context);
42  // FIXME: let user specify whether to treat this case as an error or ignore
43  // it as is currently done.
44  if (!EditRange)
46  auto Replacement = Edit.Replacement(Result);
47  if (!Replacement)
48  return Replacement.takeError();
50  T.Range = *EditRange;
51  T.Replacement = std::move(*Replacement);
52  Transformations.push_back(std::move(T));
53  }
54  return Transformations;
55 }
56 
58  ASTEdit E;
59  E.TargetRange = std::move(S);
60  E.Replacement = std::move(Replacement);
61  return E;
62 }
63 
65  TextGenerator Explanation) {
67  std::move(M), std::move(Edits), std::move(Explanation), {}}}};
68 }
69 
70 void transformer::addInclude(RewriteRule &Rule, StringRef Header,
71  IncludeFormat Format) {
72  for (auto &Case : Rule.Cases)
73  Case.AddedIncludes.emplace_back(Header.str(), Format);
74 }
75 
76 #ifndef NDEBUG
77 // Filters for supported matcher kinds. FIXME: Explicitly list the allowed kinds
78 // (all node matcher types except for `QualType` and `Type`), rather than just
79 // banning `QualType` and `Type`.
80 static bool hasValidKind(const DynTypedMatcher &M) {
81  return !M.canConvertTo<QualType>();
82 }
83 #endif
84 
85 // Binds each rule's matcher to a unique (and deterministic) tag based on
86 // `TagBase` and the id paired with the case.
87 static std::vector<DynTypedMatcher> taggedMatchers(
88  StringRef TagBase,
89  const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases) {
90  std::vector<DynTypedMatcher> Matchers;
91  Matchers.reserve(Cases.size());
92  for (const auto &Case : Cases) {
93  std::string Tag = (TagBase + Twine(Case.first)).str();
94  // HACK: Many matchers are not bindable, so ensure that tryBind will work.
95  DynTypedMatcher BoundMatcher(Case.second.Matcher);
96  BoundMatcher.setAllowBind(true);
97  auto M = BoundMatcher.tryBind(Tag);
98  Matchers.push_back(*std::move(M));
99  }
100  return Matchers;
101 }
102 
103 // Simply gathers the contents of the various rules into a single rule. The
104 // actual work to combine these into an ordered choice is deferred to matcher
105 // registration.
107  RewriteRule R;
108  for (auto &Rule : Rules)
109  R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());
110  return R;
111 }
112 
113 std::vector<DynTypedMatcher>
115  // Map the cases into buckets of matchers -- one for each "root" AST kind,
116  // which guarantees that they can be combined in a single anyOf matcher. Each
117  // case is paired with an identifying number that is converted to a string id
118  // in `taggedMatchers`.
119  std::map<ASTNodeKind, SmallVector<std::pair<size_t, RewriteRule::Case>, 1>>
120  Buckets;
121  const SmallVectorImpl<RewriteRule::Case> &Cases = Rule.Cases;
122  for (int I = 0, N = Cases.size(); I < N; ++I) {
123  assert(hasValidKind(Cases[I].Matcher) &&
124  "Matcher must be non-(Qual)Type node matcher");
125  Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);
126  }
127 
128  std::vector<DynTypedMatcher> Matchers;
129  for (const auto &Bucket : Buckets) {
130  DynTypedMatcher M = DynTypedMatcher::constructVariadic(
131  DynTypedMatcher::VO_AnyOf, Bucket.first,
132  taggedMatchers("Tag", Bucket.second));
133  M.setAllowBind(true);
134  // `tryBind` is guaranteed to succeed, because `AllowBind` was set to true.
135  Matchers.push_back(*M.tryBind(RewriteRule::RootID));
136  }
137  return Matchers;
138 }
139 
140 DynTypedMatcher transformer::detail::buildMatcher(const RewriteRule &Rule) {
141  std::vector<DynTypedMatcher> Ms = buildMatchers(Rule);
142  assert(Ms.size() == 1 && "Cases must have compatible matchers.");
143  return Ms[0];
144 }
145 
147  auto &NodesMap = Result.Nodes.getMap();
148  auto Root = NodesMap.find(RewriteRule::RootID);
149  assert(Root != NodesMap.end() && "Transformation failed: missing root node.");
151  CharSourceRange::getTokenRange(Root->second.getSourceRange()),
152  *Result.Context);
153  if (RootRange)
154  return RootRange->getBegin();
155  // The match doesn't have a coherent range, so fall back to the expansion
156  // location as the "beginning" of the match.
157  return Result.SourceManager->getExpansionLoc(
158  Root->second.getSourceRange().getBegin());
159 }
160 
161 // Finds the case that was "selected" -- that is, whose matcher triggered the
162 // `MatchResult`.
163 const RewriteRule::Case &
165  const RewriteRule &Rule) {
166  if (Rule.Cases.size() == 1)
167  return Rule.Cases[0];
168 
169  auto &NodesMap = Result.Nodes.getMap();
170  for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {
171  std::string Tag = ("Tag" + Twine(i)).str();
172  if (NodesMap.find(Tag) != NodesMap.end())
173  return Rule.Cases[i];
174  }
175  llvm_unreachable("No tag found for this rule.");
176 }
177 
178 constexpr llvm::StringLiteral RewriteRule::RootID;
A class to allow finding matches over the Clang AST.
A (possibly-)qualified type.
Definition: Type.h:643
Expected< SmallVector< Transformation, 1 > > translateEdits(const ast_matchers::MatchFinder::MatchResult &Result, llvm::ArrayRef< ASTEdit > Edits)
Attempts to translate Edits, which are in terms of AST nodes bound in the match Result, into Transformations, which are in terms of the source code text.
Definition: RewriteRule.cpp:33
void addInclude(RewriteRule &Rule, llvm::StringRef Header, IncludeFormat Format=IncludeFormat::Quoted)
For every case in Rule, adds an include directive for the given header.
static CharSourceRange getTokenRange(SourceRange R)
ast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRule &Rule)
Builds a single matcher for the rule, covering all of the rule&#39;s cases.
Description of a source-code transformation.
Definition: RewriteRule.h:106
MatchFinder::MatchResult MatchResult
IncludeFormat
Format of the path in an include directive – angle brackets or quotes.
Definition: RewriteRule.h:78
MatchFinder::MatchResult MatchResult
Definition: RewriteRule.cpp:30
static constexpr llvm::StringLiteral RootID
Definition: RewriteRule.h:121
SmallVector< Case, 1 > Cases
Definition: RewriteRule.h:117
static std::vector< DynTypedMatcher > taggedMatchers(StringRef TagBase, const SmallVectorImpl< std::pair< size_t, RewriteRule::Case >> &Cases)
Definition: RewriteRule.cpp:87
const RewriteRule::Case & findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, const RewriteRule &Rule)
Returns the Case of Rule that was selected in the match result.
Contains all information for a given match.
std::vector< ast_matchers::internal::DynTypedMatcher > buildMatchers(const RewriteRule &Rule)
Builds a set of matchers that cover the rule (one for each distinct node matcher base kind: Stmt...
MatchConsumer< CharSourceRange > RangeSelector
Definition: RangeSelector.h:27
ASTEdit change(RangeSelector Target, TextGenerator Replacement)
Replaces a portion of the source text with Replacement.
Definition: RewriteRule.cpp:57
Encodes a location in the source.
RewriteRule applyFirst(ArrayRef< RewriteRule > Rules)
Applies the first rule whose pattern matches; other rules are ignored.
RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, SmallVector< ASTEdit, 1 > Edits, TextGenerator Explanation=nullptr)
Convenience function for constructing a simple RewriteRule.
Dataflow Directional Tag Classes.
MatchConsumer< std::string > TextGenerator
Definition: RewriteRule.h:33
llvm::Optional< CharSourceRange > getRangeForEdit(const CharSourceRange &EditRange, const SourceManager &SM, const LangOptions &LangOpts)
Definition: SourceCode.cpp:34
A source "transformation," represented by a character range in the source to be replaced and a corres...
Definition: RewriteRule.h:261
SourceLocation getRuleMatchLoc(const ast_matchers::MatchFinder::MatchResult &Result)
Gets the beginning location of the source matched by a rewrite rule.
Defines the clang::SourceLocation class and associated facilities.
static bool hasValidKind(const DynTypedMatcher &M)
Definition: RewriteRule.cpp:80
Defines the RewriteRule class and related functions for creating, modifying and interpreting RewriteR...