reference, declarationdefinition
definition → references, declarations, derived classes, virtual overrides
reference to multiple definitions → definitions
unreferenced
    1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167
  168
  169
  170
  171
  172
  173
  174
  175
  176
  177
  178
  179
  180
  181
  182
  183
  184
  185
  186
  187
  188
  189
  190
  191
  192
  193
  194
  195
  196
  197
  198
  199
  200
  201
  202
  203
  204
  205
  206
  207
  208
  209
  210
  211
  212
  213
  214
  215
  216
  217
  218
  219
  220
  221
//===--- Stencil.h - Stencil class ------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file defines the *Stencil* abstraction: a code-generating object,
/// parameterized by named references to (bound) AST nodes.  Given a match
/// result, a stencil can be evaluated to a string of source code.
///
/// A stencil is similar in spirit to a format string: it is composed of a
/// series of raw text strings, references to nodes (the parameters) and helper
/// code-generation operations.
///
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_
#define LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_

#include "clang/AST/ASTContext.h"
#include "clang/AST/ASTTypeTraits.h"
#include "clang/ASTMatchers/ASTMatchFinder.h"
#include "clang/Tooling/Transformer/MatchConsumer.h"
#include "clang/Tooling/Transformer/RangeSelector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Error.h"
#include <string>
#include <vector>

namespace clang {
namespace transformer {
/// A stencil is represented as a sequence of "parts" that can each individually
/// generate a code string based on a match result.  The different kinds of
/// parts include (raw) text, references to bound nodes and assorted operations
/// on bound nodes.
///
/// Users can create custom Stencil operations by implementing this interface.
class StencilPartInterface {
public:
  virtual ~StencilPartInterface() = default;

  /// Evaluates this part to a string and appends it to \c Result.  \c Result is
  /// undefined in the case of an error.
  virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
                           std::string *Result) const = 0;

  /// Constructs a string representation of the StencilPart. StencilParts
  /// generated by the `selection` and `run` functions do not have a unique
  /// string representation.
  virtual std::string toString() const = 0;

protected:
  StencilPartInterface() = default;

  // Since this is an abstract class, copying/assigning only make sense for
  // derived classes implementing `clone()`.
  StencilPartInterface(const StencilPartInterface &) = default;
  StencilPartInterface &operator=(const StencilPartInterface &) = default;
};

/// A copyable facade for a std::unique_ptr<StencilPartInterface>. Copies result
/// in a copy of the underlying pointee object.
class StencilPart {
public:
  explicit StencilPart(std::shared_ptr<StencilPartInterface> Impl)
      : Impl(std::move(Impl)) {}

  /// See `StencilPartInterface::eval()`.
  llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match,
                   std::string *Result) const {
    return Impl->eval(Match, Result);
  }

  std::string toString() const {
    if (Impl == nullptr)
      return "";
    return Impl->toString();
  }

private:
  std::shared_ptr<StencilPartInterface> Impl;
};

/// A sequence of code fragments, references to parameters and code-generation
/// operations that together can be evaluated to (a fragment of) source code,
/// given a match result.
class Stencil {
public:
  Stencil() = default;

  /// Composes a stencil from a series of parts.
  template <typename... Ts> static Stencil cat(Ts &&... Parts) {
    Stencil S;
    S.Parts = {wrap(std::forward<Ts>(Parts))...};
    return S;
  }

  /// Appends data from a \p OtherStencil to this stencil.
  void append(Stencil OtherStencil);

  // Evaluates the stencil given a match result. Requires that the nodes in the
  // result includes any ids referenced in the stencil. References to missing
  // nodes will result in an invalid_argument error.
  llvm::Expected<std::string>
  eval(const ast_matchers::MatchFinder::MatchResult &Match) const;

  // Allow Stencils to operate as std::function, for compatibility with
  // Transformer's TextGenerator.
  llvm::Expected<std::string>
  operator()(const ast_matchers::MatchFinder::MatchResult &Result) const {
    return eval(Result);
  }

