blob: 8f6b6ced7311282fbdbb6a85cdfa5ce887e4c6b7 [file] [log] [blame]
Luca Versari99fddff2022-05-25 10:22:32 -07001// 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_analysis/object_repository.h"
6
7#include <functional>
8#include <optional>
9#include <string>
10#include <utility>
11#include <vector>
12
Luca Versaria12c9d52023-02-23 08:40:48 -080013#include "absl/strings/str_cat.h"
14#include "lifetime_analysis/builtin_lifetimes.h"
Luca Versari99fddff2022-05-25 10:22:32 -070015#include "lifetime_analysis/object.h"
Luca Versari91a56ff2022-08-22 01:58:33 -070016#include "lifetime_annotations/function_lifetimes.h"
Luca Versari99fddff2022-05-25 10:22:32 -070017#include "lifetime_annotations/lifetime.h"
18#include "lifetime_annotations/pointee_type.h"
19#include "lifetime_annotations/type_lifetimes.h"
20#include "clang/AST/Decl.h"
21#include "clang/AST/DeclCXX.h"
22#include "clang/AST/Expr.h"
23#include "clang/AST/ExprCXX.h"
24#include "clang/AST/RecursiveASTVisitor.h"
25#include "clang/AST/Type.h"
26#include "clang/Basic/LLVM.h"
27#include "llvm/ADT/SmallVector.h"
28#include "llvm/ADT/StringRef.h"
29#include "llvm/Support/ErrorHandling.h"
30
31namespace clang {
32namespace tidy {
33namespace lifetimes {
34
Luca Versaria12c9d52023-02-23 08:40:48 -080035FunctionLifetimesOrError GetFunctionLifetimes(
36 const FunctionDecl* decl, const FunctionLifetimesMap& known_lifetimes) {
37 // Note that this cannot be a simple .find() on the map because `decl` might
38 // be a builtin.
39 bool is_builtin = decl->getBuiltinID() != 0;
40 if (is_builtin) {
41 return GetBuiltinLifetimes(decl);
42 }
43 if (!known_lifetimes.count(decl->getCanonicalDecl())) {
44 return FunctionAnalysisError(
45 absl::StrCat("Unknown callee ", decl->getNameAsString()));
46 }
47 return known_lifetimes.lookup(decl->getCanonicalDecl());
48}
49
Luca Versari99fddff2022-05-25 10:22:32 -070050class ObjectRepository::VarDeclVisitor
51 : public clang::RecursiveASTVisitor<VarDeclVisitor> {
52 public:
Luca Versaria12c9d52023-02-23 08:40:48 -080053 explicit VarDeclVisitor(ObjectRepository& object_repository,
54 const FunctionLifetimesMap& callee_lifetimes)
55 : object_repository_(object_repository),
56 callee_lifetimes_(callee_lifetimes) {}
Luca Versari99fddff2022-05-25 10:22:32 -070057
58 // We need to visit implicitly-defined constructors and assignment operators.
59 bool shouldVisitImplicitCode() { return true; }
60
61 bool VisitVarDecl(clang::VarDecl* var) {
62 // Add objects for any local variables declared in this function.
63 AddObjectForVar(var);
64 return true;
65 }
66
67 bool VisitReturnStmt(clang::ReturnStmt* stmt) {
68 const clang::Expr* expr = stmt->getRetValue();
69 if (IsInitExprInitializingARecordObject(expr)) {
Martin Brænneecd58c32022-07-01 02:25:47 -070070 PropagateInitializedObject(expr, object_repository_.return_object_);
Luca Versari99fddff2022-05-25 10:22:32 -070071 }
72 return true;
73 }
74
75 bool VisitMemberExpr(clang::MemberExpr* member) {
76 if (auto* method =
77 clang::dyn_cast<clang::CXXMethodDecl>(member->getMemberDecl());
78 method && method->isStatic()) {
79 // Create objects for static member functions.
80 AddObjectForFunc(method);
81 }
82 return true;
83 }
84
85 bool VisitDeclRefExpr(clang::DeclRefExpr* decl_ref) {
86 // Add objects for any global variables referenced in this function.
87 // This also runs for local variables, but we don't have to treat those
88 // differently as AddObjectForVar() protects against duplication.
89 if (auto* var_decl = clang::dyn_cast<clang::VarDecl>(decl_ref->getDecl())) {
90 AddObjectForVar(var_decl);
91 }
92 // Add objects for any function referenced in this function.
93 if (auto* function_decl =
94 clang::dyn_cast<clang::FunctionDecl>(decl_ref->getDecl())) {
95 AddObjectForFunc(function_decl);
96 }
97 return true;
98 }
99
100 bool VisitObjCMessageExpr(clang::ObjCMessageExpr* msg_expr) {
101 // ObjCMessageExpr is an initializer expression terminator, so we should
102 // have walked down from the object which requires initialization to find
103 // its terminating expressions, which should have found this expression and
104 // connected it to that object already.
105 if (!object_repository_.initialized_objects_.count(msg_expr)) {
106 msg_expr->dump();
107 llvm::report_fatal_error(
108 "Missing initializer for ObjCMessageExpr, we did not record it "
109 "when we visited something earlier in the tree yet?");
110 }
111 return true;
112 }
113
114 // Create objects for function call arguments.
115 bool VisitCallExpr(clang::CallExpr* call_expr) {
116 if (IsInitExprInitializingARecordObject(call_expr)) {
117 assert(InitializedObjectWasPropagatedTo(call_expr));
118 }
119
Luca Versariefeaf272023-01-16 10:19:28 -0800120 FunctionLifetimeFactorySingleCallback lifetime_factory(
121 [](auto) { return Lifetime::CreateVariable(); });
122
123 // If we have a direct callee, construct a FunctionLifetimes out of the
124 // function/method definition.
125 if (auto callee = call_expr->getDirectCallee()) {
126 bool is_operator_call = clang::isa<clang::CXXOperatorCallExpr>(call_expr);
127 bool is_method = clang::isa<clang::CXXMethodDecl>(callee);
128 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
129 FunctionLifetimes::CreateForDecl(callee, lifetime_factory).get();
130 PrepareFunctionCall(
131 call_expr, /*index_shift=*/is_operator_call && is_method ? 1 : 0);
Luca Versari99fddff2022-05-25 10:22:32 -0700132 } else {
133 // Always a function pointer.
Luca Versariefeaf272023-01-16 10:19:28 -0800134 // TODO(veluca): pointers-to-members are not supported (yet?)
135 clang::QualType callee_type =
136 call_expr->getCallee()->getType()->getPointeeType().IgnoreParens();
137 // TODO(veluca): what about FunctionNoProtoType??
138 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
139 FunctionLifetimes::CreateForFunctionType(
140 clang::cast<clang::FunctionProtoType>(callee_type),
141 lifetime_factory)
142 .get();
143 PrepareFunctionCall(call_expr, /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700144 }
145
146 return true;
147 }
148
Luca Versaria12c9d52023-02-23 08:40:48 -0800149 bool VisitStringLiteral(clang::StringLiteral* lit_expr) {
150 object_repository_.string_literal_object_ = object_repository_.CreateObject(
151 lit_expr->getType(), Lifetime::Static(),
152 [](const clang::Expr*) { return Lifetime::Static(); });
153 return true;
154 }
155
Luca Versari99fddff2022-05-25 10:22:32 -0700156 bool VisitCXXConstructExpr(clang::CXXConstructExpr* construct_expr) {
157 assert(InitializedObjectWasPropagatedTo(construct_expr));
158
Luca Versariefeaf272023-01-16 10:19:28 -0800159 FunctionLifetimeFactorySingleCallback lifetime_factory(
160 [](auto) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700161 const clang::FunctionDecl* constructor = construct_expr->getConstructor();
Luca Versariefeaf272023-01-16 10:19:28 -0800162 object_repository_.call_expr_virtual_lifetimes_[construct_expr] =
163 FunctionLifetimes::CreateForDecl(constructor, lifetime_factory).get();
164 PrepareFunctionCall(construct_expr,
165 /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700166 return true;
167 }
168
169 bool VisitInitListExpr(clang::InitListExpr* init_list_expr) {
170 // We only want to visit in Semantic form, we ignore Syntactic form.
171 if (IsInitExprInitializingARecordObject(init_list_expr) &&
172 init_list_expr->isSemanticForm() && !init_list_expr->isTransparent()) {
173 assert(InitializedObjectWasPropagatedTo(init_list_expr));
174 }
175 return true;
176 }
177
178 bool VisitMaterializeTemporaryExpr(
179 clang::MaterializeTemporaryExpr* temporary_expr) {
180 object_repository_.temporary_objects_[temporary_expr] =
181 AddTemporaryObjectForExpression(temporary_expr->getSubExpr());
182 return true;
183 }
184
185 bool VisitCompoundStmt(clang::CompoundStmt* compound) {
186 // Create temporary objects for any top-level `CXXTemporaryObjectExpr`s,
187 // i.e. ones that are used as statements.
188 for (clang::Stmt* stmt : compound->body()) {
189 if (auto* temporary = clang::dyn_cast<CXXTemporaryObjectExpr>(stmt)) {
190 AddTemporaryObjectForExpression(temporary);
191 }
192 }
193 return true;
194 }
195
Luca Versariefeaf272023-01-16 10:19:28 -0800196 void PrepareFunctionCall(const clang::Expr* expr, size_t index_shift) {
197 const auto& func_lifetimes =
198 object_repository_.call_expr_virtual_lifetimes_[expr];
199 auto make_object = [this](const ValueLifetimes& lifetime) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800200 return object_repository_.CreateObject(
201 ObjectLifetimes(Lifetime::CreateLocal(), lifetime),
202 object_repository_.initial_points_to_map_);
Luca Versariefeaf272023-01-16 10:19:28 -0800203 };
204 for (size_t i = 0; i < func_lifetimes.GetNumParams(); ++i) {
Luca Versari99fddff2022-05-25 10:22:32 -0700205 object_repository_
206 .call_expr_args_objects_[std::make_pair(expr, i + index_shift)] =
Luca Versariefeaf272023-01-16 10:19:28 -0800207 make_object(func_lifetimes.GetParamLifetimes(i));
Luca Versari99fddff2022-05-25 10:22:32 -0700208 }
Luca Versariefeaf272023-01-16 10:19:28 -0800209 if (func_lifetimes.IsNonStaticMethod()) {
210 object_repository_.call_expr_this_pointers_[expr] =
211 make_object(func_lifetimes.GetThisLifetimes());
212 }
213 object_repository_.call_expr_ret_objects_[expr] =
214 make_object(func_lifetimes.GetReturnLifetimes());
Luca Versari99fddff2022-05-25 10:22:32 -0700215 }
216
217 void AddObjectForVar(clang::VarDecl* var) {
218 if (object_repository_.object_repository_.count(var)) {
219 return;
220 }
221
222 Lifetime lifetime;
223 LifetimeFactory lifetime_factory;
224
225 switch (var->getStorageClass()) {
226 case clang::SC_Extern:
227 case clang::SC_Static:
228 case clang::SC_PrivateExtern:
229 lifetime = Lifetime::Static();
Martin Brænne03d93302022-06-23 00:23:38 -0700230 lifetime_factory = [](const clang::Expr*) {
231 return Lifetime::Static();
232 };
Luca Versari99fddff2022-05-25 10:22:32 -0700233 break;
234 default:
235 lifetime = Lifetime::CreateLocal();
Martin Brænne03d93302022-06-23 00:23:38 -0700236 lifetime_factory = [](const clang::Expr*) {
237 return Lifetime::CreateVariable();
238 };
Luca Versari99fddff2022-05-25 10:22:32 -0700239 break;
240 }
241
Luca Versaria12c9d52023-02-23 08:40:48 -0800242 const Object* object = object_repository_.CreateObject(
243 var->getType(), lifetime, lifetime_factory);
Luca Versari99fddff2022-05-25 10:22:32 -0700244
Martin Brænnee9a4a472022-07-01 02:26:55 -0700245 object_repository_.object_repository_[var] = object;
Luca Versari53a2f582023-01-16 10:09:29 -0800246 if (!var->getType()->isArrayType()) {
247 object_repository_.initial_single_valued_objects_.Add(object);
248 }
Luca Versari99fddff2022-05-25 10:22:32 -0700249
250 // Remember the original value of function parameters.
251 if (auto parm_var_decl = clang::dyn_cast<const clang::ParmVarDecl>(var)) {
252 object_repository_.initial_parameter_object_[parm_var_decl] =
253 object_repository_.CloneObject(object);
254 }
255
256 if (var->hasInit() && var->getType()->isRecordType()) {
Martin Brænneecd58c32022-07-01 02:25:47 -0700257 PropagateInitializedObject(var->getInit(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700258 }
259 }
260
261 void AddObjectForFunc(clang::FunctionDecl* func) {
262 if (object_repository_.object_repository_.count(func)) {
263 return;
264 }
265
Luca Versaria12c9d52023-02-23 08:40:48 -0800266 FunctionLifetimesOrError func_lifetimes =
267 GetFunctionLifetimes(func, callee_lifetimes_);
268 if (std::holds_alternative<FunctionAnalysisError>(func_lifetimes)) {
269 error_ = "No lifetimes for callee '" + func->getNameAsString() +
270 "': " + std::get<FunctionAnalysisError>(func_lifetimes).message;
271 } else {
272 object_repository_.object_repository_[func] =
273 object_repository_.ConstructObject(
274 Lifetime::Static(), func->getType(),
275 std::get<FunctionLifetimes>(func_lifetimes));
276 }
Luca Versari99fddff2022-05-25 10:22:32 -0700277 }
278
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700279 const Object* AddTemporaryObjectForExpression(clang::Expr* expr) {
Luca Versari99fddff2022-05-25 10:22:32 -0700280 clang::QualType type = expr->getType().getCanonicalType();
Luca Versaria12c9d52023-02-23 08:40:48 -0800281 const Object* object = object_repository_.CreateObject(
282 type, Lifetime::CreateLocal(),
283 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700284
285 if (type->isRecordType()) {
Martin Brænneecd58c32022-07-01 02:25:47 -0700286 PropagateInitializedObject(expr, object);
Luca Versari99fddff2022-05-25 10:22:32 -0700287 }
288 return object;
289 }
290
291 // Propagates an `object` of record type that is to be initialized to the
292 // expressions that actually perform the initialization (we call these
293 // "terminating expressions").
294 //
295 // `expr` is the initializer for a variable; this will contain one or
296 // several terminating expressions (such as a CXXConstructExpr, InitListExpr,
297 // or CallExpr).
298 //
299 // Note that not all terminating expressions below `expr` necessarily
300 // initialize `object`; some of these terminating expressions may also
301 // initialize temporary objects. This function takes care to propagate
302 // `object` only to the appropriate terminating expressions.
303 //
304 // The mapping from a terminating expression to the object it initializes
305 // is stored in `object_repository_.initialized_objects_`.
Martin Brænneecd58c32022-07-01 02:25:47 -0700306 void PropagateInitializedObject(const clang::Expr* expr,
307 const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700308 // TODO(danakj): Use StmtVisitor to implement this method.
Luca Versari99fddff2022-05-25 10:22:32 -0700309
310 // Terminating expressions. Expressions that don't initialize a record
311 // object can not be such, and their existence is unexpected as we should
312 // be converting to and initializing a record object from such expressions
313 // further up in the initializer expression's AST. We will assert later in
314 // this function if we find this situation somehow due to incorrect
315 // expectations in this comment.
316 if (IsInitExprInitializingARecordObject(expr)) {
317 if (clang::isa<clang::CXXConstructExpr>(expr) ||
318 clang::isa<clang::CallExpr>(expr) ||
319 clang::isa<clang::ObjCMessageExpr>(expr) ||
320 clang::isa<clang::LambdaExpr>(expr)) {
321 object_repository_.initialized_objects_[expr] = object;
322 return;
323 }
324 if (auto* e = clang::dyn_cast<clang::InitListExpr>(expr)) {
325 if (!e->isSemanticForm()) return;
326 if (e->isTransparent()) {
327 // A field initializer like `S s{cond ? S{} : S{}}` is considered
328 // transparent, and the actual initializer is within.
329 for (const clang::Expr* init : e->inits()) {
330 PropagateInitializedObject(init, object);
331 }
332 } else {
333 object_repository_.initialized_objects_[e] = object;
334 }
335 return;
336 }
337 }
338
339 // Expressions to walk through. Logic is similar to the AggExprEmitter in
340 // clang third_party/llvm-project/clang/lib/CodeGen/CGExprAgg.cpp though we
341 // don't have to visit all the sub-expressions that clang codegen needs to,
342 // as we can stop at terminating expressions and ignore many expressions
343 // that don't occur in the code we're analyzing.
344 if (auto* e = clang::dyn_cast<clang::ParenExpr>(expr)) {
345 PropagateInitializedObject(e->getSubExpr(), object);
346 return;
347 }
348 if (auto* e = clang::dyn_cast<clang::UnaryOperator>(expr)) {
349 PropagateInitializedObject(e->getSubExpr(), object);
350 return;
351 }
352 if (auto* e = clang::dyn_cast<clang::SubstNonTypeTemplateParmExpr>(expr)) {
353 PropagateInitializedObject(e->getReplacement(), object);
354 return;
355 }
356 if (auto* e = clang::dyn_cast<clang::CastExpr>(expr)) {
357 PropagateInitializedObject(e->getSubExpr(), object);
358 return;
359 }
360 if (auto* e = clang::dyn_cast<clang::CXXDefaultArgExpr>(expr)) {
361 PropagateInitializedObject(e->getExpr(), object);
362 return;
363 }
364 if (auto* e = clang::dyn_cast<clang::CXXDefaultInitExpr>(expr)) {
365 PropagateInitializedObject(e->getExpr(), object);
366 return;
367 }
368 if (auto* e = clang::dyn_cast<clang::ExprWithCleanups>(expr)) {
369 PropagateInitializedObject(e->getSubExpr(), object);
370 return;
371 }
372
373 // Expressions that produce a temporary object.
374 if (auto* e = clang::dyn_cast<clang::BinaryOperator>(expr)) {
375 if (e->isCommaOp()) {
376 AddTemporaryObjectForExpression(e->getLHS());
377 PropagateInitializedObject(e->getRHS(), object);
378 return;
379 }
380
381 // Any other binary operator should not produce a record type, it would be
382 // used to construct a record further up the AST, so we should not arrive
383 // here.
384 expr->dump();
385 llvm::report_fatal_error(
386 "Unexpected binary operator in initializer expression tree");
387 }
388 if (auto* e = clang::dyn_cast<clang::AbstractConditionalOperator>(expr)) {
389 AddTemporaryObjectForExpression(e->getCond());
390 PropagateInitializedObject(e->getTrueExpr(), object);
391 PropagateInitializedObject(e->getFalseExpr(), object);
392 return;
393 }
394
395 expr->dump();
396 llvm::report_fatal_error(
397 "Unexpected expression in initializer expression tree");
398 }
399
400 bool InitializedObjectWasPropagatedTo(clang::Expr* terminating_expr) {
401 // An expression that initializes an object should have already been
402 // connected to the object it initializes. We should have walked down from
403 // the object which requires initialization to find its terminating
404 // expressions.
405 if (!object_repository_.initialized_objects_.count(terminating_expr)) {
406 llvm::errs() << "Missing initialized object for terminating expression, "
407 "we did not record it when we visited something earlier "
408 "in the tree yet?\n";
409 terminating_expr->dump();
410 return false;
411 } else {
412 return true;
413 }
414 }
415
416 void TraverseCXXMemberInitializers(
417 const clang::CXXConstructorDecl* constructor) {
418 // For constructors, we also need to create lifetimes for variables
419 // referenced by in-class member initializers; the visitor by default only
420 // visits expressions in the initializer list.
421 // We also need to associate member initializers with the members they
422 // initialize.
423 for (const auto* init : constructor->inits()) {
424 const auto* init_expr = init->getInit();
425 if (const auto* default_init =
426 clang::dyn_cast<clang::CXXDefaultInitExpr>(init_expr)) {
427 init_expr = default_init->getExpr();
428 }
429
430 if (init->getMember() && init->getMember()->getType()->isRecordType()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700431 std::optional<const Object*> this_object =
432 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700433 assert(this_object.has_value());
434
Martin Brænne46f1a572022-07-01 02:07:07 -0700435 const Object* field_object =
Martin Brænne1b98ac62022-07-01 06:24:52 -0700436 object_repository_.GetFieldObject(*this_object, init->getMember());
Martin Brænneecd58c32022-07-01 02:25:47 -0700437 PropagateInitializedObject(init_expr, field_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700438 } else if (init->getBaseClass()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700439 std::optional<const Object*> this_object =
440 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700441 assert(this_object.has_value());
442
Martin Brænnee08ac882022-07-01 02:24:49 -0700443 const Object* base_object = object_repository_.GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700444 *this_object, init->getBaseClass());
Martin Brænneecd58c32022-07-01 02:25:47 -0700445 PropagateInitializedObject(init_expr, base_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700446 }
447
448 // Traverse after finishing with the outer expression, including
449 // connecting the initializer (constructor) to its object.
450 TraverseStmt(const_cast<clang::Expr*>(init_expr));
451 }
452 }
453
454 ObjectRepository& object_repository_;
Luca Versaria12c9d52023-02-23 08:40:48 -0800455 const FunctionLifetimesMap& callee_lifetimes_;
456 std::optional<std::string> error_;
Luca Versari99fddff2022-05-25 10:22:32 -0700457};
458
Luca Versaria12c9d52023-02-23 08:40:48 -0800459llvm::Expected<ObjectRepository> ObjectRepository::Create(
460 const clang::FunctionDecl* func,
461 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
462 callee_lifetimes) {
463 ObjectRepository object_repository;
Luca Versari99fddff2022-05-25 10:22:32 -0700464 const auto* method_decl = clang::dyn_cast<clang::CXXMethodDecl>(func);
465
466 const auto* definition = func->getDefinition();
467 assert(definition || (method_decl && method_decl->isPure()));
468 if (definition) func = definition;
Luca Versaria12c9d52023-02-23 08:40:48 -0800469 object_repository.func_ = func;
Luca Versari99fddff2022-05-25 10:22:32 -0700470
Luca Versaria12c9d52023-02-23 08:40:48 -0800471 object_repository.return_object_ = object_repository.CreateObject(
472 func->getReturnType(), Lifetime::CreateVariable(),
473 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700474
475 if (method_decl) {
476 if (!method_decl->isStatic()) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800477 object_repository.this_object_ = object_repository.CreateObject(
478 method_decl->getThisObjectType(), Lifetime::CreateVariable(),
Luca Versaricd873a62023-01-18 13:45:08 -0800479 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700480 }
481 }
482
Luca Versaria12c9d52023-02-23 08:40:48 -0800483 VarDeclVisitor decl_visitor(object_repository, callee_lifetimes);
Luca Versari99fddff2022-05-25 10:22:32 -0700484 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
485 decl_visitor.TraverseCXXMemberInitializers(constructor);
486 }
487 decl_visitor.TraverseFunctionDecl(const_cast<clang::FunctionDecl*>(func));
Luca Versaria12c9d52023-02-23 08:40:48 -0800488
489 if (decl_visitor.error_.has_value()) {
490 return llvm::createStringError(llvm::inconvertibleErrorCode(),
491 *decl_visitor.error_);
492 }
493 return object_repository;
Luca Versari99fddff2022-05-25 10:22:32 -0700494}
495
496std::string ObjectRepository::DebugString() const {
497 std::string result;
498 llvm::raw_string_ostream os(result);
499
500 if (this_object_) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700501 os << "This " << (*this_object_)->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700502 }
503 for (const auto& [decl, object] : object_repository_) {
504 os << decl->getDeclKindName() << " " << decl << " (";
505 decl->printName(os);
Martin Brænnee9a4a472022-07-01 02:26:55 -0700506 os << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700507 }
508 for (const auto& [expr_i, object] : call_expr_args_objects_) {
509 const auto& [expr, i] = expr_i;
510 os << "Call " << expr << " (arg " << i
Martin Brænne982a1152022-07-01 01:55:53 -0700511 << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700512 }
513 for (const auto& [expr, object] : call_expr_this_pointers_) {
Martin Brænne982a1152022-07-01 01:55:53 -0700514 os << "Call " << expr << " (this) pointer: " << object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700515 << "\n";
516 }
517 os << "InitialPointsToMap:\n" << initial_points_to_map_.DebugString() << "\n";
518 for (const auto& [field, object] : field_object_map_) {
519 os << "Field '";
520 field.second->printName(os);
Luca Versarid430c3f2022-08-22 02:10:31 -0700521 os << "' on " << field.first->DebugString()
522 << " object: " << object->DebugString() << "\n";
523 }
524 for (const auto& [base, object] : base_object_map_) {
525 os << "Base of type " << clang::QualType(base.second, 0).getAsString()
526 << " of " << base.first->DebugString()
Martin Brænneb6764af2022-07-01 02:01:49 -0700527 << " object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700528 }
Martin Brænne04fb3a42022-07-01 01:52:21 -0700529 os << "Return " << return_object_->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700530 os.flush();
531 return result;
532}
533
Martin Brænne46b5f072022-07-01 02:29:16 -0700534const Object* ObjectRepository::GetDeclObject(
535 const clang::ValueDecl* decl) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700536 auto iter = object_repository_.find(decl);
537 if (iter == object_repository_.end()) {
538 llvm::errs() << "Didn't find object for Decl:\n";
539 decl->dump();
540 llvm::errs() << "\n" << DebugString();
541 llvm::report_fatal_error("Didn't find object for Decl");
542 }
Martin Brænne46b5f072022-07-01 02:29:16 -0700543 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700544}
545
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700546const Object* ObjectRepository::GetTemporaryObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700547 const clang::MaterializeTemporaryExpr* expr) const {
548 auto iter = temporary_objects_.find(expr);
549 if (iter == temporary_objects_.end()) {
550 llvm::errs() << "Didn't find object for temporary expression:\n";
551 expr->dump();
552 llvm::errs() << "\n" << DebugString();
553 llvm::report_fatal_error("Didn't find object for temporary expression");
554 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700555 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700556}
557
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700558const Object* ObjectRepository::GetOriginalParameterValue(
Luca Versari99fddff2022-05-25 10:22:32 -0700559 const clang::ParmVarDecl* var_decl) const {
560 auto iter = initial_parameter_object_.find(var_decl);
561 if (iter == initial_parameter_object_.end()) {
562 llvm::errs() << "Didn't find caller object for parameter:\n";
563 var_decl->dump();
564 llvm::errs() << "\n" << DebugString();
565 llvm::report_fatal_error("Didn't find caller object for parameter");
566 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700567 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700568}
569
Luca Versari91a56ff2022-08-22 01:58:33 -0700570FunctionLifetimes ObjectRepository::GetOriginalFunctionLifetimes() const {
571 FunctionLifetimes ret;
572 auto get_initial_lifetimes_or_die = [&](const Object* object) {
573 auto iter = initial_object_lifetimes_.find(object);
574 if (iter == initial_object_lifetimes_.end()) {
575 llvm::errs() << "Didn't find lifetimes for object "
576 << object->DebugString();
577 llvm::report_fatal_error("Didn't find lifetimes for object");
578 }
579 return iter->second;
580 };
581 ret.return_lifetimes_ =
582 get_initial_lifetimes_or_die(GetReturnObject()).GetValueLifetimes();
583 if (this_object_.has_value()) {
584 ret.this_lifetimes_ = ValueLifetimes::PointerTo(
585 clang::dyn_cast<clang::CXXMethodDecl>(func_)->getThisType(),
586 get_initial_lifetimes_or_die(*this_object_));
587 }
588 ret.param_lifetimes_.reserve(func_->getNumParams());
589 for (size_t i = 0; i < func_->getNumParams(); i++) {
590 ret.param_lifetimes_.push_back(
591 get_initial_lifetimes_or_die(
592 GetOriginalParameterValue(func_->getParamDecl(i)))
593 .GetValueLifetimes());
594 }
595 if (!ret.IsValidForDecl(func_)) {
596 llvm::errs() << "Internal error: did not produce valid function lifetimes";
597 llvm::report_fatal_error(
598 "Internal error: did not produce valid function lifetimes");
599 }
600 return ret;
601}
602
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700603const Object* ObjectRepository::GetCallExprArgumentObject(
604 const clang::CallExpr* expr, size_t arg_index) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700605 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
606 if (iter == call_expr_args_objects_.end()) {
607 llvm::errs() << "Didn't find object for argument " << arg_index
608 << " of call:\n";
609 expr->dump();
610 llvm::errs() << "\n" << DebugString();
611 llvm::report_fatal_error("Didn't find object for argument");
612 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700613 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700614}
615
Luca Versariefeaf272023-01-16 10:19:28 -0800616const Object* ObjectRepository::GetCallExprRetObject(
617 const clang::Expr* expr) const {
618 auto iter = call_expr_ret_objects_.find(expr);
619 if (iter == call_expr_ret_objects_.end()) {
620 llvm::errs() << "Didn't find object for return value of call:\n";
621 expr->dump();
622 llvm::errs() << "\n" << DebugString();
623 llvm::report_fatal_error("Didn't find object for return value");
624 }
625 return iter->second;
626}
627
628const FunctionLifetimes& ObjectRepository::GetCallExprVirtualLifetimes(
629 const clang::Expr* expr) const {
630 auto iter = call_expr_virtual_lifetimes_.find(expr);
631 if (iter == call_expr_virtual_lifetimes_.end()) {
632 llvm::errs() << "Didn't find object for return value of call:\n";
633 expr->dump();
634 llvm::errs() << "\n" << DebugString();
635 llvm::report_fatal_error("Didn't find object for return value");
636 }
637 return iter->second;
638}
639
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700640const Object* ObjectRepository::GetCallExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700641 const clang::CallExpr* expr) const {
642 auto iter = call_expr_this_pointers_.find(expr);
643 if (iter == call_expr_this_pointers_.end()) {
644 llvm::errs() << "Didn't find `this` object for call:\n";
645 expr->dump();
646 llvm::errs() << "\n" << DebugString();
647 llvm::report_fatal_error("Didn't find `this` object for call");
648 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700649 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700650}
651
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700652const Object* ObjectRepository::GetCXXConstructExprArgumentObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700653 const clang::CXXConstructExpr* expr, size_t arg_index) const {
654 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
655 if (iter == call_expr_args_objects_.end()) {
656 llvm::errs() << "Didn't find object for argument " << arg_index
657 << " of constructor call:\n";
658 expr->dump();
659 llvm::errs() << "\n" << DebugString();
660 llvm::report_fatal_error(
661 "Didn't find object for argument of constructor call");
662 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700663 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700664}
665
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700666const Object* ObjectRepository::GetCXXConstructExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700667 const clang::CXXConstructExpr* expr) const {
668 auto iter = call_expr_this_pointers_.find(expr);
669 if (iter == call_expr_this_pointers_.end()) {
670 llvm::errs() << "Didn't find `this` object for constructor:\n";
671 expr->dump();
672 llvm::errs() << "\n" << DebugString();
673 llvm::report_fatal_error("Didn't find `this` object for constructor");
674 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700675 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700676}
677
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700678const Object* ObjectRepository::GetInitializedObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700679 const clang::Expr* initializer_expr) const {
680 assert(clang::isa<clang::CXXConstructExpr>(initializer_expr) ||
681 clang::isa<clang::InitListExpr>(initializer_expr) ||
682 clang::isa<clang::CallExpr>(initializer_expr));
683
684 auto iter = initialized_objects_.find(initializer_expr);
685 if (iter == initialized_objects_.end()) {
686 llvm::errs() << "Didn't find object for initializer:\n";
687 initializer_expr->dump();
688 llvm::errs() << "\n" << DebugString();
689 llvm::report_fatal_error("Didn't find object for initializer");
690 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700691 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700692}
693
Martin Brænne46f1a572022-07-01 02:07:07 -0700694const Object* ObjectRepository::GetFieldObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700695 const Object* struct_object, const clang::FieldDecl* field) const {
Martin Brænne46f1a572022-07-01 02:07:07 -0700696 std::optional<const Object*> field_object =
Luca Versari99fddff2022-05-25 10:22:32 -0700697 GetFieldObjectInternal(struct_object, field);
698 if (!field_object.has_value()) {
699 llvm::errs() << "On an object of type "
Martin Brænne1b98ac62022-07-01 06:24:52 -0700700 << struct_object->Type().getAsString()
Luca Versari99fddff2022-05-25 10:22:32 -0700701 << ", trying to get field:\n";
702 field->dump();
703 llvm::errs() << "\n" << DebugString();
704 llvm::report_fatal_error("Didn't find field object");
705 }
706 return *field_object;
707}
708
709ObjectSet ObjectRepository::GetFieldObject(
710 const ObjectSet& struct_objects, const clang::FieldDecl* field) const {
711 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700712 for (const Object* object : struct_objects) {
713 ret.Add(GetFieldObject(object, field));
Luca Versari99fddff2022-05-25 10:22:32 -0700714 }
715 return ret;
716}
717
Martin Brænnee08ac882022-07-01 02:24:49 -0700718const Object* ObjectRepository::GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700719 const Object* struct_object, const clang::Type* base) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700720 base = base->getCanonicalTypeInternal().getTypePtr();
721 auto iter = base_object_map_.find(std::make_pair(struct_object, base));
722 if (iter == base_object_map_.end()) {
Martin Brænne1b98ac62022-07-01 06:24:52 -0700723 llvm::errs() << "On object " << struct_object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700724 << ", trying to get base:\n";
725 base->dump();
726 llvm::errs() << "\n" << DebugString();
727 llvm::report_fatal_error("Didn't find base object");
728 }
Martin Brænnee08ac882022-07-01 02:24:49 -0700729 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700730}
731
732ObjectSet ObjectRepository::GetBaseClassObject(const ObjectSet& struct_objects,
733 const clang::Type* base) const {
734 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700735 for (const Object* object : struct_objects) {
736 ret.Add(GetBaseClassObject(object, base));
Luca Versari99fddff2022-05-25 10:22:32 -0700737 }
738 return ret;
739}
740
Luca Versaricd873a62023-01-18 13:45:08 -0800741namespace {
742
743llvm::SmallVector<std::string> GetFieldLifetimeArguments(
744 const clang::FieldDecl* field) {
745 // TODO(mboehme): Report errors as Clang diagnostics, not through
746 // llvm::report_fatal_error().
747
748 const clang::AnnotateAttr* member_lifetimes_attr = nullptr;
749 for (auto annotate : field->specific_attrs<clang::AnnotateAttr>()) {
750 if (annotate->getAnnotation() == "member_lifetimes") {
751 if (member_lifetimes_attr) {
752 llvm::report_fatal_error("repeated lifetime annotation");
753 }
754 member_lifetimes_attr = annotate;
755 }
756 }
757 if (!member_lifetimes_attr) {
758 return {};
759 }
760
761 llvm::SmallVector<std::string> ret;
762 for (const auto& arg : member_lifetimes_attr->args()) {
763 llvm::StringRef lifetime;
764 if (llvm::Error err = EvaluateAsStringLiteral(arg, field->getASTContext())
765 .moveInto(lifetime)) {
766 llvm::report_fatal_error(llvm::StringRef(toString(std::move(err))));
767 }
768 ret.push_back(lifetime.str());
769 }
770
771 return ret;
772}
773
774template <typename CallbackField, typename CallackBase>
775void ForEachFieldAndBase(clang::QualType record_type,
776 const ObjectLifetimes& object_lifetimes,
777 const CallbackField& callback_field,
778 const CallackBase& callback_base) {
779 assert(record_type->isRecordType());
780 for (clang::FieldDecl* f :
781 record_type->getAs<clang::RecordType>()->getDecl()->fields()) {
782 ObjectLifetimes field_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
783 f->getType(), GetFieldLifetimeArguments(f));
784 callback_field(field_lifetimes, f);
785 }
786 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
787 record_type->getAs<clang::RecordType>()->getDecl())) {
788 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
789 clang::QualType base_type = base.getType();
790 auto base_object_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
791 base_type, GetLifetimeParameters(base_type));
792 callback_base(base_object_lifetimes, &*base_type.getCanonicalType());
793 ForEachFieldAndBase(base.getType(), base_object_lifetimes, callback_field,
794 callback_base);
795 }
796 }
797}
798
799} // namespace
800
801struct ObjectRepository::ObjectCreator {
802 ObjectCreator(ObjectRepository& object_repository, PointsToMap& points_to_map)
803 : object_repository_(object_repository), points_to_map_(points_to_map) {}
804
Luca Versaricd873a62023-01-18 13:45:08 -0800805 const Object* CreateObjectsRecursively(
806 const ObjectLifetimes& object_lifetimes) {
807 if (auto it = object_cache_.find(object_lifetimes);
808 it != object_cache_.end()) {
809 return it->second;
810 }
Luca Versaria12c9d52023-02-23 08:40:48 -0800811
812 const clang::QualType type = object_lifetimes.Type();
813 const ValueLifetimes& value_lifetimes =
814 object_lifetimes.GetValueLifetimes();
815
816 std::optional<FunctionLifetimes> function_lifetimes;
817
818 if (type->getAs<clang::FunctionType>()) {
819 function_lifetimes = value_lifetimes.GetFuncLifetimes();
820 }
821
822 const Object* obj = object_repository_.ConstructObject(
823 object_lifetimes.GetLifetime(), object_lifetimes.Type(),
824 function_lifetimes);
Luca Versaricd873a62023-01-18 13:45:08 -0800825 object_cache_[object_lifetimes] = obj;
826
Luca Versaria12c9d52023-02-23 08:40:48 -0800827 object_repository_.initial_object_lifetimes_[obj] = object_lifetimes;
828
829 if (type->isIncompleteType()) {
830 // Nothing we can do.
831 return obj;
832 }
833
834 // Pointer type.
835 if (!PointeeType(type).isNull()) {
836 points_to_map_.ExtendPointerPointsToSet(
837 obj,
838 {CreateObjectsRecursively(value_lifetimes.GetPointeeLifetimes())});
839 return obj;
840 }
841
842 // Record type.
843 if (type->getAs<clang::RecordType>()) {
844 ForEachFieldAndBase(
845 type, object_lifetimes,
846 [this, obj](const ObjectLifetimes& field_lifetimes,
847 const clang::FieldDecl* f) {
848 const Object* field = CreateObjectsRecursively(field_lifetimes);
849 object_repository_.field_object_map_[std::make_pair(obj, f)] =
850 field;
851 },
852 [this, obj](const ObjectLifetimes& base_lifetimes,
853 const clang::Type* base_type) {
854 const Object* base_obj = CreateObjectsRecursively(base_lifetimes);
855 object_repository_
856 .base_object_map_[std::make_pair(obj, base_type)] = base_obj;
857 }
858
859 );
860 }
Luca Versaricd873a62023-01-18 13:45:08 -0800861
862 return obj;
863 }
864
Luca Versaria12c9d52023-02-23 08:40:48 -0800865 private:
Luca Versaricd873a62023-01-18 13:45:08 -0800866 ObjectRepository& object_repository_;
867 PointsToMap& points_to_map_;
868 // We re-use the same Object for all the sub-objects with the same type and
869 // lifetimes. This avoids infinite loops in the case of structs like lists.
870 llvm::DenseMap<ObjectLifetimes, const Object*> object_cache_;
871};
872
Luca Versaria12c9d52023-02-23 08:40:48 -0800873const Object* ObjectRepository::CreateObject(
874 const ObjectLifetimes& object_lifetimes, PointsToMap& points_to_map) {
Luca Versaricd873a62023-01-18 13:45:08 -0800875 ObjectCreator object_creator(*this, points_to_map);
Luca Versaria12c9d52023-02-23 08:40:48 -0800876 return object_creator.CreateObjectsRecursively(object_lifetimes);
Luca Versariefeaf272023-01-16 10:19:28 -0800877}
878
Luca Versaria12c9d52023-02-23 08:40:48 -0800879const Object* ObjectRepository::CreateObject(clang::QualType type,
880 Lifetime root_object_lifetime,
881 LifetimeFactory lifetime_factory) {
882 return CreateObject(
883 ObjectLifetimes(root_object_lifetime,
884 ValueLifetimes::Create(type, lifetime_factory).get()),
Luca Versaricd873a62023-01-18 13:45:08 -0800885 initial_points_to_map_);
Luca Versari99fddff2022-05-25 10:22:32 -0700886}
887
Luca Versaria12c9d52023-02-23 08:40:48 -0800888template <typename... Args>
889const Object* ObjectRepository::ConstructObject(Args&&... args) {
890 return new (object_allocator_.Allocate()) Object(args...);
891}
892
Luca Versari99fddff2022-05-25 10:22:32 -0700893// Clones an object and its base classes and fields, if any.
Martin Brænned8e32142022-07-01 01:54:41 -0700894const Object* ObjectRepository::CloneObject(const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700895 struct ObjectPair {
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700896 const Object* orig_object;
Martin Brænned8e32142022-07-01 01:54:41 -0700897 const Object* new_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700898 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700899 auto clone = [this](const Object* obj) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800900 auto new_obj = ConstructObject(obj->GetLifetime(), obj->Type(),
901 obj->GetFuncLifetimes());
Luca Versari99fddff2022-05-25 10:22:32 -0700902 initial_points_to_map_.SetPointerPointsToSet(
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700903 new_obj, initial_points_to_map_.GetPointerPointsToSet(obj));
Luca Versari99fddff2022-05-25 10:22:32 -0700904 return new_obj;
905 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700906 const Object* new_root = clone(object);
Luca Versari91a56ff2022-08-22 01:58:33 -0700907 initial_object_lifetimes_[new_root] = initial_object_lifetimes_[object];
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700908 std::vector<ObjectPair> object_stack{{object, new_root}};
Luca Versari99fddff2022-05-25 10:22:32 -0700909 while (!object_stack.empty()) {
910 auto [orig_object, new_object] = object_stack.back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700911 assert(orig_object->Type() == new_object->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700912 object_stack.pop_back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700913 auto record_type = orig_object->Type()->getAs<clang::RecordType>();
Luca Versari99fddff2022-05-25 10:22:32 -0700914 if (!record_type) {
915 continue;
916 }
917
918 // Base classes.
919 if (auto* cxxrecord =
920 clang::dyn_cast<clang::CXXRecordDecl>(record_type->getDecl())) {
921 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700922 const Object* base_obj =
923 GetBaseClassObject(orig_object, base.getType());
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700924 const Object* new_base_obj = clone(base_obj);
Luca Versari99fddff2022-05-25 10:22:32 -0700925 base_object_map_[std::make_pair(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700926 new_object, base.getType().getCanonicalType().getTypePtr())] =
Martin Brænnea7ca8382022-07-01 02:03:10 -0700927 new_base_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700928 object_stack.push_back(ObjectPair{base_obj, new_base_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700929 }
930 }
931
932 // Fields.
933 for (auto f : record_type->getDecl()->fields()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700934 const Object* field_obj = GetFieldObject(orig_object, f);
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700935 const Object* new_field_obj = clone(field_obj);
Martin Brænne1b98ac62022-07-01 06:24:52 -0700936 field_object_map_[std::make_pair(new_object, f)] = new_field_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700937 object_stack.push_back(ObjectPair{field_obj, new_field_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700938 }
939 }
940 return new_root;
941}
942
Martin Brænne46f1a572022-07-01 02:07:07 -0700943std::optional<const Object*> ObjectRepository::GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700944 const Object* struct_object, const clang::FieldDecl* field) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700945 auto iter = field_object_map_.find(std::make_pair(struct_object, field));
946 if (iter != field_object_map_.end()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700947 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700948 }
949 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700950 struct_object->Type()->getAs<clang::RecordType>()->getDecl())) {
Luca Versari99fddff2022-05-25 10:22:32 -0700951 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700952 std::optional<const Object*> field_object = GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700953 GetBaseClassObject(struct_object, base.getType()), field);
Luca Versari99fddff2022-05-25 10:22:32 -0700954 if (field_object.has_value()) {
955 return field_object;
956 }
957 }
958 }
959 return std::nullopt;
960}
961
962} // namespace lifetimes
963} // namespace tidy
964} // namespace clang