LifetimeTracker.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * C++ Insights, copyright (C) by Andreas Fertig
4  * Distributed under an MIT license. See LICENSE for details
5  *
6  ****************************************************************************/
7 
8 #include <algorithm>
9 
10 #include "ASTHelpers.h"
11 #include "CodeGenerator.h"
12 #include "DPrint.h"
13 #include "Insights.h"
14 #include "InsightsHelpers.h"
15 #include "NumberIterator.h"
16 //-----------------------------------------------------------------------------
17 
18 namespace clang::insights {
19 
20 using namespace asthelpers;
21 //-----------------------------------------------------------------------------
22 
23 void LifetimeTracker::StartScope(bool funcStart)
24 {
25  RETURN_IF(not GetInsightsOptions().ShowLifetime)
26 
27  ++scopeCounter;
28 
29  objects.push_back(
30  {.funcStart = funcStart ? LifetimeEntry::FuncStart::Yes : LifetimeEntry::FuncStart::No, .scope = scopeCounter});
31 }
32 //-----------------------------------------------------------------------------
33 
34 void LifetimeTracker::AddExtended(const VarDecl* decl, const ValueDecl* extending)
35 {
36  // Search for the extending VarlDecl which is already in `objects`. Insert this decl _after_
37  if(auto it = std::ranges::find_if(objects, [&](const auto& e) { return e.item == extending; });
38  it != objects.end()) {
39  const auto scope = (*it).scope;
40  objects.insert(std::next(it), {decl, LifetimeEntry::FuncStart::No, scope});
41  }
42 }
43 //-----------------------------------------------------------------------------
44 
45 void LifetimeTracker::Add(const VarDecl* decl)
46 {
47  RETURN_IF(not GetInsightsOptions().ShowLifetime)
48 
49  QualType type{decl->getType()};
50 
51  RETURN_IF(type->isPointerType() or type->isRValueReferenceType());
52 
53  // For life-time extended objects
54  // XXX contains in C++23
55  RETURN_IF(std::ranges::find_if(objects, [&](const auto& e) { return e.item == decl; }) != objects.end());
56 
57  objects.push_back({decl, LifetimeEntry::FuncStart::No, scopeCounter});
58 }
59 //-----------------------------------------------------------------------------
60 
61 void LifetimeTracker::InsertDtorCall(const VarDecl* vd, OutputFormatHelper& ofm)
62 {
63  QualType type{vd->getType()};
64 
65  if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(type)) {
66  type = ar->getElementType();
67  }
68 
69  if(type->isLValueReferenceType()) {
70  type = type.getNonReferenceType();
71  }
72 
73  if(const auto& ctx = GetGlobalAST(); QualType::DK_cxx_destructor != vd->needsDestruction(ctx)) {
74  CodeGeneratorVariant cg{ofm};
75  cg->InsertArg(Comment(StrCat(GetName(*vd), " // lifetime ends here")));
76 
77  return;
78  }
79 
80  auto* dtorDecl = type->getAsCXXRecordDecl()->getDestructor();
81  auto* ic = CastLToRValue(vd);
82  CodeGeneratorVariant cg{ofm};
83 
84  auto insertDtor = [&](Expr* member) {
85  auto* mem = AccessMember(member, dtorDecl, vd->getType()->isPointerType());
86  cg->InsertArg(CallMemberFun(mem, dtorDecl->getType()));
87  ofm.AppendSemiNewLine();
88  };
89 
90  if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(vd->getType()); ar and not GetInsightsOptions().UseShow2C) {
91  // not nice but call the destructor for each array element
92  for(const auto& i : NumberIterator{GetSize(ar)}) {
93  insertDtor(ArraySubscript(ic, i, type));
94  }
95 
96  return;
97  }
98 
99  insertDtor(ic);
100 }
101 //-----------------------------------------------------------------------------
102 
104 {
105  RETURN_FALSE_IF(not GetInsightsOptions().ShowLifetime or objects.empty())
106 
107  bool ret{};
108 
109  for(OnceTrue needsSemi{}; auto& e : llvm::reverse(objects)) {
110  if(LifetimeEntry::FuncStart::Yes == e.funcStart) {
111  break;
112  }
113 
114  if(nullptr == e.item) {
115  continue;
116  }
117 
118  if(needsSemi) {
119  CodeGeneratorVariant cg{ofm};
120  cg->InsertArg(mkNullStmt());
121  }
122 
123  InsertDtorCall(e.item, ofm);
124  ret = true;
125  }
126 
127  return ret;
128 }
129 //-----------------------------------------------------------------------------
130 
132 {
133  objects.pop_back();
134 
135  auto it = std::ranges::remove_if(objects, [&](const LifetimeEntry& e) { return (e.scope == scopeCounter); });
136  objects.erase(it.begin(), it.end());
137 
138  --scopeCounter;
139 }
140 //-----------------------------------------------------------------------------
141 
142 bool LifetimeTracker::EndScope(OutputFormatHelper& ofm, bool coveredByReturn)
143 {
144  RETURN_FALSE_IF(not GetInsightsOptions().ShowLifetime or objects.empty())
145 
146  bool ret{};
147 
148  if(not coveredByReturn) {
149  for(auto& e : llvm::reverse(objects)) {
150  if(e.scope != scopeCounter) {
151  break;
152  }
153 
154  if(nullptr == e.item) {
155  break;
156  }
157 
158  InsertDtorCall(e.item, ofm);
159  ret = true;
160  }
161  }
162 
163  removeTop();
164 
165  return ret;
166 }
167 //-----------------------------------------------------------------------------
168 
169 } // namespace clang::insights
const ASTContext & GetGlobalAST()
Get access to the ASTContext.
Definition: Insights.cpp:81
const InsightsOptions & GetInsightsOptions()
Get the global C++ Insights options.
Definition: Insights.cpp:37
#define RETURN_IF(cond)
! A helper inspired by https://github.com/Microsoft/wil/wiki/Error-handling-helpers
#define RETURN_FALSE_IF(cond)
A special container which creates either a CodeGenerator or a CfrontCodeGenerator depending on the co...
bool EndScope(OutputFormatHelper &ofm, bool clear)
void Add(const VarDecl *decl)
bool Return(OutputFormatHelper &ofm)
void AddExtended(const VarDecl *decl, const ValueDecl *extending)
The C++ Insights formatter.
void AppendSemiNewLine()
Append a semicolon and a newline.
MemberExpr * AccessMember(const Expr *expr, const ValueDecl *vd, bool isArrow)
Definition: ASTHelpers.cpp:318
ArraySubscriptExpr * ArraySubscript(const Expr *lhs, uint64_t index, QualType type)
Definition: ASTHelpers.cpp:553
Stmt * Comment(std::string_view comment)
Definition: ASTHelpers.cpp:506
ImplicitCastExpr * CastLToRValue(const VarDecl *vd)
Definition: ASTHelpers.cpp:441
CXXMemberCallExpr * CallMemberFun(Expr *memExpr, QualType retType)
Definition: ASTHelpers.cpp:448
uint64_t GetSize(const ConstantArrayType *arrayType)
std::string GetName(const NamedDecl &nd, const QualifiedName qualifiedName)
std::string StrCat(const auto &... args)
Definition: CodeGenerator.h:58
int scope
Definition: CodeGenerator.h:63