1706b4fc4SDimitry Andric //===- ComputeReplacements.cpp --------------------------------*- C++ -*-=====//
2706b4fc4SDimitry Andric //
3706b4fc4SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4706b4fc4SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5706b4fc4SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6706b4fc4SDimitry Andric //
7706b4fc4SDimitry Andric //===----------------------------------------------------------------------===//
8706b4fc4SDimitry Andric #include "clang/Tooling/Core/Replacement.h"
9706b4fc4SDimitry Andric #include "clang/Tooling/Syntax/Mutations.h"
104b4fe385SDimitry Andric #include "clang/Tooling/Syntax/TokenBufferTokenManager.h"
11706b4fc4SDimitry Andric #include "clang/Tooling/Syntax/Tokens.h"
124b4fe385SDimitry Andric #include "clang/Tooling/Syntax/Tree.h"
13706b4fc4SDimitry Andric #include "llvm/Support/Error.h"
14706b4fc4SDimitry Andric
15706b4fc4SDimitry Andric using namespace clang;
16706b4fc4SDimitry Andric
17706b4fc4SDimitry Andric namespace {
18706b4fc4SDimitry Andric using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>,
19706b4fc4SDimitry Andric bool /*IsOriginal*/)>;
20706b4fc4SDimitry Andric /// Enumerates spans of tokens from the tree consecutively laid out in memory.
enumerateTokenSpans(const syntax::Tree * Root,const syntax::TokenBufferTokenManager & STM,ProcessTokensFn Callback)214b4fe385SDimitry Andric void enumerateTokenSpans(const syntax::Tree *Root,
224b4fe385SDimitry Andric const syntax::TokenBufferTokenManager &STM,
234b4fe385SDimitry Andric ProcessTokensFn Callback) {
24706b4fc4SDimitry Andric struct Enumerator {
254b4fe385SDimitry Andric Enumerator(const syntax::TokenBufferTokenManager &STM,
264b4fe385SDimitry Andric ProcessTokensFn Callback)
274b4fe385SDimitry Andric : STM(STM), SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false),
28706b4fc4SDimitry Andric Callback(Callback) {}
29706b4fc4SDimitry Andric
30706b4fc4SDimitry Andric void run(const syntax::Tree *Root) {
31706b4fc4SDimitry Andric process(Root);
32706b4fc4SDimitry Andric // Report the last span to the user.
33706b4fc4SDimitry Andric if (SpanBegin)
34e3b55780SDimitry Andric Callback(llvm::ArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
35706b4fc4SDimitry Andric }
36706b4fc4SDimitry Andric
37706b4fc4SDimitry Andric private:
38706b4fc4SDimitry Andric void process(const syntax::Node *N) {
39706b4fc4SDimitry Andric if (auto *T = dyn_cast<syntax::Tree>(N)) {
40b60736ecSDimitry Andric for (const auto *C = T->getFirstChild(); C != nullptr;
41b60736ecSDimitry Andric C = C->getNextSibling())
42706b4fc4SDimitry Andric process(C);
43706b4fc4SDimitry Andric return;
44706b4fc4SDimitry Andric }
45706b4fc4SDimitry Andric
46706b4fc4SDimitry Andric auto *L = cast<syntax::Leaf>(N);
474b4fe385SDimitry Andric if (SpanEnd == STM.getToken(L->getTokenKey()) &&
484b4fe385SDimitry Andric SpanIsOriginal == L->isOriginal()) {
49706b4fc4SDimitry Andric // Extend the current span.
50706b4fc4SDimitry Andric ++SpanEnd;
51706b4fc4SDimitry Andric return;
52706b4fc4SDimitry Andric }
53706b4fc4SDimitry Andric // Report the current span to the user.
54706b4fc4SDimitry Andric if (SpanBegin)
55e3b55780SDimitry Andric Callback(llvm::ArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
56706b4fc4SDimitry Andric // Start recording a new span.
574b4fe385SDimitry Andric SpanBegin = STM.getToken(L->getTokenKey());
58706b4fc4SDimitry Andric SpanEnd = SpanBegin + 1;
59706b4fc4SDimitry Andric SpanIsOriginal = L->isOriginal();
60706b4fc4SDimitry Andric }
61706b4fc4SDimitry Andric
624b4fe385SDimitry Andric const syntax::TokenBufferTokenManager &STM;
63706b4fc4SDimitry Andric const syntax::Token *SpanBegin;
64706b4fc4SDimitry Andric const syntax::Token *SpanEnd;
65706b4fc4SDimitry Andric bool SpanIsOriginal;
66706b4fc4SDimitry Andric ProcessTokensFn Callback;
67706b4fc4SDimitry Andric };
68706b4fc4SDimitry Andric
694b4fe385SDimitry Andric return Enumerator(STM, Callback).run(Root);
70706b4fc4SDimitry Andric }
71706b4fc4SDimitry Andric
rangeOfExpanded(const syntax::TokenBufferTokenManager & STM,llvm::ArrayRef<syntax::Token> Expanded)724b4fe385SDimitry Andric syntax::FileRange rangeOfExpanded(const syntax::TokenBufferTokenManager &STM,
73706b4fc4SDimitry Andric llvm::ArrayRef<syntax::Token> Expanded) {
744b4fe385SDimitry Andric const auto &Buffer = STM.tokenBuffer();
754b4fe385SDimitry Andric const auto &SM = STM.sourceManager();
76706b4fc4SDimitry Andric
77706b4fc4SDimitry Andric // Check that \p Expanded actually points into expanded tokens.
78706b4fc4SDimitry Andric assert(Buffer.expandedTokens().begin() <= Expanded.begin());
79706b4fc4SDimitry Andric assert(Expanded.end() < Buffer.expandedTokens().end());
80706b4fc4SDimitry Andric
81706b4fc4SDimitry Andric if (Expanded.empty())
82706b4fc4SDimitry Andric // (!) empty tokens must always point before end().
83706b4fc4SDimitry Andric return syntax::FileRange(
84706b4fc4SDimitry Andric SM, SM.getExpansionLoc(Expanded.begin()->location()), /*Length=*/0);
85706b4fc4SDimitry Andric
86706b4fc4SDimitry Andric auto Spelled = Buffer.spelledForExpanded(Expanded);
87706b4fc4SDimitry Andric assert(Spelled && "could not find spelled tokens for expanded");
88706b4fc4SDimitry Andric return syntax::Token::range(SM, Spelled->front(), Spelled->back());
89706b4fc4SDimitry Andric }
90706b4fc4SDimitry Andric } // namespace
91706b4fc4SDimitry Andric
92706b4fc4SDimitry Andric tooling::Replacements
computeReplacements(const TokenBufferTokenManager & TBTM,const syntax::TranslationUnit & TU)934b4fe385SDimitry Andric syntax::computeReplacements(const TokenBufferTokenManager &TBTM,
94706b4fc4SDimitry Andric const syntax::TranslationUnit &TU) {
954b4fe385SDimitry Andric const auto &Buffer = TBTM.tokenBuffer();
964b4fe385SDimitry Andric const auto &SM = TBTM.sourceManager();
97706b4fc4SDimitry Andric
98706b4fc4SDimitry Andric tooling::Replacements Replacements;
99706b4fc4SDimitry Andric // Text inserted by the replacement we are building now.
100706b4fc4SDimitry Andric std::string Replacement;
101706b4fc4SDimitry Andric auto emitReplacement = [&](llvm::ArrayRef<syntax::Token> ReplacedRange) {
102706b4fc4SDimitry Andric if (ReplacedRange.empty() && Replacement.empty())
103706b4fc4SDimitry Andric return;
104706b4fc4SDimitry Andric llvm::cantFail(Replacements.add(tooling::Replacement(
1054b4fe385SDimitry Andric SM, rangeOfExpanded(TBTM, ReplacedRange).toCharRange(SM),
1064b4fe385SDimitry Andric Replacement)));
107706b4fc4SDimitry Andric Replacement = "";
108706b4fc4SDimitry Andric };
109706b4fc4SDimitry Andric const syntax::Token *NextOriginal = Buffer.expandedTokens().begin();
110706b4fc4SDimitry Andric enumerateTokenSpans(
1114b4fe385SDimitry Andric &TU, TBTM, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) {
112706b4fc4SDimitry Andric if (!IsOriginal) {
113706b4fc4SDimitry Andric Replacement +=
114706b4fc4SDimitry Andric syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM);
115706b4fc4SDimitry Andric return;
116706b4fc4SDimitry Andric }
117706b4fc4SDimitry Andric assert(NextOriginal <= Tokens.begin());
118706b4fc4SDimitry Andric // We are looking at a span of original tokens.
119706b4fc4SDimitry Andric if (NextOriginal != Tokens.begin()) {
120706b4fc4SDimitry Andric // There is a gap, record a replacement or deletion.
121e3b55780SDimitry Andric emitReplacement(llvm::ArrayRef(NextOriginal, Tokens.begin()));
122706b4fc4SDimitry Andric } else {
123706b4fc4SDimitry Andric // No gap, but we may have pending insertions. Emit them now.
124e3b55780SDimitry Andric emitReplacement(llvm::ArrayRef(NextOriginal, /*Length=*/(size_t)0));
125706b4fc4SDimitry Andric }
126706b4fc4SDimitry Andric NextOriginal = Tokens.end();
127706b4fc4SDimitry Andric });
128706b4fc4SDimitry Andric
129706b4fc4SDimitry Andric // We might have pending replacements at the end of file. If so, emit them.
130e3b55780SDimitry Andric emitReplacement(
131e3b55780SDimitry Andric llvm::ArrayRef(NextOriginal, Buffer.expandedTokens().drop_back().end()));
132706b4fc4SDimitry Andric
133706b4fc4SDimitry Andric return Replacements;
134706b4fc4SDimitry Andric }
135