blob: eaa31055e43881f7bead9cebbf1008ecf031adad [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æ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
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ænne493d4d42022-07-01 05:44:23 -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ænne493d4d42022-07-01 05:44:23 -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ænnee9a4a472022-07-01 02:26:55 -0700244 object_repository_.object_repository_[var] = object;
Martin Brænned8e32142022-07-01 01:54:41 -0700245 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ænneecd58c32022-07-01 02:25:47 -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ænnee9a4a472022-07-01 02:26:55 -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ænne493d4d42022-07-01 05:44:23 -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ænneecd58c32022-07-01 02:25:47 -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_`.
Martin Brænneecd58c32022-07-01 02:25:47 -0700300 void PropagateInitializedObject(const clang::Expr* expr,
301 const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700302 // TODO(danakj): Use StmtVisitor to implement this method.
303 // copybara:begin_strip
304 // Context and hints:
305 // http://cl/414017975/depot/lifetime_analysis/var_decl_objects.cc?version=s3#324
306 // copybara:end_strip
307
308 // Terminating expressions. Expressions that don't initialize a record
309 // object can not be such, and their existence is unexpected as we should
310 // be converting to and initializing a record object from such expressions
311 // further up in the initializer expression's AST. We will assert later in
312 // this function if we find this situation somehow due to incorrect
313 // expectations in this comment.
314 if (IsInitExprInitializingARecordObject(expr)) {
315 if (clang::isa<clang::CXXConstructExpr>(expr) ||
316 clang::isa<clang::CallExpr>(expr) ||
317 clang::isa<clang::ObjCMessageExpr>(expr) ||
318 clang::isa<clang::LambdaExpr>(expr)) {
319 object_repository_.initialized_objects_[expr] = object;
320 return;
321 }
322 if (auto* e = clang::dyn_cast<clang::InitListExpr>(expr)) {
323 if (!e->isSemanticForm()) return;
324 if (e->isTransparent()) {
325 // A field initializer like `S s{cond ? S{} : S{}}` is considered
326 // transparent, and the actual initializer is within.
327 for (const clang::Expr* init : e->inits()) {
328 PropagateInitializedObject(init, object);
329 }
330 } else {
331 object_repository_.initialized_objects_[e] = object;
332 }
333 return;
334 }
335 }
336
337 // Expressions to walk through. Logic is similar to the AggExprEmitter in
338 // clang third_party/llvm-project/clang/lib/CodeGen/CGExprAgg.cpp though we
339 // don't have to visit all the sub-expressions that clang codegen needs to,
340 // as we can stop at terminating expressions and ignore many expressions
341 // that don't occur in the code we're analyzing.
342 if (auto* e = clang::dyn_cast<clang::ParenExpr>(expr)) {
343 PropagateInitializedObject(e->getSubExpr(), object);
344 return;
345 }
346 if (auto* e = clang::dyn_cast<clang::UnaryOperator>(expr)) {
347 PropagateInitializedObject(e->getSubExpr(), object);
348 return;
349 }
350 if (auto* e = clang::dyn_cast<clang::SubstNonTypeTemplateParmExpr>(expr)) {
351 PropagateInitializedObject(e->getReplacement(), object);
352 return;
353 }
354 if (auto* e = clang::dyn_cast<clang::CastExpr>(expr)) {
355 PropagateInitializedObject(e->getSubExpr(), object);
356 return;
357 }
358 if (auto* e = clang::dyn_cast<clang::CXXDefaultArgExpr>(expr)) {
359 PropagateInitializedObject(e->getExpr(), object);
360 return;
361 }
362 if (auto* e = clang::dyn_cast<clang::CXXDefaultInitExpr>(expr)) {
363 PropagateInitializedObject(e->getExpr(), object);
364 return;
365 }
366 if (auto* e = clang::dyn_cast<clang::ExprWithCleanups>(expr)) {
367 PropagateInitializedObject(e->getSubExpr(), object);
368 return;
369 }
370
371 // Expressions that produce a temporary object.
372 if (auto* e = clang::dyn_cast<clang::BinaryOperator>(expr)) {
373 if (e->isCommaOp()) {
374 AddTemporaryObjectForExpression(e->getLHS());
375 PropagateInitializedObject(e->getRHS(), object);
376 return;
377 }
378
379 // Any other binary operator should not produce a record type, it would be
380 // used to construct a record further up the AST, so we should not arrive
381 // here.
382 expr->dump();
383 llvm::report_fatal_error(
384 "Unexpected binary operator in initializer expression tree");
385 }
386 if (auto* e = clang::dyn_cast<clang::AbstractConditionalOperator>(expr)) {
387 AddTemporaryObjectForExpression(e->getCond());
388 PropagateInitializedObject(e->getTrueExpr(), object);
389 PropagateInitializedObject(e->getFalseExpr(), object);
390 return;
391 }
392
393 expr->dump();
394 llvm::report_fatal_error(
395 "Unexpected expression in initializer expression tree");
396 }
397
398 bool InitializedObjectWasPropagatedTo(clang::Expr* terminating_expr) {
399 // An expression that initializes an object should have already been
400 // connected to the object it initializes. We should have walked down from
401 // the object which requires initialization to find its terminating
402 // expressions.
403 if (!object_repository_.initialized_objects_.count(terminating_expr)) {
404 llvm::errs() << "Missing initialized object for terminating expression, "
405 "we did not record it when we visited something earlier "
406 "in the tree yet?\n";
407 terminating_expr->dump();
408 return false;
409 } else {
410 return true;
411 }
412 }
413
414 void TraverseCXXMemberInitializers(
415 const clang::CXXConstructorDecl* constructor) {
416 // For constructors, we also need to create lifetimes for variables
417 // referenced by in-class member initializers; the visitor by default only
418 // visits expressions in the initializer list.
419 // We also need to associate member initializers with the members they
420 // initialize.
421 for (const auto* init : constructor->inits()) {
422 const auto* init_expr = init->getInit();
423 if (const auto* default_init =
424 clang::dyn_cast<clang::CXXDefaultInitExpr>(init_expr)) {
425 init_expr = default_init->getExpr();
426 }
427
428 if (init->getMember() && init->getMember()->getType()->isRecordType()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700429 std::optional<const Object*> this_object =
430 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700431 assert(this_object.has_value());
432
Martin Brænne46f1a572022-07-01 02:07:07 -0700433 const Object* field_object =
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700434 object_repository_.GetFieldObject(**this_object, init->getMember());
Martin Brænneecd58c32022-07-01 02:25:47 -0700435 PropagateInitializedObject(init_expr, field_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700436 } else if (init->getBaseClass()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700437 std::optional<const Object*> this_object =
438 object_repository_.GetThisObject();
Luca Versari99fddff2022-05-25 10:22:32 -0700439 assert(this_object.has_value());
440
Martin Brænnee08ac882022-07-01 02:24:49 -0700441 const Object* base_object = object_repository_.GetBaseClassObject(
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700442 **this_object, init->getBaseClass());
Martin Brænneecd58c32022-07-01 02:25:47 -0700443 PropagateInitializedObject(init_expr, base_object);
Luca Versari99fddff2022-05-25 10:22:32 -0700444 }
445
446 // Traverse after finishing with the outer expression, including
447 // connecting the initializer (constructor) to its object.
448 TraverseStmt(const_cast<clang::Expr*>(init_expr));
449 }
450 }
451
452 ObjectRepository& object_repository_;
453};
454
455ObjectRepository::ObjectRepository(const clang::FunctionDecl* func) {
456 const auto* method_decl = clang::dyn_cast<clang::CXXMethodDecl>(func);
457
458 const auto* definition = func->getDefinition();
459 assert(definition || (method_decl && method_decl->isPure()));
460 if (definition) func = definition;
461
462 // For the return value, we only need to create field objects.
Martin Brænne04fb3a42022-07-01 01:52:21 -0700463 return_object_ = CreateObject(Lifetime::CreateLocal(), func->getReturnType());
Luca Versari99fddff2022-05-25 10:22:32 -0700464 CreateObjects(
Martin Brænne493d4d42022-07-01 05:44:23 -0700465 return_object_, func->getReturnType(),
Martin Brænne03d93302022-06-23 00:23:38 -0700466 [](const clang::Expr*) { return Lifetime::CreateLocal(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700467 /*transitive=*/false);
468
469 if (method_decl) {
470 if (!method_decl->isStatic()) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700471 this_object_ = CreateObject(Lifetime::CreateVariable(),
472 method_decl->getThisObjectType());
Luca Versari99fddff2022-05-25 10:22:32 -0700473 CreateObjects(
Martin Brænne493d4d42022-07-01 05:44:23 -0700474 *this_object_, method_decl->getThisObjectType(),
Martin Brænne03d93302022-06-23 00:23:38 -0700475 [](const clang::Expr*) { return Lifetime::CreateVariable(); },
Luca Versari99fddff2022-05-25 10:22:32 -0700476 /*transitive=*/true);
477 }
478 }
479
480 VarDeclVisitor decl_visitor(*this);
481 if (auto* constructor = clang::dyn_cast<clang::CXXConstructorDecl>(func)) {
482 decl_visitor.TraverseCXXMemberInitializers(constructor);
483 }
484 decl_visitor.TraverseFunctionDecl(const_cast<clang::FunctionDecl*>(func));
485}
486
487std::string ObjectRepository::DebugString() const {
488 std::string result;
489 llvm::raw_string_ostream os(result);
490
491 if (this_object_) {
Martin Brænne04fb3a42022-07-01 01:52:21 -0700492 os << "This " << (*this_object_)->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700493 }
494 for (const auto& [decl, object] : object_repository_) {
495 os << decl->getDeclKindName() << " " << decl << " (";
496 decl->printName(os);
Martin Brænnee9a4a472022-07-01 02:26:55 -0700497 os << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700498 }
499 for (const auto& [expr_i, object] : call_expr_args_objects_) {
500 const auto& [expr, i] = expr_i;
501 os << "Call " << expr << " (arg " << i
Martin Brænne982a1152022-07-01 01:55:53 -0700502 << ") object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700503 }
504 for (const auto& [expr, object] : call_expr_this_pointers_) {
Martin Brænne982a1152022-07-01 01:55:53 -0700505 os << "Call " << expr << " (this) pointer: " << object->DebugString()
Luca Versari99fddff2022-05-25 10:22:32 -0700506 << "\n";
507 }
508 os << "InitialPointsToMap:\n" << initial_points_to_map_.DebugString() << "\n";
509 for (const auto& [field, object] : field_object_map_) {
510 os << "Field '";
511 field.second->printName(os);
512 os << "' on " << field.first.Type().getAsString()
Martin Brænneb6764af2022-07-01 02:01:49 -0700513 << " object: " << object->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700514 }
Martin Brænne04fb3a42022-07-01 01:52:21 -0700515 os << "Return " << return_object_->DebugString() << "\n";
Luca Versari99fddff2022-05-25 10:22:32 -0700516 os.flush();
517 return result;
518}
519
Martin Brænne4a1231d2022-07-01 01:45:44 -0700520const Object* ObjectRepository::CreateObject(Lifetime lifetime,
521 clang::QualType type) {
522 return new (object_allocator_.Allocate()) Object(lifetime, type);
523}
524
525const Object* ObjectRepository::CreateObjectFromFunctionDecl(
526 const clang::FunctionDecl& func) {
527 return new (object_allocator_.Allocate()) Object(func);
528}
529
Martin Brænne46b5f072022-07-01 02:29:16 -0700530const Object* ObjectRepository::GetDeclObject(
531 const clang::ValueDecl* decl) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700532 auto iter = object_repository_.find(decl);
533 if (iter == object_repository_.end()) {
534 llvm::errs() << "Didn't find object for Decl:\n";
535 decl->dump();
536 llvm::errs() << "\n" << DebugString();
537 llvm::report_fatal_error("Didn't find object for Decl");
538 }
Martin Brænne46b5f072022-07-01 02:29:16 -0700539 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700540}
541
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700542const Object* ObjectRepository::GetTemporaryObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700543 const clang::MaterializeTemporaryExpr* expr) const {
544 auto iter = temporary_objects_.find(expr);
545 if (iter == temporary_objects_.end()) {
546 llvm::errs() << "Didn't find object for temporary expression:\n";
547 expr->dump();
548 llvm::errs() << "\n" << DebugString();
549 llvm::report_fatal_error("Didn't find object for temporary expression");
550 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700551 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700552}
553
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700554const Object* ObjectRepository::GetOriginalParameterValue(
Luca Versari99fddff2022-05-25 10:22:32 -0700555 const clang::ParmVarDecl* var_decl) const {
556 auto iter = initial_parameter_object_.find(var_decl);
557 if (iter == initial_parameter_object_.end()) {
558 llvm::errs() << "Didn't find caller object for parameter:\n";
559 var_decl->dump();
560 llvm::errs() << "\n" << DebugString();
561 llvm::report_fatal_error("Didn't find caller object for parameter");
562 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700563 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700564}
565
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700566const Object* ObjectRepository::GetCallExprArgumentObject(
567 const clang::CallExpr* expr, size_t arg_index) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700568 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
569 if (iter == call_expr_args_objects_.end()) {
570 llvm::errs() << "Didn't find object for argument " << arg_index
571 << " of call:\n";
572 expr->dump();
573 llvm::errs() << "\n" << DebugString();
574 llvm::report_fatal_error("Didn't find object for argument");
575 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700576 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700577}
578
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700579const Object* ObjectRepository::GetCallExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700580 const clang::CallExpr* expr) const {
581 auto iter = call_expr_this_pointers_.find(expr);
582 if (iter == call_expr_this_pointers_.end()) {
583 llvm::errs() << "Didn't find `this` object for call:\n";
584 expr->dump();
585 llvm::errs() << "\n" << DebugString();
586 llvm::report_fatal_error("Didn't find `this` object for call");
587 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700588 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700589}
590
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700591const Object* ObjectRepository::GetCXXConstructExprArgumentObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700592 const clang::CXXConstructExpr* expr, size_t arg_index) const {
593 auto iter = call_expr_args_objects_.find(std::make_pair(expr, arg_index));
594 if (iter == call_expr_args_objects_.end()) {
595 llvm::errs() << "Didn't find object for argument " << arg_index
596 << " of constructor call:\n";
597 expr->dump();
598 llvm::errs() << "\n" << DebugString();
599 llvm::report_fatal_error(
600 "Didn't find object for argument of constructor call");
601 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700602 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700603}
604
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700605const Object* ObjectRepository::GetCXXConstructExprThisPointer(
Luca Versari99fddff2022-05-25 10:22:32 -0700606 const clang::CXXConstructExpr* expr) const {
607 auto iter = call_expr_this_pointers_.find(expr);
608 if (iter == call_expr_this_pointers_.end()) {
609 llvm::errs() << "Didn't find `this` object for constructor:\n";
610 expr->dump();
611 llvm::errs() << "\n" << DebugString();
612 llvm::report_fatal_error("Didn't find `this` object for constructor");
613 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700614 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700615}
616
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700617const Object* ObjectRepository::GetInitializedObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700618 const clang::Expr* initializer_expr) const {
619 assert(clang::isa<clang::CXXConstructExpr>(initializer_expr) ||
620 clang::isa<clang::InitListExpr>(initializer_expr) ||
621 clang::isa<clang::CallExpr>(initializer_expr));
622
623 auto iter = initialized_objects_.find(initializer_expr);
624 if (iter == initialized_objects_.end()) {
625 llvm::errs() << "Didn't find object for initializer:\n";
626 initializer_expr->dump();
627 llvm::errs() << "\n" << DebugString();
628 llvm::report_fatal_error("Didn't find object for initializer");
629 }
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700630 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700631}
632
633ObjectRepository::ObjectValueType ObjectRepository::GetObjectValueType(
634 Object object) const {
Martin Brænnee7266f82022-06-28 04:03:57 -0700635 auto iter = object_value_types_.find(object);
Luca Versari99fddff2022-05-25 10:22:32 -0700636 // If we don't know this lifetime, we conservatively assume it to be
637 // multi-valued.
Martin Brænnee7266f82022-06-28 04:03:57 -0700638 if (iter == object_value_types_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700639 return ObjectValueType::kMultiValued;
640 }
641 return iter->second;
642}
643
Martin Brænne46f1a572022-07-01 02:07:07 -0700644const Object* ObjectRepository::GetFieldObject(
645 Object struct_object, const clang::FieldDecl* field) const {
646 std::optional<const Object*> field_object =
Luca Versari99fddff2022-05-25 10:22:32 -0700647 GetFieldObjectInternal(struct_object, field);
648 if (!field_object.has_value()) {
649 llvm::errs() << "On an object of type "
650 << struct_object.Type().getAsString()
651 << ", trying to get field:\n";
652 field->dump();
653 llvm::errs() << "\n" << DebugString();
654 llvm::report_fatal_error("Didn't find field object");
655 }
656 return *field_object;
657}
658
659ObjectSet ObjectRepository::GetFieldObject(
660 const ObjectSet& struct_objects, const clang::FieldDecl* field) const {
661 ObjectSet ret;
662 for (Object object : struct_objects) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700663 ret.Add(*GetFieldObject(object, field));
Luca Versari99fddff2022-05-25 10:22:32 -0700664 }
665 return ret;
666}
667
Martin Brænnee08ac882022-07-01 02:24:49 -0700668const Object* ObjectRepository::GetBaseClassObject(
669 Object struct_object, const clang::Type* base) const {
Luca Versari99fddff2022-05-25 10:22:32 -0700670 base = base->getCanonicalTypeInternal().getTypePtr();
671 auto iter = base_object_map_.find(std::make_pair(struct_object, base));
672 if (iter == base_object_map_.end()) {
673 llvm::errs() << "On object " << struct_object.DebugString()
674 << ", trying to get base:\n";
675 base->dump();
676 llvm::errs() << "\n" << DebugString();
677 llvm::report_fatal_error("Didn't find base object");
678 }
Martin Brænnee08ac882022-07-01 02:24:49 -0700679 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700680}
681
682ObjectSet ObjectRepository::GetBaseClassObject(const ObjectSet& struct_objects,
683 const clang::Type* base) const {
684 ObjectSet ret;
685 for (Object object : struct_objects) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700686 ret.Add(*GetBaseClassObject(object, base));
Luca Versari99fddff2022-05-25 10:22:32 -0700687 }
688 return ret;
689}
690
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700691const Object* ObjectRepository::CreateStaticObject(clang::QualType type) {
Luca Versari99fddff2022-05-25 10:22:32 -0700692 auto iter = static_objects_.find(type);
693 if (iter != static_objects_.end()) {
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700694 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700695 }
696
Martin Brænne3b587cf2022-07-01 01:57:01 -0700697 const Object* object = CreateObject(Lifetime::Static(), type);
Luca Versari99fddff2022-05-25 10:22:32 -0700698 static_objects_[type] = object;
699
700 CreateObjects(
Martin Brænne493d4d42022-07-01 05:44:23 -0700701 object, type, [](const clang::Expr*) { return Lifetime::Static(); },
Martin Brænne03d93302022-06-23 00:23:38 -0700702 true);
Luca Versari99fddff2022-05-25 10:22:32 -0700703
Martin Brænned7c0d0b2022-07-01 05:43:00 -0700704 return object;
Luca Versari99fddff2022-05-25 10:22:32 -0700705}
706
Martin Brænne493d4d42022-07-01 05:44:23 -0700707void ObjectRepository::CreateObjects(const Object* root_object,
708 clang::QualType type,
Luca Versari99fddff2022-05-25 10:22:32 -0700709 LifetimeFactory lifetime_factory,
710 bool transitive) {
711 class Visitor : public LifetimeVisitor {
712 public:
Martin Brænne4a1231d2022-07-01 01:45:44 -0700713 Visitor(ObjectRepository& object_repository, bool create_transitive_objects)
714 : object_repository_(object_repository),
Luca Versari99fddff2022-05-25 10:22:32 -0700715 create_transitive_objects_(create_transitive_objects) {}
716
Martin Brænne2c003b62022-07-01 05:45:42 -0700717 const Object* GetFieldObject(const ObjectSet& objects,
718 const clang::FieldDecl* field) override {
Luca Versari99fddff2022-05-25 10:22:32 -0700719 assert(!objects.empty());
Martin Brænneb6764af2022-07-01 02:01:49 -0700720 std::optional<const Object*> field_object = std::nullopt;
Luca Versari99fddff2022-05-25 10:22:32 -0700721
722 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700723 if (auto iter = object_repository_.field_object_map_.find(
724 std::make_pair(object, field));
725 iter != object_repository_.field_object_map_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700726 field_object = iter->second;
727 }
728 }
729 if (!field_object.has_value()) {
Martin Brænneb6764af2022-07-01 02:01:49 -0700730 field_object = object_repository_.CreateObject(
Martin Brænne4a1231d2022-07-01 01:45:44 -0700731 (*objects.begin()).GetLifetime(), field->getType());
Luca Versari99fddff2022-05-25 10:22:32 -0700732 }
733 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700734 object_repository_.field_object_map_[std::make_pair(object, field)] =
735 *field_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700736 }
Martin Brænne2c003b62022-07-01 05:45:42 -0700737 return *field_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700738 }
739
Martin Brænne2c003b62022-07-01 05:45:42 -0700740 const Object* GetBaseClassObject(const ObjectSet& objects,
741 clang::QualType base) override {
Luca Versari99fddff2022-05-25 10:22:32 -0700742 assert(!objects.empty());
743 base = base.getCanonicalType();
Martin Brænnea7ca8382022-07-01 02:03:10 -0700744 std::optional<const Object*> base_object = std::nullopt;
Luca Versari99fddff2022-05-25 10:22:32 -0700745
746 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700747 if (auto iter = object_repository_.base_object_map_.find(
748 std::make_pair(object, &*base));
749 iter != object_repository_.base_object_map_.end()) {
Luca Versari99fddff2022-05-25 10:22:32 -0700750 base_object = iter->second;
751 }
752 }
753 if (!base_object.has_value()) {
Martin Brænnea7ca8382022-07-01 02:03:10 -0700754 base_object = object_repository_.CreateObject(
Martin Brænne4a1231d2022-07-01 01:45:44 -0700755 (*objects.begin()).GetLifetime(), base);
Luca Versari99fddff2022-05-25 10:22:32 -0700756 }
757 for (Object object : objects) {
Martin Brænne4a1231d2022-07-01 01:45:44 -0700758 object_repository_.base_object_map_[std::make_pair(object, &*base)] =
759 *base_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700760 }
Martin Brænne2c003b62022-07-01 05:45:42 -0700761 return *base_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700762 }
763
764 ObjectSet Traverse(const ObjectLifetimes& lifetimes,
765 const ObjectSet& objects,
766 int /*pointee_depth*/) override {
767 if (!create_transitive_objects_) return {};
768 if (PointeeType(lifetimes.GetValueLifetimes().Type()).isNull()) {
769 return {};
770 }
771
772 const auto& cache_key =
773 lifetimes.GetValueLifetimes().GetPointeeLifetimes();
774
Martin Brænne06b96422022-07-01 06:07:38 -0700775 const Object* child_pointee;
Luca Versari99fddff2022-05-25 10:22:32 -0700776 if (auto iter = object_cache_.find(cache_key);
777 iter == object_cache_.end()) {
Martin Brænne06b96422022-07-01 06:07:38 -0700778 child_pointee = object_repository_.CreateObject(
Luca Versari99fddff2022-05-25 10:22:32 -0700779 lifetimes.GetValueLifetimes().GetPointeeLifetimes().GetLifetime(),
780 PointeeType(lifetimes.GetValueLifetimes().Type()));
781 object_cache_[cache_key] = child_pointee;
782 } else {
783 child_pointee = iter->second;
784 }
785
Martin Brænne4a1231d2022-07-01 01:45:44 -0700786 object_repository_.initial_points_to_map_.SetPointerPointsToSet(
787 objects, {child_pointee});
Luca Versari99fddff2022-05-25 10:22:32 -0700788 return ObjectSet{child_pointee};
789 }
790
791 private:
Martin Brænne4a1231d2022-07-01 01:45:44 -0700792 ObjectRepository& object_repository_;
Luca Versari99fddff2022-05-25 10:22:32 -0700793 bool create_transitive_objects_;
794 // Inside of a given VarDecl, we re-use the same Object for all the
795 // sub-objects with the same type and lifetimes. This avoids infinite loops
796 // in the case of structs like lists.
Martin Brænne06b96422022-07-01 06:07:38 -0700797 llvm::DenseMap<ObjectLifetimes, const Object*> object_cache_;
Luca Versari99fddff2022-05-25 10:22:32 -0700798 };
Martin Brænne4a1231d2022-07-01 01:45:44 -0700799 Visitor visitor(*this, transitive);
Luca Versari99fddff2022-05-25 10:22:32 -0700800 VisitLifetimes(
801 {root_object}, type,
Martin Brænne493d4d42022-07-01 05:44:23 -0700802 ObjectLifetimes(root_object->GetLifetime(),
Luca Versari99fddff2022-05-25 10:22:32 -0700803 ValueLifetimes::Create(type, lifetime_factory).get()),
804 visitor);
805}
806
807// Clones an object and its base classes and fields, if any.
Martin Brænned8e32142022-07-01 01:54:41 -0700808const Object* ObjectRepository::CloneObject(const Object* object) {
Luca Versari99fddff2022-05-25 10:22:32 -0700809 struct ObjectPair {
810 Object orig_object;
Martin Brænned8e32142022-07-01 01:54:41 -0700811 const Object* new_object;
Luca Versari99fddff2022-05-25 10:22:32 -0700812 };
813 auto clone = [this](Object obj) {
Martin Brænned8e32142022-07-01 01:54:41 -0700814 auto new_obj = CreateObject(obj.GetLifetime(), obj.Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700815 initial_points_to_map_.SetPointerPointsToSet(
Martin Brænned8e32142022-07-01 01:54:41 -0700816 *new_obj, initial_points_to_map_.GetPointerPointsToSet(obj));
Luca Versari99fddff2022-05-25 10:22:32 -0700817 return new_obj;
818 };
Martin Brænned8e32142022-07-01 01:54:41 -0700819 const Object* new_root = clone(*object);
820 std::vector<ObjectPair> object_stack{{*object, new_root}};
Luca Versari99fddff2022-05-25 10:22:32 -0700821 while (!object_stack.empty()) {
822 auto [orig_object, new_object] = object_stack.back();
Martin Brænned8e32142022-07-01 01:54:41 -0700823 assert(orig_object.Type() == new_object->Type());
Luca Versari99fddff2022-05-25 10:22:32 -0700824 object_stack.pop_back();
825 auto record_type = orig_object.Type()->getAs<clang::RecordType>();
826 if (!record_type) {
827 continue;
828 }
829
830 // Base classes.
831 if (auto* cxxrecord =
832 clang::dyn_cast<clang::CXXRecordDecl>(record_type->getDecl())) {
833 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænnee08ac882022-07-01 02:24:49 -0700834 const Object* base_obj =
835 GetBaseClassObject(orig_object, base.getType());
836 const Object* new_base_obj = clone(*base_obj);
Luca Versari99fddff2022-05-25 10:22:32 -0700837 base_object_map_[std::make_pair(
Martin Brænned8e32142022-07-01 01:54:41 -0700838 *new_object, base.getType().getCanonicalType().getTypePtr())] =
Martin Brænnea7ca8382022-07-01 02:03:10 -0700839 new_base_obj;
Martin Brænnee08ac882022-07-01 02:24:49 -0700840 object_stack.push_back(ObjectPair{*base_obj, new_base_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700841 }
842 }
843
844 // Fields.
845 for (auto f : record_type->getDecl()->fields()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700846 const Object* field_obj = GetFieldObject(orig_object, f);
847 const Object* new_field_obj = clone(*field_obj);
Martin Brænneb6764af2022-07-01 02:01:49 -0700848 field_object_map_[std::make_pair(*new_object, f)] = new_field_obj;
Martin Brænne46f1a572022-07-01 02:07:07 -0700849 object_stack.push_back(ObjectPair{*field_obj, new_field_obj});
Luca Versari99fddff2022-05-25 10:22:32 -0700850 }
851 }
852 return new_root;
853}
854
Martin Brænne46f1a572022-07-01 02:07:07 -0700855std::optional<const Object*> ObjectRepository::GetFieldObjectInternal(
Luca Versari99fddff2022-05-25 10:22:32 -0700856 Object struct_object, const clang::FieldDecl* field) const {
857 auto iter = field_object_map_.find(std::make_pair(struct_object, field));
858 if (iter != field_object_map_.end()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700859 return iter->second;
Luca Versari99fddff2022-05-25 10:22:32 -0700860 }
861 if (auto* cxxrecord = clang::dyn_cast<clang::CXXRecordDecl>(
862 struct_object.Type()->getAs<clang::RecordType>()->getDecl())) {
863 for (const clang::CXXBaseSpecifier& base : cxxrecord->bases()) {
Martin Brænne46f1a572022-07-01 02:07:07 -0700864 std::optional<const Object*> field_object = GetFieldObjectInternal(
Martin Brænnee08ac882022-07-01 02:24:49 -0700865 *GetBaseClassObject(struct_object, base.getType()), field);
Luca Versari99fddff2022-05-25 10:22:32 -0700866 if (field_object.has_value()) {
867 return field_object;
868 }
869 }
870 }
871 return std::nullopt;
872}
873
874} // namespace lifetimes
875} // namespace tidy
876} // namespace clang