blob: a37b3c465695ecae57a7c412d06097b690c120ed [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
5#include "lifetime_annotations/function_lifetimes.h"
6
7#include <string>
8
Googler858c86e2021-11-26 14:19:41 +00009#include "third_party/absl/strings/str_cat.h"
10#include "third_party/absl/strings/str_join.h"
Marcel Hlopko97a68a12022-03-09 11:38:51 +000011#include "lifetime_annotations/lifetime.h"
12#include "lifetime_annotations/type_lifetimes.h"
Luca Versariedf553b2022-01-26 14:10:32 +000013#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000014#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
Luca Versariedf553b2022-01-26 14:10:32 +000015#include "third_party/llvm/llvm-project/clang/include/clang/Basic/LLVM.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000016#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallVector.h"
17#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Error.h"
Googler858c86e2021-11-26 14:19:41 +000018
19namespace devtools_rust {
Googler858c86e2021-11-26 14:19:41 +000020
Luca Versari95ce68f2022-03-24 14:44:19 +000021namespace {
Googler858c86e2021-11-26 14:19:41 +000022// Track a bijective mapping between 2 sets of Lifetimes.
23class LifetimeBijection {
24 public:
25 // Returns true if the bidirectional mapping between lifetimes could be added
26 // to the bijection, or is already present. Returns false if the lifetimes
27 // conflict with other mappings already recorded in the bijection.
28 bool Add(Lifetime lifetime_in_a, Lifetime lifetime_in_b) {
Googler727e97b2021-11-30 14:38:37 +000029 auto [a_to_b_iter, a_to_b_inserted] =
30 a_to_b_.try_emplace(lifetime_in_a, lifetime_in_b);
31 if (!a_to_b_inserted) {
32 return a_to_b_iter->second == lifetime_in_b;
Googler858c86e2021-11-26 14:19:41 +000033 }
Googler727e97b2021-11-30 14:38:37 +000034 auto [_, b_to_a_inserted] =
35 b_to_a_.try_emplace(lifetime_in_b, lifetime_in_a);
36 return b_to_a_inserted;
Googler858c86e2021-11-26 14:19:41 +000037 }
38
39 private:
40 llvm::DenseMap<Lifetime, Lifetime> a_to_b_;
41 llvm::DenseMap<Lifetime, Lifetime> b_to_a_;
42};
43
44} // namespace
45
Luca Versari95ce68f2022-03-24 14:44:19 +000046llvm::Expected<FunctionLifetimes> FunctionLifetimes::CreateForDecl(
47 const clang::FunctionDecl* func,
48 const FunctionLifetimeFactory& lifetime_factory) {
49 clang::QualType this_type;
50 if (auto method = clang::dyn_cast<clang::CXXMethodDecl>(func);
51 method && !method->isStatic()) {
52 this_type = method->getThisType();
53 }
54 return Create(func->getType()->getAs<clang::FunctionProtoType>(), this_type,
55 lifetime_factory);
56}
57
Luca Versaricc7e6cb2022-04-05 08:08:23 -070058llvm::Expected<FunctionLifetimes> FunctionLifetimes::CreateForFunctionType(
59 const clang::FunctionProtoType* func,
60 const FunctionLifetimeFactory& lifetime_factory) {
61 return Create(func, clang::QualType(), lifetime_factory);
62}
63
Luca Versari95ce68f2022-03-24 14:44:19 +000064bool FunctionLifetimes::IsValidForDecl(const clang::FunctionDecl* function) {
65 // TODO(veluca): also validate the types of the arguments, and/or the type of
66 // the function itself.
67 if (auto method = clang::dyn_cast<clang::CXXMethodDecl>(function);
68 method && !method->isStatic()) {
69 if (!this_lifetimes_.has_value()) return false;
70 }
71 return param_lifetimes_.size() == function->param_size();
72}
73
74llvm::Expected<FunctionLifetimes> FunctionLifetimes::Create(
75 const clang::FunctionProtoType* type, const clang::QualType this_type,
76 const FunctionLifetimeFactory& lifetime_factory) {
77 FunctionLifetimes ret;
78
79 if (!this_type.isNull()) {
80 ValueLifetimes tmp;
81 if (llvm::Error err =
82 ValueLifetimes::Create(this_type, [&](clang::QualType type,
83 llvm::StringRef param) {
84 return lifetime_factory.CreateParamLifetime(type, param);
85 }).moveInto(tmp)) {
86 return std::move(err);
Googler858c86e2021-11-26 14:19:41 +000087 }
Luca Versari95ce68f2022-03-24 14:44:19 +000088 ret.this_lifetimes_ = std::move(tmp);
Googler858c86e2021-11-26 14:19:41 +000089 }
90
Luca Versari95ce68f2022-03-24 14:44:19 +000091 ret.param_lifetimes_.reserve(type->getNumParams());
92 for (size_t i = 0; i < type->getNumParams(); i++) {
93 ValueLifetimes tmp;
94 if (llvm::Error err = ValueLifetimes::Create(
95 type->getParamType(i),
96 [&](clang::QualType type, llvm::StringRef param) {
97 return lifetime_factory.CreateParamLifetime(
98 type, param);
99 })
100 .moveInto(tmp)) {
101 return std::move(err);
102 }
103 ret.param_lifetimes_.push_back(std::move(tmp));
104 }
105
106 if (llvm::Error err = ValueLifetimes::Create(
107 type->getReturnType(),
108 [&](clang::QualType type, llvm::StringRef param) {
109 return lifetime_factory.CreateReturnLifetime(
110 type, param, ret.param_lifetimes_,
111 ret.this_lifetimes_);
112 })
113 .moveInto(ret.return_lifetimes_)) {
114 return std::move(err);
115 }
116
117 return ret;
118}
119
Luca Versari043a36e2022-04-08 00:55:36 -0700120bool FunctionLifetimes::HasAny(
121 const std::function<bool(Lifetime)>& predicate) const {
122 return std::any_of(param_lifetimes_.begin(), param_lifetimes_.end(),
123 [&predicate](const ValueLifetimes& v) {
124 return v.HasAny(predicate);
125 }) ||
126 return_lifetimes_.HasAny(predicate) ||
127 (this_lifetimes_.has_value() && this_lifetimes_->HasAny(predicate));
128}
129
Luca Versari95ce68f2022-03-24 14:44:19 +0000130void FunctionLifetimes::Traverse(
131 std::function<void(Lifetime&, Variance)> visitor) {
132 for (auto& param : param_lifetimes_) {
133 param.Traverse(visitor);
134 }
135 return_lifetimes_.Traverse(visitor);
136 if (this_lifetimes_.has_value()) {
137 this_lifetimes_->Traverse(visitor);
138 }
139}
140
141void FunctionLifetimes::Traverse(
142 std::function<void(const Lifetime&, Variance)> visitor) const {
143 const_cast<FunctionLifetimes*>(this)->Traverse(
144 [visitor](Lifetime& l, Variance v) { visitor(l, v); });
Googler858c86e2021-11-26 14:19:41 +0000145}
146
147bool FunctionLifetimes::IsIsomorphic(const FunctionLifetimes& other) const {
148 // We expect this function to only be called for 2 FunctionLifetime objects
149 // that are for the same function, thus the number of parameters, and the
150 // number of Lifetimes for each type, should always match.
Luca Versari95ce68f2022-03-24 14:44:19 +0000151 assert(param_lifetimes_.size() == other.param_lifetimes_.size());
152 assert(this_lifetimes_.has_value() == other.this_lifetimes_.has_value());
Googler858c86e2021-11-26 14:19:41 +0000153
154 // Map of equivalent lifetimes between `*this` and `other`.
155 LifetimeBijection bijection;
156
Luca Versari95ce68f2022-03-24 14:44:19 +0000157 llvm::SmallVector<Lifetime> my_lifetimes;
158 Traverse(
159 [&my_lifetimes](Lifetime l, Variance) { my_lifetimes.push_back(l); });
160 llvm::SmallVector<Lifetime> other_lifetimes;
161 other.Traverse([&other_lifetimes](Lifetime l, Variance) {
162 other_lifetimes.push_back(l);
163 });
Googler858c86e2021-11-26 14:19:41 +0000164
Luca Versari95ce68f2022-03-24 14:44:19 +0000165 assert(my_lifetimes.size() == other_lifetimes.size());
166 for (size_t i = 0; i < my_lifetimes.size(); ++i) {
167 if (!bijection.Add(my_lifetimes[i], other_lifetimes[i])) {
Googler858c86e2021-11-26 14:19:41 +0000168 return false;
Luca Versari95ce68f2022-03-24 14:44:19 +0000169 }
Googler858c86e2021-11-26 14:19:41 +0000170 }
171 return true;
172}
173
174std::string FunctionLifetimes::DebugString(LifetimeFormatter formatter) const {
175 std::vector<std::string> formatted_param_lifetimes;
176
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700177 // Add parenteses to non-trivial nested lifetimes, i.e. fn parameters with >1
178 // lifetimes, as their DebugString does not contain parentheses.
Luca Versari6ee6b342022-04-05 05:40:52 -0700179 auto maybe_add_parentheses = [&](std::string s) {
180 if (s.find_first_of(",()") != std::string::npos || s.empty()) {
181 return absl::StrCat("(", s, ")");
182 }
183 return s;
184 };
185
Luca Versari95ce68f2022-03-24 14:44:19 +0000186 for (const auto& param : param_lifetimes_) {
Luca Versari6ee6b342022-04-05 05:40:52 -0700187 formatted_param_lifetimes.push_back(
188 maybe_add_parentheses(param.DebugString(formatter)));
Googler858c86e2021-11-26 14:19:41 +0000189 }
190
191 std::string result;
Luca Versari95ce68f2022-03-24 14:44:19 +0000192 if (this_lifetimes_.has_value()) {
Luca Versari6ee6b342022-04-05 05:40:52 -0700193 result = absl::StrCat(
194 maybe_add_parentheses(this_lifetimes_->DebugString(formatter)), ":");
Googler858c86e2021-11-26 14:19:41 +0000195 }
196 if (!result.empty() && !formatted_param_lifetimes.empty()) {
197 absl::StrAppend(&result, " ");
198 }
199 absl::StrAppend(&result, absl::StrJoin(formatted_param_lifetimes, ", "));
200
Luca Versari95ce68f2022-03-24 14:44:19 +0000201 if (return_lifetimes_.HasLifetimes()) {
Googler858c86e2021-11-26 14:19:41 +0000202 if (!result.empty()) {
203 absl::StrAppend(&result, " ");
204 }
Luca Versari6ee6b342022-04-05 05:40:52 -0700205 absl::StrAppend(
206 &result, "-> ",
207 maybe_add_parentheses(return_lifetimes_.DebugString(formatter)));
Googler858c86e2021-11-26 14:19:41 +0000208 }
209
210 return result;
211}
212
Googler858c86e2021-11-26 14:19:41 +0000213std::ostream& operator<<(std::ostream& os,
214 const FunctionLifetimes& func_lifetimes) {
215 return os << func_lifetimes.DebugString();
216}
217
218} // namespace devtools_rust