blob: 7bf6599e9bd32672af951d5d46fe282babd5e699 [file] [log] [blame]
Googlerace85a22021-11-26 14:18:31 +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/type_lifetimes.h"
6
7#include <algorithm>
Googlerc071e242021-12-16 15:23:41 +00008#include <memory>
9#include <optional>
Googlerace85a22021-11-26 14:18:31 +000010#include <string>
Googler705f9452021-12-16 15:30:08 +000011#include <utility>
Googlerace85a22021-11-26 14:18:31 +000012
Luca Versari7f1783d2022-01-31 14:40:39 +000013#include "third_party/absl/strings/str_cat.h"
Googlerace85a22021-11-26 14:18:31 +000014#include "third_party/absl/strings/str_format.h"
15#include "third_party/absl/strings/str_join.h"
Luca Versaricc7e6cb2022-04-05 08:08:23 -070016#include "lifetime_annotations/function_lifetimes.h"
Marcel Hlopko97a68a12022-03-09 11:38:51 +000017#include "lifetime_annotations/lifetime.h"
18#include "lifetime_annotations/lifetime_symbol_table.h"
19#include "lifetime_annotations/pointee_type.h"
Luca Versarid101a292022-01-27 17:28:42 +000020#include "third_party/llvm/llvm-project/clang/include/clang/AST/Attr.h"
21#include "third_party/llvm/llvm-project/clang/include/clang/AST/Attrs.inc"
22#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclCXX.h"
Googlerace85a22021-11-26 14:18:31 +000023#include "third_party/llvm/llvm-project/clang/include/clang/AST/DeclTemplate.h"
24#include "third_party/llvm/llvm-project/clang/include/clang/AST/TemplateBase.h"
25#include "third_party/llvm/llvm-project/clang/include/clang/AST/Type.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000026#include "third_party/llvm/llvm-project/clang/include/clang/Basic/LLVM.h"
Luca Versarid101a292022-01-27 17:28:42 +000027#include "third_party/llvm/llvm-project/clang/include/clang/Basic/SourceLocation.h"
Luca Versari162a4c52021-12-10 08:57:05 +000028#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/ArrayRef.h"
Luca Versari7f1783d2022-01-31 14:40:39 +000029#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/DenseMapInfo.h"
30#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/Hashing.h"
Luca Versarid101a292022-01-27 17:28:42 +000031#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/SmallVector.h"
32#include "third_party/llvm/llvm-project/llvm/include/llvm/ADT/StringRef.h"
Luca Versari95ce68f2022-03-24 14:44:19 +000033#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/Error.h"
Luca Versarid101a292022-01-27 17:28:42 +000034#include "third_party/llvm/llvm-project/llvm/include/llvm/Support/ErrorHandling.h"
Googlerace85a22021-11-26 14:18:31 +000035
Martin Brænne1a207c52022-04-19 00:05:38 -070036namespace clang {
37namespace tidy {
38namespace lifetimes {
Googlerace85a22021-11-26 14:18:31 +000039
Googler247cef72022-03-02 15:13:38 +000040llvm::SmallVector<std::string> GetLifetimeParameters(clang::QualType type) {
41 // TODO(mboehme):
42 // - Add support for type aliases with lifetime parameters
43 // - Report errors as Clang diagnostics, not through
44 // llvm::report_fatal_error().
45
46 auto record = type->getAs<clang::RecordType>();
47 if (!record) {
48 return {};
49 }
50
51 auto cxx_record = record->getAsCXXRecordDecl();
52 if (!cxx_record) {
53 return {};
54 }
Googler17a2d512022-02-23 12:09:43 +000055
Luca Versarid101a292022-01-27 17:28:42 +000056 const clang::AnnotateAttr* lifetime_params_attr = nullptr;
57 for (auto annotate : cxx_record->specific_attrs<clang::AnnotateAttr>()) {
Googler17a2d512022-02-23 12:09:43 +000058 if (annotate->getAnnotation() == "lifetime_params") {
Luca Versarid101a292022-01-27 17:28:42 +000059 if (lifetime_params_attr) {
60 llvm::report_fatal_error("repeated lifetime annotation");
61 }
62 lifetime_params_attr = annotate;
63 }
64 }
Luca Versarid101a292022-01-27 17:28:42 +000065
Luca Versarid101a292022-01-27 17:28:42 +000066 llvm::SmallVector<std::string> ret;
Martin Brænnecf5d8972022-04-25 23:27:52 -070067
68 // TODO(mboehme): Require derived class to explicitly declare all lifetime
69 // parameters inherited from the base class.
70 if (cxx_record->hasDefinition()) {
71 for (const clang::CXXBaseSpecifier& base : cxx_record->bases()) {
72 if (lifetime_params_attr) {
73 llvm::report_fatal_error(
74 "derived classes may not add lifetime parameters");
75 }
76 if (!ret.empty()) {
77 llvm::report_fatal_error(
78 "only one base class may have lifetime parameters");
79 }
80 ret = GetLifetimeParameters(base.getType());
81 }
82 }
83
84 if (!lifetime_params_attr) {
85 return ret;
86 }
87
Googler17a2d512022-02-23 12:09:43 +000088 for (const auto& arg : lifetime_params_attr->args()) {
89 llvm::StringRef lifetime;
90 if (llvm::Error err =
91 EvaluateAsStringLiteral(arg, cxx_record->getASTContext())
92 .moveInto(lifetime)) {
93 llvm::report_fatal_error(llvm::StringRef(toString(std::move(err))));
Luca Versarid101a292022-01-27 17:28:42 +000094 }
Googler17a2d512022-02-23 12:09:43 +000095 ret.push_back(lifetime.str());
Luca Versarid101a292022-01-27 17:28:42 +000096 }
97
98 return ret;
99}
100
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700101ValueLifetimes::ValueLifetimes(const ValueLifetimes& other) { *this = other; }
102
Googlerc071e242021-12-16 15:23:41 +0000103ValueLifetimes& ValueLifetimes::operator=(const ValueLifetimes& other) {
Googler41f3e352021-12-16 15:24:21 +0000104 type_ = other.type_;
Googlerc071e242021-12-16 15:23:41 +0000105 template_argument_lifetimes_ = other.template_argument_lifetimes_;
Luca Versarid101a292022-01-27 17:28:42 +0000106 lifetime_parameters_by_name_ = other.lifetime_parameters_by_name_;
Googlerc071e242021-12-16 15:23:41 +0000107 pointee_lifetimes_ =
108 other.pointee_lifetimes_
109 ? std::make_unique<ObjectLifetimes>(*other.pointee_lifetimes_)
110 : nullptr;
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700111 function_lifetimes_ =
112 other.function_lifetimes_
113 ? std::make_unique<FunctionLifetimes>(*other.function_lifetimes_)
114 : nullptr;
Googlerc071e242021-12-16 15:23:41 +0000115 return *this;
116}
117
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700118// Defined here because FunctionLifetimes is an incomplete type in the header.
119ValueLifetimes::~ValueLifetimes() = default;
120
Luca Versariaf14c372022-04-04 07:30:24 -0700121namespace {
122
123llvm::Error ForEachTemplateArgument(
124 clang::QualType type,
125 const std::function<llvm::Error(int, clang::QualType)>& callback) {
126 llvm::SmallVector<llvm::ArrayRef<clang::TemplateArgument>> template_args =
127 GetTemplateArgs(type);
128 for (size_t depth = 0; depth < template_args.size(); depth++) {
129 const auto& args_at_depth = template_args[depth];
130 for (const clang::TemplateArgument& arg : args_at_depth) {
131 if (arg.getKind() == clang::TemplateArgument::Type) {
132 if (llvm::Error err = callback(depth, arg.getAsType())) {
133 return err;
134 }
135 } else if (arg.getKind() == clang::TemplateArgument::Pack) {
136 for (const clang::TemplateArgument& inner_arg : arg.getPackAsArray()) {
137 if (inner_arg.getKind() == clang::TemplateArgument::Type) {
138 if (llvm::Error err = callback(depth, inner_arg.getAsType())) {
139 return err;
140 }
141 }
142 }
Martin Brænne16d86dd2022-04-08 00:33:36 -0700143 } else {
144 if (llvm::Error err = callback(depth, clang::QualType())) {
145 return err;
146 }
Luca Versariaf14c372022-04-04 07:30:24 -0700147 }
148 }
149 }
150 return llvm::Error::success();
151}
152
153} // namespace
154
Luca Versari95ce68f2022-03-24 14:44:19 +0000155llvm::Expected<ValueLifetimes> ValueLifetimes::Create(
156 clang::QualType type, LifetimeFactory lifetime_factory) {
Googlerc071e242021-12-16 15:23:41 +0000157 assert(!type.isNull());
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700158 type = type.IgnoreParens();
Googler6a06dbc2021-12-16 15:25:02 +0000159 ValueLifetimes ret(type);
Googlerc071e242021-12-16 15:23:41 +0000160
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700161 if (const auto* fn = clang::dyn_cast<clang::FunctionProtoType>(type)) {
162 // TODO(veluca): this will not correctly handle the distinction between
163 // parameter and return lifetimes.
164 FunctionLifetimeFactorySingleCallback factory(lifetime_factory);
165 FunctionLifetimes fn_lftm;
166 if (llvm::Error err = FunctionLifetimes::CreateForFunctionType(fn, factory)
167 .moveInto(fn_lftm)) {
168 return std::move(err);
169 }
170 ret.function_lifetimes_ =
171 std::make_unique<FunctionLifetimes>(std::move(fn_lftm));
172 return ret;
173 }
174
Luca Versari95ce68f2022-03-24 14:44:19 +0000175 for (const auto& lftm_param : GetLifetimeParameters(type)) {
176 Lifetime l;
177 if (llvm::Error err = lifetime_factory(type, lftm_param).moveInto(l)) {
178 return std::move(err);
Luca Versarid101a292022-01-27 17:28:42 +0000179 }
Luca Versari95ce68f2022-03-24 14:44:19 +0000180 ret.lifetime_parameters_by_name_.Add(lftm_param, l);
Luca Versarid101a292022-01-27 17:28:42 +0000181 }
182
Luca Versari95ce68f2022-03-24 14:44:19 +0000183 // Add implicit lifetime parameters for type template parameters.
Luca Versariaf14c372022-04-04 07:30:24 -0700184 if (llvm::Error err = ForEachTemplateArgument(
185 type,
186 [&ret, &lifetime_factory](int depth,
187 clang::QualType arg_type) -> llvm::Error {
Martin Brænne16d86dd2022-04-08 00:33:36 -0700188 std::optional<ValueLifetimes> maybe_template_arg_lifetime;
189 if (!arg_type.isNull()) {
190 maybe_template_arg_lifetime.emplace();
191 if (llvm::Error err =
192 ValueLifetimes::Create(arg_type, lifetime_factory)
193 .moveInto(*maybe_template_arg_lifetime)) {
194 return err;
195 }
Luca Versari95ce68f2022-03-24 14:44:19 +0000196 }
Luca Versariaf14c372022-04-04 07:30:24 -0700197 if (ret.template_argument_lifetimes_.size() <= depth) {
198 ret.template_argument_lifetimes_.resize(depth + 1);
199 }
200 ret.template_argument_lifetimes_[depth].push_back(
Martin Brænne16d86dd2022-04-08 00:33:36 -0700201 maybe_template_arg_lifetime);
Luca Versariaf14c372022-04-04 07:30:24 -0700202 return llvm::Error::success();
203 })) {
204 return std::move(err);
Googlerc071e242021-12-16 15:23:41 +0000205 }
206
Luca Versari95ce68f2022-03-24 14:44:19 +0000207 clang::QualType pointee = PointeeType(type);
208 if (pointee.isNull()) return ret;
209 ObjectLifetimes obj_lftm;
210 if (llvm::Error err = ObjectLifetimes::Create(pointee, lifetime_factory)
211 .moveInto(obj_lftm)) {
212 return std::move(err);
Googlerc071e242021-12-16 15:23:41 +0000213 }
Luca Versari95ce68f2022-03-24 14:44:19 +0000214 ret.pointee_lifetimes_ =
215 std::make_unique<ObjectLifetimes>(std::move(obj_lftm));
Googlerc071e242021-12-16 15:23:41 +0000216 return ret;
217}
218
Luca Versari95ce68f2022-03-24 14:44:19 +0000219llvm::Expected<ObjectLifetimes> ObjectLifetimes::Create(
220 clang::QualType type, LifetimeFactory lifetime_factory) {
221 ValueLifetimes v;
222 if (llvm::Error err =
223 ValueLifetimes::Create(type, lifetime_factory).moveInto(v)) {
224 return std::move(err);
225 }
226 Lifetime l;
227 if (llvm::Error err = lifetime_factory(type, "").moveInto(l)) {
228 return std::move(err);
229 }
230 return ObjectLifetimes(l, v);
231}
232
Googler705f9452021-12-16 15:30:08 +0000233ValueLifetimes ValueLifetimes::ForLifetimeLessType(clang::QualType type) {
Googlerfc1b55c2022-03-04 13:03:46 +0000234 assert(PointeeType(type).isNull() && !type->isRecordType());
Googler705f9452021-12-16 15:30:08 +0000235 return ValueLifetimes(type);
236}
237
238ValueLifetimes ValueLifetimes::ForPointerLikeType(
239 clang::QualType type, const ObjectLifetimes& object_lifetimes) {
Googlerfc1b55c2022-03-04 13:03:46 +0000240 assert(!PointeeType(type).isNull());
Googler705f9452021-12-16 15:30:08 +0000241 ValueLifetimes result(type);
242 result.pointee_lifetimes_ =
243 std::make_unique<ObjectLifetimes>(object_lifetimes);
244 return result;
245}
246
247ValueLifetimes ValueLifetimes::ForRecord(
248 clang::QualType type,
Googlere4d4ec42022-03-28 06:52:23 -0700249 std::vector<std::vector<std::optional<ValueLifetimes>>>
250 template_argument_lifetimes,
Luca Versarid101a292022-01-27 17:28:42 +0000251 LifetimeSymbolTable lifetime_parameters) {
Googler705f9452021-12-16 15:30:08 +0000252 assert(type->isRecordType());
253 assert(GetTemplateArgs(type).size() == template_argument_lifetimes.size());
Googlere4d4ec42022-03-28 06:52:23 -0700254 for (size_t depth = 0; depth < template_argument_lifetimes.size(); ++depth) {
255 assert(GetTemplateArgs(type)[depth].size() ==
256 template_argument_lifetimes[depth].size());
257 }
Googler705f9452021-12-16 15:30:08 +0000258 ValueLifetimes result(type);
259 result.template_argument_lifetimes_ = std::move(template_argument_lifetimes);
Luca Versarid101a292022-01-27 17:28:42 +0000260 result.lifetime_parameters_by_name_ = lifetime_parameters;
Googler705f9452021-12-16 15:30:08 +0000261 return result;
262}
263
Luca Versari95ce68f2022-03-24 14:44:19 +0000264std::string ValueLifetimes::DebugString(
265 const LifetimeFormatter& formatter) const {
Luca Versari6ee6b342022-04-05 05:40:52 -0700266 if (!PointeeType(Type()).isNull()) {
267 assert(pointee_lifetimes_);
268 return pointee_lifetimes_->DebugString(formatter);
Luca Versari95ce68f2022-03-24 14:44:19 +0000269 }
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700270 if (clang::isa<clang::FunctionProtoType>(Type())) {
271 assert(function_lifetimes_);
272 std::string fn_lifetimes = function_lifetimes_->DebugString(formatter);
273 if (fn_lifetimes.empty()) return "";
274 return absl::StrCat("(", fn_lifetimes, ")");
275 }
Luca Versari6ee6b342022-04-05 05:40:52 -0700276
277 std::vector<std::vector<std::string>> tmpl_lifetimes;
278 for (auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
279 tmpl_lifetimes.emplace_back();
280 for (const std::optional<ValueLifetimes>& tmpl_arg : tmpl_arg_at_depth) {
281 if (tmpl_arg) {
282 std::string inner = tmpl_arg->DebugString(formatter);
283 if (!inner.empty()) {
284 tmpl_lifetimes.back().push_back(std::move(inner));
285 }
286 }
287 }
288 }
289 std::vector<std::string> lifetime_parameters;
290 for (const auto& lftm_arg : GetLifetimeParameters(type_)) {
291 std::optional<Lifetime> lifetime =
292 lifetime_parameters_by_name_.LookupName(lftm_arg);
293 assert(lifetime.has_value());
294 lifetime_parameters.push_back(formatter(*lifetime));
295 }
296 bool empty_tmpl_lifetimes = true;
297 for (const auto& tmpl_arg_at_depth : tmpl_lifetimes) {
298 for (const auto& tmpl : tmpl_arg_at_depth) {
299 empty_tmpl_lifetimes &= tmpl.empty();
300 }
301 }
302 if (empty_tmpl_lifetimes && lifetime_parameters.empty()) {
303 return "";
304 } else if (empty_tmpl_lifetimes) {
305 if (lifetime_parameters.size() == 1) {
306 return lifetime_parameters[0];
307 }
308 return absl::StrCat("[", absl::StrJoin(lifetime_parameters, ", "), "]");
309 } else if (lifetime_parameters.empty() && tmpl_lifetimes.size() == 1 &&
310 tmpl_lifetimes[0].size() == 1) {
311 return tmpl_lifetimes[0][0];
312 }
313
314 std::vector<std::string> tmpl_lifetimes_per_depth;
315 tmpl_lifetimes_per_depth.reserve(tmpl_lifetimes.size());
316 for (const auto& tmpl_depth : tmpl_lifetimes) {
317 tmpl_lifetimes_per_depth.push_back(
318 absl::StrCat("<", absl::StrJoin(tmpl_depth, ", "), ">"));
319 }
320 std::string lifetime_parameter_string;
321 if (!lifetime_parameters.empty()) {
322 lifetime_parameter_string =
323 absl::StrCat(" [", absl::StrJoin(lifetime_parameters, ", "), "]");
324 }
325
326 return absl::StrCat(absl::StrJoin(tmpl_lifetimes_per_depth, "::"),
327 lifetime_parameter_string);
Luca Versari95ce68f2022-03-24 14:44:19 +0000328}
329
Googler41f3e352021-12-16 15:24:21 +0000330const ObjectLifetimes& ValueLifetimes::GetPointeeLifetimes() const {
Googlerfc1b55c2022-03-04 13:03:46 +0000331 assert(!PointeeType(type_).isNull());
Googler41f3e352021-12-16 15:24:21 +0000332 return *pointee_lifetimes_;
333}
334
Luca Versari043a36e2022-04-08 00:55:36 -0700335bool ValueLifetimes::HasAny(
336 const std::function<bool(Lifetime)>& predicate) const {
337 for (const auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
338 for (const std::optional<ValueLifetimes>& tmpl_arg : tmpl_arg_at_depth) {
339 if (tmpl_arg && tmpl_arg->HasAny(predicate)) {
340 return true;
341 }
342 }
343 }
344 if (pointee_lifetimes_ && pointee_lifetimes_->HasAny(predicate)) {
345 return true;
346 }
347 for (const auto& lftm_arg : GetLifetimeParameters(type_)) {
348 std::optional<Lifetime> lifetime =
349 lifetime_parameters_by_name_.LookupName(lftm_arg);
350 assert(lifetime.has_value());
351 if (predicate(lifetime.value())) {
352 return true;
353 }
354 }
355 if (function_lifetimes_ && function_lifetimes_->HasAny(predicate)) {
356 return true;
357 }
358 return false;
359}
360
Luca Versaric5231632022-04-11 07:36:35 -0700361void ValueLifetimes::SubstituteLifetimes(const LifetimeSubstitutions& subst) {
362 for (auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
363 for (std::optional<ValueLifetimes>& tmpl_arg : tmpl_arg_at_depth) {
364 if (tmpl_arg) {
365 tmpl_arg->SubstituteLifetimes(subst);
366 }
367 }
368 }
369 if (pointee_lifetimes_) {
370 pointee_lifetimes_->SubstituteLifetimes(subst);
371 }
372 for (const auto& lftm_arg : GetLifetimeParameters(type_)) {
373 std::optional<Lifetime> lifetime =
374 lifetime_parameters_by_name_.LookupName(lftm_arg);
375 assert(lifetime.has_value());
376 lifetime_parameters_by_name_.Rebind(lftm_arg, subst.Substitute(*lifetime));
377 }
378 if (function_lifetimes_) {
379 function_lifetimes_->SubstituteLifetimes(subst);
380 }
381}
382
Luca Versari95ce68f2022-03-24 14:44:19 +0000383void ValueLifetimes::Traverse(std::function<void(Lifetime&, Variance)> visitor,
384 Variance variance) {
Googlere4d4ec42022-03-28 06:52:23 -0700385 for (auto& tmpl_arg_at_depth : template_argument_lifetimes_) {
386 for (std::optional<ValueLifetimes>& tmpl_arg : tmpl_arg_at_depth) {
387 if (tmpl_arg) {
388 tmpl_arg->Traverse(visitor, kInvariant);
389 }
Luca Versari95ce68f2022-03-24 14:44:19 +0000390 }
391 }
392 if (pointee_lifetimes_) {
393 pointee_lifetimes_->Traverse(visitor, variance, Type());
394 }
395 for (const auto& lftm_arg : GetLifetimeParameters(type_)) {
396 std::optional<Lifetime> lifetime =
397 lifetime_parameters_by_name_.LookupName(lftm_arg);
398 assert(lifetime.has_value());
399 Lifetime new_lifetime = *lifetime;
400 visitor(new_lifetime, variance);
401
402 // Note that this check is not an optimization, but a guard against UB:
403 // if one calls the const version of Traverse, with a callback that does not
404 // mutate the lifetime, on a const instance of the Value/ObjectLifetimes,
405 // then calling Rebind would be UB, even if Rebind would do nothing in
406 // practice.
407 if (new_lifetime != lifetime) {
408 lifetime_parameters_by_name_.Rebind(lftm_arg, new_lifetime);
409 }
410 }
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700411 if (function_lifetimes_) {
412 function_lifetimes_->Traverse(visitor);
413 }
Googlerace85a22021-11-26 14:18:31 +0000414}
415
Luca Versari95ce68f2022-03-24 14:44:19 +0000416void ValueLifetimes::Traverse(
417 std::function<void(const Lifetime&, Variance)> visitor,
418 Variance variance) const {
419 const_cast<ValueLifetimes*>(this)->Traverse(
420 [&visitor](Lifetime& l, Variance v) { visitor(l, v); }, variance);
Googlerace85a22021-11-26 14:18:31 +0000421}
422
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700423ValueLifetimes::ValueLifetimes(clang::QualType type) : type_(type) {}
424
Googlere4d4ec42022-03-28 06:52:23 -0700425const llvm::SmallVector<llvm::ArrayRef<clang::TemplateArgument>>
426GetTemplateArgs(clang::QualType type) {
427 llvm::SmallVector<llvm::ArrayRef<clang::TemplateArgument>> result;
428
Martin Brænne5cc52fc2022-04-20 05:42:30 -0700429 // Desugar any typedefs on `type`. We need to do this so that the "depth" of
430 // the template arguments is compatible with
431 // TemplateTypeParmType::getDepth(), which likewise assumes that typedefs are
432 // desugared; see the call to getCanonicalTypeInternal() in
433 // TemplateTypeParmType::getCanTTPTInfo(). Unlike that function, we can't
434 // simply canonicalize the type, as that would also remove type annotations,
435 // and we need those.
436 while (const auto* typedef_type = type->getAs<clang::TypedefType>()) {
437 type = typedef_type->desugar();
438 }
439
Googlere4d4ec42022-03-28 06:52:23 -0700440 if (auto elaborated = type->getAs<clang::ElaboratedType>()) {
441 if (clang::NestedNameSpecifier* qualifier = elaborated->getQualifier()) {
442 if (const clang::Type* qualifier_type = qualifier->getAsType()) {
443 result = GetTemplateArgs(clang::QualType(qualifier_type, 0));
444 }
445 }
Googlerace85a22021-11-26 14:18:31 +0000446 }
Googlere4d4ec42022-03-28 06:52:23 -0700447
448 if (auto specialization = type->getAs<clang::TemplateSpecializationType>()) {
449 result.push_back(specialization->template_arguments());
450 } else if (auto record = type->getAs<clang::RecordType>()) {
Googlerace85a22021-11-26 14:18:31 +0000451 if (auto specialization_decl =
452 clang::dyn_cast<clang::ClassTemplateSpecializationDecl>(
453 record->getDecl())) {
Googlere4d4ec42022-03-28 06:52:23 -0700454 result.push_back(specialization_decl->getTemplateArgs().asArray());
Googlerace85a22021-11-26 14:18:31 +0000455 }
456 }
Googlere4d4ec42022-03-28 06:52:23 -0700457
458 return result;
Googlerace85a22021-11-26 14:18:31 +0000459}
460
Luca Versarid101a292022-01-27 17:28:42 +0000461ObjectLifetimes ObjectLifetimes::GetObjectLifetimesForTypeInContext(
462 clang::QualType type, llvm::SmallVector<std::string> type_lifetime_args,
463 llvm::StringRef object_lifetime_parameter) const {
Googler41f3e352021-12-16 15:24:21 +0000464 assert(value_lifetimes_.Type()->isRecordType());
Googlerace85a22021-11-26 14:18:31 +0000465
466 // The object of the `type` (i.e. field or a base class) basically has the
467 // same lifetime as the struct.
Googler705f9452021-12-16 15:30:08 +0000468 Lifetime ret_lifetime = lifetime_;
Luca Versarid101a292022-01-27 17:28:42 +0000469 // ... unless the field has lifetime parameters.
470 if (!object_lifetime_parameter.empty()) {
471 ret_lifetime =
472 value_lifetimes_.GetLifetimeParameter(object_lifetime_parameter);
473 }
Googlerace85a22021-11-26 14:18:31 +0000474
475 // `type` is one of a template argument, a struct, a pointer, or a type
476 // with no lifetimes (other than its own).
477
478 // First case: template argument. We just attach the
479 // template argument's lifetimes to the leaf ObjectLifetimes.
480 if (auto targ = type->getAs<clang::SubstTemplateTypeParmType>()) {
Googlere4d4ec42022-03-28 06:52:23 -0700481 const clang::TemplateTypeParmType* type_parm = targ->getReplacedParameter();
Googlerace85a22021-11-26 14:18:31 +0000482 const std::optional<ValueLifetimes>& arg_lifetimes =
Googlere4d4ec42022-03-28 06:52:23 -0700483 value_lifetimes_.GetTemplateArgumentLifetimes(type_parm->getDepth(),
484 type_parm->getIndex());
Googlerace85a22021-11-26 14:18:31 +0000485 if (!arg_lifetimes) {
486 assert(false);
Googler6a06dbc2021-12-16 15:25:02 +0000487 return llvm::DenseMapInfo<ObjectLifetimes>::getEmptyKey();
Googlerace85a22021-11-26 14:18:31 +0000488 }
Googler705f9452021-12-16 15:30:08 +0000489 return ObjectLifetimes(ret_lifetime, *arg_lifetimes);
Googlerace85a22021-11-26 14:18:31 +0000490 } else if (type->isStructureOrClassType()) {
Luca Versarid101a292022-01-27 17:28:42 +0000491 // Second case: struct.
492 // Resolve lifetime parameters for the struct, if it has any.
493 LifetimeSymbolTable lifetime_params;
Googler247cef72022-03-02 15:13:38 +0000494 llvm::SmallVector<std::string> params = GetLifetimeParameters(type);
Luca Versarid101a292022-01-27 17:28:42 +0000495 for (size_t i = params.size(); i-- > 0;) {
496 assert(!type_lifetime_args.empty());
497 auto lftm_arg = type_lifetime_args.back();
498 type_lifetime_args.pop_back();
499 lifetime_params.Add(params[i],
500 value_lifetimes_.GetLifetimeParameter(lftm_arg));
501 }
502
503 // We need to construct potentally reshuffled
Googlerace85a22021-11-26 14:18:31 +0000504 // template arguments, if the struct is a template.
Luca Versarid101a292022-01-27 17:28:42 +0000505
506 // TODO(veluca): mixing lifetimes and template parameters is not supported
507 // yet.
Googlere4d4ec42022-03-28 06:52:23 -0700508 std::vector<std::vector<std::optional<ValueLifetimes>>>
509 template_argument_lifetimes;
510 for (const auto& args_at_depth : GetTemplateArgs(type)) {
511 size_t parameter_pack_expansion_index = 0;
512 template_argument_lifetimes.push_back({});
513 for (const clang::TemplateArgument& arg : args_at_depth) {
514 if (arg.getKind() == clang::TemplateArgument::Type) {
515 if (auto templ_arg =
516 clang::dyn_cast<clang::SubstTemplateTypeParmType>(
517 arg.getAsType())) {
518 const clang::TemplateTypeParmType* type_parm =
519 templ_arg->getReplacedParameter();
520 // Template parameter packs get the index of the *pack*, not the
521 // index of the type inside the pack itself. As they must appear
522 // last, we can just increase the counter at every occurrence and
523 // wraparound when we run out of template arguments.
524 size_t index = type_parm->getIndex();
525 if (type_parm->isParameterPack()) {
526 index += parameter_pack_expansion_index++;
527 if (index + 1 >= value_lifetimes_.GetNumTemplateArgumentsAtDepth(
528 type_parm->getDepth())) {
529 parameter_pack_expansion_index = 0;
530 }
Luca Versari29c00862022-01-21 20:53:06 +0000531 }
Googlere4d4ec42022-03-28 06:52:23 -0700532 template_argument_lifetimes.back().push_back(
533 value_lifetimes_.GetTemplateArgumentLifetimes(
534 type_parm->getDepth(), index));
535 } else {
536 // Create a new ValueLifetimes of the type of the template
537 // parameter, with lifetime `lifetime_`.
538 // TODO(veluca): we need to propagate lifetime parameters here.
539 template_argument_lifetimes.back().push_back(
540 ValueLifetimes::Create(arg.getAsType(), [this](
541 clang::QualType,
542 llvm::StringRef) {
543 return this->lifetime_;
544 }).get());
Luca Versari29c00862022-01-21 20:53:06 +0000545 }
Luca Versari162a4c52021-12-10 08:57:05 +0000546 } else {
Googlere4d4ec42022-03-28 06:52:23 -0700547 template_argument_lifetimes.back().push_back(std::nullopt);
Luca Versari162a4c52021-12-10 08:57:05 +0000548 }
Googlerace85a22021-11-26 14:18:31 +0000549 }
550 }
Luca Versarid101a292022-01-27 17:28:42 +0000551
552 return ObjectLifetimes(
553 ret_lifetime,
554 ValueLifetimes::ForRecord(type, std::move(template_argument_lifetimes),
555 std::move(lifetime_params)));
Googlerfc1b55c2022-03-04 13:03:46 +0000556 } else if (clang::QualType pointee_type = PointeeType(type);
557 !pointee_type.isNull()) {
Martin Brænne0656ebf2022-04-25 23:52:54 -0700558 if (type_lifetime_args.empty()) {
559 llvm::report_fatal_error(
560 llvm::Twine("didn't find type lifetimes for object of type " +
561 type.getAsString()));
Luca Versarid101a292022-01-27 17:28:42 +0000562 }
Martin Brænne0656ebf2022-04-25 23:52:54 -0700563 std::string pointee_object_lifetime_parameter =
564 std::move(type_lifetime_args.back());
565 type_lifetime_args.pop_back();
Googlerace85a22021-11-26 14:18:31 +0000566 // Third case: pointer.
Googler705f9452021-12-16 15:30:08 +0000567 return ObjectLifetimes(
Googlerfc1b55c2022-03-04 13:03:46 +0000568 ret_lifetime, ValueLifetimes::ForPointerLikeType(
569 type, GetObjectLifetimesForTypeInContext(
570 pointee_type, std::move(type_lifetime_args),
Martin Brænne0656ebf2022-04-25 23:52:54 -0700571 pointee_object_lifetime_parameter)));
Googlerace85a22021-11-26 14:18:31 +0000572 }
573
Googler705f9452021-12-16 15:30:08 +0000574 return ObjectLifetimes(ret_lifetime,
575 ValueLifetimes::ForLifetimeLessType(type));
Googlerace85a22021-11-26 14:18:31 +0000576}
577
Luca Versari95ce68f2022-03-24 14:44:19 +0000578std::string ObjectLifetimes::DebugString(
579 const LifetimeFormatter& formatter) const {
Luca Versari6ee6b342022-04-05 05:40:52 -0700580 std::string inner_lifetimes = value_lifetimes_.DebugString(formatter);
581 std::string lifetime = formatter(lifetime_);
582 if (inner_lifetimes.empty()) {
583 return lifetime;
Luca Versari95ce68f2022-03-24 14:44:19 +0000584 }
Luca Versari6ee6b342022-04-05 05:40:52 -0700585 return absl::StrCat(std::move(inner_lifetimes), ", ", std::move(lifetime));
Luca Versari95ce68f2022-03-24 14:44:19 +0000586}
587
Luca Versarid101a292022-01-27 17:28:42 +0000588ObjectLifetimes ObjectLifetimes::GetFieldOrBaseLifetimes(
589 clang::QualType type,
590 llvm::SmallVector<std::string> type_lifetime_args) const {
591 return GetObjectLifetimesForTypeInContext(type, std::move(type_lifetime_args),
592 "");
593}
594
Luca Versari043a36e2022-04-08 00:55:36 -0700595bool ObjectLifetimes::HasAny(
596 const std::function<bool(Lifetime)>& predicate) const {
597 return predicate(lifetime_) || value_lifetimes_.HasAny(predicate);
598}
599
Luca Versaric5231632022-04-11 07:36:35 -0700600void ObjectLifetimes::SubstituteLifetimes(const LifetimeSubstitutions& subst) {
601 lifetime_ = subst.Substitute(lifetime_);
602 value_lifetimes_.SubstituteLifetimes(subst);
603}
604
Luca Versari95ce68f2022-03-24 14:44:19 +0000605void ObjectLifetimes::Traverse(std::function<void(Lifetime&, Variance)> visitor,
606 Variance variance,
607 clang::QualType indirection_type) {
608 assert(indirection_type.isNull() ||
Luca Versaricc7e6cb2022-04-05 08:08:23 -0700609 indirection_type->getPointeeType().IgnoreParens() == Type());
Luca Versari95ce68f2022-03-24 14:44:19 +0000610 value_lifetimes_.Traverse(
611 visitor, indirection_type.isNull() || indirection_type.isConstQualified()
612 ? kCovariant
613 : kInvariant);
614 visitor(lifetime_, variance);
615}
616
617void ObjectLifetimes::Traverse(
618 std::function<void(const Lifetime&, Variance)> visitor, Variance variance,
619 clang::QualType indirection_type) const {
620 const_cast<ObjectLifetimes*>(this)->Traverse(
621 [&visitor](Lifetime& l, Variance v) { visitor(l, v); }, variance,
622 indirection_type);
623}
624
Googler17a2d512022-02-23 12:09:43 +0000625llvm::Expected<llvm::StringRef> EvaluateAsStringLiteral(
626 const clang::Expr* expr, const clang::ASTContext& ast_context) {
627 auto error = []() {
628 return llvm::createStringError(
629 llvm::inconvertibleErrorCode(),
630 "cannot evaluate argument as a string literal");
631 };
632
633 clang::Expr::EvalResult eval_result;
634 if (!expr->EvaluateAsConstantExpr(eval_result, ast_context) ||
635 !eval_result.Val.isLValue()) {
636 return error();
637 }
638
639 const auto* eval_result_expr =
640 eval_result.Val.getLValueBase().dyn_cast<const clang::Expr*>();
641 if (!eval_result_expr) {
642 return error();
643 }
644
645 const auto* strlit = clang::dyn_cast<clang::StringLiteral>(eval_result_expr);
646 if (!strlit) {
647 return error();
648 }
649
650 return strlit->getString();
651}
652
Martin Brænne1a207c52022-04-19 00:05:38 -0700653} // namespace lifetimes
654} // namespace tidy
655} // namespace clang
Googlerace85a22021-11-26 14:18:31 +0000656
657namespace llvm {
658
Martin Brænne1a207c52022-04-19 00:05:38 -0700659bool DenseMapInfo<clang::tidy::lifetimes::ValueLifetimes>::isEqual(
660 const clang::tidy::lifetimes::ValueLifetimes& lhs,
661 const clang::tidy::lifetimes::ValueLifetimes& rhs) {
Googler41f3e352021-12-16 15:24:21 +0000662 if (lhs.type_ != rhs.type_) {
663 return false;
664 }
Googlerace85a22021-11-26 14:18:31 +0000665 if ((lhs.pointee_lifetimes_ == nullptr) !=
666 (rhs.pointee_lifetimes_ == nullptr)) {
667 return false;
668 }
669 if (lhs.pointee_lifetimes_ &&
Martin Brænne1a207c52022-04-19 00:05:38 -0700670 !DenseMapInfo<clang::tidy::lifetimes::ObjectLifetimes>::isEqual(
Googler2e87fae2021-12-16 15:24:41 +0000671 *lhs.pointee_lifetimes_, *rhs.pointee_lifetimes_)) {
Googlerace85a22021-11-26 14:18:31 +0000672 return false;
673 }
674 if (lhs.template_argument_lifetimes_.size() !=
675 rhs.template_argument_lifetimes_.size()) {
676 return false;
677 }
678 for (size_t i = 0; i < lhs.template_argument_lifetimes_.size(); i++) {
Googlere4d4ec42022-03-28 06:52:23 -0700679 if (lhs.template_argument_lifetimes_[i].size() !=
680 rhs.template_argument_lifetimes_[i].size()) {
Googlerace85a22021-11-26 14:18:31 +0000681 return false;
682 }
Googlere4d4ec42022-03-28 06:52:23 -0700683 for (size_t j = 0; j < lhs.template_argument_lifetimes_[i].size(); j++) {
684 const auto& alhs = lhs.template_argument_lifetimes_[i][j];
685 const auto& arhs = rhs.template_argument_lifetimes_[i][j];
686 if (alhs.has_value() != arhs.has_value()) {
687 return false;
688 }
689 if (alhs.has_value() && !isEqual(*alhs, *arhs)) {
690 return false;
691 }
Googlerace85a22021-11-26 14:18:31 +0000692 }
693 }
Luca Versari7f1783d2022-01-31 14:40:39 +0000694 if (lhs.lifetime_parameters_by_name_.GetMapping() !=
695 rhs.lifetime_parameters_by_name_.GetMapping()) {
696 return false;
697 }
Googlerace85a22021-11-26 14:18:31 +0000698 return true;
699}
700
Martin Brænne1a207c52022-04-19 00:05:38 -0700701unsigned DenseMapInfo<clang::tidy::lifetimes::ValueLifetimes>::getHashValue(
702 const clang::tidy::lifetimes::ValueLifetimes& value_lifetimes) {
Googlerace85a22021-11-26 14:18:31 +0000703 llvm::hash_code hash = 0;
Googler2e87fae2021-12-16 15:24:41 +0000704 if (value_lifetimes.pointee_lifetimes_) {
Martin Brænne1a207c52022-04-19 00:05:38 -0700705 hash = DenseMapInfo<clang::tidy::lifetimes::ObjectLifetimes>::getHashValue(
Googler2e87fae2021-12-16 15:24:41 +0000706 *value_lifetimes.pointee_lifetimes_);
Googlerace85a22021-11-26 14:18:31 +0000707 }
Googlere4d4ec42022-03-28 06:52:23 -0700708 for (const auto& lifetimes_at_depth :
Googler2e87fae2021-12-16 15:24:41 +0000709 value_lifetimes.template_argument_lifetimes_) {
Googlere4d4ec42022-03-28 06:52:23 -0700710 for (const auto& tmpl_lifetime : lifetimes_at_depth) {
711 if (tmpl_lifetime) {
712 hash = hash_combine(hash, getHashValue(*tmpl_lifetime));
713 }
Googlerace85a22021-11-26 14:18:31 +0000714 }
715 }
Luca Versari7f1783d2022-01-31 14:40:39 +0000716 for (const auto& lifetime_arg :
717 value_lifetimes.lifetime_parameters_by_name_.GetMapping()) {
718 hash = hash_combine(hash, DenseMapInfo<llvm::StringRef>::getHashValue(
719 lifetime_arg.first()));
Martin Brænne1a207c52022-04-19 00:05:38 -0700720 hash = hash_combine(
721 hash, DenseMapInfo<clang::tidy::lifetimes::Lifetime>::getHashValue(
722 lifetime_arg.second));
Luca Versari7f1783d2022-01-31 14:40:39 +0000723 }
Googler41f3e352021-12-16 15:24:21 +0000724 return hash_combine(
Googler2e87fae2021-12-16 15:24:41 +0000725 hash, DenseMapInfo<clang::QualType>::getHashValue(value_lifetimes.type_));
Googlerace85a22021-11-26 14:18:31 +0000726}
727
728} // namespace llvm