clang: lib/Tooling/Transformer/RewriteRule.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

16#include "llvm/ADT/StringRef.h"

17#include "llvm/Support/Errc.h"

18#include "llvm/Support/Error.h"

19#include

20#include

21#include

22#include

23

24using namespace clang;

25using namespace transformer;

26

28using ast_matchers::internal::DynTypedMatcher;

29

31

33

37 for (const auto &E : ASTEdits) {

40 return Range.takeError();

41 std::optional EditRange =

43

44

45

46

47

48

49

50 if (!EditRange)

53 T.Kind = E.Kind;

54 T.Range = *EditRange;

55 if (E.Replacement) {

56 auto Replacement = E.Replacement->eval(Result);

57 if (!Replacement)

58 return Replacement.takeError();

59 T.Replacement = std::move(*Replacement);

60 }

61 if (E.Note) {

62 auto Note = E.Note->eval(Result);

64 return Note.takeError();

65 T.Note = std::move(*Note);

66 }

67 if (E.Metadata) {

68 auto Metadata = E.Metadata(Result);

69 if (!Metadata)

70 return Metadata.takeError();

71 T.Metadata = std::move(*Metadata);

72 }

73 Edits.push_back(std::move(T));

74 }

75 return Edits;

76}

77

79 return [Edits = std::move(Edits)](const MatchResult &Result) {

81 };

82}

83

87 };

88}

89

91 return [Anchor = std::move(Anchor)](const MatchResult &Result)

95 return Range.takeError();

96

97

99 Result.SourceManager->getSpellingLoc(Range->getBegin());

101

102 E.Kind = EditKind::Range;

105 };

106}

107

110 if (Generators.size() == 1)

111 return std::move(Generators[0]);

112 return

113 [Gs = std::move(Generators)](

116 for (const auto &G : Gs) {

118 if (!Edits)

119 return Edits.takeError();

120 AllEdits.append(Edits->begin(), Edits->end());

121 }

122 return AllEdits;

123 };

124}

125

128 E.TargetRange = std::move(Target);

129 E.Replacement = std::move(Replacement);

130 return E;

131}

132

136 E.Note = std::move(Note);

137 return E;

138}

139

140namespace {

141

142class SimpleTextGenerator : public MatchComputationstd::string {

143 std::string S;

144

145public:

146 SimpleTextGenerator(std::string S) : S(std::move(S)) {}

148 std::string *Result) const override {

149 Result->append(S);

150 return llvm::Error::success();

151 }

152 std::string toString() const override {

153 return (llvm::Twine("text(\"") + S + "\")").str();

154 }

155};

156}

157

159 return std::make_shared(std::move(S));

160}

161

164}

165

167 switch (Format) {

168 case transformer::IncludeFormat::Quoted:

169 return Header.str();

170 case transformer::IncludeFormat::Angled:

171 return ("<" + Header + ">").str();

172 }

173 llvm_unreachable("Unknown transformer::IncludeFormat enum");

174}

175

179 E.Kind = EditKind::AddInclude;

182 return E;

183}

184

187 return editList(std::move(Edits));

188}

189

191 return edit(std::move(Edit));

192}

193

197 R.Cases = {{std::move(M), std::move(Edits)}};

198 return R;

199}

200

202 std::initializer_list Edits) {

205}

206

207namespace {

208

209

210

211template

212class BindingsMatcher : public ast_matchers::internal::MatcherInterface {

214 const ast_matchers::internal::Matcher InnerMatcher;

215

216public:

218 ast_matchers::internal::Matcher InnerMatcher)

219 : Nodes(std::move(Nodes)), InnerMatcher(std::move(InnerMatcher)) {}

220

221 bool matches(

222 const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,

223 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {

224 ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);

225 for (const auto &N : Nodes.getMap())

226 Result.setBinding(N.first, N.second);

227 if (InnerMatcher.matches(Node, Finder, &Result)) {

228 *Builder = std::move(Result);

229 return true;

230 }

231 return false;

232 }

233};

234

235

236

237

238

239

240template

241class DynamicForEachDescendantMatcher

242 : public ast_matchers::internal::MatcherInterface {

243 const DynTypedMatcher DescendantMatcher;

244

245public:

246 explicit DynamicForEachDescendantMatcher(DynTypedMatcher DescendantMatcher)

247 : DescendantMatcher(std::move(DescendantMatcher)) {}

248

250 const T &Node, ast_matchers::internal::ASTMatchFinder *Finder,

251 ast_matchers::internal::BoundNodesTreeBuilder *Builder) const override {

252 return Finder->matchesDescendantOf(

253 Node, this->DescendantMatcher, Builder,

254 ast_matchers::internal::ASTMatchFinder::BK_All);

255 }

256};

257

258template

259ast_matchers::internal::Matcher

261 DynTypedMatcher M) {

262 return ast_matchers::internal::makeMatcher(new BindingsMatcher(

263 std::move(Nodes),

264 ast_matchers::internal::makeMatcher(

265 new DynamicForEachDescendantMatcher(std::move(M)))));

266}

