Stephen Hines | c6ca60f | 2023-05-09 02:19:22 -0700 | [diff] [blame^] | 1 | //===--- MatchConsumer.h - MatchConsumer abstraction ------------*- 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 This file defines the *MatchConsumer* abstraction: a computation over |
| 10 | /// match results, specifically the `ast_matchers::MatchFinder::MatchResult` |
| 11 | /// class. |
| 12 | /// |
| 13 | //===----------------------------------------------------------------------===// |
| 14 | |
| 15 | #ifndef LLVM_CLANG_TOOLING_TRANSFORMER_MATCHCONSUMER_H |
| 16 | #define LLVM_CLANG_TOOLING_TRANSFORMER_MATCHCONSUMER_H |
| 17 | |
| 18 | #include "clang/AST/ASTTypeTraits.h" |
| 19 | #include "clang/ASTMatchers/ASTMatchFinder.h" |
| 20 | #include "llvm/ADT/StringRef.h" |
| 21 | #include "llvm/Support/Errc.h" |
| 22 | #include "llvm/Support/Error.h" |
| 23 | |
| 24 | namespace clang { |
| 25 | namespace transformer { |
| 26 | /// A failable computation over nodes bound by AST matchers. |
| 27 | /// |
| 28 | /// The computation should report any errors though its return value (rather |
| 29 | /// than terminating the program) to enable usage in interactive scenarios like |
| 30 | /// clang-query. |
| 31 | /// |
| 32 | /// This is a central abstraction of the Transformer framework. |
| 33 | template <typename T> |
| 34 | using MatchConsumer = |
| 35 | std::function<Expected<T>(const ast_matchers::MatchFinder::MatchResult &)>; |
| 36 | |
| 37 | /// Creates an error that signals that a `MatchConsumer` expected a certain node |
| 38 | /// to be bound by AST matchers, but it was not actually bound. |
| 39 | inline llvm::Error notBoundError(llvm::StringRef Id) { |
| 40 | return llvm::make_error<llvm::StringError>(llvm::errc::invalid_argument, |
| 41 | "Id not bound: " + Id); |
| 42 | } |
| 43 | |
| 44 | /// Chooses between the two consumers, based on whether \p ID is bound in the |
| 45 | /// match. |
| 46 | template <typename T> |
| 47 | MatchConsumer<T> ifBound(std::string ID, MatchConsumer<T> TrueC, |
| 48 | MatchConsumer<T> FalseC) { |
| 49 | return [=](const ast_matchers::MatchFinder::MatchResult &Result) { |
| 50 | auto &Map = Result.Nodes.getMap(); |
| 51 | return (Map.find(ID) != Map.end() ? TrueC : FalseC)(Result); |
| 52 | }; |
| 53 | } |
| 54 | |
| 55 | /// A failable computation over nodes bound by AST matchers, with (limited) |
| 56 | /// reflection via the `toString` method. |
| 57 | /// |
| 58 | /// The computation should report any errors though its return value (rather |
| 59 | /// than terminating the program) to enable usage in interactive scenarios like |
| 60 | /// clang-query. |
| 61 | /// |
| 62 | /// This is a central abstraction of the Transformer framework. It is a |
| 63 | /// generalization of `MatchConsumer` and intended to replace it. |
| 64 | template <typename T> class MatchComputation { |
| 65 | public: |
| 66 | virtual ~MatchComputation() = default; |
| 67 | |
| 68 | /// Evaluates the computation and (potentially) updates the accumulator \c |
| 69 | /// Result. \c Result is undefined in the case of an error. `Result` is an |
| 70 | /// out parameter to optimize case where the computation involves composing |
| 71 | /// the result of sub-computation evaluations. |
| 72 | virtual llvm::Error eval(const ast_matchers::MatchFinder::MatchResult &Match, |
| 73 | T *Result) const = 0; |
| 74 | |
| 75 | /// Convenience version of `eval`, for the case where the computation is being |
| 76 | /// evaluated on its own. |
| 77 | llvm::Expected<T> eval(const ast_matchers::MatchFinder::MatchResult &R) const; |
| 78 | |
| 79 | /// Constructs a string representation of the computation, for informational |
| 80 | /// purposes. The representation must be deterministic, but is not required to |
| 81 | /// be unique. |
| 82 | virtual std::string toString() const = 0; |
| 83 | |
| 84 | protected: |
| 85 | MatchComputation() = default; |
| 86 | |
| 87 | // Since this is an abstract class, copying/assigning only make sense for |
| 88 | // derived classes implementing `clone()`. |
| 89 | MatchComputation(const MatchComputation &) = default; |
| 90 | MatchComputation &operator=(const MatchComputation &) = default; |
| 91 | }; |
| 92 | |
| 93 | template <typename T> |
| 94 | llvm::Expected<T> MatchComputation<T>::eval( |
| 95 | const ast_matchers::MatchFinder::MatchResult &R) const { |
| 96 | T Output; |
| 97 | if (auto Err = eval(R, &Output)) |
| 98 | return std::move(Err); |
| 99 | return Output; |
| 100 | } |
| 101 | } // namespace transformer |
| 102 | } // namespace clang |
| 103 | #endif // LLVM_CLANG_TOOLING_TRANSFORMER_MATCHCONSUMER_H |