annotate clang/lib/Tooling/Syntax/ComputeReplacements.cpp @ 176:de4ac79aef9d

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 17:13:11 +0900
parents 1d019706d866
children 2e18cbf3894f
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
150
anatofuz
parents:
diff changeset
1 //===- ComputeReplacements.cpp --------------------------------*- C++ -*-=====//
anatofuz
parents:
diff changeset
2 //
anatofuz
parents:
diff changeset
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
anatofuz
parents:
diff changeset
4 // See https://llvm.org/LICENSE.txt for license information.
anatofuz
parents:
diff changeset
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
anatofuz
parents:
diff changeset
6 //
anatofuz
parents:
diff changeset
7 //===----------------------------------------------------------------------===//
anatofuz
parents:
diff changeset
8 #include "clang/Tooling/Core/Replacement.h"
anatofuz
parents:
diff changeset
9 #include "clang/Tooling/Syntax/Mutations.h"
anatofuz
parents:
diff changeset
10 #include "clang/Tooling/Syntax/Tokens.h"
anatofuz
parents:
diff changeset
11 #include "llvm/Support/Error.h"
anatofuz
parents:
diff changeset
12
anatofuz
parents:
diff changeset
13 using namespace clang;
anatofuz
parents:
diff changeset
14
anatofuz
parents:
diff changeset
15 namespace {
anatofuz
parents:
diff changeset
16 using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>,
anatofuz
parents:
diff changeset
17 bool /*IsOriginal*/)>;
anatofuz
parents:
diff changeset
18 /// Enumerates spans of tokens from the tree consecutively laid out in memory.
anatofuz
parents:
diff changeset
19 void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
anatofuz
parents:
diff changeset
20 struct Enumerator {
anatofuz
parents:
diff changeset
21 Enumerator(ProcessTokensFn Callback)
anatofuz
parents:
diff changeset
22 : SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false),
anatofuz
parents:
diff changeset
23 Callback(Callback) {}
anatofuz
parents:
diff changeset
24
anatofuz
parents:
diff changeset
25 void run(const syntax::Tree *Root) {
anatofuz
parents:
diff changeset
26 process(Root);
anatofuz
parents:
diff changeset
27 // Report the last span to the user.
anatofuz
parents:
diff changeset
28 if (SpanBegin)
anatofuz
parents:
diff changeset
29 Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
anatofuz
parents:
diff changeset
30 }
anatofuz
parents:
diff changeset
31
anatofuz
parents:
diff changeset
32 private:
anatofuz
parents:
diff changeset
33 void process(const syntax::Node *N) {
anatofuz
parents:
diff changeset
34 if (auto *T = dyn_cast<syntax::Tree>(N)) {
anatofuz
parents:
diff changeset
35 for (auto *C = T->firstChild(); C != nullptr; C = C->nextSibling())
anatofuz
parents:
diff changeset
36 process(C);
anatofuz
parents:
diff changeset
37 return;
anatofuz
parents:
diff changeset
38 }
anatofuz
parents:
diff changeset
39
anatofuz
parents:
diff changeset
40 auto *L = cast<syntax::Leaf>(N);
anatofuz
parents:
diff changeset
41 if (SpanEnd == L->token() && SpanIsOriginal == L->isOriginal()) {
anatofuz
parents:
diff changeset
42 // Extend the current span.
anatofuz
parents:
diff changeset
43 ++SpanEnd;
anatofuz
parents:
diff changeset
44 return;
anatofuz
parents:
diff changeset
45 }
anatofuz
parents:
diff changeset
46 // Report the current span to the user.
anatofuz
parents:
diff changeset
47 if (SpanBegin)
anatofuz
parents:
diff changeset
48 Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
anatofuz
parents:
diff changeset
49 // Start recording a new span.
anatofuz
parents:
diff changeset
50 SpanBegin = L->token();
anatofuz
parents:
diff changeset
51 SpanEnd = SpanBegin + 1;
anatofuz
parents:
diff changeset
52 SpanIsOriginal = L->isOriginal();
anatofuz
parents:
diff changeset
53 }
anatofuz
parents:
diff changeset
54
anatofuz
parents:
diff changeset
55 const syntax::Token *SpanBegin;
anatofuz
parents:
diff changeset
56 const syntax::Token *SpanEnd;
anatofuz
parents:
diff changeset
57 bool SpanIsOriginal;
anatofuz
parents:
diff changeset
58 ProcessTokensFn Callback;
anatofuz
parents:
diff changeset
59 };
anatofuz
parents:
diff changeset
60
anatofuz
parents:
diff changeset
61 return Enumerator(Callback).run(Root);
anatofuz
parents:
diff changeset
62 }
anatofuz
parents:
diff changeset
63
anatofuz
parents:
diff changeset
64 syntax::FileRange rangeOfExpanded(const syntax::Arena &A,
anatofuz
parents:
diff changeset
65 llvm::ArrayRef<syntax::Token> Expanded) {
anatofuz
parents:
diff changeset
66 auto &Buffer = A.tokenBuffer();
anatofuz
parents:
diff changeset
67 auto &SM = A.sourceManager();
anatofuz
parents:
diff changeset
68
anatofuz
parents:
diff changeset
69 // Check that \p Expanded actually points into expanded tokens.
anatofuz
parents:
diff changeset
70 assert(Buffer.expandedTokens().begin() <= Expanded.begin());
anatofuz
parents:
diff changeset
71 assert(Expanded.end() < Buffer.expandedTokens().end());
anatofuz
parents:
diff changeset
72
anatofuz
parents:
diff changeset
73 if (Expanded.empty())
anatofuz
parents:
diff changeset
74 // (!) empty tokens must always point before end().
anatofuz
parents:
diff changeset
75 return syntax::FileRange(
anatofuz
parents:
diff changeset
76 SM, SM.getExpansionLoc(Expanded.begin()->location()), /*Length=*/0);
anatofuz
parents:
diff changeset
77
anatofuz
parents:
diff changeset
78 auto Spelled = Buffer.spelledForExpanded(Expanded);
anatofuz
parents:
diff changeset
79 assert(Spelled && "could not find spelled tokens for expanded");
anatofuz
parents:
diff changeset
80 return syntax::Token::range(SM, Spelled->front(), Spelled->back());
anatofuz
parents:
diff changeset
81 }
anatofuz
parents:
diff changeset
82 } // namespace
anatofuz
parents:
diff changeset
83
anatofuz
parents:
diff changeset
84 tooling::Replacements
anatofuz
parents:
diff changeset
85 syntax::computeReplacements(const syntax::Arena &A,
anatofuz
parents:
diff changeset
86 const syntax::TranslationUnit &TU) {
anatofuz
parents:
diff changeset
87 auto &Buffer = A.tokenBuffer();
anatofuz
parents:
diff changeset
88 auto &SM = A.sourceManager();
anatofuz
parents:
diff changeset
89
anatofuz
parents:
diff changeset
90 tooling::Replacements Replacements;
anatofuz
parents:
diff changeset
91 // Text inserted by the replacement we are building now.
anatofuz
parents:
diff changeset
92 std::string Replacement;
anatofuz
parents:
diff changeset
93 auto emitReplacement = [&](llvm::ArrayRef<syntax::Token> ReplacedRange) {
anatofuz
parents:
diff changeset
94 if (ReplacedRange.empty() && Replacement.empty())
anatofuz
parents:
diff changeset
95 return;
anatofuz
parents:
diff changeset
96 llvm::cantFail(Replacements.add(tooling::Replacement(
anatofuz
parents:
diff changeset
97 SM, rangeOfExpanded(A, ReplacedRange).toCharRange(SM), Replacement)));
anatofuz
parents:
diff changeset
98 Replacement = "";
anatofuz
parents:
diff changeset
99 };
anatofuz
parents:
diff changeset
100
anatofuz
parents:
diff changeset
101 const syntax::Token *NextOriginal = Buffer.expandedTokens().begin();
anatofuz
parents:
diff changeset
102 enumerateTokenSpans(
anatofuz
parents:
diff changeset
103 &TU, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) {
anatofuz
parents:
diff changeset
104 if (!IsOriginal) {
anatofuz
parents:
diff changeset
105 Replacement +=
anatofuz
parents:
diff changeset
106 syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM);
anatofuz
parents:
diff changeset
107 return;
anatofuz
parents:
diff changeset
108 }
anatofuz
parents:
diff changeset
109 assert(NextOriginal <= Tokens.begin());
anatofuz
parents:
diff changeset
110 // We are looking at a span of original tokens.
anatofuz
parents:
diff changeset
111 if (NextOriginal != Tokens.begin()) {
anatofuz
parents:
diff changeset
112 // There is a gap, record a replacement or deletion.
anatofuz
parents:
diff changeset
113 emitReplacement(llvm::makeArrayRef(NextOriginal, Tokens.begin()));
anatofuz
parents:
diff changeset
114 } else {
anatofuz
parents:
diff changeset
115 // No gap, but we may have pending insertions. Emit them now.
anatofuz
parents:
diff changeset
116 emitReplacement(llvm::makeArrayRef(NextOriginal, /*Length=*/0));
anatofuz
parents:
diff changeset
117 }
anatofuz
parents:
diff changeset
118 NextOriginal = Tokens.end();
anatofuz
parents:
diff changeset
119 });
anatofuz
parents:
diff changeset
120
anatofuz
parents:
diff changeset
121 // We might have pending replacements at the end of file. If so, emit them.
anatofuz
parents:
diff changeset
122 emitReplacement(llvm::makeArrayRef(
anatofuz
parents:
diff changeset
123 NextOriginal, Buffer.expandedTokens().drop_back().end()));
anatofuz
parents:
diff changeset
124
anatofuz
parents:
diff changeset
125 return Replacements;
anatofuz
parents:
diff changeset
126 }