blob: cac8e58fa917322198df10bd28a514494cbf3e09 [file] [log] [blame]
Googler858c86e2021-11-26 14:19:41 +00001// 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 Gribenkoe4e77d02022-03-17 14:09:39 +00005#ifndef CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_
6#define CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_
Googler858c86e2021-11-26 14:19:41 +00007
8#include <iosfwd>
9#include <string>
Googler9873f4b2022-03-08 13:18:48 +000010#include <variant>
Googler858c86e2021-11-26 14:19:41 +000011
Luca Versaric5231632022-04-11 07:36:35 -070012#include "lifetime_annotations/lifetime_substitutions.h"
Googler858c86e2021-11-26 14:19:41 +000013#include "lifetime_annotations/type_lifetimes.h"
Lukasz Anforowiczcec7a8a2022-04-27 10:24:51 -070014#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"
Googler858c86e2021-11-26 14:19:41 +000021
Martin Brænne1a207c52022-04-19 00:05:38 -070022namespace clang {
23namespace tidy {
24namespace lifetimes {
Googler858c86e2021-11-26 14:19:41 +000025
Luca Versari95ce68f2022-03-24 14:44:19 +000026// Interface used to create lifetimes in FunctionLifetimes::CreateForDecl.
Martin Brænne9e309582022-04-26 05:16:29 -070027// CreateReturnLifetimes will be called with the ValueLifetimes that were
28// created through calls to CreateParamLifetimes.
Luca Versari95ce68f2022-03-24 14:44:19 +000029class FunctionLifetimeFactory {
30 public:
31 virtual ~FunctionLifetimeFactory() {}
Martin Brænne712b7f42022-06-23 00:55:17 -070032
Martin Brænne1c097f22022-06-23 01:14:09 -070033 virtual llvm::Expected<ValueLifetimes> CreateThisLifetimes(
34 clang::QualType type, const clang::Expr* lifetime_name) const = 0;
35
Martin Brænne712b7f42022-06-23 00:55:17 -070036 // Note: The `type_loc` parameter passed into `CreateParamLifetimes` and
37 // `CreateReturnLifetimes` may be null if no type location is available.
38
Martin Brænne9e309582022-04-26 05:16:29 -070039 virtual llvm::Expected<ValueLifetimes> CreateParamLifetimes(
Martin Brænne712b7f42022-06-23 00:55:17 -070040 clang::QualType type, clang::TypeLoc type_loc) const = 0;
Martin Brænne9e309582022-04-26 05:16:29 -070041 virtual llvm::Expected<ValueLifetimes> CreateReturnLifetimes(
Martin Brænne712b7f42022-06-23 00:55:17 -070042 clang::QualType type, clang::TypeLoc type_loc,
Luca Versari95ce68f2022-03-24 14:44:19 +000043 const llvm::SmallVector<ValueLifetimes>& param_lifetimes,
44 const std::optional<ValueLifetimes>& this_lifetimes) const = 0;
45};
46
Martin Brænne9e309582022-04-26 05:16:29 -070047// Implementation of FunctionLifetimeFactory that defers to a LifetimeFactory.
Luca Versari95ce68f2022-03-24 14:44:19 +000048class FunctionLifetimeFactorySingleCallback : public FunctionLifetimeFactory {
49 public:
50 FunctionLifetimeFactorySingleCallback(LifetimeFactory factory)
51 : factory_(std::move(factory)) {}
Martin Brænne1c097f22022-06-23 01:14:09 -070052 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ænne9e309582022-04-26 05:16:29 -070060 llvm::Expected<ValueLifetimes> CreateParamLifetimes(
Martin Brænne712b7f42022-06-23 00:55:17 -070061 clang::QualType type, clang::TypeLoc type_loc) const override {
62 return ValueLifetimes::Create(type, type_loc, factory_);
Luca Versari95ce68f2022-03-24 14:44:19 +000063 }
Martin Brænne9e309582022-04-26 05:16:29 -070064 llvm::Expected<ValueLifetimes> CreateReturnLifetimes(
Martin Brænne712b7f42022-06-23 00:55:17 -070065 clang::QualType type, clang::TypeLoc type_loc,
Luca Versari95ce68f2022-03-24 14:44:19 +000066 const llvm::SmallVector<ValueLifetimes>& /*param_lifetimes*/,
67 const std::optional<ValueLifetimes>& /*this_lifetimes*/) const override {
Martin Brænne712b7f42022-06-23 00:55:17 -070068 return ValueLifetimes::Create(type, type_loc, factory_);
Luca Versari95ce68f2022-03-24 14:44:19 +000069 }
70
71 private:
72 LifetimeFactory factory_;
73};
74
Googler858c86e2021-11-26 14:19:41 +000075// Lifetimes for the signature of a function.
Luca Versari95ce68f2022-03-24 14:44:19 +000076class FunctionLifetimes {
77 public:
78 // Returns lifetimes for the `i`-th parameter.
Googler858c86e2021-11-26 14:19:41 +000079 // These are the same number and order as FunctionDecl::parameters().
Luca Versari95ce68f2022-03-24 14:44:19 +000080 const ValueLifetimes& GetParamLifetimes(size_t i) const {
81 return param_lifetimes_[i];
82 }
Googler858c86e2021-11-26 14:19:41 +000083
Luca Versari96343612022-04-19 07:57:12 -070084 // Returns the number of function parameters (excluding the implicit `this).
85 const size_t GetNumParams() const { return param_lifetimes_.size(); }
86
Googler858c86e2021-11-26 14:19:41 +000087 // Lifetimes for the return type.
Luca Versari95ce68f2022-03-24 14:44:19 +000088 const ValueLifetimes& GetReturnLifetimes() const { return return_lifetimes_; }
Googler858c86e2021-11-26 14:19:41 +000089
90 // Lifetimes for the `this` parameter for non-static member functions.
Luca Versari95ce68f2022-03-24 14:44:19 +000091 const ValueLifetimes& GetThisLifetimes() const {
92 assert(this_lifetimes_.has_value());
93 return *this_lifetimes_;
94 }
Googler858c86e2021-11-26 14:19:41 +000095
Luca Versari96343612022-04-19 07:57:12 -070096 // Returns whether this FunctionLifetimes represents a non-static method.
97 bool IsNonStaticMethod() const { return this_lifetimes_.has_value(); }
98
Luca Versari95ce68f2022-03-24 14:44:19 +000099 // 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 Versaricc7e6cb2022-04-05 08:08:23 -0700107 static llvm::Expected<FunctionLifetimes> CreateForFunctionType(
Martin Brænne712b7f42022-06-23 00:55:17 -0700108 const clang::FunctionProtoType* function, clang::TypeLoc func_type_loc,
109 const FunctionLifetimeFactory& lifetime_factory);
110 static llvm::Expected<FunctionLifetimes> CreateForFunctionType(
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700111 const clang::FunctionProtoType* function,
112 const FunctionLifetimeFactory& lifetime_factory);
113
114 // TODO(veluca): add support for pointer-to-member-fn.
115
Luca Versari96343612022-04-19 07:57:12 -0700116 // 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 Versari95ce68f2022-03-24 14:44:19 +0000130 // Checks if this FunctionLifetimes represents valid lifetimes for the given
131 // Decl.
132 bool IsValidForDecl(const clang::FunctionDecl* function);
Googler858c86e2021-11-26 14:19:41 +0000133
Googler858c86e2021-11-26 14:19:41 +0000134 // 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 Versari95ce68f2022-03-24 14:44:19 +0000140
Luca Versari043a36e2022-04-08 00:55:36 -0700141 // 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 Versarid6901162022-04-08 02:59:33 -0700145 // 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 Versaric5231632022-04-11 07:36:35 -0700150 // 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 Versari95ce68f2022-03-24 14:44:19 +0000158 // 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ænne712b7f42022-06-23 00:55:17 -0700169 const clang::FunctionProtoType* type, clang::TypeLoc type_loc,
170 const clang::QualType this_type,
Luca Versari95ce68f2022-03-24 14:44:19 +0000171 const FunctionLifetimeFactory& lifetime_factory);
Googler858c86e2021-11-26 14:19:41 +0000172};
173
174std::ostream& operator<<(std::ostream& os,
175 const FunctionLifetimes& func_lifetimes);
176
Googler9873f4b2022-03-08 13:18:48 +0000177// An error that occurred while analyzing a function.
178struct FunctionAnalysisError {
Luca Versari95ce68f2022-03-24 14:44:19 +0000179 explicit FunctionAnalysisError(llvm::StringRef message = "")
180 : message(message) {}
Googler9873f4b2022-03-08 13:18:48 +0000181
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
196using FunctionLifetimesOrError =
Luca Versari95ce68f2022-03-24 14:44:19 +0000197 std::variant<FunctionAnalysisError, FunctionLifetimes>;
Googler9873f4b2022-03-08 13:18:48 +0000198
Martin Brænne1a207c52022-04-19 00:05:38 -0700199} // namespace lifetimes
200} // namespace tidy
201} // namespace clang
Googler858c86e2021-11-26 14:19:41 +0000202
Dmitri Gribenkoe4e77d02022-03-17 14:09:39 +0000203#endif // CRUBIT_LIFETIME_ANNOTATIONS_FUNCTION_LIFETIMES_H_