clang  14.0.0git
ComputeReplacements.cpp
Go to the documentation of this file.
1 //===- ComputeReplacements.cpp --------------------------------*- 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 //===----------------------------------------------------------------------===//
11 #include "llvm/Support/Error.h"
12 
13 using namespace clang;
14 
15 namespace {
16 using ProcessTokensFn = llvm::function_ref<void(llvm::ArrayRef<syntax::Token>,
17  bool /*IsOriginal*/)>;
18 /// Enumerates spans of tokens from the tree consecutively laid out in memory.
19 void enumerateTokenSpans(const syntax::Tree *Root, ProcessTokensFn Callback) {
20  struct Enumerator {
21  Enumerator(ProcessTokensFn Callback)
22  : SpanBegin(nullptr), SpanEnd(nullptr), SpanIsOriginal(false),
23  Callback(Callback) {}
24 
25  void run(const syntax::Tree *Root) {
26  process(Root);
27  // Report the last span to the user.
28  if (SpanBegin)
29  Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
30  }
31 
32  private:
33  void process(const syntax::Node *N) {
34  if (auto *T = dyn_cast<syntax::Tree>(N)) {
35  for (const auto *C = T->getFirstChild(); C != nullptr;
36  C = C->getNextSibling())
37  process(C);
38  return;
39  }
40 
41  auto *L = cast<syntax::Leaf>(N);
42  if (SpanEnd == L->getToken() && SpanIsOriginal == L->isOriginal()) {
43  // Extend the current span.
44  ++SpanEnd;
45  return;
46  }
47  // Report the current span to the user.
48  if (SpanBegin)
49  Callback(llvm::makeArrayRef(SpanBegin, SpanEnd), SpanIsOriginal);
50  // Start recording a new span.
51  SpanBegin = L->getToken();
52  SpanEnd = SpanBegin + 1;
53  SpanIsOriginal = L->isOriginal();
54  }
55 
56  const syntax::Token *SpanBegin;
57  const syntax::Token *SpanEnd;
58  bool SpanIsOriginal;
59  ProcessTokensFn Callback;
60  };
61 
62  return Enumerator(Callback).run(Root);
63 }
64 
65 syntax::FileRange rangeOfExpanded(const syntax::Arena &A,
67  const auto &Buffer = A.getTokenBuffer();
68  const auto &SM = A.getSourceManager();
69 
70  // Check that \p Expanded actually points into expanded tokens.
71  assert(Buffer.expandedTokens().begin() <= Expanded.begin());
72  assert(Expanded.end() < Buffer.expandedTokens().end());
73 
74  if (Expanded.empty())
75  // (!) empty tokens must always point before end().
76  return syntax::FileRange(
77  SM, SM.getExpansionLoc(Expanded.begin()->location()), /*Length=*/0);
78 
79  auto Spelled = Buffer.spelledForExpanded(Expanded);
80  assert(Spelled && "could not find spelled tokens for expanded");
81  return syntax::Token::range(SM, Spelled->front(), Spelled->back());
82 }
83 } // namespace
84 
87  const syntax::TranslationUnit &TU) {
88  const auto &Buffer = A.getTokenBuffer();
89  const auto &SM = A.getSourceManager();
90 
91  tooling::Replacements Replacements;
92  // Text inserted by the replacement we are building now.
93  std::string Replacement;
94  auto emitReplacement = [&](llvm::ArrayRef<syntax::Token> ReplacedRange) {
95  if (ReplacedRange.empty() && Replacement.empty())
96  return;
97  llvm::cantFail(Replacements.add(tooling::Replacement(
98  SM, rangeOfExpanded(A, ReplacedRange).toCharRange(SM), Replacement)));
99  Replacement = "";
100  };
101 
102  const syntax::Token *NextOriginal = Buffer.expandedTokens().begin();
103  enumerateTokenSpans(
104  &TU, [&](llvm::ArrayRef<syntax::Token> Tokens, bool IsOriginal) {
105  if (!IsOriginal) {
106  Replacement +=
107  syntax::Token::range(SM, Tokens.front(), Tokens.back()).text(SM);
108  return;
109  }
110  assert(NextOriginal <= Tokens.begin());
111  // We are looking at a span of original tokens.
112  if (NextOriginal != Tokens.begin()) {
113  // There is a gap, record a replacement or deletion.
114  emitReplacement(llvm::makeArrayRef(NextOriginal, Tokens.begin()));
115  } else {
116  // No gap, but we may have pending insertions. Emit them now.
117  emitReplacement(llvm::makeArrayRef(NextOriginal, /*Length=*/0));
118  }
119  NextOriginal = Tokens.end();
120  });
121 
122  // We might have pending replacements at the end of file. If so, emit them.
123  emitReplacement(llvm::makeArrayRef(
124  NextOriginal, Buffer.expandedTokens().drop_back().end()));
125 
126  return Replacements;
127 }
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
clang::syntax::Node
A node in a syntax tree.
Definition: Tree.h:80
AttributeLangSupport::C
@ C
Definition: SemaDeclAttr.cpp:54
clang::tooling::Replacements
Maintains a set of replacements that are conflict-free.
Definition: Replacement.h:209
clang::transformer::run
Stencil run(MatchConsumer< std::string > C)
Wraps a MatchConsumer in a Stencil, so that it can be used in a Stencil.
Definition: Stencil.cpp:540
clang::syntax::Token::range
FileRange range(const SourceManager &SM) const
Gets a range of this token.
Definition: Tokens.cpp:119
clang::syntax::Tree
A node that has children and represents a syntactic language construct.
Definition: Tree.h:169
clang::syntax::computeReplacements
tooling::Replacements computeReplacements(const Arena &A, const syntax::TranslationUnit &TU)
Computes textual replacements required to mimic the tree modifications made to the syntax tree.
Definition: ComputeReplacements.cpp:86
Tokens.h
false
#define false
Definition: stdbool.h:17
emitReplacement
static void emitReplacement(Sema &S, SourceLocation Loc, SourceRange Range, unsigned AbsKind, QualType ArgType)
Definition: SemaChecking.cpp:10046
Replacement.h
clang::syntax::Arena::getTokenBuffer
const TokenBuffer & getTokenBuffer() const
Definition: Tree.cpp:39
clang::syntax::Arena
A memory arena for syntax trees.
Definition: Tree.h:41
llvm::ArrayRef
Definition: LLVM.h:34
clang::tooling::Replacement
A text replacement.
Definition: Replacement.h:83
clang::ast_matchers::MatchFinder::MatchCallback::run
virtual void run(const MatchResult &Result)=0
Called on every match by the MatchFinder.
clang::syntax::Token
A token coming directly from a file or from a macro invocation.
Definition: Tokens.h:105
clang
Definition: CalledOnceCheck.h:17
clang::syntax::FileRange::text
llvm::StringRef text(const SourceManager &SM) const
Gets the substring that this FileRange refers to.
Definition: Tokens.cpp:176
clang::tooling::Replacements::add
llvm::Error add(const Replacement &R)
Adds a new replacement R to the current set of replacements.
Definition: Replacement.cpp:245
clang::syntax::FileRange
A half-open character range inside a particular file, the start offset is included and the end offset...
Definition: Tokens.h:52
SM
#define SM(sm)
Definition: Cuda.cpp:78
Mutations.h
clang::syntax::Arena::getSourceManager
const SourceManager & getSourceManager() const
Definition: Tree.h:46