blob: bd8d94fd11a679055a1b743cc34d3588b4ad91ef [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
13#include "lifetime_analysis/object.h"
Luca Versari91a56ff2022-08-22 01:58:33 -070014#include "lifetime_annotations/function_lifetimes.h"
Luca Versari99fddff2022-05-25 10:22:32 -070015#include "lifetime_annotations/lifetime.h"
16#include "lifetime_annotations/pointee_type.h"
17#include "lifetime_annotations/type_lifetimes.h"
18#include "clang/AST/Decl.h"
19#include "clang/AST/DeclCXX.h"
20#include "clang/AST/Expr.h"
21#include "clang/AST/ExprCXX.h"
22#include "clang/AST/RecursiveASTVisitor.h"
23#include "clang/AST/Type.h"
24#include "clang/Basic/LLVM.h"
25#include "llvm/ADT/SmallVector.h"
26#include "llvm/ADT/StringRef.h"
27#include "llvm/Support/ErrorHandling.h"
28
29namespace clang {
30namespace tidy {
31namespace lifetimes {
32
33class ObjectRepository::VarDeclVisitor
34 : public clang::RecursiveASTVisitor<VarDeclVisitor> {
35 public:
36 explicit VarDeclVisitor(ObjectRepository& object_repository)
37 : object_repository_(object_repository) {}
38
39 // We need to visit implicitly-defined constructors and assignment operators.
40 bool shouldVisitImplicitCode() { return true; }
41
42 bool VisitVarDecl(clang::VarDecl* var) {
43 // Add objects for any local variables declared in this function.
44 AddObjectForVar(var);
45 return true;
46 }
47
48 bool VisitReturnStmt(clang::ReturnStmt* stmt) {
49 const clang::Expr* expr = stmt->getRetValue();
50 if (IsInitExprInitializingARecordObject(expr)) {
Martin Brænneecd58c32022-07-01 02:25:47 -070051 PropagateInitializedObject(expr, object_repository_.return_object_);
Luca Versari99fddff2022-05-25 10:22:32 -070052 }
53 return true;
54 }
55
56 bool VisitMemberExpr(clang::MemberExpr* member) {
57 if (auto* method =
58 clang::dyn_cast<clang::CXXMethodDecl>(member->getMemberDecl());
59 method && method->isStatic()) {
60 // Create objects for static member functions.
61 AddObjectForFunc(method);
62 }
63 return true;
64 }
65
66 bool VisitDeclRefExpr(clang::DeclRefExpr* decl_ref) {
67 // Add objects for any global variables referenced in this function.
68 // This also runs for local variables, but we don't have to treat those
69 // differently as AddObjectForVar() protects against duplication.
70 if (auto* var_decl = clang::dyn_cast<clang::VarDecl>(decl_ref->getDecl())) {
71 AddObjectForVar(var_decl);
72 }
73 // Add objects for any function referenced in this function.
74 if (auto* function_decl =
75 clang::dyn_cast<clang::FunctionDecl>(decl_ref->getDecl())) {
76 AddObjectForFunc(function_decl);
77 }
78 return true;
79 }
80
81 bool VisitObjCMessageExpr(clang::ObjCMessageExpr* msg_expr) {
82 // ObjCMessageExpr is an initializer expression terminator, so we should
83 // have walked down from the object which requires initialization to find
84 // its terminating expressions, which should have found this expression and
85 // connected it to that object already.
86 if (!object_repository_.initialized_objects_.count(msg_expr)) {
87 msg_expr->dump();
88 llvm::report_fatal_error(
89 "Missing initializer for ObjCMessageExpr, we did not record it "
90 "when we visited something earlier in the tree yet?");
91 }
92 return true;
93 }
94
95 // Create objects for function call arguments.
96 bool VisitCallExpr(clang::CallExpr* call_expr) {
97 if (IsInitExprInitializingARecordObject(call_expr)) {
98 assert(InitializedObjectWasPropagatedTo(call_expr));
99 }
100
Luca Versariefeaf272023-01-16 10:19:28 -0800101 FunctionLifetimeFactorySingleCallback lifetime_factory(
102 [](auto) { return Lifetime::CreateVariable(); });
103
104 // If we have a direct callee, construct a FunctionLifetimes out of the
105 // function/method definition.
106 if (auto callee = call_expr->getDirectCallee()) {
107 bool is_operator_call = clang::isa<clang::CXXOperatorCallExpr>(call_expr);
108 bool is_method = clang::isa<clang::CXXMethodDecl>(callee);
109 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
110 FunctionLifetimes::CreateForDecl(callee, lifetime_factory).get();
111 PrepareFunctionCall(
112 call_expr, /*index_shift=*/is_operator_call && is_method ? 1 : 0);
Luca Versari99fddff2022-05-25 10:22:32 -0700113 } else {
114 // Always a function pointer.
Luca Versariefeaf272023-01-16 10:19:28 -0800115 // TODO(veluca): pointers-to-members are not supported (yet?)
116 clang::QualType callee_type =
117 call_expr->getCallee()->getType()->getPointeeType().IgnoreParens();
118 // TODO(veluca): what about FunctionNoProtoType??
119 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
120 FunctionLifetimes::CreateForFunctionType(
121 clang::cast<clang::FunctionProtoType>(callee_type),
122 lifetime_factory)
123 .get();
124 PrepareFunctionCall(call_expr, /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700125 }
126
127 return true;
128 }
129
130 bool VisitCXXConstructExpr(clang::CXXConstructExpr* construct_expr) {
131 assert(InitializedObjectWasPropagatedTo(construct_expr));
132
Luca Versariefeaf272023-01-16 10:19:28 -0800133 FunctionLifetimeFactorySingleCallback lifetime_factory(
134 [](auto) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700135 const clang::FunctionDecl* constructor = construct_expr->getConstructor();
Luca Versariefeaf272023-01-16 10:19:28 -0800136 object_repository_.call_expr_virtual_lifetimes_[construct_expr] =
137 FunctionLifetimes::CreateForDecl(constructor, lifetime_factory).get();
138 PrepareFunctionCall(construct_expr,
139 /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700140 return true;
141 }
142
143 bool VisitInitListExpr(clang::InitListExpr* init_list_expr) {
144 // We only want to visit in Semantic form, we ignore Syntactic form.
145 if (IsInitExprInitializingARecordObject(init_list_expr) &&
146 init_list_expr->isSemanticForm() && !init_list_expr->isTransparent()) {
147 assert(InitializedObjectWasPropagatedTo(init_list_expr));
148 }
149 return true;
150 }
151
152 bool VisitMaterializeTemporaryExpr(
153 clang::MaterializeTemporaryExpr* temporary_expr) {
154 object_repository_.temporary_objects_[temporary_expr] =
155 AddTemporaryObjectForExpression(temporary_expr->getSubExpr());
156 return true;
157 }
158
159 bool VisitCompoundStmt(clang::CompoundStmt* compound) {
160 // Create temporary objects for any top-level `CXXTemporaryObjectExpr`s,
161 // i.e. ones that are used as statements.
162 for (clang::Stmt* stmt : compound->body()) {
163 if (auto* temporary = clang::dyn_cast<CXXTemporaryObjectExpr>(stmt)) {
164 AddTemporaryObjectForExpression(temporary);
165 }
166 }
167 return true;
168 }
169
Luca Versariefeaf272023-01-16 10:19:28 -0800170 void PrepareFunctionCall(const clang::Expr* expr, size_t index_shift) {
171 const auto& func_lifetimes =
172 object_repository_.call_expr_virtual_lifetimes_[expr];
173 auto make_object = [this](const ValueLifetimes& lifetime) {
174 const Object* object = object_repository_.CreateObject(
175 Lifetime::CreateLocal(), lifetime.Type());
176 object_repository_.CreateObjectsWithLifetimes(
Luca Versaricd873a62023-01-18 13:45:08 -0800177 object, lifetime, object_repository_.initial_points_to_map_);
Luca Versariefeaf272023-01-16 10:19:28 -0800178 return object;
179 };
180 for (size_t i = 0; i < func_lifetimes.GetNumParams(); ++i) {
Luca Versari99fddff2022-05-25 10:22:32 -0700181 object_repository_
182 .call_expr_args_objects_[std::make_pair(expr, i + index_shift)] =
Luca Versariefeaf272023-01-16 10:19:28 -0800183 make_object(func_lifetimes.GetParamLifetimes(i));
Luca Versari99fddff2022-05-25 10:22:32 -0700184 }
Luca Versariefeaf272023-01-16 10:19:28 -0800185 if (func_lifetimes.IsNonStaticMethod()) {
186 object_repository_.call_expr_this_pointers_[expr] =
187 make_object(func_lifetimes.GetThisLifetimes());
188 }
189 object_repository_.call_expr_ret_objects_[expr] =
190 make_object(func_lifetimes.GetReturnLifetimes());
Luca Versari99fddff2022-05-25 10:22:32 -0700191 }
192
193 void AddObjectForVar(clang::VarDecl* var) {
194 if (object_repository_.object_repository_.count(var)) {
195 return;
196 }
197
198 Lifetime lifetime;
199 LifetimeFactory lifetime_factory;
200
201 switch (var->getStorageClass()) {
202 case clang::SC_Extern:
203 case clang::SC_Static:
204 case clang::SC_PrivateExtern:
205 lifetime = Lifetime::Static();
Martin Brænne03d93302022-06-23 00:23:38 -0700206 lifetime_factory = [](const clang::Expr*) {
207 return Lifetime::Static();
208 };
Luca Versari99fddff2022-05-25 10:22:32 -0700209 break;
210 default:
211 lifetime = Lifetime::CreateLocal();
Martin Brænne03d93302022-06-23 00:23:38 -0700212 lifetime_factory = [](const clang::Expr*) {
213 return Lifetime::CreateVariable();
214 };
Luca Versari99fddff2022-05-25 10:22:32 -0700215 break;
216 }
217
Martin Brænned8e32142022-07-01 01:54:41 -0700218 const Object* object =
219 object_repository_.CreateObject(lifetime, var->getType());
Luca Versari99fddff2022-05-25 10:22:32 -0700220
Luca Versaricd873a62023-01-18 13:45:08 -0800221 object_repository_.CreateObjects(object, var->getType(), lifetime_factory);
Luca Versari99fddff2022-05-25 10:22:32 -0700222
Martin Brænnee9a4a472022-07-01 02:26:55 -0700223 object_repository_.object_repository_[var] = object;
Luca Versari53a2f582023-01-16 10:09:29 -0800224 if (!var->getType()->isArrayType()) {
225 object_repository_.initial_single_valued_objects_.Add(object);
226 }
Luca Versari99fddff2022-05-25 10:22:32 -0700227
228 // Remember the original value of function parameters.
229 if (auto parm_var_decl = clang::dyn_cast<const clang::ParmVarDecl>(var)) {
230 object_repository_.initial_parameter_object_[parm_var_decl] =
231 object_repository_.CloneObject(object);
232 }
233
234 if (var->hasInit() && var->getType()->isRecordType()) {
Martin Brænneecd58c32022-07-01 02:25:47 -0700235 PropagateInitializedObject(var->getInit(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700236 }
237 }
238
239 void AddObjectForFunc(clang::FunctionDecl* func) {
240 if (object_repository_.object_repository_.count(func)) {
241 return;
242 }
243
244 object_repository_.object_repository_[func] =
Martin Brænnee9a4a472022-07-01 02:26:55 -0700245 object_repository_.CreateObjectFromFunctionDecl(*func);
Luca Versari99fddff2022-05-25 10:22:32 -0700246 }
247
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700248 const Object* AddTemporaryObjectForExpression(clang::Expr* expr) {
Luca Versari99fddff2022-05-25 10:22:32 -0700249 clang::QualType type = expr->getType().getCanonicalType();
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700250 const Object* object =
251 object_repository_.CreateObject(Lifetime::CreateLocal(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700252
Luca Versaricd873a62023-01-18 13:45:08 -0800253 object_repository_.CreateObjects(object, type, [](const clang::Expr*) {
254 return Lifetime::CreateVariable();
255 });
Luca Versari99fddff2022-05-25 10:22:32 -0700256
257 if (type->isRecordType()) {
Martin Brænneecd58c32022-07-01 02:25:47 -0700258 PropagateInitializedObject(expr, object);
Luca Versari99fddff2022-05-25 10:22:32 -0700259 }
260 return object;
261 }
262
263 // Propagates an `object` of record type that is to be initialized to the
264 // expressions that actually perform the initialization (we call these
265 // "terminating expressions").
266 //
267 // `expr` is the initializer for a variable; this will contain one or
268 // several terminating expressions (such as a CXXConstructExpr, InitListExpr,
269 // or CallExpr).
270 //
271 // Note that not all terminating expressions below `expr` necessarily
272 // initialize `object`; some of these terminating expressions may also
273 // initialize temporary objects. This function takes care to propagate
274 // `object` only to the appropriate terminating expressions.
275 //
276 // The mapping from a terminating expression to the object it initializes
277 // is stored in `object_repository_.initialized_objects_`.
Martin Brænneecd58c32022-07-01 02:25:47 -0700278 void PropagateInitializedObject(const clang::Expr* expr,
279 const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700280 // TODO(danakj): Use StmtVisitor to implement this method.
Luca Versari99fddff2022-05-25 10:22:32 -0700281
282 // Terminating expressions. Expressions that don't initialize a record
283 // object can not be such, and their existence is unexpected as we should
284 // be converting to and initializing a record object from such expressions
285 // further up in the initializer expression's AST. We will assert later in
286 // this function if we find this situation somehow due to incorrect
287 // expectations in this comment.
288 if (IsInitExprInitializingARecordObject(expr)) {
289 if (clang::isa<clang::CXXConstructExpr>(expr) ||
290 clang::isa<clang::CallExpr>(expr) ||
291 clang::isa<clang::ObjCMessageExpr>(expr) ||
292 clang::isa<clang::LambdaExpr>(expr)) {
293 object_repository_.initialized_objects_[expr] = object;
294 return;
295 }
296 if (auto* e = clang::dyn_cast<clang::InitListExpr>(expr)) {
297 if (!e->isSemanticForm()) return;
298 if (e->isTransparent()) {
299 // A field initializer like `S s{cond ? S{} : S{}}` is considered
300 // transparent, and the actual initializer is within.
301 for (const clang::Expr* init : e->inits()) {
302 PropagateInitializedObject(init, object);
303 }
304 } else {
305 object_repository_.initialized_objects_[e] = object;
306 }
307 return;
308 }
309 }
310
311 // Expressions to walk through. Logic is similar to the AggExprEmitter in
312 // clang third_party/llvm-project/clang/lib/CodeGen/CGExprAgg.cpp though we
313 // don't have to visit all the sub-expressions that clang codegen needs to,
314 // as we can stop at terminating expressions and ignore many expressions
315 // that don't occur in the code we're analyzing.
316 if (auto* e = clang::dyn_cast<clang::ParenExpr>(expr)) {
317 PropagateInitializedObject(e->getSubExpr(), object);
318 return;
319 }
320 if (auto* e = clang::dyn_cast<clang::UnaryOperator>(expr)) {
321 PropagateInitializedObject(e->getSubExpr(), object);
322 return;
323 }
324 if (auto* e = clang::dyn_cast<clang::SubstNonTypeTemplateParmExpr>(expr)) {
325 PropagateInitializedObject(e->getReplacement(), object);
326 return;
327 }
328 if (auto* e = clang::dyn_cast<clang::CastExpr>(expr)) {
329 PropagateInitializedObject(e->getSubExpr(), object);
330 return;
331 }
332 if (auto* e = clang::dyn_cast<clang::CXXDefaultArgExpr>(expr)) {
333 PropagateInitializedObject(e->getExpr(), object);
334 return;
335 }
336 if (auto* e = clang::dyn_cast<clang::CXXDefaultInitExpr>(expr)) {
337 PropagateInitializedObject(e->getExpr(), object);
338 return;
339 }
340 if (auto* e = clang::dyn_cast<clang::ExprWithCleanups>(expr)) {
341 PropagateInitializedObject(e->getSubExpr(), object);
342 return;
343 }
344
345 // Expressions that produce a temporary object.
346 if (auto* e = clang::dyn_cast<clang::BinaryOperator>(expr)) {
347 if (e->isCommaOp()) {
348 AddTemporaryObjectForExpression(e->getLHS());
349 PropagateInitializedObject(e->getRHS(), object);
350 return;
351 }
352
353 // Any other binary operator should not produce a record type, it would be
354 // used to construct a record further up the AST, so we should not arrive
355 // here.
356 expr->dump();
357 llvm::report_fatal_error(
358 "Unexpected binary operator in initializer expression tree");
359 }
360 if (auto* e = clang::dyn_cast<clang::AbstractConditionalOperator>(expr)) {
361 AddTemporaryObjectForExpression(e->getCond());
362 PropagateInitializedObject(e->getTrueExpr(), object);
363 PropagateInitializedObject(e->getFalseExpr(), object);
364 return;
365 }
366
367 expr->dump();
368 llvm::report_fatal_error(
369 "Unexpected expression in initializer expression tree");
370 }
371
372 bool InitializedObjectWasPropagatedTo(clang::Expr* terminating_expr) {
373 // An expression that initializes an object should have already been
374 // connected to the object it initializes. We should have walked down from
375 // the object which requires initialization to find its terminating
376 // expressions.
377 if (!object_repository_.initialized_objects_.count(terminating_expr)) {
378 llvm::errs() << "Missing initialized object for terminating expression, "
379 "we did not record it when we visited something earlier "
380 "in the tree yet?\n";
381 terminating_expr->dump();
382 return false;
383 } else {
384 return true;
385 }
386 }
387
388 void TraverseCXXMemberInitializers(
389 const clang::CXXConstructorDecl* constructor) {
390 // For constructors, we also need to create lifetimes for variables
391 // referenced by in-class member initializers; the visitor by default only
392 // visits expressions in the initializer list.
393 // We also need to associate member initializers with the members they
394 // initialize.
395 for (const auto* init : constructor->inits()) {
396 const auto* init_expr = init->getInit();
397 if (const auto* default_init =
398 clang::dyn_cast<clang::CXXDefaultInitExpr>(init_expr)) {
399 init_expr = default_init->getExpr();
400 }
401
402 if (init->getMember() && init->getMember()->getType()->isRecordType()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700403 std::optional<const Object*> this_object =
404 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700405 assert(this_object.has_value());
406
Martin Brænne46f1a572022-07-01 02:07:07 -0700407 const Object* field_object =
Martin Brænne1b98ac62022-07-01 06:24:52 -0700408 object_repository_.GetFieldObject(*this_object, init->getMember());
Martin Brænneecd58c32022-07-01 02:25:47 -0700409 PropagateInitializedObject(init_expr, field_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700410 } else if (init->getBaseClass()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700411 std::optional<const Object*> this_object =
412 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700413 assert(this_object.has_value());
414
Martin Brænnee08ac882022-07-01 02:24:49 -0700415 const Object* base_object = object_repository_.GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700416 *this_object, init->getBaseClass());
Martin Brænneecd58c32022-07-01 02:25:47 -0700417 PropagateInitializedObject(init_expr, base_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700418 }
419
420 // Traverse after finishing with the outer expression, including
421 // connecting the initializer (constructor) to its object.
422 TraverseStmt(const_cast<clang::Expr*>(init_expr));
423 }
424 }
425
426 ObjectRepository& object_repository_;
427};
428
429ObjectRepository::ObjectRepository(const clang::FunctionDecl* func) {
430 const auto* method_decl = clang::dyn_cast<clang::CXXMethodDecl>(func);
431
432 const auto* definition = func->getDefinition();
433 assert(definition || (method_decl && method_decl->isPure()));
434 if (definition) func = definition;
Luca Versari91a56ff2022-08-22 01:58:33 -0700435 func_ = func;
Luca Versari99fddff2022-05-25 10:22:32 -0700436
Luca Versaricd257d32022-08-22 02:09:25 -0700437 // For the return value, we only need to create field objects, except if we
438 // use constraint-based analysis.
439 return_object_ =
440 CreateObject(Lifetime::CreateVariable(), func->getReturnType());
Luca Versaricd873a62023-01-18 13:45:08 -0800441 CreateObjects(return_object_, func->getReturnType(),
442 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700443
444 if (method_decl) {
445 if (!method_decl->isStatic()) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700446 this_object_ = CreateObject(Lifetime::CreateVariable(),
447 method_decl->getThisObjectType());
Luca Versari99fddff2022-05-25 10:22:32 -0700448 CreateObjects(
Martin Brænne493d4d42022-07-01 05:44:23 -0700449 *this_object_, method_decl->getThisObjectType(),
Luca Versaricd873a62023-01-18 13:45:08 -0800450 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700451 }
452 }
453
454 VarDeclVisitor decl_visitor(*this);
455 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
456 decl_visitor.TraverseCXXMemberInitializers(constructor);
457 }
458 decl_visitor.TraverseFunctionDecl(const_cast<clang::FunctionDecl*>(func));
459}
460
461std::string ObjectRepository::DebugString() const {
462 std::string result;
463 llvm::raw_string_ostream os(result);
464
465 if (this_object_) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700466 os << "This " << (*this_object_)->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700467 }
468 for (const auto& [decl, object] : object_repository_) {
469 os << decl->getDeclKindName() << " " << decl << " (";
470 decl->printName(os);
Martin Brænnee9a4a472022-07-01 02:26:55 -0700471 os << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700472 }
473 for (const auto& [expr_i, object] : call_expr_args_objects_) {
474 const auto& [expr, i] = expr_i;
475 os << "Call " << expr << " (arg " << i
Martin Brænne982a1152022-07-01 01:55:53 -0700476 << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700477 }
478 for (const auto& [expr, object] : call_expr_this_pointers_) {
Martin Brænne982a1152022-07-01 01:55:53 -0700479 os << "Call " << expr << " (this) pointer: " << object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700480 << "\n";
481 }
482 os << "InitialPointsToMap:\n" << initial_points_to_map_.DebugString() << "\n";
483 for (const auto& [field, object] : field_object_map_) {
484 os << "Field '";
485 field.second->printName(os);
Luca Versarid430c3f2022-08-22 02:10:31 -0700486 os << "' on " << field.first->DebugString()
487 << " object: " << object->DebugString() << "\n";
488 }
489 for (const auto& [base, object] : base_object_map_) {
490 os << "Base of type " << clang::QualType(base.second, 0).getAsString()
491 << " of " << base.first->DebugString()
Martin Brænneb6764af2022-07-01 02:01:49 -0700492 << " object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700493 }
Martin Brænne04fb3a42022-07-01 01:52:21 -0700494 os << "Return " << return_object_->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700495 os.flush();
496 return result;
497}
498
Martin Brænne4a1231d2022-07-01 01:45:44 -0700499const Object* ObjectRepository::CreateObject(Lifetime lifetime,
500 clang::QualType type) {
501 return new (object_allocator_.Allocate()) Object(lifetime, type);
502}
503
504const Object* ObjectRepository::CreateObjectFromFunctionDecl(
505 const clang::FunctionDecl& func) {
506 return new (object_allocator_.Allocate()) Object(func);
507}
508
Martin Brænne46b5f072022-07-01 02:29:16 -0700509const Object* ObjectRepository::GetDeclObject(
510 const clang::ValueDecl* decl) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700511 auto iter = object_repository_.find(decl);
512 if (iter == object_repository_.end()) {
513 llvm::errs() << "Didn't find object for Decl:\n";
514 decl->dump();
515 llvm::errs() << "\n" << DebugString();
516 llvm::report_fatal_error("Didn't find object for Decl");
517 }
Martin Brænne46b5f072022-07-01 02:29:16 -0700518 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700519}
520
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700521const Object* ObjectRepository::GetTemporaryObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700522 const clang::MaterializeTemporaryExpr* expr) const {
523 auto iter = temporary_objects_.find(expr);
524 if (iter == temporary_objects_.end()) {
525 llvm::errs() << "Didn't find object for temporary expression:\n";
526 expr->dump();
527 llvm::errs() << "\n" << DebugString();
528 llvm::report_fatal_error("Didn't find object for temporary expression");
529 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700530 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700531}
532
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700533const Object* ObjectRepository::GetOriginalParameterValue(
Luca Versari99fddff2022-05-25 10:22:32 -0700534 const clang::ParmVarDecl* var_decl) const {
535 auto iter = initial_parameter_object_.find(var_decl);
536 if (iter == initial_parameter_object_.end()) {
537 llvm::errs() << "Didn't find caller object for parameter:\n";
538 var_decl->dump();
539 llvm::errs() << "\n" << DebugString();
540 llvm::report_fatal_error("Didn't find caller object for parameter");
541 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700542 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700543}
544
Luca Versari91a56ff2022-08-22 01:58:33 -0700545FunctionLifetimes ObjectRepository::GetOriginalFunctionLifetimes() const {
546 FunctionLifetimes ret;
547 auto get_initial_lifetimes_or_die = [&](const Object* object) {
548 auto iter = initial_object_lifetimes_.find(object);
549 if (iter == initial_object_lifetimes_.end()) {
550 llvm::errs() << "Didn't find lifetimes for object "
551 << object->DebugString();
552 llvm::report_fatal_error("Didn't find lifetimes for object");
553 }
554 return iter->second;
555 };
556 ret.return_lifetimes_ =
557 get_initial_lifetimes_or_die(GetReturnObject()).GetValueLifetimes();
558 if (this_object_.has_value()) {
559 ret.this_lifetimes_ = ValueLifetimes::PointerTo(
560 clang::dyn_cast<clang::CXXMethodDecl>(func_)->getThisType(),
561 get_initial_lifetimes_or_die(*this_object_));
562 }
563 ret.param_lifetimes_.reserve(func_->getNumParams());
564 for (size_t i = 0; i < func_->getNumParams(); i++) {
565 ret.param_lifetimes_.push_back(
566 get_initial_lifetimes_or_die(
567 GetOriginalParameterValue(func_->getParamDecl(i)))
568 .GetValueLifetimes());
569 }
570 if (!ret.IsValidForDecl(func_)) {
571 llvm::errs() << "Internal error: did not produce valid function lifetimes";
572 llvm::report_fatal_error(
573 "Internal error: did not produce valid function lifetimes");
574 }
575 return ret;
576}
577
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700578const Object* ObjectRepository::GetCallExprArgumentObject(
579 const clang::CallExpr* expr, size_t arg_index) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700580 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
581 if (iter == call_expr_args_objects_.end()) {
582 llvm::errs() << "Didn't find object for argument " << arg_index
583 << " of call:\n";
584 expr->dump();
585 llvm::errs() << "\n" << DebugString();
586 llvm::report_fatal_error("Didn't find object for argument");
587 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700588 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700589}
590
Luca Versariefeaf272023-01-16 10:19:28 -0800591const Object* ObjectRepository::GetCallExprRetObject(
592 const clang::Expr* expr) const {
593 auto iter = call_expr_ret_objects_.find(expr);
594 if (iter == call_expr_ret_objects_.end()) {
595 llvm::errs() << "Didn't find object for return value of call:\n";
596 expr->dump();
597 llvm::errs() << "\n" << DebugString();
598 llvm::report_fatal_error("Didn't find object for return value");
599 }
600 return iter->second;
601}
602
603const FunctionLifetimes& ObjectRepository::GetCallExprVirtualLifetimes(
604 const clang::Expr* expr) const {
605 auto iter = call_expr_virtual_lifetimes_.find(expr);
606 if (iter == call_expr_virtual_lifetimes_.end()) {
607 llvm::errs() << "Didn't find object for return value of call:\n";
608 expr->dump();
609 llvm::errs() << "\n" << DebugString();
610 llvm::report_fatal_error("Didn't find object for return value");
611 }
612 return iter->second;
613}
614
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700615const Object* ObjectRepository::GetCallExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700616 const clang::CallExpr* expr) const {
617 auto iter = call_expr_this_pointers_.find(expr);
618 if (iter == call_expr_this_pointers_.end()) {
619 llvm::errs() << "Didn't find `this` object for call:\n";
620 expr->dump();
621 llvm::errs() << "\n" << DebugString();
622 llvm::report_fatal_error("Didn't find `this` object for call");
623 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700624 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700625}
626
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700627const Object* ObjectRepository::GetCXXConstructExprArgumentObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700628 const clang::CXXConstructExpr* expr, size_t arg_index) const {
629 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
630 if (iter == call_expr_args_objects_.end()) {
631 llvm::errs() << "Didn't find object for argument " << arg_index
632 << " of constructor call:\n";
633 expr->dump();
634 llvm::errs() << "\n" << DebugString();
635 llvm::report_fatal_error(
636 "Didn't find object for argument of constructor call");
637 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700638 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700639}
640
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700641const Object* ObjectRepository::GetCXXConstructExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700642 const clang::CXXConstructExpr* expr) const {
643 auto iter = call_expr_this_pointers_.find(expr);
644 if (iter == call_expr_this_pointers_.end()) {
645 llvm::errs() << "Didn't find `this` object for constructor:\n";
646 expr->dump();
647 llvm::errs() << "\n" << DebugString();
648 llvm::report_fatal_error("Didn't find `this` object for constructor");
649 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700650 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700651}
652
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700653const Object* ObjectRepository::GetInitializedObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700654 const clang::Expr* initializer_expr) const {
655 assert(clang::isa<clang::CXXConstructExpr>(initializer_expr) ||
656 clang::isa<clang::InitListExpr>(initializer_expr) ||
657 clang::isa<clang::CallExpr>(initializer_expr));
658
659 auto iter = initialized_objects_.find(initializer_expr);
660 if (iter == initialized_objects_.end()) {
661 llvm::errs() << "Didn't find object for initializer:\n";
662 initializer_expr->dump();
663 llvm::errs() << "\n" << DebugString();
664 llvm::report_fatal_error("Didn't find object for initializer");
665 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700666 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700667}
668
Martin Brænne46f1a572022-07-01 02:07:07 -0700669const Object* ObjectRepository::GetFieldObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700670 const Object* struct_object, const clang::FieldDecl* field) const {
Martin Brænne46f1a572022-07-01 02:07:07 -0700671 std::optional<const Object*> field_object =
Luca Versari99fddff2022-05-25 10:22:32 -0700672 GetFieldObjectInternal(struct_object, field);
673 if (!field_object.has_value()) {
674 llvm::errs() << "On an object of type "
Martin Brænne1b98ac62022-07-01 06:24:52 -0700675 << struct_object->Type().getAsString()
Luca Versari99fddff2022-05-25 10:22:32 -0700676 << ", trying to get field:\n";
677 field->dump();
678 llvm::errs() << "\n" << DebugString();
679 llvm::report_fatal_error("Didn't find field object");
680 }
681 return *field_object;
682}
683
684ObjectSet ObjectRepository::GetFieldObject(
685 const ObjectSet& struct_objects, const clang::FieldDecl* field) const {
686 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700687 for (const Object* object : struct_objects) {
688 ret.Add(GetFieldObject(object, field));
Luca Versari99fddff2022-05-25 10:22:32 -0700689 }
690 return ret;
691}
692
Martin Brænnee08ac882022-07-01 02:24:49 -0700693const Object* ObjectRepository::GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700694 const Object* struct_object, const clang::Type* base) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700695 base = base->getCanonicalTypeInternal().getTypePtr();
696 auto iter = base_object_map_.find(std::make_pair(struct_object, base));
697 if (iter == base_object_map_.end()) {
Martin Brænne1b98ac62022-07-01 06:24:52 -0700698 llvm::errs() << "On object " << struct_object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700699 << ", trying to get base:\n";
700 base->dump();
701 llvm::errs() << "\n" << DebugString();
702 llvm::report_fatal_error("Didn't find base object");
703 }
Martin Brænnee08ac882022-07-01 02:24:49 -0700704 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700705}
706
707ObjectSet ObjectRepository::GetBaseClassObject(const ObjectSet& struct_objects,
708 const clang::Type* base) const {
709 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700710 for (const Object* object : struct_objects) {
711 ret.Add(GetBaseClassObject(object, base));
Luca Versari99fddff2022-05-25 10:22:32 -0700712 }
713 return ret;
714}
715
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700716const Object* ObjectRepository::CreateStaticObject(clang::QualType type) {
Luca Versari99fddff2022-05-25 10:22:32 -0700717 auto iter = static_objects_.find(type);
718 if (iter != static_objects_.end()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700719 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700720 }
721
Martin Brænne3b587cf2022-07-01 01:57:01 -0700722 const Object* object = CreateObject(Lifetime::Static(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700723 static_objects_[type] = object;
724
Luca Versaricd873a62023-01-18 13:45:08 -0800725 CreateObjects(object, type,
726 [](const clang::Expr*) { return Lifetime::Static(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700727
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700728 return object;
Luca Versari99fddff2022-05-25 10:22:32 -0700729}
730
Luca Versariefeaf272023-01-16 10:19:28 -0800731const Object* ObjectRepository::CreateObjectsRecursively(
732 const ObjectLifetimes& object_lifetimes, PointsToMap& points_to_map) {
733 const auto* obj =
734 CreateObject(object_lifetimes.GetLifetime(), object_lifetimes.Type());
735 CreateObjectsWithLifetimes(obj, object_lifetimes.GetValueLifetimes(),
Luca Versaricd873a62023-01-18 13:45:08 -0800736 points_to_map);
Luca Versariefeaf272023-01-16 10:19:28 -0800737 return obj;
738}
739
Luca Versaricd873a62023-01-18 13:45:08 -0800740namespace {
741
742llvm::SmallVector<std::string> GetFieldLifetimeArguments(
743 const clang::FieldDecl* field) {
744 // TODO(mboehme): Report errors as Clang diagnostics, not through
745 // llvm::report_fatal_error().
746
747 const clang::AnnotateAttr* member_lifetimes_attr = nullptr;
748 for (auto annotate : field->specific_attrs<clang::AnnotateAttr>()) {
749 if (annotate->getAnnotation() == "member_lifetimes") {
750 if (member_lifetimes_attr) {
751 llvm::report_fatal_error("repeated lifetime annotation");
752 }
753 member_lifetimes_attr = annotate;
754 }
755 }
756 if (!member_lifetimes_attr) {
757 return {};
758 }
759
760 llvm::SmallVector<std::string> ret;
761 for (const auto& arg : member_lifetimes_attr->args()) {
762 llvm::StringRef lifetime;
763 if (llvm::Error err = EvaluateAsStringLiteral(arg, field->getASTContext())
764 .moveInto(lifetime)) {
765 llvm::report_fatal_error(llvm::StringRef(toString(std::move(err))));
766 }
767 ret.push_back(lifetime.str());
768 }
769
770 return ret;
771}
772
773template <typename CallbackField, typename CallackBase>
774void ForEachFieldAndBase(clang::QualType record_type,
775 const ObjectLifetimes& object_lifetimes,
776 const CallbackField& callback_field,
777 const CallackBase& callback_base) {
778 assert(record_type->isRecordType());
779 for (clang::FieldDecl* f :
780 record_type->getAs<clang::RecordType>()->getDecl()->fields()) {
781 ObjectLifetimes field_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
782 f->getType(), GetFieldLifetimeArguments(f));
783 callback_field(field_lifetimes, f);
784 }
785 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
786 record_type->getAs<clang::RecordType>()->getDecl())) {
787 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
788 clang::QualType base_type = base.getType();
789 auto base_object_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
790 base_type, GetLifetimeParameters(base_type));
791 callback_base(base_object_lifetimes, &*base_type.getCanonicalType());
792 ForEachFieldAndBase(base.getType(), base_object_lifetimes, callback_field,
793 callback_base);
794 }
795 }
796}
797
798} // namespace
799
800struct ObjectRepository::ObjectCreator {
801 ObjectCreator(ObjectRepository& object_repository, PointsToMap& points_to_map)
802 : object_repository_(object_repository), points_to_map_(points_to_map) {}
803
804 void CreateChildrenForObjectWithValue(const Object* object,
805 const ValueLifetimes& value_lifetimes) {
806 ObjectLifetimes object_lifetimes(object->GetLifetime(), value_lifetimes);
807 object_repository_.initial_object_lifetimes_[object] = object_lifetimes;
808
809 const clang::QualType type = value_lifetimes.Type();
810
811 if (type->isIncompleteType()) {
812 // Nothing we can do.
813 return;
814 }
815
816 // Pointer type.
817 if (!PointeeType(type).isNull()) {
818 points_to_map_.ExtendPointerPointsToSet(
819 object,
820 {CreateObjectsRecursively(value_lifetimes.GetPointeeLifetimes())});
821 return;
822 }
823
824 // Record type.
825 if (type->getAs<clang::RecordType>()) {
826 ForEachFieldAndBase(
827 type, object_lifetimes,
828 [this, object](const ObjectLifetimes& field_lifetimes,
829 const clang::FieldDecl* f) {
830 const Object* field = CreateObjectsRecursively(field_lifetimes);
831 object_repository_.field_object_map_[std::make_pair(object, f)] =
832 field;
833 },
834 [this, object](const ObjectLifetimes& base_lifetimes,
835 const clang::Type* base_type) {
836 const Object* base_obj = CreateObjectsRecursively(base_lifetimes);
837 object_repository_
838 .base_object_map_[std::make_pair(object, base_type)] = base_obj;
839 }
840
841 );
842 }
843 }
844
845 private:
846 const Object* CreateObjectsRecursively(
847 const ObjectLifetimes& object_lifetimes) {
848 if (auto it = object_cache_.find(object_lifetimes);
849 it != object_cache_.end()) {
850 return it->second;
851 }
852 const Object* obj = object_repository_.CreateObject(
853 object_lifetimes.GetLifetime(), object_lifetimes.Type());
854 object_cache_[object_lifetimes] = obj;
855
856 CreateChildrenForObjectWithValue(obj, object_lifetimes.GetValueLifetimes());
857
858 return obj;
859 }
860
861 ObjectRepository& object_repository_;
862 PointsToMap& points_to_map_;
863 // We re-use the same Object for all the sub-objects with the same type and
864 // lifetimes. This avoids infinite loops in the case of structs like lists.
865 llvm::DenseMap<ObjectLifetimes, const Object*> object_cache_;
866};
867
Luca Versariefeaf272023-01-16 10:19:28 -0800868void ObjectRepository::CreateObjectsWithLifetimes(
869 const Object* root_object, const ValueLifetimes& value_lifetimes,
Luca Versaricd873a62023-01-18 13:45:08 -0800870 PointsToMap& points_to_map) {
871 ObjectCreator object_creator(*this, points_to_map);
872 object_creator.CreateChildrenForObjectWithValue(root_object, value_lifetimes);
Luca Versariefeaf272023-01-16 10:19:28 -0800873}
874
875void ObjectRepository::CreateObjects(const Object* root_object,
876 clang::QualType type,
Luca Versaricd873a62023-01-18 13:45:08 -0800877 LifetimeFactory lifetime_factory) {
Luca Versariefeaf272023-01-16 10:19:28 -0800878 CreateObjectsWithLifetimes(
879 root_object, ValueLifetimes::Create(type, lifetime_factory).get(),
Luca Versaricd873a62023-01-18 13:45:08 -0800880 initial_points_to_map_);
Luca Versari99fddff2022-05-25 10:22:32 -0700881}
882
883// Clones an object and its base classes and fields, if any.
Martin Brænned8e32142022-07-01 01:54:41 -0700884const Object* ObjectRepository::CloneObject(const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700885 struct ObjectPair {
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700886 const Object* orig_object;
Martin Brænned8e32142022-07-01 01:54:41 -0700887 const Object* new_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700888 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700889 auto clone = [this](const Object* obj) {
890 auto new_obj = CreateObject(obj->GetLifetime(), obj->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700891 initial_points_to_map_.SetPointerPointsToSet(
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700892 new_obj, initial_points_to_map_.GetPointerPointsToSet(obj));
Luca Versari99fddff2022-05-25 10:22:32 -0700893 return new_obj;
894 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700895 const Object* new_root = clone(object);
Luca Versari91a56ff2022-08-22 01:58:33 -0700896 initial_object_lifetimes_[new_root] = initial_object_lifetimes_[object];
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700897 std::vector<ObjectPair> object_stack{{object, new_root}};
Luca Versari99fddff2022-05-25 10:22:32 -0700898 while (!object_stack.empty()) {
899 auto [orig_object, new_object] = object_stack.back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700900 assert(orig_object->Type() == new_object->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700901 object_stack.pop_back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700902 auto record_type = orig_object->Type()->getAs<clang::RecordType>();
Luca Versari99fddff2022-05-25 10:22:32 -0700903 if (!record_type) {
904 continue;
905 }
906
907 // Base classes.
908 if (auto* cxxrecord =
909 clang::dyn_cast<clang::CXXRecordDecl>(record_type->getDecl())) {
910 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700911 const Object* base_obj =
912 GetBaseClassObject(orig_object, base.getType());
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700913 const Object* new_base_obj = clone(base_obj);
Luca Versari99fddff2022-05-25 10:22:32 -0700914 base_object_map_[std::make_pair(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700915 new_object, base.getType().getCanonicalType().getTypePtr())] =
Martin Brænnea7ca8382022-07-01 02:03:10 -0700916 new_base_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700917 object_stack.push_back(ObjectPair{base_obj, new_base_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700918 }
919 }
920
921 // Fields.
922 for (auto f : record_type->getDecl()->fields()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700923 const Object* field_obj = GetFieldObject(orig_object, f);
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700924 const Object* new_field_obj = clone(field_obj);
Martin Brænne1b98ac62022-07-01 06:24:52 -0700925 field_object_map_[std::make_pair(new_object, f)] = new_field_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700926 object_stack.push_back(ObjectPair{field_obj, new_field_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700927 }
928 }
929 return new_root;
930}
931
Martin Brænne46f1a572022-07-01 02:07:07 -0700932std::optional<const Object*> ObjectRepository::GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700933 const Object* struct_object, const clang::FieldDecl* field) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700934 auto iter = field_object_map_.find(std::make_pair(struct_object, field));
935 if (iter != field_object_map_.end()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700936 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700937 }
938 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700939 struct_object->Type()->getAs<clang::RecordType>()->getDecl())) {
Luca Versari99fddff2022-05-25 10:22:32 -0700940 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700941 std::optional<const Object*> field_object = GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700942 GetBaseClassObject(struct_object, base.getType()), field);
Luca Versari99fddff2022-05-25 10:22:32 -0700943 if (field_object.has_value()) {
944 return field_object;
945 }
946 }
947 }
948 return std::nullopt;
949}
950
951} // namespace lifetimes
952} // namespace tidy
953} // namespace clang