Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 1 | // Part of the Crubit project, under the Apache License v2.0 with LLVM |
| 2 | // Exceptions. See /LICENSE for license information. |
| 3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 4 | |
Dmitri Gribenko | e4e77d0 | 2022-03-17 14:09:39 +0000 | [diff] [blame] | 5 | #ifndef CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_ |
| 6 | #define CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_ |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 7 | |
| 8 | #include <iosfwd> |
| 9 | #include <string> |
Googler | 9873f4b | 2022-03-08 13:18:48 +0000 | [diff] [blame] | 10 | #include <variant> |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 11 | |
Luca Versari | c523163 | 2022-04-11 07:36:35 -0700 | [diff] [blame] | 12 | #include "lifetime_annotations/lifetime_substitutions.h" |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 13 | #include "lifetime_annotations/type_lifetimes.h" |
Lukasz Anforowicz | cec7a8a | 2022-04-27 10:24:51 -0700 | [diff] [blame] | 14 | #include "clang/AST/Decl.h" |
| 15 | #include "clang/AST/DeclCXX.h" |
| 16 | #include "clang/AST/Type.h" |
| 17 | #include "llvm/ADT/DenseSet.h" |
| 18 | #include "llvm/ADT/SmallVector.h" |
| 19 | #include "llvm/ADT/StringRef.h" |
| 20 | #include "llvm/Support/Error.h" |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 21 | |
Martin Brænne | 1a207c5 | 2022-04-19 00:05:38 -0700 | [diff] [blame] | 22 | namespace clang { |
| 23 | namespace tidy { |
| 24 | namespace lifetimes { |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 25 | |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 26 | // Interface used to create lifetimes in FunctionLifetimes::CreateForDecl. |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 27 | // CreateReturnLifetimes will be called with the ValueLifetimes that were |
| 28 | // created through calls to CreateParamLifetimes. |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 29 | class FunctionLifetimeFactory { |
| 30 | public: |
| 31 | virtual ~FunctionLifetimeFactory() {} |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 32 | |
Martin Brænne | 1c097f2 | 2022-06-23 01:14:09 -0700 | [diff] [blame] | 33 | virtual llvm::Expected<ValueLifetimes> CreateThisLifetimes( |
| 34 | clang::QualType type, const clang::Expr* lifetime_name) const = 0; |
| 35 | |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 36 | // Note: The `type_loc` parameter passed into `CreateParamLifetimes` and |
| 37 | // `CreateReturnLifetimes` may be null if no type location is available. |
| 38 | |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 39 | virtual llvm::Expected<ValueLifetimes> CreateParamLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 40 | clang::QualType type, clang::TypeLoc type_loc) const = 0; |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 41 | virtual llvm::Expected<ValueLifetimes> CreateReturnLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 42 | clang::QualType type, clang::TypeLoc type_loc, |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 43 | const llvm::SmallVector<ValueLifetimes>& param_lifetimes, |
| 44 | const std::optional<ValueLifetimes>& this_lifetimes) const = 0; |
| 45 | }; |
| 46 | |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 47 | // Implementation of FunctionLifetimeFactory that defers to a LifetimeFactory. |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 48 | class FunctionLifetimeFactorySingleCallback : public FunctionLifetimeFactory { |
| 49 | public: |
| 50 | FunctionLifetimeFactorySingleCallback(LifetimeFactory factory) |
| 51 | : factory_(std::move(factory)) {} |
Martin Brænne | 1c097f2 | 2022-06-23 01:14:09 -0700 | [diff] [blame] | 52 | llvm::Expected<ValueLifetimes> CreateThisLifetimes( |
| 53 | clang::QualType type, |
| 54 | const clang::Expr* /*lifetime_name*/) const override { |
| 55 | // TODO(mboehme): There's currently no way for us to pass `lifetime_name` on |
| 56 | // into `ValueLifetimes::Create()`. We may need to add another overload of |
| 57 | // `ValueLifetimes::Create()` if we ever need this. |
| 58 | return ValueLifetimes::Create(type, TypeLoc(), factory_); |
| 59 | } |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 60 | llvm::Expected<ValueLifetimes> CreateParamLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 61 | clang::QualType type, clang::TypeLoc type_loc) const override { |
| 62 | return ValueLifetimes::Create(type, type_loc, factory_); |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 63 | } |
Martin Brænne | 9e30958 | 2022-04-26 05:16:29 -0700 | [diff] [blame] | 64 | llvm::Expected<ValueLifetimes> CreateReturnLifetimes( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 65 | clang::QualType type, clang::TypeLoc type_loc, |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 66 | const llvm::SmallVector<ValueLifetimes>& /*param_lifetimes*/, |
| 67 | const std::optional<ValueLifetimes>& /*this_lifetimes*/) const override { |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 68 | return ValueLifetimes::Create(type, type_loc, factory_); |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 69 | } |
| 70 | |
| 71 | private: |
| 72 | LifetimeFactory factory_; |
| 73 | }; |
| 74 | |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 75 | // Lifetimes for the signature of a function. |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 76 | class FunctionLifetimes { |
| 77 | public: |
| 78 | // Returns lifetimes for the `i`-th parameter. |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 79 | // These are the same number and order as FunctionDecl::parameters(). |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 80 | const ValueLifetimes& GetParamLifetimes(size_t i) const { |
| 81 | return param_lifetimes_[i]; |
| 82 | } |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 83 | |
Luca Versari | 9634361 | 2022-04-19 07:57:12 -0700 | [diff] [blame] | 84 | // Returns the number of function parameters (excluding the implicit `this). |
| 85 | const size_t GetNumParams() const { return param_lifetimes_.size(); } |
| 86 | |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 87 | // Lifetimes for the return type. |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 88 | const ValueLifetimes& GetReturnLifetimes() const { return return_lifetimes_; } |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 89 | |
| 90 | // Lifetimes for the `this` parameter for non-static member functions. |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 91 | const ValueLifetimes& GetThisLifetimes() const { |
| 92 | assert(this_lifetimes_.has_value()); |
| 93 | return *this_lifetimes_; |
| 94 | } |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 95 | |
Luca Versari | 9634361 | 2022-04-19 07:57:12 -0700 | [diff] [blame] | 96 | // Returns whether this FunctionLifetimes represents a non-static method. |
| 97 | bool IsNonStaticMethod() const { return this_lifetimes_.has_value(); } |
| 98 | |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 99 | // Creates lifetimes for a function with a given decl. |
| 100 | // Only fails if lifetime_factory fails. |
| 101 | // Lifetimes will be created first for the object parameter, if any, then for |
| 102 | // parameters in increasing order, and finally for the return type. |
| 103 | static llvm::Expected<FunctionLifetimes> CreateForDecl( |
| 104 | const clang::FunctionDecl* function, |
| 105 | const FunctionLifetimeFactory& lifetime_factory); |
| 106 | |
Luca Versari | cc7e6cb | 2022-04-05 08:08:23 -0700 | [diff] [blame] | 107 | static llvm::Expected<FunctionLifetimes> CreateForFunctionType( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 108 | const clang::FunctionProtoType* function, clang::TypeLoc func_type_loc, |
| 109 | const FunctionLifetimeFactory& lifetime_factory); |
| 110 | static llvm::Expected<FunctionLifetimes> CreateForFunctionType( |
Luca Versari | cc7e6cb | 2022-04-05 08:08:23 -0700 | [diff] [blame] | 111 | const clang::FunctionProtoType* function, |
| 112 | const FunctionLifetimeFactory& lifetime_factory); |
| 113 | |
| 114 | // TODO(veluca): add support for pointer-to-member-fn. |
| 115 | |
Luca Versari | 9634361 | 2022-04-19 07:57:12 -0700 | [diff] [blame] | 116 | // Creates a copy of this FunctionLifetimes with the same structure, but |
| 117 | // fresh, unrelated lifetimes independently of whether the lifetimes where |
| 118 | // identical in this FunctionLifetimes. |
| 119 | // TODO(veluca): remove this method once FunctionLifetimes keeps track of its |
| 120 | // own type, and replace it with an appropriate call to Create(). |
| 121 | llvm::Expected<FunctionLifetimes> CreateCopy( |
| 122 | const LifetimeFactory& factory) const; |
| 123 | |
| 124 | // Returns FunctionLifetimes for a method that this method overrides. |
| 125 | // Precondition: `IsNonStaticMethod()` is true, |
| 126 | // `method`'s signature is compatible with this FunctionLifetimes except for |
| 127 | // the `this` parameter. |
| 128 | FunctionLifetimes ForOverriddenMethod(const clang::CXXMethodDecl* method); |
| 129 | |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 130 | // Checks if this FunctionLifetimes represents valid lifetimes for the given |
| 131 | // Decl. |
| 132 | bool IsValidForDecl(const clang::FunctionDecl* function); |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 133 | |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 134 | // Returns a human-readable representation of `func_lifetimes`. Formats |
| 135 | // lifetimes using `formatter`, or Lifetime::DebugString() if `formatter` is |
| 136 | // null. |
| 137 | std::string DebugString(LifetimeFormatter formatter = [](Lifetime l) { |
| 138 | return l.DebugString(); |
| 139 | }) const; |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 140 | |
Luca Versari | 043a36e | 2022-04-08 00:55:36 -0700 | [diff] [blame] | 141 | // Returns true if `predicate` returns true for any lifetime that appears in |
| 142 | // the `FunctionLifetimes`. |
| 143 | bool HasAny(const std::function<bool(Lifetime)>& predicate) const; |
| 144 | |
Luca Versari | d690116 | 2022-04-08 02:59:33 -0700 | [diff] [blame] | 145 | // Returns the set of all lifetimes that are either lifetime parameters of |
| 146 | // this function, or (if this FunctionLifetimes is a declaration of a method) |
| 147 | // of the enclosing class. |
| 148 | llvm::DenseSet<Lifetime> AllFreeLifetimes() const; |
| 149 | |
Luca Versari | c523163 | 2022-04-11 07:36:35 -0700 | [diff] [blame] | 150 | // Applies `subst` to all lifetimes in this FunctionLifetimes. |
| 151 | // Any lifetime parameter declarations will moved to the innermost location |
| 152 | // that is valid for the new lifetimes. Note that this operation is |
| 153 | // well-defined and declarations of lifetime parameters can only "move up"; |
| 154 | // in particular, it results lifetime parameters being as tightly bound as |
| 155 | // possible, which is what we want inference to infer. |
| 156 | void SubstituteLifetimes(const LifetimeSubstitutions& subst); |
| 157 | |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 158 | // Traverses all the lifetimes in the function signature, recursively. The |
| 159 | // visit is done in post-order on the lifetime tree of this type. |
| 160 | void Traverse(std::function<void(Lifetime&, Variance)> visitor); |
| 161 | void Traverse(std::function<void(const Lifetime&, Variance)> visitor) const; |
| 162 | |
| 163 | private: |
| 164 | llvm::SmallVector<ValueLifetimes> param_lifetimes_; |
| 165 | ValueLifetimes return_lifetimes_; |
| 166 | std::optional<ValueLifetimes> this_lifetimes_; |
| 167 | |
| 168 | static llvm::Expected<FunctionLifetimes> Create( |
Martin Brænne | 712b7f4 | 2022-06-23 00:55:17 -0700 | [diff] [blame] | 169 | const clang::FunctionProtoType* type, clang::TypeLoc type_loc, |
| 170 | const clang::QualType this_type, |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 171 | const FunctionLifetimeFactory& lifetime_factory); |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 172 | }; |
| 173 | |
| 174 | std::ostream& operator<<(std::ostream& os, |
| 175 | const FunctionLifetimes& func_lifetimes); |
| 176 | |
Googler | 9873f4b | 2022-03-08 13:18:48 +0000 | [diff] [blame] | 177 | // An error that occurred while analyzing a function. |
| 178 | struct FunctionAnalysisError { |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 179 | explicit FunctionAnalysisError(llvm::StringRef message = "") |
| 180 | : message(message) {} |
Googler | 9873f4b | 2022-03-08 13:18:48 +0000 | [diff] [blame] | 181 | |
| 182 | explicit FunctionAnalysisError(const llvm::Error& err) { |
| 183 | ::llvm::raw_string_ostream stream(message); |
| 184 | stream << err; |
| 185 | } |
| 186 | |
| 187 | // Human-readable description of the error. |
| 188 | std::string message; |
| 189 | }; |
| 190 | |
| 191 | // Lifetimes for a function, or an error if we couldn't analyze the function. |
| 192 | // We can't use llvm::Expected<FunctionLifetimes> for this because: |
| 193 | // - llvm::Expected doesn't allow us to check for an error state without moving |
| 194 | // the error out of the llvm::Expected |
| 195 | // - llvm::Expected asserts in the destructor if we didn't check for an error |
| 196 | using FunctionLifetimesOrError = |
Luca Versari | 95ce68f | 2022-03-24 14:44:19 +0000 | [diff] [blame] | 197 | std::variant<FunctionAnalysisError, FunctionLifetimes>; |
Googler | 9873f4b | 2022-03-08 13:18:48 +0000 | [diff] [blame] | 198 | |
Martin Brænne | 1a207c5 | 2022-04-19 00:05:38 -0700 | [diff] [blame] | 199 | } // namespace lifetimes |
| 200 | } // namespace tidy |
| 201 | } // namespace clang |
Googler | 858c86e | 2021-11-26 14:19:41 +0000 | [diff] [blame] | 202 | |
Dmitri Gribenko | e4e77d0 | 2022-03-17 14:09:39 +0000 | [diff] [blame] | 203 | #endif // CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_ |