267

269public:

271

272 template

276 MF->addMatcher(forEachDescendantDynamically(Nodes, Matcher), this);

277 }

278

280 if (!Edits)

281 return;

283 auto Transformations = Rule.Cases[I].Edits(Result);

284 if (!Transformations) {

285 Edits = Transformations.takeError();

286 return;

287 }

288 Edits->append(Transformations->begin(), Transformations->end());

289 }

290

292

293

295};

296}

297

298template

302 ApplyRuleCallback Callback(std::move(Rule));

304 Callback.registerMatchers<T>(Result.Nodes, &Finder);

305 Finder.match(Node, *Result.Context);

306 return std::move(Callback.Edits);

307}

308

313}

314

319}

320

325}

326

331 if (const auto *Node = DNode.get<Decl>())

333 if (const auto *Node = DNode.get<Stmt>())

337

338 return llvm::make_errorllvm::StringError(

339 llvm::errc::invalid_argument,

340 "type unsupported for recursive rewriting, Kind=" +

342}

343

346 return [NodeId = std::move(NodeId),

347 Rule = std::move(Rule)](const MatchResult &Result)

350 Result.Nodes.getMap();

351 auto It = NodesMap.find(NodeId);

352 if (It == NodesMap.end())

353 return llvm::make_errorllvm::StringError(llvm::errc::invalid_argument,

354 "ID not bound: " + NodeId);

356 };

357}

358

361 for (auto &Case : Rule.Cases)

362 Case.Edits = flatten(std::move(Case.Edits), addInclude(Header, Format));

363}

364

365#ifndef NDEBUG

366

367

368

370 return !M.canConvertTo<QualType>();

371}

372#endif

373

374

375

376

377

379 StringRef TagBase,

380 const SmallVectorImpl<std::pair<size_t, RewriteRule::Case>> &Cases,

382 std::vector Matchers;

383 Matchers.reserve(Cases.size());

384 for (const auto &Case : Cases) {

385 std::string Tag = (TagBase + Twine(Case.first)).str();

386

387 DynTypedMatcher BoundMatcher(Case.second.Matcher);

388 BoundMatcher.setAllowBind(true);

389 auto M = *BoundMatcher.tryBind(Tag);

390 Matchers.push_back(!M.getTraversalKind()

391 ? M.withTraversalKind(DefaultTraversalKind)

392 : std::move(M));

393 }

394 return Matchers;

395}

396

397

398

399

400template <>

404 for (auto &Rule : Rules)

405 R.Cases.append(Rule.Cases.begin(), Rule.Cases.end());

406 return R;

407}

408

409std::vector

411

412

413

414

417 Buckets;

419 for (int I = 0, N = Cases.size(); I < N; ++I) {

421 "Matcher must be non-(Qual)Type node matcher");

422 Buckets[Cases[I].Matcher.getSupportedKind()].emplace_back(I, Cases[I]);

423 }

424

425

426

427

428

429

430 std::vector Matchers;

431 for (const auto &Bucket : Buckets) {

432 DynTypedMatcher M = DynTypedMatcher::constructVariadic(

433 DynTypedMatcher::VO_AnyOf, Bucket.first,

435 M.setAllowBind(true);

436

437 Matchers.push_back(M.tryBind(RootID)->withTraversalKind(TK_AsIs));

438 }

439 return Matchers;

440}

441

443 std::vector Ms = buildMatchers(Rule);

444 assert(Ms.size() == 1 && "Cases must have compatible matchers.");

445 return Ms[0];

446}

447

449 auto &NodesMap = Result.Nodes.getMap();

450 auto Root = NodesMap.find(RootID);

451 assert(Root != NodesMap.end() && "Transformation failed: missing root node.");

454 *Result.Context);

455 if (RootRange)

456 return RootRange->getBegin();

457

458

459 return Result.SourceManager->getExpansionLoc(

460 Root->second.getSourceRange().getBegin());

461}

462

463

464

467 if (Rule.Cases.size() == 1)

468 return 0;

469

470 auto &NodesMap = Result.Nodes.getMap();

471 for (size_t i = 0, N = Rule.Cases.size(); i < N; ++i) {

472 std::string Tag = ("Tag" + Twine(i)).str();

473 if (NodesMap.find(Tag) != NodesMap.end())

474 return i;

475 }

476 llvm_unreachable("No tag found for this rule.");

477}

BoundNodesTreeBuilder Nodes

llvm::MachO::Target Target

static TextGenerator makeText(std::string S)

llvm::Expected< SmallVector< clang::transformer::Edit, 1 > > rewriteDescendantsImpl(const T &Node, RewriteRule Rule, const MatchResult &Result)

static std::string formatHeaderPath(StringRef Header, IncludeFormat Format)

static Expected< SmallVector< transformer::Edit, 1 > > translateEdits(const MatchResult &Result, ArrayRef< ASTEdit > ASTEdits)

static std::vector< DynTypedMatcher > taggedMatchers(StringRef TagBase, const SmallVectorImpl< std::pair< size_t, RewriteRule::Case > > &Cases, TraversalKind DefaultTraversalKind)

