blob: 5327e58bb52d567ff8e37617b7c97c11af0037bf [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"
14#include "lifetime_analysis/visit_lifetimes.h"
15#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ænne04fb3a42022-07-01 01:52:21 -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
101 // For calls to members, the type of the callee is a "bound member function
102 // type", so we look at the declaration instead.
103 if (auto member_call =
104 clang::dyn_cast<clang::CXXMemberCallExpr>(call_expr)) {
105 const clang::FunctionDecl* callee = call_expr->getDirectCallee();
106 // TODO(veluca): pointers-to-members are not supported (yet?)
107 assert(callee);
108 AddObjectsForArguments(call_expr, callee->getType(),
109 /*index_shift=*/0);
110 auto method = clang::cast<clang::CXXMethodDecl>(callee);
111 clang::QualType type = method->getThisType();
112 object_repository_.call_expr_this_pointers_[call_expr] =
113 CreateLocalObject(type);
114 } else if (auto op_call =
115 clang::dyn_cast<clang::CXXOperatorCallExpr>(call_expr)) {
116 const clang::FunctionDecl* callee = call_expr->getDirectCallee();
117 auto method = clang::dyn_cast<clang::CXXMethodDecl>(callee);
118 AddObjectsForArguments(call_expr, callee->getType(),
119 /*index_shift=*/method ? 1 : 0);
120 if (method) {
121 clang::QualType type = method->getThisType();
122 object_repository_.call_expr_this_pointers_[call_expr] =
123 CreateLocalObject(type);
124 }
125 } else {
126 // Always a function pointer.
127 clang::QualType callee_type = call_expr->getCallee()->getType();
128 AddObjectsForArguments(call_expr, callee_type, /*index_shift=*/0);
129 }
130
131 return true;
132 }
133
134 bool VisitCXXConstructExpr(clang::CXXConstructExpr* construct_expr) {
135 assert(InitializedObjectWasPropagatedTo(construct_expr));
136
137 // Create objects for constructor arguments.
138 const clang::FunctionDecl* constructor = construct_expr->getConstructor();
139 AddObjectsForArguments(construct_expr, constructor->getType(),
140 /*index_shift=*/0);
141 clang::QualType type = construct_expr->getConstructor()->getThisType();
142 object_repository_.call_expr_this_pointers_[construct_expr] =
143 CreateLocalObject(type);
144 return true;
145 }
146
147 bool VisitInitListExpr(clang::InitListExpr* init_list_expr) {
148 // We only want to visit in Semantic form, we ignore Syntactic form.
149 if (IsInitExprInitializingARecordObject(init_list_expr) &&
150 init_list_expr->isSemanticForm() && !init_list_expr->isTransparent()) {
151 assert(InitializedObjectWasPropagatedTo(init_list_expr));
152 }
153 return true;
154 }
155
156 bool VisitMaterializeTemporaryExpr(
157 clang::MaterializeTemporaryExpr* temporary_expr) {
158 object_repository_.temporary_objects_[temporary_expr] =
159 AddTemporaryObjectForExpression(temporary_expr->getSubExpr());
160 return true;
161 }
162
163 bool VisitCompoundStmt(clang::CompoundStmt* compound) {
164 // Create temporary objects for any top-level `CXXTemporaryObjectExpr`s,
165 // i.e. ones that are used as statements.
166 for (clang::Stmt* stmt : compound->body()) {
167 if (auto* temporary = clang::dyn_cast<CXXTemporaryObjectExpr>(stmt)) {
168 AddTemporaryObjectForExpression(temporary);
169 }
170 }
171 return true;
172 }
173
Martin Brænne982a1152022-07-01 01:55:53 -0700174 const Object* CreateLocalObject(clang::QualType type) {
175 const Object* object =
176 object_repository_.CreateObject(Lifetime::CreateLocal(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700177 object_repository_.CreateObjects(
Martin Brænne982a1152022-07-01 01:55:53 -0700178 *object, type,
Martin Brænne03d93302022-06-23 00:23:38 -0700179 [](const clang::Expr*) { return Lifetime::CreateVariable(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700180 /*transitive=*/false);
181 return object;
182 }
183
184 void AddObjectsForArguments(const clang::Expr* expr,
185 clang::QualType callee_type, size_t index_shift) {
186 if (callee_type->isDependentType()) {
187 // TODO(veluca): the fact that we reach this point is a clang bug: it
188 // should not be possible to reach dependent types from a template
189 // instantiation. See also the following discussion, where richardsmith@
190 // agrees this looks like a Clang bug and suggests how it might be fixed:
191 // https://chat.google.com/room/AAAAb6i7WDQ/OvLC9NgO91A
192 return;
193 }
194 if (callee_type->isPointerType()) {
195 callee_type = callee_type->getPointeeType();
196 }
197 // TODO(veluca): figure out how to create a test where the callee is a
198 // ParenType.
199 // For reference, this was triggered in the implementation of `bsearch`.
200 callee_type = callee_type.IgnoreParens();
201 assert(callee_type->isFunctionType());
202 // TODO(veluca): could this be a clang::FunctionNoProtoType??
203 const auto* fn_type = clang::cast<clang::FunctionProtoType>(callee_type);
204 for (size_t i = 0; i < fn_type->getNumParams(); ++i) {
205 object_repository_
206 .call_expr_args_objects_[std::make_pair(expr, i + index_shift)] =
207 CreateLocalObject(fn_type->getParamType(i));
208 }
209 }
210
211 void AddObjectForVar(clang::VarDecl* var) {
212 if (object_repository_.object_repository_.count(var)) {
213 return;
214 }
215
216 Lifetime lifetime;
217 LifetimeFactory lifetime_factory;
218
219 switch (var->getStorageClass()) {
220 case clang::SC_Extern:
221 case clang::SC_Static:
222 case clang::SC_PrivateExtern:
223 lifetime = Lifetime::Static();
Martin Brænne03d93302022-06-23 00:23:38 -0700224 lifetime_factory = [](const clang::Expr*) {
225 return Lifetime::Static();
226 };
Luca Versari99fddff2022-05-25 10:22:32 -0700227 break;
228 default:
229 lifetime = Lifetime::CreateLocal();
Martin Brænne03d93302022-06-23 00:23:38 -0700230 lifetime_factory = [](const clang::Expr*) {
231 return Lifetime::CreateVariable();
232 };
Luca Versari99fddff2022-05-25 10:22:32 -0700233 break;
234 }
235
Martin Brænned8e32142022-07-01 01:54:41 -0700236 const Object* object =
237 object_repository_.CreateObject(lifetime, var->getType());
Luca Versari99fddff2022-05-25 10:22:32 -0700238
239 object_repository_.CreateObjects(
Martin Brænned8e32142022-07-01 01:54:41 -0700240 *object, var->getType(), lifetime_factory,
Luca Versari99fddff2022-05-25 10:22:32 -0700241 /*transitive=*/clang::isa<clang::ParmVarDecl>(var) ||
242 lifetime == Lifetime::Static());
243
Martin Brænned8e32142022-07-01 01:54:41 -0700244 object_repository_.object_repository_[var] = *object;
245 object_repository_.object_value_types_[*object] =
Luca Versari99fddff2022-05-25 10:22:32 -0700246 var->getType()->isArrayType() ? ObjectValueType::kMultiValued
247 : ObjectValueType::kSingleValued;
248
249 // Remember the original value of function parameters.
250 if (auto parm_var_decl = clang::dyn_cast<const clang::ParmVarDecl>(var)) {
251 object_repository_.initial_parameter_object_[parm_var_decl] =
252 object_repository_.CloneObject(object);
253 }
254
255 if (var->hasInit() && var->getType()->isRecordType()) {
Martin Brænned8e32142022-07-01 01:54:41 -0700256 PropagateInitializedObject(var->getInit(), *object);
Luca Versari99fddff2022-05-25 10:22:32 -0700257 }
258 }
259
260 void AddObjectForFunc(clang::FunctionDecl* func) {
261 if (object_repository_.object_repository_.count(func)) {
262 return;
263 }
264
265 object_repository_.object_repository_[func] =
Martin Brænne4a1231d2022-07-01 01:45:44 -0700266 *object_repository_.CreateObjectFromFunctionDecl(*func);
Luca Versari99fddff2022-05-25 10:22:32 -0700267 }
268
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700269 const Object* AddTemporaryObjectForExpression(clang::Expr* expr) {
Luca Versari99fddff2022-05-25 10:22:32 -0700270 clang::QualType type = expr->getType().getCanonicalType();
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700271 const Object* object =
272 object_repository_.CreateObject(Lifetime::CreateLocal(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700273
274 object_repository_.CreateObjects(
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700275 *object, type,
Martin Brænne03d93302022-06-23 00:23:38 -0700276 [](const clang::Expr*) { return Lifetime::CreateVariable(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700277 /*transitive=*/false);
278
279 if (type->isRecordType()) {
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700280 PropagateInitializedObject(expr, *object);
Luca Versari99fddff2022-05-25 10:22:32 -0700281 }
282 return object;
283 }
284
285 // Propagates an `object` of record type that is to be initialized to the
286 // expressions that actually perform the initialization (we call these
287 // "terminating expressions").
288 //
289 // `expr` is the initializer for a variable; this will contain one or
290 // several terminating expressions (such as a CXXConstructExpr, InitListExpr,
291 // or CallExpr).
292 //
293 // Note that not all terminating expressions below `expr` necessarily
294 // initialize `object`; some of these terminating expressions may also
295 // initialize temporary objects. This function takes care to propagate
296 // `object` only to the appropriate terminating expressions.
297 //
298 // The mapping from a terminating expression to the object it initializes
299 // is stored in `object_repository_.initialized_objects_`.
300 void PropagateInitializedObject(const clang::Expr* expr, Object object) {
301 // TODO(danakj): Use StmtVisitor to implement this method.
302 // copybara:begin_strip
303 // Context and hints:
304 // http://cl/414017975/depot/lifetime_analysis/var_decl_objects.cc?version=s3#324
305 // copybara:end_strip
306
307 // Terminating expressions. Expressions that don't initialize a record
308 // object can not be such, and their existence is unexpected as we should
309 // be converting to and initializing a record object from such expressions
310 // further up in the initializer expression's AST. We will assert later in
311 // this function if we find this situation somehow due to incorrect
312 // expectations in this comment.
313 if (IsInitExprInitializingARecordObject(expr)) {
314 if (clang::isa<clang::CXXConstructExpr>(expr) ||
315 clang::isa<clang::CallExpr>(expr) ||
316 clang::isa<clang::ObjCMessageExpr>(expr) ||
317 clang::isa<clang::LambdaExpr>(expr)) {
318 object_repository_.initialized_objects_[expr] = object;
319 return;
320 }
321 if (auto* e = clang::dyn_cast<clang::InitListExpr>(expr)) {
322 if (!e->isSemanticForm()) return;
323 if (e->isTransparent()) {
324 // A field initializer like `S s{cond ? S{} : S{}}` is considered
325 // transparent, and the actual initializer is within.
326 for (const clang::Expr* init : e->inits()) {
327 PropagateInitializedObject(init, object);
328 }
329 } else {
330 object_repository_.initialized_objects_[e] = object;
331 }
332 return;
333 }
334 }
335
336 // Expressions to walk through. Logic is similar to the AggExprEmitter in
337 // clang third_party/llvm-project/clang/lib/CodeGen/CGExprAgg.cpp though we
338 // don't have to visit all the sub-expressions that clang codegen needs to,
339 // as we can stop at terminating expressions and ignore many expressions
340 // that don't occur in the code we're analyzing.
341 if (auto* e = clang::dyn_cast<clang::ParenExpr>(expr)) {
342 PropagateInitializedObject(e->getSubExpr(), object);
343 return;
344 }
345 if (auto* e = clang::dyn_cast<clang::UnaryOperator>(expr)) {
346 PropagateInitializedObject(e->getSubExpr(), object);
347 return;
348 }
349 if (auto* e = clang::dyn_cast<clang::SubstNonTypeTemplateParmExpr>(expr)) {
350 PropagateInitializedObject(e->getReplacement(), object);
351 return;
352 }
353 if (auto* e = clang::dyn_cast<clang::CastExpr>(expr)) {
354 PropagateInitializedObject(e->getSubExpr(), object);
355 return;
356 }
357 if (auto* e = clang::dyn_cast<clang::CXXDefaultArgExpr>(expr)) {
358 PropagateInitializedObject(e->getExpr(), object);
359 return;
360 }
361 if (auto* e = clang::dyn_cast<clang::CXXDefaultInitExpr>(expr)) {
362 PropagateInitializedObject(e->getExpr(), object);
363 return;
364 }
365 if (auto* e = clang::dyn_cast<clang::ExprWithCleanups>(expr)) {
366 PropagateInitializedObject(e->getSubExpr(), object);
367 return;
368 }
369
370 // Expressions that produce a temporary object.
371 if (auto* e = clang::dyn_cast<clang::BinaryOperator>(expr)) {
372 if (e->isCommaOp()) {
373 AddTemporaryObjectForExpression(e->getLHS());
374 PropagateInitializedObject(e->getRHS(), object);
375 return;
376 }
377
378 // Any other binary operator should not produce a record type, it would be
379 // used to construct a record further up the AST, so we should not arrive
380 // here.
381 expr->dump();
382 llvm::report_fatal_error(
383 "Unexpected binary operator in initializer expression tree");
384 }
385 if (auto* e = clang::dyn_cast<clang::AbstractConditionalOperator>(expr)) {
386 AddTemporaryObjectForExpression(e->getCond());
387 PropagateInitializedObject(e->getTrueExpr(), object);
388 PropagateInitializedObject(e->getFalseExpr(), object);
389 return;
390 }
391
392 expr->dump();
393 llvm::report_fatal_error(
394 "Unexpected expression in initializer expression tree");
395 }
396
397 bool InitializedObjectWasPropagatedTo(clang::Expr* terminating_expr) {
398 // An expression that initializes an object should have already been
399 // connected to the object it initializes. We should have walked down from
400 // the object which requires initialization to find its terminating
401 // expressions.
402 if (!object_repository_.initialized_objects_.count(terminating_expr)) {
403 llvm::errs() << "Missing initialized object for terminating expression, "
404 "we did not record it when we visited something earlier "
405 "in the tree yet?\n";
406 terminating_expr->dump();
407 return false;
408 } else {
409 return true;
410 }
411 }
412
413 void TraverseCXXMemberInitializers(
414 const clang::CXXConstructorDecl* constructor) {
415 // For constructors, we also need to create lifetimes for variables
416 // referenced by in-class member initializers; the visitor by default only
417 // visits expressions in the initializer list.
418 // We also need to associate member initializers with the members they
419 // initialize.
420 for (const auto* init : constructor->inits()) {
421 const auto* init_expr = init->getInit();
422 if (const auto* default_init =
423 clang::dyn_cast<clang::CXXDefaultInitExpr>(init_expr)) {
424 init_expr = default_init->getExpr();
425 }
426
427 if (init->getMember() && init->getMember()->getType()->isRecordType()) {
428 std::optional<Object> this_object = object_repository_.GetThisObject();
429 assert(this_object.has_value());
430
431 Object field_object =
432 object_repository_.GetFieldObject(*this_object, init->getMember());
433 PropagateInitializedObject(init_expr, field_object);
434 } else if (init->getBaseClass()) {
435 std::optional<Object> this_object = object_repository_.GetThisObject();
436 assert(this_object.has_value());
437
438 Object base_object = object_repository_.GetBaseClassObject(
439 *this_object, init->getBaseClass());
440 PropagateInitializedObject(init_expr, base_object);
441 }
442
443 // Traverse after finishing with the outer expression, including
444 // connecting the initializer (constructor) to its object.
445 TraverseStmt(const_cast<clang::Expr*>(init_expr));
446 }
447 }
448
449 ObjectRepository& object_repository_;
450};
451
452ObjectRepository::ObjectRepository(const clang::FunctionDecl* func) {
453 const auto* method_decl = clang::dyn_cast<clang::CXXMethodDecl>(func);
454
455 const auto* definition = func->getDefinition();
456 assert(definition || (method_decl && method_decl->isPure()));
457 if (definition) func = definition;
458
459 // For the return value, we only need to create field objects.
Martin Brænne04fb3a42022-07-01 01:52:21 -0700460 return_object_ = CreateObject(Lifetime::CreateLocal(), func->getReturnType());
Luca Versari99fddff2022-05-25 10:22:32 -0700461 CreateObjects(
Martin Brænne04fb3a42022-07-01 01:52:21 -0700462 *return_object_, func->getReturnType(),
Martin Brænne03d93302022-06-23 00:23:38 -0700463 [](const clang::Expr*) { return Lifetime::CreateLocal(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700464 /*transitive=*/false);
465
466 if (method_decl) {
467 if (!method_decl->isStatic()) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700468 this_object_ = CreateObject(Lifetime::CreateVariable(),
469 method_decl->getThisObjectType());
Luca Versari99fddff2022-05-25 10:22:32 -0700470 CreateObjects(
Martin Brænne04fb3a42022-07-01 01:52:21 -0700471 **this_object_, method_decl->getThisObjectType(),
Martin Brænne03d93302022-06-23 00:23:38 -0700472 [](const clang::Expr*) { return Lifetime::CreateVariable(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700473 /*transitive=*/true);
474 }
475 }
476
477 VarDeclVisitor decl_visitor(*this);
478 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
479 decl_visitor.TraverseCXXMemberInitializers(constructor);
480 }
481 decl_visitor.TraverseFunctionDecl(const_cast<clang::FunctionDecl*>(func));
482}
483
484std::string ObjectRepository::DebugString() const {
485 std::string result;
486 llvm::raw_string_ostream os(result);
487
488 if (this_object_) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700489 os << "This " << (*this_object_)->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700490 }
491 for (const auto& [decl, object] : object_repository_) {
492 os << decl->getDeclKindName() << " " << decl << " (";
493 decl->printName(os);
494 os << ") object: " << object.DebugString() << "\n";
495 }
496 for (const auto& [expr_i, object] : call_expr_args_objects_) {
497 const auto& [expr, i] = expr_i;
498 os << "Call " << expr << " (arg " << i
Martin Brænne982a1152022-07-01 01:55:53 -0700499 << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700500 }
501 for (const auto& [expr, object] : call_expr_this_pointers_) {
Martin Brænne982a1152022-07-01 01:55:53 -0700502 os << "Call " << expr << " (this) pointer: " << object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700503 << "\n";
504 }
505 os << "InitialPointsToMap:\n" << initial_points_to_map_.DebugString() << "\n";
506 for (const auto& [field, object] : field_object_map_) {
507 os << "Field '";
508 field.second->printName(os);
509 os << "' on " << field.first.Type().getAsString()
Martin Brænneb6764af2022-07-01 02:01:49 -0700510 << " object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700511 }
Martin Brænne04fb3a42022-07-01 01:52:21 -0700512 os << "Return " << return_object_->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700513 os.flush();
514 return result;
515}
516
Martin Brænne4a1231d2022-07-01 01:45:44 -0700517const Object* ObjectRepository::CreateObject(Lifetime lifetime,
518 clang::QualType type) {
519 return new (object_allocator_.Allocate()) Object(lifetime, type);
520}
521
522const Object* ObjectRepository::CreateObjectFromFunctionDecl(
523 const clang::FunctionDecl& func) {
524 return new (object_allocator_.Allocate()) Object(func);
525}
526
Luca Versari99fddff2022-05-25 10:22:32 -0700527Object ObjectRepository::GetDeclObject(const clang::ValueDecl* decl) const {
528 auto iter = object_repository_.find(decl);
529 if (iter == object_repository_.end()) {
530 llvm::errs() << "Didn't find object for Decl:\n";
531 decl->dump();
532 llvm::errs() << "\n" << DebugString();
533 llvm::report_fatal_error("Didn't find object for Decl");
534 }
535 return iter->second;
536}
537
538Object ObjectRepository::GetTemporaryObject(
539 const clang::MaterializeTemporaryExpr* expr) const {
540 auto iter = temporary_objects_.find(expr);
541 if (iter == temporary_objects_.end()) {
542 llvm::errs() << "Didn't find object for temporary expression:\n";
543 expr->dump();
544 llvm::errs() << "\n" << DebugString();
545 llvm::report_fatal_error("Didn't find object for temporary expression");
546 }
Martin Brænne8f8e4fe2022-07-01 01:53:28 -0700547 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700548}
549
550Object ObjectRepository::GetOriginalParameterValue(
551 const clang::ParmVarDecl* var_decl) const {
552 auto iter = initial_parameter_object_.find(var_decl);
553 if (iter == initial_parameter_object_.end()) {
554 llvm::errs() << "Didn't find caller object for parameter:\n";
555 var_decl->dump();
556 llvm::errs() << "\n" << DebugString();
557 llvm::report_fatal_error("Didn't find caller object for parameter");
558 }
Martin Brænned8e32142022-07-01 01:54:41 -0700559 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700560}
561
562Object ObjectRepository::GetCallExprArgumentObject(const clang::CallExpr* expr,
563 size_t arg_index) const {
564 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
565 if (iter == call_expr_args_objects_.end()) {
566 llvm::errs() << "Didn't find object for argument " << arg_index
567 << " of call:\n";
568 expr->dump();
569 llvm::errs() << "\n" << DebugString();
570 llvm::report_fatal_error("Didn't find object for argument");
571 }
Martin Brænne982a1152022-07-01 01:55:53 -0700572 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700573}
574
575Object ObjectRepository::GetCallExprThisPointer(
576 const clang::CallExpr* expr) const {
577 auto iter = call_expr_this_pointers_.find(expr);
578 if (iter == call_expr_this_pointers_.end()) {
579 llvm::errs() << "Didn't find `this` object for call:\n";
580 expr->dump();
581 llvm::errs() << "\n" << DebugString();
582 llvm::report_fatal_error("Didn't find `this` object for call");
583 }
Martin Brænne982a1152022-07-01 01:55:53 -0700584 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700585}
586
587Object ObjectRepository::GetCXXConstructExprArgumentObject(
588 const clang::CXXConstructExpr* expr, size_t arg_index) const {
589 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
590 if (iter == call_expr_args_objects_.end()) {
591 llvm::errs() << "Didn't find object for argument " << arg_index
592 << " of constructor call:\n";
593 expr->dump();
594 llvm::errs() << "\n" << DebugString();
595 llvm::report_fatal_error(
596 "Didn't find object for argument of constructor call");
597 }
Martin Brænne982a1152022-07-01 01:55:53 -0700598 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700599}
600
601Object ObjectRepository::GetCXXConstructExprThisPointer(
602 const clang::CXXConstructExpr* expr) const {
603 auto iter = call_expr_this_pointers_.find(expr);
604 if (iter == call_expr_this_pointers_.end()) {
605 llvm::errs() << "Didn't find `this` object for constructor:\n";
606 expr->dump();
607 llvm::errs() << "\n" << DebugString();
608 llvm::report_fatal_error("Didn't find `this` object for constructor");
609 }
Martin Brænne982a1152022-07-01 01:55:53 -0700610 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700611}
612
613Object ObjectRepository::GetInitializedObject(
614 const clang::Expr* initializer_expr) const {
615 assert(clang::isa<clang::CXXConstructExpr>(initializer_expr) ||
616 clang::isa<clang::InitListExpr>(initializer_expr) ||
617 clang::isa<clang::CallExpr>(initializer_expr));
618
619 auto iter = initialized_objects_.find(initializer_expr);
620 if (iter == initialized_objects_.end()) {
621 llvm::errs() << "Didn't find object for initializer:\n";
622 initializer_expr->dump();
623 llvm::errs() << "\n" << DebugString();
624 llvm::report_fatal_error("Didn't find object for initializer");
625 }
626 return iter->second;
627}
628
629ObjectRepository::ObjectValueType ObjectRepository::GetObjectValueType(
630 Object object) const {
Martin Brænnee7266f82022-06-28 04:03:57 -0700631 auto iter = object_value_types_.find(object);
Luca Versari99fddff2022-05-25 10:22:32 -0700632 // If we don't know this lifetime, we conservatively assume it to be
633 // multi-valued.
Martin Brænnee7266f82022-06-28 04:03:57 -0700634 if (iter == object_value_types_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700635 return ObjectValueType::kMultiValued;
636 }
637 return iter->second;
638}
639
640Object ObjectRepository::GetFieldObject(Object struct_object,
641 const clang::FieldDecl* field) const {
642 std::optional<Object> field_object =
643 GetFieldObjectInternal(struct_object, field);
644 if (!field_object.has_value()) {
645 llvm::errs() << "On an object of type "
646 << struct_object.Type().getAsString()
647 << ", trying to get field:\n";
648 field->dump();
649 llvm::errs() << "\n" << DebugString();
650 llvm::report_fatal_error("Didn't find field object");
651 }
652 return *field_object;
653}
654
655ObjectSet ObjectRepository::GetFieldObject(
656 const ObjectSet& struct_objects, const clang::FieldDecl* field) const {
657 ObjectSet ret;
658 for (Object object : struct_objects) {
659 ret.Add(GetFieldObject(object, field));
660 }
661 return ret;
662}
663
664Object ObjectRepository::GetBaseClassObject(Object struct_object,
665 const clang::Type* base) const {
666 base = base->getCanonicalTypeInternal().getTypePtr();
667 auto iter = base_object_map_.find(std::make_pair(struct_object, base));
668 if (iter == base_object_map_.end()) {
669 llvm::errs() << "On object " << struct_object.DebugString()
670 << ", trying to get base:\n";
671 base->dump();
672 llvm::errs() << "\n" << DebugString();
673 llvm::report_fatal_error("Didn't find base object");
674 }
Martin Brænnea7ca8382022-07-01 02:03:10 -0700675 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700676}
677
678ObjectSet ObjectRepository::GetBaseClassObject(const ObjectSet& struct_objects,
679 const clang::Type* base) const {
680 ObjectSet ret;
681 for (Object object : struct_objects) {
682 ret.Add(GetBaseClassObject(object, base));
683 }
684 return ret;
685}
686
687Object ObjectRepository::CreateStaticObject(clang::QualType type) {
688 auto iter = static_objects_.find(type);
689 if (iter != static_objects_.end()) {
Martin Brænne3b587cf2022-07-01 01:57:01 -0700690 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700691 }
692
Martin Brænne3b587cf2022-07-01 01:57:01 -0700693 const Object* object = CreateObject(Lifetime::Static(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700694 static_objects_[type] = object;
695
696 CreateObjects(
Martin Brænne3b587cf2022-07-01 01:57:01 -0700697 *object, type, [](const clang::Expr*) { return Lifetime::Static(); },
Martin Brænne03d93302022-06-23 00:23:38 -0700698 true);
Luca Versari99fddff2022-05-25 10:22:32 -0700699
Martin Brænne3b587cf2022-07-01 01:57:01 -0700700 return *object;
Luca Versari99fddff2022-05-25 10:22:32 -0700701}
702
703void ObjectRepository::CreateObjects(Object root_object, clang::QualType type,
704 LifetimeFactory lifetime_factory,
705 bool transitive) {
706 class Visitor : public LifetimeVisitor {
707 public:
Martin Brænne4a1231d2022-07-01 01:45:44 -0700708 Visitor(ObjectRepository& object_repository, bool create_transitive_objects)
709 : object_repository_(object_repository),
Luca Versari99fddff2022-05-25 10:22:32 -0700710 create_transitive_objects_(create_transitive_objects) {}
711
712 Object GetFieldObject(const ObjectSet& objects,
713 const clang::FieldDecl* field) override {
714 assert(!objects.empty());
Martin Brænneb6764af2022-07-01 02:01:49 -0700715 std::optional<const Object*> field_object = std::nullopt;
Luca Versari99fddff2022-05-25 10:22:32 -0700716
717 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700718 if (auto iter = object_repository_.field_object_map_.find(
719 std::make_pair(object, field));
720 iter != object_repository_.field_object_map_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700721 field_object = iter->second;
722 }
723 }
724 if (!field_object.has_value()) {
Martin Brænneb6764af2022-07-01 02:01:49 -0700725 field_object = object_repository_.CreateObject(
Martin Brænne4a1231d2022-07-01 01:45:44 -0700726 (*objects.begin()).GetLifetime(), field->getType());
Luca Versari99fddff2022-05-25 10:22:32 -0700727 }
728 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700729 object_repository_.field_object_map_[std::make_pair(object, field)] =
730 *field_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700731 }
Martin Brænneb6764af2022-07-01 02:01:49 -0700732 return **field_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700733 }
734
735 Object GetBaseClassObject(const ObjectSet& objects,
736 clang::QualType base) override {
737 assert(!objects.empty());
738 base = base.getCanonicalType();
Martin Brænnea7ca8382022-07-01 02:03:10 -0700739 std::optional<const Object*> base_object = std::nullopt;
Luca Versari99fddff2022-05-25 10:22:32 -0700740
741 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700742 if (auto iter = object_repository_.base_object_map_.find(
743 std::make_pair(object, &*base));
744 iter != object_repository_.base_object_map_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700745 base_object = iter->second;
746 }
747 }
748 if (!base_object.has_value()) {
Martin Brænnea7ca8382022-07-01 02:03:10 -0700749 base_object = object_repository_.CreateObject(
Martin Brænne4a1231d2022-07-01 01:45:44 -0700750 (*objects.begin()).GetLifetime(), base);
Luca Versari99fddff2022-05-25 10:22:32 -0700751 }
752 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700753 object_repository_.base_object_map_[std::make_pair(object, &*base)] =
754 *base_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700755 }
Martin Brænnea7ca8382022-07-01 02:03:10 -0700756 return **base_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700757 }
758
759 ObjectSet Traverse(const ObjectLifetimes& lifetimes,
760 const ObjectSet& objects,
761 int /*pointee_depth*/) override {
762 if (!create_transitive_objects_) return {};
763 if (PointeeType(lifetimes.GetValueLifetimes().Type()).isNull()) {
764 return {};
765 }
766
767 const auto& cache_key =
768 lifetimes.GetValueLifetimes().GetPointeeLifetimes();
769
770 Object child_pointee;
771 if (auto iter = object_cache_.find(cache_key);
772 iter == object_cache_.end()) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700773 child_pointee = *object_repository_.CreateObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700774 lifetimes.GetValueLifetimes().GetPointeeLifetimes().GetLifetime(),
775 PointeeType(lifetimes.GetValueLifetimes().Type()));
776 object_cache_[cache_key] = child_pointee;
777 } else {
778 child_pointee = iter->second;
779 }
780
Martin Brænne4a1231d2022-07-01 01:45:44 -0700781 object_repository_.initial_points_to_map_.SetPointerPointsToSet(
782 objects, {child_pointee});
Luca Versari99fddff2022-05-25 10:22:32 -0700783 return ObjectSet{child_pointee};
784 }
785
786 private:
Martin Brænne4a1231d2022-07-01 01:45:44 -0700787 ObjectRepository& object_repository_;
Luca Versari99fddff2022-05-25 10:22:32 -0700788 bool create_transitive_objects_;
789 // Inside of a given VarDecl, we re-use the same Object for all the
790 // sub-objects with the same type and lifetimes. This avoids infinite loops
791 // in the case of structs like lists.
792 llvm::DenseMap<ObjectLifetimes, Object> object_cache_;
793 };
Martin Brænne4a1231d2022-07-01 01:45:44 -0700794 Visitor visitor(*this, transitive);
Luca Versari99fddff2022-05-25 10:22:32 -0700795 VisitLifetimes(
796 {root_object}, type,
797 ObjectLifetimes(root_object.GetLifetime(),
798 ValueLifetimes::Create(type, lifetime_factory).get()),
799 visitor);
800}
801
802// Clones an object and its base classes and fields, if any.
Martin Brænned8e32142022-07-01 01:54:41 -0700803const Object* ObjectRepository::CloneObject(const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700804 struct ObjectPair {
805 Object orig_object;
Martin Brænned8e32142022-07-01 01:54:41 -0700806 const Object* new_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700807 };
808 auto clone = [this](Object obj) {
Martin Brænned8e32142022-07-01 01:54:41 -0700809 auto new_obj = CreateObject(obj.GetLifetime(), obj.Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700810 initial_points_to_map_.SetPointerPointsToSet(
Martin Brænned8e32142022-07-01 01:54:41 -0700811 *new_obj, initial_points_to_map_.GetPointerPointsToSet(obj));
Luca Versari99fddff2022-05-25 10:22:32 -0700812 return new_obj;
813 };
Martin Brænned8e32142022-07-01 01:54:41 -0700814 const Object* new_root = clone(*object);
815 std::vector<ObjectPair> object_stack{{*object, new_root}};
Luca Versari99fddff2022-05-25 10:22:32 -0700816 while (!object_stack.empty()) {
817 auto [orig_object, new_object] = object_stack.back();
Martin Brænned8e32142022-07-01 01:54:41 -0700818 assert(orig_object.Type() == new_object->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700819 object_stack.pop_back();
820 auto record_type = orig_object.Type()->getAs<clang::RecordType>();
821 if (!record_type) {
822 continue;
823 }
824
825 // Base classes.
826 if (auto* cxxrecord =
827 clang::dyn_cast<clang::CXXRecordDecl>(record_type->getDecl())) {
828 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
829 auto base_obj = GetBaseClassObject(orig_object, base.getType());
Martin Brænned8e32142022-07-01 01:54:41 -0700830 const Object* new_base_obj = clone(base_obj);
Luca Versari99fddff2022-05-25 10:22:32 -0700831 base_object_map_[std::make_pair(
Martin Brænned8e32142022-07-01 01:54:41 -0700832 *new_object, base.getType().getCanonicalType().getTypePtr())] =
Martin Brænnea7ca8382022-07-01 02:03:10 -0700833 new_base_obj;
Luca Versari99fddff2022-05-25 10:22:32 -0700834 object_stack.push_back(ObjectPair{base_obj, new_base_obj});
835 }
836 }
837
838 // Fields.
839 for (auto f : record_type->getDecl()->fields()) {
840 auto field_obj = GetFieldObject(orig_object, f);
Martin Brænned8e32142022-07-01 01:54:41 -0700841 const Object* new_field_obj = clone(field_obj);
Martin Brænneb6764af2022-07-01 02:01:49 -0700842 field_object_map_[std::make_pair(*new_object, f)] = new_field_obj;
Luca Versari99fddff2022-05-25 10:22:32 -0700843 object_stack.push_back(ObjectPair{field_obj, new_field_obj});
844 }
845 }
846 return new_root;
847}
848
849std::optional<Object> ObjectRepository::GetFieldObjectInternal(
850 Object struct_object, const clang::FieldDecl* field) const {
851 auto iter = field_object_map_.find(std::make_pair(struct_object, field));
852 if (iter != field_object_map_.end()) {
Martin Brænneb6764af2022-07-01 02:01:49 -0700853 return *iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700854 }
855 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
856 struct_object.Type()->getAs<clang::RecordType>()->getDecl())) {
857 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
858 std::optional<Object> field_object = GetFieldObjectInternal(
859 GetBaseClassObject(struct_object, base.getType()), field);
860 if (field_object.has_value()) {
861 return field_object;
862 }
863 }
864 }
865 return std::nullopt;
866}
867
868} // namespace lifetimes
869} // namespace tidy
870} // namespace clang