1//===--- RewriteRule.h - RewriteRule class ----------------------*- 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//===----------------------------------------------------------------------===// 8/// 9/// \file 10/// Defines the RewriteRule class and related functions for creating, 11/// modifying and interpreting RewriteRules. 12/// 13//===----------------------------------------------------------------------===// 14 15#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 16#define LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 17 18#include "clang/ASTMatchers/ASTMatchFinder.h" 19#include "clang/ASTMatchers/ASTMatchers.h" 20#include "clang/ASTMatchers/ASTMatchersInternal.h" 21#include "clang/Tooling/Refactoring/AtomicChange.h" 22#include "clang/Tooling/Transformer/MatchConsumer.h" 23#include "clang/Tooling/Transformer/RangeSelector.h" 24#include "llvm/ADT/STLExtras.h" 25#include "llvm/ADT/SmallVector.h" 26#include "llvm/Support/Error.h" 27#include <functional> 28#include <string> 29#include <utility> 30 31namespace clang { 32namespace transformer { 33using TextGenerator = std::shared_ptr<MatchComputation<std::string>>; 34 35// Description of a source-code edit, expressed in terms of an AST node. 36// Includes: an ID for the (bound) node, a selector for source related to the 37// node, a replacement and, optionally, an explanation for the edit. 38// 39// * Target: the source code impacted by the rule. This identifies an AST node, 40// or part thereof (\c Part), whose source range indicates the extent of the 41// replacement applied by the replacement term. By default, the extent is the 42// node matched by the pattern term (\c NodePart::Node). Target's are typed 43// (\c Kind), which guides the determination of the node extent. 44// 45// * Replacement: a function that produces a replacement string for the target, 46// based on the match result. 47// 48// * Note: (optional) a note specifically for this edit, potentially referencing 49// elements of the match. This will be displayed to the user, where possible; 50// for example, in clang-tidy diagnostics. Use of notes should be rare -- 51// explanations of the entire rewrite should be set in the rule 52// (`RewriteRule::Explanation`) instead. Notes serve the rare cases wherein 53// edit-specific diagnostics are required. 54// 55// `ASTEdit` should be built using the `change` convenience functions. For 56// example, 57// \code 58// changeTo(name(fun), cat("Frodo")) 59// \endcode 60// Or, if we use Stencil for the TextGenerator: 61// \code 62// using stencil::cat; 63// changeTo(statement(thenNode), cat("{", thenNode, "}")) 64// changeTo(callArgs(call), cat(x, ",", y)) 65// \endcode 66// Or, if you are changing the node corresponding to the rule's matcher, you can 67// use the single-argument override of \c change: 68// \code 69// changeTo(cat("different_expr")) 70// \endcode 71struct ASTEdit { 72 RangeSelector TargetRange; 73 TextGenerator Replacement; 74 TextGenerator Note; 75}; 76 77/// Format of the path in an include directive -- angle brackets or quotes. 78enum class IncludeFormat { 79 Quoted, 80 Angled, 81}; 82 83/// Description of a source-code transformation. 84// 85// A *rewrite rule* describes a transformation of source code. A simple rule 86// contains each of the following components: 87// 88// * Matcher: the pattern term, expressed as clang matchers (with Transformer 89// extensions). 90// 91// * Edits: a set of Edits to the source code, described with ASTEdits. 92// 93// * Explanation: explanation of the rewrite. This will be displayed to the 94// user, where possible; for example, in clang-tidy diagnostics. 95// 96// However, rules can also consist of (sub)rules, where the first that matches 97// is applied and the rest are ignored. So, the above components are gathered 98// as a `Case` and a rule is a list of cases. 99// 100// Rule cases have an additional, implicit, component: the parameters. These are 101// portions of the pattern which are left unspecified, yet bound in the pattern 102// so that we can reference them in the edits. 103// 104// The \c Transformer class can be used to apply the rewrite rule and obtain the 105// corresponding replacements. 106struct RewriteRule { 107 struct Case { 108 ast_matchers::internal::DynTypedMatcher Matcher; 109 SmallVector<ASTEdit, 1> Edits; 110 TextGenerator Explanation; 111 // Include paths to add to the file affected by this case. These are 112 // bundled with the `Case`, rather than the `RewriteRule`, because each case 113 // might have different associated changes to the includes. 114 std::vector<std::pair<std::string, IncludeFormat>> AddedIncludes; 115 }; 116 // We expect RewriteRules will most commonly include only one case. 117 SmallVector<Case, 1> Cases; 118 119 // ID used as the default target of each match. The node described by the 120 // matcher is should always be bound to this id. 121 static constexpr llvm::StringLiteral RootID = "___root___"; 122}; 123 124/// Convenience function for constructing a simple \c RewriteRule. 125RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, 126 SmallVector<ASTEdit, 1> Edits, 127 TextGenerator Explanation = nullptr); 128 129/// Convenience overload of \c makeRule for common case of only one edit. 130inline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, 131 ASTEdit Edit, 132 TextGenerator Explanation = nullptr) { 133 SmallVector<ASTEdit, 1> Edits; 134 Edits.emplace_back(std::move(Edit)); 135 return makeRule(std::move(M), std::move(Edits), std::move(Explanation)); 136} 137 138/// For every case in Rule, adds an include directive for the given header. The 139/// common use is assumed to be a rule with only one case. For example, to 140/// replace a function call and add headers corresponding to the new code, one 141/// could write: 142/// \code 143/// auto R = makeRule(callExpr(callee(functionDecl(hasName("foo")))), 144/// changeTo(cat("bar()"))); 145/// AddInclude(R, "path/to/bar_header.h"); 146/// AddInclude(R, "vector", IncludeFormat::Angled); 147/// \endcode 148void addInclude(RewriteRule &Rule, llvm::StringRef Header, 149 IncludeFormat Format = IncludeFormat::Quoted); 150 151/// Applies the first rule whose pattern matches; other rules are ignored. If 152/// the matchers are independent then order doesn't matter. In that case, 153/// `applyFirst` is simply joining the set of rules into one. 154// 155// `applyFirst` is like an `anyOf` matcher with an edit action attached to each 156// of its cases. Anywhere you'd use `anyOf(m1.bind("id1"), m2.bind("id2"))` and 157// then dispatch on those ids in your code for control flow, `applyFirst` lifts 158// that behavior to the rule level. So, you can write `applyFirst({makeRule(m1, 159// action1), makeRule(m2, action2), ...});` 160// 161// For example, consider a type `T` with a deterministic serialization function, 162// `serialize()`. For performance reasons, we would like to make it 163// non-deterministic. Therefore, we want to drop the expectation that 164// `a.serialize() = b.serialize() iff a = b` (although we'll maintain 165// `deserialize(a.serialize()) = a`). 166// 167// We have three cases to consider (for some equality function, `eq`): 168// ``` 169// eq(a.serialize(), b.serialize()) --> eq(a,b) 170// eq(a, b.serialize()) --> eq(deserialize(a), b) 171// eq(a.serialize(), b) --> eq(a, deserialize(b)) 172// ``` 173// 174// `applyFirst` allows us to specify each independently: 175// ``` 176// auto eq_fun = functionDecl(...); 177// auto method_call = cxxMemberCallExpr(...); 178// 179// auto two_calls = callExpr(callee(eq_fun), hasArgument(0, method_call), 180// hasArgument(1, method_call)); 181// auto left_call = 182// callExpr(callee(eq_fun), callExpr(hasArgument(0, method_call))); 183// auto right_call = 184// callExpr(callee(eq_fun), callExpr(hasArgument(1, method_call))); 185// 186// RewriteRule R = applyFirst({makeRule(two_calls, two_calls_action), 187// makeRule(left_call, left_call_action), 188// makeRule(right_call, right_call_action)}); 189// ``` 190RewriteRule applyFirst(ArrayRef<RewriteRule> Rules); 191 192/// Replaces a portion of the source text with \p Replacement. 193ASTEdit changeTo(RangeSelector Target, TextGenerator Replacement); 194/// DEPRECATED: use \c changeTo. 195inline ASTEdit change(RangeSelector Target, TextGenerator Replacement) { 196 return changeTo(std::move(Target), std::move(Replacement)); 197} 198 199/// Replaces the entirety of a RewriteRule's match with \p Replacement. For 200/// example, to replace a function call, one could write: 201/// \code 202/// makeRule(callExpr(callee(functionDecl(hasName("foo")))), 203/// changeTo(cat("bar()"))) 204/// \endcode 205inline ASTEdit changeTo(TextGenerator Replacement) { 206 return changeTo(node(RewriteRule::RootID), std::move(Replacement)); 207} 208/// DEPRECATED: use \c changeTo. 209inline ASTEdit change(TextGenerator Replacement) { 210 return changeTo(std::move(Replacement)); 211} 212 213/// Inserts \p Replacement before \p S, leaving the source selected by \S 214/// unchanged. 215inline ASTEdit insertBefore(RangeSelector S, TextGenerator Replacement) { 216 return changeTo(before(std::move(S)), std::move(Replacement)); 217} 218 219/// Inserts \p Replacement after \p S, leaving the source selected by \S 220/// unchanged. 221inline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) { 222 return changeTo(after(std::move(S)), std::move(Replacement)); 223} 224 225/// Removes the source selected by \p S. 226ASTEdit remove(RangeSelector S); 227 228/// The following three functions are a low-level part of the RewriteRule 229/// API. We expose them for use in implementing the fixtures that interpret 230/// RewriteRule, like Transformer and TransfomerTidy, or for more advanced 231/// users. 232// 233// FIXME: These functions are really public, if advanced, elements of the 234// RewriteRule API. Recast them as such. Or, just declare these functions 235// public and well-supported and move them out of `detail`. 236namespace detail { 237/// Builds a single matcher for the rule, covering all of the rule's cases. 238/// Only supports Rules whose cases' matchers share the same base "kind" 239/// (`Stmt`, `Decl`, etc.) Deprecated: use `buildMatchers` instead, which 240/// supports mixing matchers of different kinds. 241ast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRule &Rule); 242 243/// Builds a set of matchers that cover the rule (one for each distinct node 244/// matcher base kind: Stmt, Decl, etc.). Node-matchers for `QualType` and 245/// `Type` are not permitted, since such nodes carry no source location 246/// information and are therefore not relevant for rewriting. If any such 247/// matchers are included, will return an empty vector. 248std::vector<ast_matchers::internal::DynTypedMatcher> 249buildMatchers(const RewriteRule &Rule); 250 251/// Gets the beginning location of the source matched by a rewrite rule. If the 252/// match occurs within a macro expansion, returns the beginning of the 253/// expansion point. `Result` must come from the matching of a rewrite rule. 254SourceLocation 255getRuleMatchLoc(const ast_matchers::MatchFinder::MatchResult &Result); 256 257/// Returns the \c Case of \c Rule that was selected in the match result. 258/// Assumes a matcher built with \c buildMatcher. 259const RewriteRule::Case & 260findSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, 261 const RewriteRule &Rule); 262 263/// A source "transformation," represented by a character range in the source to 264/// be replaced and a corresponding replacement string. 265struct Transformation { 266 CharSourceRange Range; 267 std::string Replacement; 268}; 269 270/// Attempts to translate `Edits`, which are in terms of AST nodes bound in the 271/// match `Result`, into Transformations, which are in terms of the source code 272/// text. 273/// 274/// Returns an empty vector if any of the edits apply to portions of the source 275/// that are ineligible for rewriting (certain interactions with macros, for 276/// example). Fails if any invariants are violated relating to bound nodes in 277/// the match. However, it does not fail in the case of conflicting edits -- 278/// conflict handling is left to clients. We recommend use of the \c 279/// AtomicChange or \c Replacements classes for assistance in detecting such 280/// conflicts. 281Expected<SmallVector<Transformation, 1>> 282translateEdits(const ast_matchers::MatchFinder::MatchResult &Result, 283 llvm::ArrayRef<ASTEdit> Edits); 284} // namespace detail 285} // namespace transformer 286 287namespace tooling { 288// DEPRECATED: These are temporary aliases supporting client migration to the 289// `transformer` namespace. 290/// Wraps a string as a TextGenerator. 291using TextGenerator = transformer::TextGenerator; 292 293TextGenerator text(std::string M); 294 295using transformer::addInclude; 296using transformer::applyFirst; 297using transformer::change; 298using transformer::insertAfter; 299using transformer::insertBefore; 300using transformer::makeRule; 301using transformer::remove; 302using transformer::RewriteRule; 303using transformer::IncludeFormat; 304namespace detail { 305using namespace transformer::detail; 306} // namespace detail 307} // namespace tooling 308} // namespace clang 309 310#endif // LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 311