static bool hasValidKind(const DynTypedMatcher &M)

Defines the RewriteRule class and related functions for creating, modifying and interpreting RewriteR...

Defines the clang::SourceLocation class and associated facilities.

StringRef asStringRef() const

String representation of the kind.

static CharSourceRange getCharRange(SourceRange R)

static CharSourceRange getTokenRange(SourceRange R)

Decl - This represents one declaration (or definition), e.g.

A dynamically typed AST node container.

ASTNodeKind getNodeKind() const

const T * get() const

Retrieve the stored node as type T.

A (possibly-)qualified type.

Encodes a location in the source.

SourceLocation getBegin() const

Stmt - This represents one statement.

Base wrapper for a particular "section" of type source info.

Maps string IDs to AST nodes matched by parts of a matcher.

internal::BoundNodesMap::IDToNodeMap IDToNodeMap

Type of mapping from binding identifiers to bound nodes.

Called when the Match registered for it was successfully found in the AST.

virtual void run(const MatchResult &Result)=0

Called on every match by the MatchFinder.

A class to allow finding matches over the Clang AST.

void addMatcher(const DeclarationMatcher &NodeMatch, MatchCallback *Action)

Adds a matcher to execute when running over the AST.

A failable computation over nodes bound by AST matchers, with (limited) reflection via the toString m...

virtual std::string toString() const =0

Constructs a string representation of the computation, for informational purposes.

virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, T *Result) const =0

Evaluates the computation and (potentially) updates the accumulator Result.

const Regex Rule("(.+)/(.+)\\.framework/")

bool matches(const til::SExpr *E1, const til::SExpr *E2)

llvm::Expected< SmallVector< Edit, 1 > > rewriteDescendants(const Decl &Node, RewriteRule Rule, const ast_matchers::MatchFinder::MatchResult &Result)

The following overload set is a version of rewriteDescendants that operates directly on the AST,...

RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, EditGenerator Edits)

EditGenerator makeEditGenerator(EditGenerator Edits)

SourceLocation getRuleMatchLoc(const ast_matchers::MatchFinder::MatchResult &Result)

Gets the beginning location of the source matched by a rewrite rule.

ast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRuleBase &Rule)

Builds a single matcher for the rule, covering all of the rule's cases.

size_t findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, const RewriteRuleBase &Rule)

Returns the index of the Case of Rule that was selected in the match result.

std::vector< ast_matchers::internal::DynTypedMatcher > buildMatchers(const RewriteRuleBase &Rule)

Builds a set of matchers that cover the rule.

EditGenerator flattenVector(SmallVector< EditGenerator, 2 > Generators)

Flattens a list of generators into a single generator whose elements are the concatenation of the res...

EditGenerator flatten(Ts &&...Edits)

ASTEdit note(RangeSelector Anchor, TextGenerator Note)

Generates a single, no-op edit with the associated note anchored at the start location of the specifi...

Generator< std::string > TextGenerator

RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, EditsT &&Edits)

Constructs a simple RewriteRule.

EditGenerator editList(llvm::SmallVector< ASTEdit, 1 > Edits)

Lifts a list of ASTEdits into an EditGenerator.

MatchConsumer< CharSourceRange > RangeSelector

ASTEdit changeTo(RangeSelector Target, TextGenerator Replacement)

Replaces a portion of the source text with Replacement.

RewriteRuleWith< MetadataT > applyFirst(ArrayRef< RewriteRuleWith< MetadataT > > Rules)

Applies the first rule whose pattern matches; other rules are ignored.

EditGenerator noopEdit(RangeSelector Anchor)

Generates a single, no-op edit anchored at the start location of the specified range.

RangeSelector before(RangeSelector Selector)

Selects the (empty) range [B,B) when Selector selects the range [B,E).

IncludeFormat

Format of the path in an include directive – angle brackets or quotes.

ASTEdit remove(RangeSelector S)

Removes the source selected by S.

MatchConsumer< llvm::SmallVector< Edit, 1 > > EditGenerator

Maps a match result to a list of concrete edits (with possible failure).

ASTEdit addInclude(RangeSelector Target, StringRef Header, IncludeFormat Format=IncludeFormat::Quoted)

Adds an include directive for the given header to the file of Target.

EditGenerator rewriteDescendants(std::string NodeId, RewriteRule Rule)

Applies Rule to all descendants of the node bound to NodeId.

EditGenerator edit(ASTEdit E)

Generates a single (specified) edit.

ASTEdit change(RangeSelector Target, TextGenerator Replacement)

DEPRECATED: use changeTo.

The JSON file list parser is used to communicate input to InstallAPI.

TraversalKind

Defines how we descend a level in the AST when we pass through expressions.

@ TK_AsIs

Will traverse all child nodes.

const FunctionProtoType * T

Contains all information for a given match.

A concrete description of a source edit, represented by a character range in the source to be replace...

Description of a source-code transformation.

SmallVector< Case, 1 > Cases

A source-code transformation with accompanying metadata.