  /// Constructs a string representation of the Stencil. The string is not
  /// guaranteed to be unique.
  std::string toString() const {
    std::vector<std::string> PartStrings;
    PartStrings.reserve(Parts.size());
    for (const auto &Part : Parts)
      PartStrings.push_back(Part.toString());
    return llvm::join(PartStrings, ", ");
  }

private:
  static StencilPart wrap(llvm::StringRef Text);
  static StencilPart wrap(RangeSelector Selector);
  static StencilPart wrap(StencilPart Part) { return Part; }

  std::vector<StencilPart> Parts;
};

//
// Functions for conveniently building stencils.
//

/// Convenience wrapper for Stencil::cat that can be imported with a using decl.
template <typename... Ts> Stencil cat(Ts &&... Parts) {
  return Stencil::cat(std::forward<Ts>(Parts)...);
}

/// \returns exactly the text provided.
StencilPart text(llvm::StringRef Text);

/// \returns the source corresponding to the selected range.
StencilPart selection(RangeSelector Selector);

/// Generates the source of the expression bound to \p Id, wrapping it in
/// parentheses if it may parse differently depending on context. For example, a
/// binary operation is always wrapped, while a variable reference is never
/// wrapped.
StencilPart expression(llvm::StringRef Id);

/// Constructs an idiomatic dereferencing of the expression bound to \p ExprId.
/// \p ExprId is wrapped in parentheses, if needed.
StencilPart deref(llvm::StringRef ExprId);

/// Constructs an expression that idiomatically takes the address of the
/// expression bound to \p ExprId. \p ExprId is wrapped in parentheses, if
/// needed.
StencilPart addressOf(llvm::StringRef ExprId);

/// Constructs a `MemberExpr` that accesses the named member (\p Member) of the
/// object bound to \p BaseId. The access is constructed idiomatically: if \p
/// BaseId is bound to `e` and \p Member identifies member `m`, then returns
/// `e->m`, when e is a pointer, `e2->m` when e = `*e2` and `e.m` otherwise.
/// Additionally, `e` is wrapped in parentheses, if needed.
StencilPart access(llvm::StringRef BaseId, StencilPart Member);
inline StencilPart access(llvm::StringRef BaseId, llvm::StringRef Member) {
  return access(BaseId, text(Member));
}

/// Chooses between the two stencil parts, based on whether \p ID is bound in
/// the match.
StencilPart ifBound(llvm::StringRef Id, StencilPart TruePart,
                    StencilPart FalsePart);

/// Chooses between the two strings, based on whether \p ID is bound in the
/// match.
inline StencilPart ifBound(llvm::StringRef Id, llvm::StringRef TrueText,
                           llvm::StringRef FalseText) {
  return ifBound(Id, text(TrueText), text(FalseText));
}

/// Wraps a MatchConsumer in a StencilPart, so that it can be used in a Stencil.
/// This supports user-defined extensions to the Stencil language.
StencilPart run(MatchConsumer<std::string> C);

/// For debug use only; semantics are not guaranteed.
///
/// \returns the string resulting from calling the node's print() method.
StencilPart dPrint(llvm::StringRef Id);
} // namespace transformer

namespace tooling {
// DEPRECATED: These are temporary aliases supporting client migration to the
// `transformer` namespace.
using Stencil = transformer::Stencil;
using StencilPart = transformer::StencilPart;
namespace stencil {
using transformer::access;
using transformer::addressOf;
using transformer::cat;
using transformer::deref;
using transformer::dPrint;
using transformer::expression;
using transformer::ifBound;
using transformer::run;
using transformer::selection;
using transformer::text;
/// \returns the source corresponding to the identified node.
/// FIXME: Deprecated. Write `selection(node(Id))` instead.
inline transformer::StencilPart node(llvm::StringRef Id) {
  return selection(tooling::node(Id));
}
} // namespace stencil
} // namespace tooling
} // namespace clang
#endif // LLVM_CLANG_TOOLING_TRANSFORMER_STENCIL_H_