1353942Sdim//===--- RewriteRule.h - RewriteRule class ----------------------*- C++ -*-===// 2353942Sdim// 3353942Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353942Sdim// See https://llvm.org/LICENSE.txt for license information. 5353942Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6353942Sdim// 7353942Sdim//===----------------------------------------------------------------------===// 8353942Sdim/// 9353942Sdim/// \file 10353942Sdim/// Defines the RewriteRule class and related functions for creating, 11353942Sdim/// modifying and interpreting RewriteRules. 12353942Sdim/// 13353942Sdim//===----------------------------------------------------------------------===// 14353942Sdim 15353942Sdim#ifndef LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 16353942Sdim#define LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 17353942Sdim 18353942Sdim#include "clang/ASTMatchers/ASTMatchFinder.h" 19353942Sdim#include "clang/ASTMatchers/ASTMatchers.h" 20353942Sdim#include "clang/ASTMatchers/ASTMatchersInternal.h" 21353942Sdim#include "clang/Tooling/Refactoring/AtomicChange.h" 22353942Sdim#include "clang/Tooling/Transformer/MatchConsumer.h" 23353942Sdim#include "clang/Tooling/Transformer/RangeSelector.h" 24353942Sdim#include "llvm/ADT/STLExtras.h" 25353942Sdim#include "llvm/ADT/SmallVector.h" 26353942Sdim#include "llvm/Support/Error.h" 27353942Sdim#include <functional> 28353942Sdim#include <string> 29353942Sdim#include <utility> 30353942Sdim 31353942Sdimnamespace clang { 32353942Sdimnamespace transformer { 33357095Sdimusing TextGenerator = std::shared_ptr<MatchComputation<std::string>>; 34353942Sdim 35353942Sdim// Description of a source-code edit, expressed in terms of an AST node. 36353942Sdim// Includes: an ID for the (bound) node, a selector for source related to the 37353942Sdim// node, a replacement and, optionally, an explanation for the edit. 38353942Sdim// 39353942Sdim// * Target: the source code impacted by the rule. This identifies an AST node, 40353942Sdim// or part thereof (\c Part), whose source range indicates the extent of the 41353942Sdim// replacement applied by the replacement term. By default, the extent is the 42353942Sdim// node matched by the pattern term (\c NodePart::Node). Target's are typed 43353942Sdim// (\c Kind), which guides the determination of the node extent. 44353942Sdim// 45353942Sdim// * Replacement: a function that produces a replacement string for the target, 46353942Sdim// based on the match result. 47353942Sdim// 48353942Sdim// * Note: (optional) a note specifically for this edit, potentially referencing 49353942Sdim// elements of the match. This will be displayed to the user, where possible; 50353942Sdim// for example, in clang-tidy diagnostics. Use of notes should be rare -- 51353942Sdim// explanations of the entire rewrite should be set in the rule 52353942Sdim// (`RewriteRule::Explanation`) instead. Notes serve the rare cases wherein 53353942Sdim// edit-specific diagnostics are required. 54353942Sdim// 55353942Sdim// `ASTEdit` should be built using the `change` convenience functions. For 56353942Sdim// example, 57353942Sdim// \code 58357095Sdim// changeTo(name(fun), cat("Frodo")) 59353942Sdim// \endcode 60353942Sdim// Or, if we use Stencil for the TextGenerator: 61353942Sdim// \code 62353942Sdim// using stencil::cat; 63357095Sdim// changeTo(statement(thenNode), cat("{", thenNode, "}")) 64357095Sdim// changeTo(callArgs(call), cat(x, ",", y)) 65353942Sdim// \endcode 66353942Sdim// Or, if you are changing the node corresponding to the rule's matcher, you can 67353942Sdim// use the single-argument override of \c change: 68353942Sdim// \code 69357095Sdim// changeTo(cat("different_expr")) 70353942Sdim// \endcode 71353942Sdimstruct ASTEdit { 72353942Sdim RangeSelector TargetRange; 73353942Sdim TextGenerator Replacement; 74353942Sdim TextGenerator Note; 75353942Sdim}; 76353942Sdim 77353942Sdim/// Format of the path in an include directive -- angle brackets or quotes. 78353942Sdimenum class IncludeFormat { 79353942Sdim Quoted, 80353942Sdim Angled, 81353942Sdim}; 82353942Sdim 83353942Sdim/// Description of a source-code transformation. 84353942Sdim// 85353942Sdim// A *rewrite rule* describes a transformation of source code. A simple rule 86353942Sdim// contains each of the following components: 87353942Sdim// 88353942Sdim// * Matcher: the pattern term, expressed as clang matchers (with Transformer 89353942Sdim// extensions). 90353942Sdim// 91353942Sdim// * Edits: a set of Edits to the source code, described with ASTEdits. 92353942Sdim// 93353942Sdim// * Explanation: explanation of the rewrite. This will be displayed to the 94353942Sdim// user, where possible; for example, in clang-tidy diagnostics. 95353942Sdim// 96353942Sdim// However, rules can also consist of (sub)rules, where the first that matches 97353942Sdim// is applied and the rest are ignored. So, the above components are gathered 98353942Sdim// as a `Case` and a rule is a list of cases. 99353942Sdim// 100353942Sdim// Rule cases have an additional, implicit, component: the parameters. These are 101353942Sdim// portions of the pattern which are left unspecified, yet bound in the pattern 102353942Sdim// so that we can reference them in the edits. 103353942Sdim// 104353942Sdim// The \c Transformer class can be used to apply the rewrite rule and obtain the 105353942Sdim// corresponding replacements. 106353942Sdimstruct RewriteRule { 107353942Sdim struct Case { 108353942Sdim ast_matchers::internal::DynTypedMatcher Matcher; 109353942Sdim SmallVector<ASTEdit, 1> Edits; 110353942Sdim TextGenerator Explanation; 111353942Sdim // Include paths to add to the file affected by this case. These are 112353942Sdim // bundled with the `Case`, rather than the `RewriteRule`, because each case 113353942Sdim // might have different associated changes to the includes. 114353942Sdim std::vector<std::pair<std::string, IncludeFormat>> AddedIncludes; 115353942Sdim }; 116353942Sdim // We expect RewriteRules will most commonly include only one case. 117353942Sdim SmallVector<Case, 1> Cases; 118353942Sdim 119353942Sdim // ID used as the default target of each match. The node described by the 120353942Sdim // matcher is should always be bound to this id. 121353942Sdim static constexpr llvm::StringLiteral RootID = "___root___"; 122353942Sdim}; 123353942Sdim 124353942Sdim/// Convenience function for constructing a simple \c RewriteRule. 125353942SdimRewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, 126353942Sdim SmallVector<ASTEdit, 1> Edits, 127353942Sdim TextGenerator Explanation = nullptr); 128353942Sdim 129353942Sdim/// Convenience overload of \c makeRule for common case of only one edit. 130353942Sdiminline RewriteRule makeRule(ast_matchers::internal::DynTypedMatcher M, 131353942Sdim ASTEdit Edit, 132353942Sdim TextGenerator Explanation = nullptr) { 133353942Sdim SmallVector<ASTEdit, 1> Edits; 134353942Sdim Edits.emplace_back(std::move(Edit)); 135353942Sdim return makeRule(std::move(M), std::move(Edits), std::move(Explanation)); 136353942Sdim} 137353942Sdim 138353942Sdim/// For every case in Rule, adds an include directive for the given header. The 139353942Sdim/// common use is assumed to be a rule with only one case. For example, to 140353942Sdim/// replace a function call and add headers corresponding to the new code, one 141353942Sdim/// could write: 142353942Sdim/// \code 143353942Sdim/// auto R = makeRule(callExpr(callee(functionDecl(hasName("foo")))), 144357095Sdim/// changeTo(cat("bar()"))); 145353942Sdim/// AddInclude(R, "path/to/bar_header.h"); 146353942Sdim/// AddInclude(R, "vector", IncludeFormat::Angled); 147353942Sdim/// \endcode 148353942Sdimvoid addInclude(RewriteRule &Rule, llvm::StringRef Header, 149353942Sdim IncludeFormat Format = IncludeFormat::Quoted); 150353942Sdim 151353942Sdim/// Applies the first rule whose pattern matches; other rules are ignored. If 152353942Sdim/// the matchers are independent then order doesn't matter. In that case, 153353942Sdim/// `applyFirst` is simply joining the set of rules into one. 154353942Sdim// 155353942Sdim// `applyFirst` is like an `anyOf` matcher with an edit action attached to each 156353942Sdim// of its cases. Anywhere you'd use `anyOf(m1.bind("id1"), m2.bind("id2"))` and 157353942Sdim// then dispatch on those ids in your code for control flow, `applyFirst` lifts 158353942Sdim// that behavior to the rule level. So, you can write `applyFirst({makeRule(m1, 159353942Sdim// action1), makeRule(m2, action2), ...});` 160353942Sdim// 161353942Sdim// For example, consider a type `T` with a deterministic serialization function, 162353942Sdim// `serialize()`. For performance reasons, we would like to make it 163353942Sdim// non-deterministic. Therefore, we want to drop the expectation that 164353942Sdim// `a.serialize() = b.serialize() iff a = b` (although we'll maintain 165353942Sdim// `deserialize(a.serialize()) = a`). 166353942Sdim// 167353942Sdim// We have three cases to consider (for some equality function, `eq`): 168353942Sdim// ``` 169353942Sdim// eq(a.serialize(), b.serialize()) --> eq(a,b) 170353942Sdim// eq(a, b.serialize()) --> eq(deserialize(a), b) 171353942Sdim// eq(a.serialize(), b) --> eq(a, deserialize(b)) 172353942Sdim// ``` 173353942Sdim// 174353942Sdim// `applyFirst` allows us to specify each independently: 175353942Sdim// ``` 176353942Sdim// auto eq_fun = functionDecl(...); 177353942Sdim// auto method_call = cxxMemberCallExpr(...); 178353942Sdim// 179353942Sdim// auto two_calls = callExpr(callee(eq_fun), hasArgument(0, method_call), 180353942Sdim// hasArgument(1, method_call)); 181353942Sdim// auto left_call = 182353942Sdim// callExpr(callee(eq_fun), callExpr(hasArgument(0, method_call))); 183353942Sdim// auto right_call = 184353942Sdim// callExpr(callee(eq_fun), callExpr(hasArgument(1, method_call))); 185353942Sdim// 186353942Sdim// RewriteRule R = applyFirst({makeRule(two_calls, two_calls_action), 187353942Sdim// makeRule(left_call, left_call_action), 188353942Sdim// makeRule(right_call, right_call_action)}); 189353942Sdim// ``` 190353942SdimRewriteRule applyFirst(ArrayRef<RewriteRule> Rules); 191353942Sdim 192353942Sdim/// Replaces a portion of the source text with \p Replacement. 193357095SdimASTEdit changeTo(RangeSelector Target, TextGenerator Replacement); 194357095Sdim/// DEPRECATED: use \c changeTo. 195357095Sdiminline ASTEdit change(RangeSelector Target, TextGenerator Replacement) { 196357095Sdim return changeTo(std::move(Target), std::move(Replacement)); 197357095Sdim} 198353942Sdim 199353942Sdim/// Replaces the entirety of a RewriteRule's match with \p Replacement. For 200353942Sdim/// example, to replace a function call, one could write: 201353942Sdim/// \code 202353942Sdim/// makeRule(callExpr(callee(functionDecl(hasName("foo")))), 203357095Sdim/// changeTo(cat("bar()"))) 204353942Sdim/// \endcode 205357095Sdiminline ASTEdit changeTo(TextGenerator Replacement) { 206357095Sdim return changeTo(node(RewriteRule::RootID), std::move(Replacement)); 207357095Sdim} 208357095Sdim/// DEPRECATED: use \c changeTo. 209353942Sdiminline ASTEdit change(TextGenerator Replacement) { 210357095Sdim return changeTo(std::move(Replacement)); 211353942Sdim} 212353942Sdim 213353942Sdim/// Inserts \p Replacement before \p S, leaving the source selected by \S 214353942Sdim/// unchanged. 215353942Sdiminline ASTEdit insertBefore(RangeSelector S, TextGenerator Replacement) { 216357095Sdim return changeTo(before(std::move(S)), std::move(Replacement)); 217353942Sdim} 218353942Sdim 219353942Sdim/// Inserts \p Replacement after \p S, leaving the source selected by \S 220353942Sdim/// unchanged. 221353942Sdiminline ASTEdit insertAfter(RangeSelector S, TextGenerator Replacement) { 222357095Sdim return changeTo(after(std::move(S)), std::move(Replacement)); 223353942Sdim} 224353942Sdim 225353942Sdim/// Removes the source selected by \p S. 226357095SdimASTEdit remove(RangeSelector S); 227353942Sdim 228353942Sdim/// The following three functions are a low-level part of the RewriteRule 229353942Sdim/// API. We expose them for use in implementing the fixtures that interpret 230353942Sdim/// RewriteRule, like Transformer and TransfomerTidy, or for more advanced 231353942Sdim/// users. 232353942Sdim// 233353942Sdim// FIXME: These functions are really public, if advanced, elements of the 234353942Sdim// RewriteRule API. Recast them as such. Or, just declare these functions 235353942Sdim// public and well-supported and move them out of `detail`. 236353942Sdimnamespace detail { 237353942Sdim/// Builds a single matcher for the rule, covering all of the rule's cases. 238353942Sdim/// Only supports Rules whose cases' matchers share the same base "kind" 239353942Sdim/// (`Stmt`, `Decl`, etc.) Deprecated: use `buildMatchers` instead, which 240353942Sdim/// supports mixing matchers of different kinds. 241353942Sdimast_matchers::internal::DynTypedMatcher buildMatcher(const RewriteRule &Rule); 242353942Sdim 243353942Sdim/// Builds a set of matchers that cover the rule (one for each distinct node 244353942Sdim/// matcher base kind: Stmt, Decl, etc.). Node-matchers for `QualType` and 245353942Sdim/// `Type` are not permitted, since such nodes carry no source location 246353942Sdim/// information and are therefore not relevant for rewriting. If any such 247353942Sdim/// matchers are included, will return an empty vector. 248353942Sdimstd::vector<ast_matchers::internal::DynTypedMatcher> 249353942SdimbuildMatchers(const RewriteRule &Rule); 250353942Sdim 251353942Sdim/// Gets the beginning location of the source matched by a rewrite rule. If the 252353942Sdim/// match occurs within a macro expansion, returns the beginning of the 253353942Sdim/// expansion point. `Result` must come from the matching of a rewrite rule. 254353942SdimSourceLocation 255353942SdimgetRuleMatchLoc(const ast_matchers::MatchFinder::MatchResult &Result); 256353942Sdim 257353942Sdim/// Returns the \c Case of \c Rule that was selected in the match result. 258353942Sdim/// Assumes a matcher built with \c buildMatcher. 259353942Sdimconst RewriteRule::Case & 260353942SdimfindSelectedCase(const ast_matchers::MatchFinder::MatchResult &Result, 261353942Sdim const RewriteRule &Rule); 262353942Sdim 263353942Sdim/// A source "transformation," represented by a character range in the source to 264353942Sdim/// be replaced and a corresponding replacement string. 265353942Sdimstruct Transformation { 266353942Sdim CharSourceRange Range; 267353942Sdim std::string Replacement; 268353942Sdim}; 269353942Sdim 270353942Sdim/// Attempts to translate `Edits`, which are in terms of AST nodes bound in the 271353942Sdim/// match `Result`, into Transformations, which are in terms of the source code 272353942Sdim/// text. 273353942Sdim/// 274353942Sdim/// Returns an empty vector if any of the edits apply to portions of the source 275353942Sdim/// that are ineligible for rewriting (certain interactions with macros, for 276353942Sdim/// example). Fails if any invariants are violated relating to bound nodes in 277353942Sdim/// the match. However, it does not fail in the case of conflicting edits -- 278353942Sdim/// conflict handling is left to clients. We recommend use of the \c 279353942Sdim/// AtomicChange or \c Replacements classes for assistance in detecting such 280353942Sdim/// conflicts. 281353942SdimExpected<SmallVector<Transformation, 1>> 282353942SdimtranslateEdits(const ast_matchers::MatchFinder::MatchResult &Result, 283353942Sdim llvm::ArrayRef<ASTEdit> Edits); 284353942Sdim} // namespace detail 285353942Sdim} // namespace transformer 286353942Sdim 287353942Sdimnamespace tooling { 288353942Sdim// DEPRECATED: These are temporary aliases supporting client migration to the 289353942Sdim// `transformer` namespace. 290353942Sdim/// Wraps a string as a TextGenerator. 291353942Sdimusing TextGenerator = transformer::TextGenerator; 292353942Sdim 293357095SdimTextGenerator text(std::string M); 294353942Sdim 295353942Sdimusing transformer::addInclude; 296353942Sdimusing transformer::applyFirst; 297353942Sdimusing transformer::change; 298353942Sdimusing transformer::insertAfter; 299353942Sdimusing transformer::insertBefore; 300353942Sdimusing transformer::makeRule; 301353942Sdimusing transformer::remove; 302353942Sdimusing transformer::RewriteRule; 303353942Sdimusing transformer::IncludeFormat; 304353942Sdimnamespace detail { 305353942Sdimusing namespace transformer::detail; 306353942Sdim} // namespace detail 307353942Sdim} // namespace tooling 308353942Sdim} // namespace clang 309353942Sdim 310353942Sdim#endif // LLVM_CLANG_TOOLING_TRANSFORMER_REWRITE_RULE_H_ 311