blob: 68cee7fce6fdcb11a13645c4e0bf43830259da82 [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
Dmitri Gribenkoa087d232023-07-10 08:03:46 -07007#include <cassert>
8#include <cstddef>
Luca Versari99fddff2022-05-25 10:22:32 -07009#include <optional>
10#include <string>
11#include <utility>
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070012#include <variant>
Luca Versari99fddff2022-05-25 10:22:32 -070013#include <vector>
14
Luca Versaria12c9d52023-02-23 08:40:48 -080015#include "absl/strings/str_cat.h"
16#include "lifetime_analysis/builtin_lifetimes.h"
Luca Versari99fddff2022-05-25 10:22:32 -070017#include "lifetime_analysis/object.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070018#include "lifetime_analysis/object_set.h"
19#include "lifetime_analysis/points_to_map.h"
Luca Versari91a56ff2022-08-22 01:58:33 -070020#include "lifetime_annotations/function_lifetimes.h"
Luca Versari99fddff2022-05-25 10:22:32 -070021#include "lifetime_annotations/lifetime.h"
22#include "lifetime_annotations/pointee_type.h"
23#include "lifetime_annotations/type_lifetimes.h"
24#include "clang/AST/Decl.h"
25#include "clang/AST/DeclCXX.h"
26#include "clang/AST/Expr.h"
27#include "clang/AST/ExprCXX.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070028#include "clang/AST/ExprObjC.h"
Luca Versari99fddff2022-05-25 10:22:32 -070029#include "clang/AST/RecursiveASTVisitor.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070030#include "clang/AST/Stmt.h"
Luca Versari99fddff2022-05-25 10:22:32 -070031#include "clang/AST/Type.h"
32#include "clang/Basic/LLVM.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070033#include "clang/Basic/Specifiers.h"
34#include "llvm/ADT/DenseMap.h"
Luca Versari99fddff2022-05-25 10:22:32 -070035#include "llvm/ADT/SmallVector.h"
36#include "llvm/ADT/StringRef.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070037#include "llvm/Support/Error.h"
Luca Versari99fddff2022-05-25 10:22:32 -070038#include "llvm/Support/ErrorHandling.h"
Dmitri Gribenkoa087d232023-07-10 08:03:46 -070039#include "llvm/Support/raw_ostream.h"
Luca Versari99fddff2022-05-25 10:22:32 -070040
41namespace clang {
42namespace tidy {
43namespace lifetimes {
44
Luca Versaria12c9d52023-02-23 08:40:48 -080045FunctionLifetimesOrError GetFunctionLifetimes(
46 const FunctionDecl* decl, const FunctionLifetimesMap& known_lifetimes) {
47 // Note that this cannot be a simple .find() on the map because `decl` might
48 // be a builtin.
49 bool is_builtin = decl->getBuiltinID() != 0;
50 if (is_builtin) {
51 return GetBuiltinLifetimes(decl);
52 }
53 if (!known_lifetimes.count(decl->getCanonicalDecl())) {
54 return FunctionAnalysisError(
55 absl::StrCat("Unknown callee ", decl->getNameAsString()));
56 }
57 return known_lifetimes.lookup(decl->getCanonicalDecl());
58}
59
Luca Versari99fddff2022-05-25 10:22:32 -070060class ObjectRepository::VarDeclVisitor
61 : public clang::RecursiveASTVisitor<VarDeclVisitor> {
62 public:
Luca Versaria12c9d52023-02-23 08:40:48 -080063 explicit VarDeclVisitor(ObjectRepository& object_repository,
64 const FunctionLifetimesMap& callee_lifetimes)
65 : object_repository_(object_repository),
66 callee_lifetimes_(callee_lifetimes) {}
Luca Versari99fddff2022-05-25 10:22:32 -070067
68 // We need to visit implicitly-defined constructors and assignment operators.
69 bool shouldVisitImplicitCode() { return true; }
70
71 bool VisitVarDecl(clang::VarDecl* var) {
72 // Add objects for any local variables declared in this function.
73 AddObjectForVar(var);
74 return true;
75 }
76
77 bool VisitReturnStmt(clang::ReturnStmt* stmt) {
78 const clang::Expr* expr = stmt->getRetValue();
79 if (IsInitExprInitializingARecordObject(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -070080 PropagateResultObject(expr, object_repository_.return_object_);
Luca Versari99fddff2022-05-25 10:22:32 -070081 }
82 return true;
83 }
84
85 bool VisitMemberExpr(clang::MemberExpr* member) {
86 if (auto* method =
87 clang::dyn_cast<clang::CXXMethodDecl>(member->getMemberDecl());
88 method && method->isStatic()) {
89 // Create objects for static member functions.
90 AddObjectForFunc(method);
91 }
92 return true;
93 }
94
95 bool VisitDeclRefExpr(clang::DeclRefExpr* decl_ref) {
96 // Add objects for any global variables referenced in this function.
97 // This also runs for local variables, but we don't have to treat those
98 // differently as AddObjectForVar() protects against duplication.
99 if (auto* var_decl = clang::dyn_cast<clang::VarDecl>(decl_ref->getDecl())) {
100 AddObjectForVar(var_decl);
101 }
102 // Add objects for any function referenced in this function.
103 if (auto* function_decl =
104 clang::dyn_cast<clang::FunctionDecl>(decl_ref->getDecl())) {
105 AddObjectForFunc(function_decl);
106 }
107 return true;
108 }
109
110 bool VisitObjCMessageExpr(clang::ObjCMessageExpr* msg_expr) {
111 // ObjCMessageExpr is an initializer expression terminator, so we should
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700112 // have walked down from the result object to find its terminating
113 // expressions, which should have found this expression and connected it to
114 // that object already.
115 if (!object_repository_.result_objects_.count(msg_expr)) {
Luca Versari99fddff2022-05-25 10:22:32 -0700116 msg_expr->dump();
117 llvm::report_fatal_error(
118 "Missing initializer for ObjCMessageExpr, we did not record it "
119 "when we visited something earlier in the tree yet?");
120 }
121 return true;
122 }
123
124 // Create objects for function call arguments.
125 bool VisitCallExpr(clang::CallExpr* call_expr) {
126 if (IsInitExprInitializingARecordObject(call_expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700127 assert(ResultObjectWasPropagatedTo(call_expr));
Luca Versari99fddff2022-05-25 10:22:32 -0700128 }
129
Luca Versariefeaf272023-01-16 10:19:28 -0800130 FunctionLifetimeFactorySingleCallback lifetime_factory(
131 [](auto) { return Lifetime::CreateVariable(); });
132
133 // If we have a direct callee, construct a FunctionLifetimes out of the
134 // function/method definition.
135 if (auto callee = call_expr->getDirectCallee()) {
136 bool is_operator_call = clang::isa<clang::CXXOperatorCallExpr>(call_expr);
137 bool is_method = clang::isa<clang::CXXMethodDecl>(callee);
138 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
139 FunctionLifetimes::CreateForDecl(callee, lifetime_factory).get();
140 PrepareFunctionCall(
141 call_expr, /*index_shift=*/is_operator_call && is_method ? 1 : 0);
Luca Versari99fddff2022-05-25 10:22:32 -0700142 } else {
143 // Always a function pointer.
Luca Versariefeaf272023-01-16 10:19:28 -0800144 // TODO(veluca): pointers-to-members are not supported (yet?)
145 clang::QualType callee_type =
146 call_expr->getCallee()->getType()->getPointeeType().IgnoreParens();
147 // TODO(veluca): what about FunctionNoProtoType??
148 object_repository_.call_expr_virtual_lifetimes_[call_expr] =
149 FunctionLifetimes::CreateForFunctionType(
150 clang::cast<clang::FunctionProtoType>(callee_type),
151 lifetime_factory)
152 .get();
153 PrepareFunctionCall(call_expr, /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700154 }
155
156 return true;
157 }
158
Luca Versaria12c9d52023-02-23 08:40:48 -0800159 bool VisitStringLiteral(clang::StringLiteral* lit_expr) {
160 object_repository_.string_literal_object_ = object_repository_.CreateObject(
161 lit_expr->getType(), Lifetime::Static(),
162 [](const clang::Expr*) { return Lifetime::Static(); });
163 return true;
164 }
165
Luca Versari99fddff2022-05-25 10:22:32 -0700166 bool VisitCXXConstructExpr(clang::CXXConstructExpr* construct_expr) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700167 assert(ResultObjectWasPropagatedTo(construct_expr));
Luca Versari99fddff2022-05-25 10:22:32 -0700168
Luca Versariefeaf272023-01-16 10:19:28 -0800169 FunctionLifetimeFactorySingleCallback lifetime_factory(
170 [](auto) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700171 const clang::FunctionDecl* constructor = construct_expr->getConstructor();
Luca Versariefeaf272023-01-16 10:19:28 -0800172 object_repository_.call_expr_virtual_lifetimes_[construct_expr] =
173 FunctionLifetimes::CreateForDecl(constructor, lifetime_factory).get();
174 PrepareFunctionCall(construct_expr,
175 /*index_shift=*/0);
Luca Versari99fddff2022-05-25 10:22:32 -0700176 return true;
177 }
178
179 bool VisitInitListExpr(clang::InitListExpr* init_list_expr) {
180 // We only want to visit in Semantic form, we ignore Syntactic form.
181 if (IsInitExprInitializingARecordObject(init_list_expr) &&
182 init_list_expr->isSemanticForm() && !init_list_expr->isTransparent()) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700183 assert(ResultObjectWasPropagatedTo(init_list_expr));
Luca Versari99fddff2022-05-25 10:22:32 -0700184 }
185 return true;
186 }
187
188 bool VisitMaterializeTemporaryExpr(
189 clang::MaterializeTemporaryExpr* temporary_expr) {
190 object_repository_.temporary_objects_[temporary_expr] =
191 AddTemporaryObjectForExpression(temporary_expr->getSubExpr());
192 return true;
193 }
194
195 bool VisitCompoundStmt(clang::CompoundStmt* compound) {
196 // Create temporary objects for any top-level `CXXTemporaryObjectExpr`s,
197 // i.e. ones that are used as statements.
198 for (clang::Stmt* stmt : compound->body()) {
199 if (auto* temporary = clang::dyn_cast<CXXTemporaryObjectExpr>(stmt)) {
200 AddTemporaryObjectForExpression(temporary);
201 }
202 }
203 return true;
204 }
205
Luca Versariefeaf272023-01-16 10:19:28 -0800206 void PrepareFunctionCall(const clang::Expr* expr, size_t index_shift) {
207 const auto& func_lifetimes =
208 object_repository_.call_expr_virtual_lifetimes_[expr];
209 auto make_object = [this](const ValueLifetimes& lifetime) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800210 return object_repository_.CreateObject(
211 ObjectLifetimes(Lifetime::CreateLocal(), lifetime),
212 object_repository_.initial_points_to_map_);
Luca Versariefeaf272023-01-16 10:19:28 -0800213 };
214 for (size_t i = 0; i < func_lifetimes.GetNumParams(); ++i) {
Luca Versari99fddff2022-05-25 10:22:32 -0700215 object_repository_
216 .call_expr_args_objects_[std::make_pair(expr, i + index_shift)] =
Luca Versariefeaf272023-01-16 10:19:28 -0800217 make_object(func_lifetimes.GetParamLifetimes(i));
Luca Versari99fddff2022-05-25 10:22:32 -0700218 }
Luca Versariefeaf272023-01-16 10:19:28 -0800219 if (func_lifetimes.IsNonStaticMethod()) {
220 object_repository_.call_expr_this_pointers_[expr] =
221 make_object(func_lifetimes.GetThisLifetimes());
222 }
223 object_repository_.call_expr_ret_objects_[expr] =
224 make_object(func_lifetimes.GetReturnLifetimes());
Luca Versari99fddff2022-05-25 10:22:32 -0700225 }
226
227 void AddObjectForVar(clang::VarDecl* var) {
228 if (object_repository_.object_repository_.count(var)) {
229 return;
230 }
231
232 Lifetime lifetime;
233 LifetimeFactory lifetime_factory;
234
235 switch (var->getStorageClass()) {
236 case clang::SC_Extern:
237 case clang::SC_Static:
238 case clang::SC_PrivateExtern:
239 lifetime = Lifetime::Static();
Martin Brænne03d93302022-06-23 00:23:38 -0700240 lifetime_factory = [](const clang::Expr*) {
241 return Lifetime::Static();
242 };
Luca Versari99fddff2022-05-25 10:22:32 -0700243 break;
244 default:
245 lifetime = Lifetime::CreateLocal();
Martin Brænne03d93302022-06-23 00:23:38 -0700246 lifetime_factory = [](const clang::Expr*) {
247 return Lifetime::CreateVariable();
248 };
Luca Versari99fddff2022-05-25 10:22:32 -0700249 break;
250 }
251
Luca Versaria12c9d52023-02-23 08:40:48 -0800252 const Object* object = object_repository_.CreateObject(
253 var->getType(), lifetime, lifetime_factory);
Luca Versari99fddff2022-05-25 10:22:32 -0700254
Martin Brænnee9a4a472022-07-01 02:26:55 -0700255 object_repository_.object_repository_[var] = object;
Luca Versari53a2f582023-01-16 10:09:29 -0800256 if (!var->getType()->isArrayType()) {
257 object_repository_.initial_single_valued_objects_.Add(object);
258 }
Luca Versari99fddff2022-05-25 10:22:32 -0700259
260 // Remember the original value of function parameters.
261 if (auto parm_var_decl = clang::dyn_cast<const clang::ParmVarDecl>(var)) {
262 object_repository_.initial_parameter_object_[parm_var_decl] =
263 object_repository_.CloneObject(object);
264 }
265
266 if (var->hasInit() && var->getType()->isRecordType()) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700267 PropagateResultObject(var->getInit(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700268 }
269 }
270
271 void AddObjectForFunc(clang::FunctionDecl* func) {
272 if (object_repository_.object_repository_.count(func)) {
273 return;
274 }
275
Luca Versaria12c9d52023-02-23 08:40:48 -0800276 FunctionLifetimesOrError func_lifetimes =
277 GetFunctionLifetimes(func, callee_lifetimes_);
278 if (std::holds_alternative<FunctionAnalysisError>(func_lifetimes)) {
279 error_ = "No lifetimes for callee '" + func->getNameAsString() +
280 "': " + std::get<FunctionAnalysisError>(func_lifetimes).message;
281 } else {
282 object_repository_.object_repository_[func] =
283 object_repository_.ConstructObject(
284 Lifetime::Static(), func->getType(),
285 std::get<FunctionLifetimes>(func_lifetimes));
286 }
Luca Versari99fddff2022-05-25 10:22:32 -0700287 }
288
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700289 const Object* AddTemporaryObjectForExpression(clang::Expr* expr) {
Luca Versari99fddff2022-05-25 10:22:32 -0700290 clang::QualType type = expr->getType().getCanonicalType();
Luca Versaria12c9d52023-02-23 08:40:48 -0800291 const Object* object = object_repository_.CreateObject(
292 type, Lifetime::CreateLocal(),
293 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700294
295 if (type->isRecordType()) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700296 PropagateResultObject(expr, object);
Luca Versari99fddff2022-05-25 10:22:32 -0700297 }
298 return object;
299 }
300
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700301 // Propagates a result object `object` of record type to the expressions that
302 // actually perform the initialization (we call these "terminating
303 // expressions").
Luca Versari99fddff2022-05-25 10:22:32 -0700304 //
305 // `expr` is the initializer for a variable; this will contain one or
306 // several terminating expressions (such as a CXXConstructExpr, InitListExpr,
307 // or CallExpr).
308 //
309 // Note that not all terminating expressions below `expr` necessarily
310 // initialize `object`; some of these terminating expressions may also
311 // initialize temporary objects. This function takes care to propagate
312 // `object` only to the appropriate terminating expressions.
313 //
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700314 // The mapping from a terminating expression to the result object it
315 // initializes is stored in `object_repository_.result_objects_`.
316 void PropagateResultObject(const clang::Expr* expr, const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700317 // TODO(danakj): Use StmtVisitor to implement this method.
Luca Versari99fddff2022-05-25 10:22:32 -0700318
319 // Terminating expressions. Expressions that don't initialize a record
320 // object can not be such, and their existence is unexpected as we should
321 // be converting to and initializing a record object from such expressions
322 // further up in the initializer expression's AST. We will assert later in
323 // this function if we find this situation somehow due to incorrect
324 // expectations in this comment.
325 if (IsInitExprInitializingARecordObject(expr)) {
326 if (clang::isa<clang::CXXConstructExpr>(expr) ||
327 clang::isa<clang::CallExpr>(expr) ||
328 clang::isa<clang::ObjCMessageExpr>(expr) ||
329 clang::isa<clang::LambdaExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700330 object_repository_.result_objects_[expr] = object;
Luca Versari99fddff2022-05-25 10:22:32 -0700331 return;
332 }
333 if (auto* e = clang::dyn_cast<clang::InitListExpr>(expr)) {
334 if (!e->isSemanticForm()) return;
335 if (e->isTransparent()) {
336 // A field initializer like `S s{cond ? S{} : S{}}` is considered
337 // transparent, and the actual initializer is within.
338 for (const clang::Expr* init : e->inits()) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700339 PropagateResultObject(init, object);
Luca Versari99fddff2022-05-25 10:22:32 -0700340 }
341 } else {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700342 object_repository_.result_objects_[e] = object;
Luca Versari99fddff2022-05-25 10:22:32 -0700343 }
344 return;
345 }
346 }
347
348 // Expressions to walk through. Logic is similar to the AggExprEmitter in
349 // clang third_party/llvm-project/clang/lib/CodeGen/CGExprAgg.cpp though we
350 // don't have to visit all the sub-expressions that clang codegen needs to,
351 // as we can stop at terminating expressions and ignore many expressions
352 // that don't occur in the code we're analyzing.
353 if (auto* e = clang::dyn_cast<clang::ParenExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700354 PropagateResultObject(e->getSubExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700355 return;
356 }
357 if (auto* e = clang::dyn_cast<clang::UnaryOperator>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700358 PropagateResultObject(e->getSubExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700359 return;
360 }
361 if (auto* e = clang::dyn_cast<clang::SubstNonTypeTemplateParmExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700362 PropagateResultObject(e->getReplacement(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700363 return;
364 }
365 if (auto* e = clang::dyn_cast<clang::CastExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700366 PropagateResultObject(e->getSubExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700367 return;
368 }
369 if (auto* e = clang::dyn_cast<clang::CXXDefaultArgExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700370 PropagateResultObject(e->getExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700371 return;
372 }
373 if (auto* e = clang::dyn_cast<clang::CXXDefaultInitExpr>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700374 PropagateResultObject(e->getExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700375 return;
376 }
377 if (auto* e = clang::dyn_cast<clang::ExprWithCleanups>(expr)) {
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700378 PropagateResultObject(e->getSubExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700379 return;
380 }
381
382 // Expressions that produce a temporary object.
383 if (auto* e = clang::dyn_cast<clang::BinaryOperator>(expr)) {
384 if (e->isCommaOp()) {
385 AddTemporaryObjectForExpression(e->getLHS());
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700386 PropagateResultObject(e->getRHS(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700387 return;
388 }
389
390 // Any other binary operator should not produce a record type, it would be
391 // used to construct a record further up the AST, so we should not arrive
392 // here.
393 expr->dump();
394 llvm::report_fatal_error(
395 "Unexpected binary operator in initializer expression tree");
396 }
397 if (auto* e = clang::dyn_cast<clang::AbstractConditionalOperator>(expr)) {
398 AddTemporaryObjectForExpression(e->getCond());
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700399 PropagateResultObject(e->getTrueExpr(), object);
400 PropagateResultObject(e->getFalseExpr(), object);
Luca Versari99fddff2022-05-25 10:22:32 -0700401 return;
402 }
403
404 expr->dump();
405 llvm::report_fatal_error(
406 "Unexpected expression in initializer expression tree");
407 }
408
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700409 bool ResultObjectWasPropagatedTo(clang::Expr* terminating_expr) {
Luca Versari99fddff2022-05-25 10:22:32 -0700410 // An expression that initializes an object should have already been
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700411 // connected to the result object it initializes. We should have walked down
412 // from the result object to find its terminating expressions.
413 if (!object_repository_.result_objects_.count(terminating_expr)) {
414 llvm::errs() << "Missing result object for terminating expression, "
Luca Versari99fddff2022-05-25 10:22:32 -0700415 "we did not record it when we visited something earlier "
416 "in the tree yet?\n";
417 terminating_expr->dump();
418 return false;
419 } else {
420 return true;
421 }
422 }
423
424 void TraverseCXXMemberInitializers(
425 const clang::CXXConstructorDecl* constructor) {
426 // For constructors, we also need to create lifetimes for variables
427 // referenced by in-class member initializers; the visitor by default only
428 // visits expressions in the initializer list.
429 // We also need to associate member initializers with the members they
430 // initialize.
431 for (const auto* init : constructor->inits()) {
432 const auto* init_expr = init->getInit();
433 if (const auto* default_init =
434 clang::dyn_cast<clang::CXXDefaultInitExpr>(init_expr)) {
435 init_expr = default_init->getExpr();
436 }
437
438 if (init->getMember() && init->getMember()->getType()->isRecordType()) {
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ænne46f1a572022-07-01 02:07:07 -0700443 const Object* field_object =
Martin Brænne1b98ac62022-07-01 06:24:52 -0700444 object_repository_.GetFieldObject(*this_object, init->getMember());
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700445 PropagateResultObject(init_expr, field_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700446 } else if (init->getBaseClass()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700447 std::optional<const Object*> this_object =
448 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700449 assert(this_object.has_value());
450
Martin Brænnee08ac882022-07-01 02:24:49 -0700451 const Object* base_object = object_repository_.GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700452 *this_object, init->getBaseClass());
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700453 PropagateResultObject(init_expr, base_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700454 }
455
456 // Traverse after finishing with the outer expression, including
457 // connecting the initializer (constructor) to its object.
458 TraverseStmt(const_cast<clang::Expr*>(init_expr));
459 }
460 }
461
462 ObjectRepository& object_repository_;
Luca Versaria12c9d52023-02-23 08:40:48 -0800463 const FunctionLifetimesMap& callee_lifetimes_;
464 std::optional<std::string> error_;
Luca Versari99fddff2022-05-25 10:22:32 -0700465};
466
Luca Versaria12c9d52023-02-23 08:40:48 -0800467llvm::Expected<ObjectRepository> ObjectRepository::Create(
468 const clang::FunctionDecl* func,
469 const llvm::DenseMap<const clang::FunctionDecl*, FunctionLifetimesOrError>&
470 callee_lifetimes) {
471 ObjectRepository object_repository;
Luca Versari99fddff2022-05-25 10:22:32 -0700472 const auto* method_decl = clang::dyn_cast<clang::CXXMethodDecl>(func);
473
474 const auto* definition = func->getDefinition();
475 assert(definition || (method_decl && method_decl->isPure()));
476 if (definition) func = definition;
Luca Versaria12c9d52023-02-23 08:40:48 -0800477 object_repository.func_ = func;
Luca Versari99fddff2022-05-25 10:22:32 -0700478
Luca Versaria12c9d52023-02-23 08:40:48 -0800479 object_repository.return_object_ = object_repository.CreateObject(
480 func->getReturnType(), Lifetime::CreateVariable(),
481 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700482
483 if (method_decl) {
484 if (!method_decl->isStatic()) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800485 object_repository.this_object_ = object_repository.CreateObject(
Googler05175972023-10-04 15:19:16 -0700486 method_decl->getFunctionObjectParameterType(),
487 Lifetime::CreateVariable(),
Luca Versaricd873a62023-01-18 13:45:08 -0800488 [](const clang::Expr*) { return Lifetime::CreateVariable(); });
Luca Versari99fddff2022-05-25 10:22:32 -0700489 }
490 }
491
Luca Versaria12c9d52023-02-23 08:40:48 -0800492 VarDeclVisitor decl_visitor(object_repository, callee_lifetimes);
Luca Versari99fddff2022-05-25 10:22:32 -0700493 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
494 decl_visitor.TraverseCXXMemberInitializers(constructor);
495 }
496 decl_visitor.TraverseFunctionDecl(const_cast<clang::FunctionDecl*>(func));
Luca Versaria12c9d52023-02-23 08:40:48 -0800497
498 if (decl_visitor.error_.has_value()) {
499 return llvm::createStringError(llvm::inconvertibleErrorCode(),
500 *decl_visitor.error_);
501 }
502 return object_repository;
Luca Versari99fddff2022-05-25 10:22:32 -0700503}
504
505std::string ObjectRepository::DebugString() const {
506 std::string result;
507 llvm::raw_string_ostream os(result);
508
509 if (this_object_) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700510 os << "This " << (*this_object_)->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700511 }
512 for (const auto& [decl, object] : object_repository_) {
513 os << decl->getDeclKindName() << " " << decl << " (";
514 decl->printName(os);
Martin Brænnee9a4a472022-07-01 02:26:55 -0700515 os << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700516 }
517 for (const auto& [expr_i, object] : call_expr_args_objects_) {
518 const auto& [expr, i] = expr_i;
519 os << "Call " << expr << " (arg " << i
Martin Brænne982a1152022-07-01 01:55:53 -0700520 << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700521 }
522 for (const auto& [expr, object] : call_expr_this_pointers_) {
Martin Brænne982a1152022-07-01 01:55:53 -0700523 os << "Call " << expr << " (this) pointer: " << object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700524 << "\n";
525 }
526 os << "InitialPointsToMap:\n" << initial_points_to_map_.DebugString() << "\n";
527 for (const auto& [field, object] : field_object_map_) {
528 os << "Field '";
Googler07e55d02023-08-24 20:27:25 -0700529 field.second->printName(os, field.second->getASTContext().getPrintingPolicy());
Luca Versarid430c3f2022-08-22 02:10:31 -0700530 os << "' on " << field.first->DebugString()
531 << " object: " << object->DebugString() << "\n";
532 }
533 for (const auto& [base, object] : base_object_map_) {
534 os << "Base of type " << clang::QualType(base.second, 0).getAsString()
535 << " of " << base.first->DebugString()
Martin Brænneb6764af2022-07-01 02:01:49 -0700536 << " object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700537 }
Martin Brænne04fb3a42022-07-01 01:52:21 -0700538 os << "Return " << return_object_->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700539 os.flush();
540 return result;
541}
542
Martin Brænne46b5f072022-07-01 02:29:16 -0700543const Object* ObjectRepository::GetDeclObject(
544 const clang::ValueDecl* decl) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700545 auto iter = object_repository_.find(decl);
546 if (iter == object_repository_.end()) {
547 llvm::errs() << "Didn't find object for Decl:\n";
548 decl->dump();
549 llvm::errs() << "\n" << DebugString();
550 llvm::report_fatal_error("Didn't find object for Decl");
551 }
Martin Brænne46b5f072022-07-01 02:29:16 -0700552 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700553}
554
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700555const Object* ObjectRepository::GetTemporaryObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700556 const clang::MaterializeTemporaryExpr* expr) const {
557 auto iter = temporary_objects_.find(expr);
558 if (iter == temporary_objects_.end()) {
559 llvm::errs() << "Didn't find object for temporary expression:\n";
560 expr->dump();
561 llvm::errs() << "\n" << DebugString();
562 llvm::report_fatal_error("Didn't find object for temporary expression");
563 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700564 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700565}
566
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700567const Object* ObjectRepository::GetOriginalParameterValue(
Luca Versari99fddff2022-05-25 10:22:32 -0700568 const clang::ParmVarDecl* var_decl) const {
569 auto iter = initial_parameter_object_.find(var_decl);
570 if (iter == initial_parameter_object_.end()) {
571 llvm::errs() << "Didn't find caller object for parameter:\n";
572 var_decl->dump();
573 llvm::errs() << "\n" << DebugString();
574 llvm::report_fatal_error("Didn't find caller object for parameter");
575 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700576 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700577}
578
Luca Versari91a56ff2022-08-22 01:58:33 -0700579FunctionLifetimes ObjectRepository::GetOriginalFunctionLifetimes() const {
580 FunctionLifetimes ret;
581 auto get_initial_lifetimes_or_die = [&](const Object* object) {
582 auto iter = initial_object_lifetimes_.find(object);
583 if (iter == initial_object_lifetimes_.end()) {
584 llvm::errs() << "Didn't find lifetimes for object "
585 << object->DebugString();
586 llvm::report_fatal_error("Didn't find lifetimes for object");
587 }
588 return iter->second;
589 };
590 ret.return_lifetimes_ =
591 get_initial_lifetimes_or_die(GetReturnObject()).GetValueLifetimes();
592 if (this_object_.has_value()) {
593 ret.this_lifetimes_ = ValueLifetimes::PointerTo(
594 clang::dyn_cast<clang::CXXMethodDecl>(func_)->getThisType(),
595 get_initial_lifetimes_or_die(*this_object_));
596 }
597 ret.param_lifetimes_.reserve(func_->getNumParams());
598 for (size_t i = 0; i < func_->getNumParams(); i++) {
599 ret.param_lifetimes_.push_back(
600 get_initial_lifetimes_or_die(
601 GetOriginalParameterValue(func_->getParamDecl(i)))
602 .GetValueLifetimes());
603 }
604 if (!ret.IsValidForDecl(func_)) {
605 llvm::errs() << "Internal error: did not produce valid function lifetimes";
606 llvm::report_fatal_error(
607 "Internal error: did not produce valid function lifetimes");
608 }
609 return ret;
610}
611
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700612const Object* ObjectRepository::GetCallExprArgumentObject(
613 const clang::CallExpr* expr, size_t arg_index) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700614 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
615 if (iter == call_expr_args_objects_.end()) {
616 llvm::errs() << "Didn't find object for argument " << arg_index
617 << " of call:\n";
618 expr->dump();
619 llvm::errs() << "\n" << DebugString();
620 llvm::report_fatal_error("Didn't find object for argument");
621 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700622 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700623}
624
Luca Versariefeaf272023-01-16 10:19:28 -0800625const Object* ObjectRepository::GetCallExprRetObject(
626 const clang::Expr* expr) const {
627 auto iter = call_expr_ret_objects_.find(expr);
628 if (iter == call_expr_ret_objects_.end()) {
629 llvm::errs() << "Didn't find object for return value of call:\n";
630 expr->dump();
631 llvm::errs() << "\n" << DebugString();
632 llvm::report_fatal_error("Didn't find object for return value");
633 }
634 return iter->second;
635}
636
637const FunctionLifetimes& ObjectRepository::GetCallExprVirtualLifetimes(
638 const clang::Expr* expr) const {
639 auto iter = call_expr_virtual_lifetimes_.find(expr);
640 if (iter == call_expr_virtual_lifetimes_.end()) {
641 llvm::errs() << "Didn't find object for return value of call:\n";
642 expr->dump();
643 llvm::errs() << "\n" << DebugString();
644 llvm::report_fatal_error("Didn't find object for return value");
645 }
646 return iter->second;
647}
648
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700649const Object* ObjectRepository::GetCallExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700650 const clang::CallExpr* expr) const {
651 auto iter = call_expr_this_pointers_.find(expr);
652 if (iter == call_expr_this_pointers_.end()) {
653 llvm::errs() << "Didn't find `this` object for call:\n";
654 expr->dump();
655 llvm::errs() << "\n" << DebugString();
656 llvm::report_fatal_error("Didn't find `this` object for call");
657 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700658 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700659}
660
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700661const Object* ObjectRepository::GetCXXConstructExprArgumentObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700662 const clang::CXXConstructExpr* expr, size_t arg_index) const {
663 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
664 if (iter == call_expr_args_objects_.end()) {
665 llvm::errs() << "Didn't find object for argument " << arg_index
666 << " of constructor call:\n";
667 expr->dump();
668 llvm::errs() << "\n" << DebugString();
669 llvm::report_fatal_error(
670 "Didn't find object for argument of constructor call");
671 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700672 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700673}
674
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700675const Object* ObjectRepository::GetCXXConstructExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700676 const clang::CXXConstructExpr* expr) const {
677 auto iter = call_expr_this_pointers_.find(expr);
678 if (iter == call_expr_this_pointers_.end()) {
679 llvm::errs() << "Didn't find `this` object for constructor:\n";
680 expr->dump();
681 llvm::errs() << "\n" << DebugString();
682 llvm::report_fatal_error("Didn't find `this` object for constructor");
683 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700684 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700685}
686
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700687const Object* ObjectRepository::GetResultObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700688 const clang::Expr* initializer_expr) const {
689 assert(clang::isa<clang::CXXConstructExpr>(initializer_expr) ||
690 clang::isa<clang::InitListExpr>(initializer_expr) ||
691 clang::isa<clang::CallExpr>(initializer_expr));
692
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700693 auto iter = result_objects_.find(initializer_expr);
694 if (iter == result_objects_.end()) {
695 llvm::errs() << "Didn't find result object for initializer:\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700696 initializer_expr->dump();
697 llvm::errs() << "\n" << DebugString();
Martin Brænne7b0a9d12023-07-10 06:07:50 -0700698 llvm::report_fatal_error("Didn't find result object for initializer");
Luca Versari99fddff2022-05-25 10:22:32 -0700699 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700700 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700701}
702
Martin Brænne46f1a572022-07-01 02:07:07 -0700703const Object* ObjectRepository::GetFieldObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700704 const Object* struct_object, const clang::FieldDecl* field) const {
Martin Brænne46f1a572022-07-01 02:07:07 -0700705 std::optional<const Object*> field_object =
Luca Versari99fddff2022-05-25 10:22:32 -0700706 GetFieldObjectInternal(struct_object, field);
707 if (!field_object.has_value()) {
708 llvm::errs() << "On an object of type "
Martin Brænne1b98ac62022-07-01 06:24:52 -0700709 << struct_object->Type().getAsString()
Luca Versari99fddff2022-05-25 10:22:32 -0700710 << ", trying to get field:\n";
711 field->dump();
712 llvm::errs() << "\n" << DebugString();
713 llvm::report_fatal_error("Didn't find field object");
714 }
715 return *field_object;
716}
717
718ObjectSet ObjectRepository::GetFieldObject(
719 const ObjectSet& struct_objects, const clang::FieldDecl* field) const {
720 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700721 for (const Object* object : struct_objects) {
722 ret.Add(GetFieldObject(object, field));
Luca Versari99fddff2022-05-25 10:22:32 -0700723 }
724 return ret;
725}
726
Martin Brænnee08ac882022-07-01 02:24:49 -0700727const Object* ObjectRepository::GetBaseClassObject(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700728 const Object* struct_object, const clang::Type* base) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700729 base = base->getCanonicalTypeInternal().getTypePtr();
730 auto iter = base_object_map_.find(std::make_pair(struct_object, base));
731 if (iter == base_object_map_.end()) {
Martin Brænne1b98ac62022-07-01 06:24:52 -0700732 llvm::errs() << "On object " << struct_object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700733 << ", trying to get base:\n";
734 base->dump();
735 llvm::errs() << "\n" << DebugString();
736 llvm::report_fatal_error("Didn't find base object");
737 }
Martin Brænnee08ac882022-07-01 02:24:49 -0700738 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700739}
740
741ObjectSet ObjectRepository::GetBaseClassObject(const ObjectSet& struct_objects,
742 const clang::Type* base) const {
743 ObjectSet ret;
Martin Brænne4d8cdfd2022-07-01 06:16:36 -0700744 for (const Object* object : struct_objects) {
745 ret.Add(GetBaseClassObject(object, base));
Luca Versari99fddff2022-05-25 10:22:32 -0700746 }
747 return ret;
748}
749
Luca Versaricd873a62023-01-18 13:45:08 -0800750namespace {
751
752llvm::SmallVector<std::string> GetFieldLifetimeArguments(
753 const clang::FieldDecl* field) {
754 // TODO(mboehme): Report errors as Clang diagnostics, not through
755 // llvm::report_fatal_error().
756
757 const clang::AnnotateAttr* member_lifetimes_attr = nullptr;
758 for (auto annotate : field->specific_attrs<clang::AnnotateAttr>()) {
759 if (annotate->getAnnotation() == "member_lifetimes") {
760 if (member_lifetimes_attr) {
761 llvm::report_fatal_error("repeated lifetime annotation");
762 }
763 member_lifetimes_attr = annotate;
764 }
765 }
766 if (!member_lifetimes_attr) {
767 return {};
768 }
769
770 llvm::SmallVector<std::string> ret;
771 for (const auto& arg : member_lifetimes_attr->args()) {
772 llvm::StringRef lifetime;
773 if (llvm::Error err = EvaluateAsStringLiteral(arg, field->getASTContext())
774 .moveInto(lifetime)) {
775 llvm::report_fatal_error(llvm::StringRef(toString(std::move(err))));
776 }
777 ret.push_back(lifetime.str());
778 }
779
780 return ret;
781}
782
783template <typename CallbackField, typename CallackBase>
784void ForEachFieldAndBase(clang::QualType record_type,
785 const ObjectLifetimes& object_lifetimes,
786 const CallbackField& callback_field,
787 const CallackBase& callback_base) {
788 assert(record_type->isRecordType());
789 for (clang::FieldDecl* f :
790 record_type->getAs<clang::RecordType>()->getDecl()->fields()) {
791 ObjectLifetimes field_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
792 f->getType(), GetFieldLifetimeArguments(f));
793 callback_field(field_lifetimes, f);
794 }
795 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
796 record_type->getAs<clang::RecordType>()->getDecl())) {
797 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
798 clang::QualType base_type = base.getType();
799 auto base_object_lifetimes = object_lifetimes.GetFieldOrBaseLifetimes(
800 base_type, GetLifetimeParameters(base_type));
801 callback_base(base_object_lifetimes, &*base_type.getCanonicalType());
802 ForEachFieldAndBase(base.getType(), base_object_lifetimes, callback_field,
803 callback_base);
804 }
805 }
806}
807
808} // namespace
809
Dmitri Gribenkoa6c5d732023-08-01 00:30:20 -0700810class ObjectRepository::ObjectCreator {
811 public:
Luca Versaricd873a62023-01-18 13:45:08 -0800812 ObjectCreator(ObjectRepository& object_repository, PointsToMap& points_to_map)
813 : object_repository_(object_repository), points_to_map_(points_to_map) {}
814
Luca Versaricd873a62023-01-18 13:45:08 -0800815 const Object* CreateObjectsRecursively(
816 const ObjectLifetimes& object_lifetimes) {
817 if (auto it = object_cache_.find(object_lifetimes);
818 it != object_cache_.end()) {
819 return it->second;
820 }
Luca Versaria12c9d52023-02-23 08:40:48 -0800821
822 const clang::QualType type = object_lifetimes.Type();
823 const ValueLifetimes& value_lifetimes =
824 object_lifetimes.GetValueLifetimes();
825
826 std::optional<FunctionLifetimes> function_lifetimes;
827
828 if (type->getAs<clang::FunctionType>()) {
829 function_lifetimes = value_lifetimes.GetFuncLifetimes();
830 }
831
832 const Object* obj = object_repository_.ConstructObject(
833 object_lifetimes.GetLifetime(), object_lifetimes.Type(),
834 function_lifetimes);
Luca Versaricd873a62023-01-18 13:45:08 -0800835 object_cache_[object_lifetimes] = obj;
836
Luca Versaria12c9d52023-02-23 08:40:48 -0800837 object_repository_.initial_object_lifetimes_[obj] = object_lifetimes;
838
839 if (type->isIncompleteType()) {
840 // Nothing we can do.
841 return obj;
842 }
843
844 // Pointer type.
845 if (!PointeeType(type).isNull()) {
846 points_to_map_.ExtendPointerPointsToSet(
847 obj,
848 {CreateObjectsRecursively(value_lifetimes.GetPointeeLifetimes())});
849 return obj;
850 }
851
852 // Record type.
853 if (type->getAs<clang::RecordType>()) {
854 ForEachFieldAndBase(
855 type, object_lifetimes,
856 [this, obj](const ObjectLifetimes& field_lifetimes,
857 const clang::FieldDecl* f) {
858 const Object* field = CreateObjectsRecursively(field_lifetimes);
859 object_repository_.field_object_map_[std::make_pair(obj, f)] =
860 field;
861 },
862 [this, obj](const ObjectLifetimes& base_lifetimes,
863 const clang::Type* base_type) {
864 const Object* base_obj = CreateObjectsRecursively(base_lifetimes);
865 object_repository_
866 .base_object_map_[std::make_pair(obj, base_type)] = base_obj;
867 }
868
869 );
870 }
Luca Versaricd873a62023-01-18 13:45:08 -0800871
872 return obj;
873 }
874
Luca Versaria12c9d52023-02-23 08:40:48 -0800875 private:
Luca Versaricd873a62023-01-18 13:45:08 -0800876 ObjectRepository& object_repository_;
877 PointsToMap& points_to_map_;
878 // We re-use the same Object for all the sub-objects with the same type and
879 // lifetimes. This avoids infinite loops in the case of structs like lists.
880 llvm::DenseMap<ObjectLifetimes, const Object*> object_cache_;
881};
882
Luca Versaria12c9d52023-02-23 08:40:48 -0800883const Object* ObjectRepository::CreateObject(
884 const ObjectLifetimes& object_lifetimes, PointsToMap& points_to_map) {
Luca Versaricd873a62023-01-18 13:45:08 -0800885 ObjectCreator object_creator(*this, points_to_map);
Luca Versaria12c9d52023-02-23 08:40:48 -0800886 return object_creator.CreateObjectsRecursively(object_lifetimes);
Luca Versariefeaf272023-01-16 10:19:28 -0800887}
888
Luca Versaria12c9d52023-02-23 08:40:48 -0800889const Object* ObjectRepository::CreateObject(clang::QualType type,
890 Lifetime root_object_lifetime,
891 LifetimeFactory lifetime_factory) {
892 return CreateObject(
893 ObjectLifetimes(root_object_lifetime,
894 ValueLifetimes::Create(type, lifetime_factory).get()),
Luca Versaricd873a62023-01-18 13:45:08 -0800895 initial_points_to_map_);
Luca Versari99fddff2022-05-25 10:22:32 -0700896}
897
Luca Versaria12c9d52023-02-23 08:40:48 -0800898template <typename... Args>
899const Object* ObjectRepository::ConstructObject(Args&&... args) {
900 return new (object_allocator_.Allocate()) Object(args...);
901}
902
Luca Versari99fddff2022-05-25 10:22:32 -0700903// Clones an object and its base classes and fields, if any.
Martin Brænned8e32142022-07-01 01:54:41 -0700904const Object* ObjectRepository::CloneObject(const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700905 struct ObjectPair {
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700906 const Object* orig_object;
Martin Brænned8e32142022-07-01 01:54:41 -0700907 const Object* new_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700908 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700909 auto clone = [this](const Object* obj) {
Luca Versaria12c9d52023-02-23 08:40:48 -0800910 auto new_obj = ConstructObject(obj->GetLifetime(), obj->Type(),
911 obj->GetFuncLifetimes());
Luca Versari99fddff2022-05-25 10:22:32 -0700912 initial_points_to_map_.SetPointerPointsToSet(
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700913 new_obj, initial_points_to_map_.GetPointerPointsToSet(obj));
Luca Versari99fddff2022-05-25 10:22:32 -0700914 return new_obj;
915 };
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700916 const Object* new_root = clone(object);
Luca Versari91a56ff2022-08-22 01:58:33 -0700917 initial_object_lifetimes_[new_root] = initial_object_lifetimes_[object];
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700918 std::vector<ObjectPair> object_stack{{object, new_root}};
Luca Versari99fddff2022-05-25 10:22:32 -0700919 while (!object_stack.empty()) {
920 auto [orig_object, new_object] = object_stack.back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700921 assert(orig_object->Type() == new_object->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700922 object_stack.pop_back();
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700923 auto record_type = orig_object->Type()->getAs<clang::RecordType>();
Luca Versari99fddff2022-05-25 10:22:32 -0700924 if (!record_type) {
925 continue;
926 }
927
928 // Base classes.
929 if (auto* cxxrecord =
930 clang::dyn_cast<clang::CXXRecordDecl>(record_type->getDecl())) {
931 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700932 const Object* base_obj =
933 GetBaseClassObject(orig_object, base.getType());
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700934 const Object* new_base_obj = clone(base_obj);
Luca Versari99fddff2022-05-25 10:22:32 -0700935 base_object_map_[std::make_pair(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700936 new_object, base.getType().getCanonicalType().getTypePtr())] =
Martin Brænnea7ca8382022-07-01 02:03:10 -0700937 new_base_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700938 object_stack.push_back(ObjectPair{base_obj, new_base_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700939 }
940 }
941
942 // Fields.
943 for (auto f : record_type->getDecl()->fields()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700944 const Object* field_obj = GetFieldObject(orig_object, f);
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700945 const Object* new_field_obj = clone(field_obj);
Martin Brænne1b98ac62022-07-01 06:24:52 -0700946 field_object_map_[std::make_pair(new_object, f)] = new_field_obj;
Martin Brænne2a1b27a2022-07-01 06:17:32 -0700947 object_stack.push_back(ObjectPair{field_obj, new_field_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700948 }
949 }
950 return new_root;
951}
952
Martin Brænne46f1a572022-07-01 02:07:07 -0700953std::optional<const Object*> ObjectRepository::GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700954 const Object* struct_object, const clang::FieldDecl* field) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700955 auto iter = field_object_map_.find(std::make_pair(struct_object, field));
956 if (iter != field_object_map_.end()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700957 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700958 }
959 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700960 struct_object->Type()->getAs<clang::RecordType>()->getDecl())) {
Luca Versari99fddff2022-05-25 10:22:32 -0700961 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700962 std::optional<const Object*> field_object = GetFieldObjectInternal(
Martin Brænne1b98ac62022-07-01 06:24:52 -0700963 GetBaseClassObject(struct_object, base.getType()), field);
Luca Versari99fddff2022-05-25 10:22:32 -0700964 if (field_object.has_value()) {
965 return field_object;
966 }
967 }
968 }
969 return std::nullopt;
970}
971
972} // namespace lifetimes
973} // namespace tidy
974} // namespace clang