CfrontCodeGenerator.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 <clang/AST/VTableBuilder.h>
9
10#include <algorithm>
11#include <vector>
12
13#include "CodeGenerator.h"
14#include "DPrint.h"
15#include "Insights.h"
16#include "InsightsHelpers.h"
17#include "InsightsOnce.h"
18#include "InsightsStrCat.h"
19#include "NumberIterator.h"
20
21#include "ASTHelpers.h"
22//-----------------------------------------------------------------------------
23
24namespace clang::insights {
25
26using namespace asthelpers;
27//-----------------------------------------------------------------------------
28
29//! Store the `this` pointer offset from derived to base class.
30static llvm::DenseMap<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, int> mThisPointerOffset{};
31//-----------------------------------------------------------------------------
32
33static MemberExpr* AccessMember(std::string_view name, const ValueDecl* vd, QualType type)
34{
35 auto* rhsDeclRef = mkVarDeclRefExpr(name, type);
36 auto* rhsMemberExpr = AccessMember(rhsDeclRef, vd);
37
38 return rhsMemberExpr;
39}
40//-----------------------------------------------------------------------------
41
43: vptpTypedef{Typedef("__vptp"sv, Function("vptp"sv, GetGlobalAST().IntTy, {})->getType())}
44, vtableRecorDecl{}
45{
46 vtableRecorDecl = Struct("__mptr"sv);
47 auto AddField = [&](FieldDecl* field) { vtableRecorDecl->addDecl(field); };
48
49 d = mkFieldDecl(vtableRecorDecl, "d"sv, GetGlobalAST().ShortTy);
50 AddField(d);
51 AddField(mkFieldDecl(vtableRecorDecl, "i"sv, GetGlobalAST().ShortTy));
52 f = mkFieldDecl(vtableRecorDecl, "f"sv, vptpTypedef);
53 AddField(f);
54
55 vtableRecorDecl->completeDefinition();
56
57 vtableRecordType = QualType{vtableRecorDecl->getTypeForDecl(), 0u};
58}
59//-----------------------------------------------------------------------------
60
62{
63 return Variable("__vtbl_array"sv, ContantArrayTy(Ptr(vtableRecordType), size));
64}
65//-----------------------------------------------------------------------------
66
67FieldDecl* CfrontCodeGenerator::CfrontVtableData::VtblPtrField(const CXXRecordDecl* parent)
68{
69 return mkFieldDecl(const_cast<CXXRecordDecl*>(parent), StrCat("__vptr"sv, GetName(*parent)), Ptr(vtableRecordType));
70}
71//-----------------------------------------------------------------------------
72
79//-----------------------------------------------------------------------------
80
81CodeGeneratorVariant::CodeGenerators::CodeGenerators(OutputFormatHelper& _outputFormatHelper,
83 CodeGenerator::ProcessingPrimaryTemplate processingPrimaryTemplate)
84{
85 if(GetInsightsOptions().UseShow2C) {
86 new(&cfcg) CfrontCodeGenerator{_outputFormatHelper, lambdaStack, processingPrimaryTemplate};
87 } else {
88 new(&cg) CodeGenerator{_outputFormatHelper, lambdaStack, processingPrimaryTemplate};
89 }
90}
91//-----------------------------------------------------------------------------
92
93CodeGeneratorVariant::CodeGenerators::CodeGenerators(OutputFormatHelper& _outputFormatHelper)
94{
95 if(GetInsightsOptions().UseShow2C) {
96 new(&cfcg) CfrontCodeGenerator{_outputFormatHelper};
97 } else {
98 new(&cg) CodeGenerator{_outputFormatHelper};
99 }
100}
101//-----------------------------------------------------------------------------
102
103CodeGeneratorVariant::CodeGenerators::~CodeGenerators()
104{
105 if(GetInsightsOptions().UseShow2C) {
106 cfcg.~CfrontCodeGenerator();
107 } else {
108 cg.~CodeGenerator();
109 }
110}
111//-----------------------------------------------------------------------------
112
113void CodeGeneratorVariant::Set()
114{
115 if(GetInsightsOptions().UseShow2C) {
116 cg = &cgs.cfcg;
117 } else {
118 cg = &cgs.cg;
119 }
120}
121//-----------------------------------------------------------------------------
122
123static bool IsCopyOrMoveCtor(const CXXConstructorDecl* ctor)
124{
125 return ctor and (ctor->isCopyConstructor() or ctor->isMoveConstructor());
126}
127//-----------------------------------------------------------------------------
128
129static bool IsCopyOrMoveAssign(const CXXMethodDecl* stmt)
130{
131 return stmt and (stmt->isCopyAssignmentOperator() or stmt->isMoveAssignmentOperator());
132}
133//-----------------------------------------------------------------------------
134
135static std::string GetSpecialMemberName(const ValueDecl* vd, QualType type)
136{
137 if(const auto* md = dyn_cast_or_null<CXXMethodDecl>(vd)) {
138 // GetName below would return a[4] for example. To avoid the array part we go for the underlying type.
139 if(const auto* ar = dyn_cast_or_null<ArrayType>(type)) {
140 type = ar->getElementType();
141 }
142
143 auto rdName = GetName(type);
144
145 if(const auto* ctor = dyn_cast_or_null<CXXConstructorDecl>(md)) {
146 if(ctor->isCopyConstructor()) {
147 return StrCat("CopyConstructor_"sv, rdName);
148 } else if(ctor->isMoveConstructor()) {
149 return StrCat("MoveConstructor_"sv, rdName);
150 }
151
152 return StrCat("Constructor_"sv, rdName);
153
154 } else if(isa<CXXDestructorDecl>(md)) {
155 return StrCat("Destructor_"sv, rdName);
156 }
157 }
158
159 return GetName(*vd);
160}
161//-----------------------------------------------------------------------------
162
163std::string GetSpecialMemberName(const ValueDecl* vd)
164{
165 if(const auto* md = dyn_cast_or_null<CXXMethodDecl>(vd)) {
167 }
168
169 return {};
170}
171//-----------------------------------------------------------------------------
172
177//-----------------------------------------------------------------------------
178
179static bool HasCtor(QualType t)
180{
181 if(auto* cxxRecordDecl = t->getAsCXXRecordDecl(); cxxRecordDecl and not cxxRecordDecl->isTrivial()) {
182 return true;
183 }
184
185 return false;
186}
187//-----------------------------------------------------------------------------
188
189static bool HasDtor(QualType t)
190{
191 if(auto* cxxRecordDecl = t->getAsCXXRecordDecl(); cxxRecordDecl and not cxxRecordDecl->hasTrivialDestructor()) {
192 return true;
193 }
194
195 return false;
196}
197//-----------------------------------------------------------------------------
198
199static auto* CallVecDeleteOrDtor(Expr* objectParam, QualType allocatedType, std::string_view name, uint64_t size)
200{
201 auto dtorName = GetSpecialMemberName(allocatedType->getAsCXXRecordDecl()->getDestructor());
202
203 SmallVector<Expr*, 4> args{objectParam,
204 Sizeof(allocatedType),
205 Int32(size), // XXX what is the correct value?
206 CastToVoidFunPtr(dtorName)};
207
208 return Call(name, args);
209}
210//-----------------------------------------------------------------------------
211
212static auto* CallVecDelete(Expr* objectParam, QualType allocatedType)
213{
215
216 return CallVecDeleteOrDtor(objectParam, allocatedType, "__cxa_vec_delete"sv, 0);
217}
218//-----------------------------------------------------------------------------
219
220static auto* CallVecDtor(Expr* objectParam, const ConstantArrayType* ar)
221{
223
224 return CallVecDeleteOrDtor(objectParam, ar->getElementType(), "__cxa_vec_dtor"sv, GetSize(ar));
225}
226//-----------------------------------------------------------------------------
227
228void CfrontCodeGenerator::InsertArg(const CXXDeleteExpr* stmt)
229{
230 auto destroyedType = stmt->getDestroyedType();
231 auto* arg = const_cast<Expr*>(stmt->getArgument());
232
233 StmtsContainer bodyStmts{};
234
235 if(const auto hasDtor{HasDtor(destroyedType)}; stmt->isArrayForm() and hasDtor) {
236 bodyStmts.Add(CallVecDelete(arg, destroyedType));
237 } else if(hasDtor) {
238 bodyStmts.Add(Call(StrCat("Destructor_"sv, GetName(destroyedType)), {arg}));
239 }
240
242
243 bodyStmts.Add(Call("free"sv, {arg}));
244
245 InsertArg(If(arg, {bodyStmts}));
246 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
247}
248//-----------------------------------------------------------------------------
249
250static auto* CallVecNewOrCtor(std::string_view ctorName,
251 Expr* objectParam,
252 QualType allocatedType,
253 Expr* arraySizeExpr,
254 std::string_view funName)
255{
256 // According to "Inside the C++ Object Model" the dtor is required in case one of the array element ctors fails the
257 // already constructed one must be destroyed.
258 // See also: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#array-ctor
259 auto dtorName = [&]() {
260 if(HasDtor(allocatedType)) {
261 return GetSpecialMemberName(allocatedType->getAsCXXRecordDecl()->getDestructor());
262 }
263
264 return std::string{kwNull};
265 }();
266
267 SmallVector<Expr*, 6> args{objectParam,
268 Sizeof(allocatedType),
269 arraySizeExpr,
270 Int32(0), // XXX what is the correct value?
271 CastToVoidFunPtr(ctorName),
272 CastToVoidFunPtr(dtorName)};
273
274 return Call(funName, args);
275}
276//-----------------------------------------------------------------------------
277
278static auto* CallVecNew(std::string_view ctorName, Expr* objectParam, QualType allocatedType, Expr* arraySizeExpr)
279{
281
282 return CallVecNewOrCtor(ctorName, objectParam, allocatedType, arraySizeExpr, "__cxa_vec_new"sv);
283}
284//-----------------------------------------------------------------------------
285
286static auto*
287CallVecCtor(std::string_view ctorName, const VarDecl* objectParam, QualType allocatedType, Expr* arraySizeExpr)
288{
290
291 return CallVecNewOrCtor(ctorName, mkDeclRefExpr(objectParam), allocatedType, arraySizeExpr, "__cxa_vec_ctor"sv);
292}
293//-----------------------------------------------------------------------------
294
295void CfrontCodeGenerator::InsertArg(const CXXNewExpr* cstmt)
296{
297 auto* stmt = const_cast<CXXNewExpr*>(cstmt);
298
299 auto allocatedType = stmt->getAllocatedType();
300 auto ctorName = StrCat("Constructor_"sv, GetName(allocatedType));
301
302 if(stmt->isArray()) {
304
305 auto* arraySizeExpr = stmt->getArraySize().value();
306 auto* callMalloc = Call("malloc"sv, {Mul(Sizeof(allocatedType), arraySizeExpr)});
307
308 Expr* assign{};
309
310 // According to "Inside the C++ Object Model" a trivial and literal type does use plain malloc as it does not
311 // require a ctor/dtor.
312 if(not HasCtor(allocatedType) and not HasDtor(allocatedType)) {
313 assign = Cast(callMalloc, Ptr(allocatedType));
314
315 } else {
316 if(allocatedType->getAsCXXRecordDecl()->ctors().empty()) {
318
319 ctorName = kwNull;
320 }
321
322 assign = Cast(CallVecNew(ctorName, callMalloc, allocatedType, arraySizeExpr), Ptr(allocatedType));
323 }
324
325 InsertArg(assign);
326
327 if(stmt->hasInitializer() and allocatedType->isBuiltinType()) { // Ignore CXXConstructExpr
328 // The resulting code here is slightly different from the cfront code. For
329 //
330 // int* p = new int(2);
331 //
332 // C++ Insights generates:
333 //
334 // int* p = (int*)malloc(sizeof(int));
335 // if(p) { *p = 2; }
336 //
337 // However, due to Cs requirement to only declare variables and delay initialization the cfront code is
338 //
339 // int* p;
340 // if(p = (int*)malloc(sizeof(int))) { *p = 2; }
342
343 if(auto* inits = dyn_cast_or_null<InitListExpr>(stmt->getInitializer())) {
344 auto* expr = [&]() -> const Expr* {
345 if(auto* vd = dyn_cast_or_null<VarDecl>(mLastDecl)) {
346 return mkDeclRefExpr(vd);
347 }
348
349 return mLastExpr;
350 }();
351
352 StmtsContainer bodyStmts{};
353
354 for(auto idx : NumberIterator(inits->getNumInits())) {
355 bodyStmts.Add(Assign(ArraySubscript(expr, idx, allocatedType), inits->getInit(idx)));
356 }
357
358 InsertArg(If(expr, {bodyStmts}));
359
360 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
361 }
362 }
363
364 return;
365 }
366
367 auto* mallocCall = [&]() -> Expr* {
368 if(stmt->getNumPlacementArgs()) {
369 return stmt->getPlacementArg(0);
370 }
371
373
374 return Call("malloc"sv, {Sizeof(allocatedType)});
375 }();
376
377 mallocCall = Cast(mallocCall, Ptr(allocatedType));
378
379 if(allocatedType->isBuiltinType()) {
380 InsertArg(mallocCall);
381
382 if(stmt->hasInitializer()) {
383 // The resulting code here is slightly different from the cfront code. For
384 //
385 // int* p = new int(2);
386 //
387 // C++ Insights generates:
388 //
389 // int* p = (int*)malloc(sizeof(int));
390 // if(p) { *p = 2; }
391 //
392 // However, due to Cs requirement to only declare variables and delay initialization the cfront code is
393 //
394 // int* p;
395 // if(p = (int*)malloc(sizeof(int))) { *p = 2; }
397
398 auto* varDeclRefExpr = mkDeclRefExpr(dyn_cast_or_null<VarDecl>(mLastDecl));
399
400 StmtsContainer bodyStmts{Assign(Dref(varDeclRefExpr), stmt->getInitializer())};
401
402 InsertArg(If(varDeclRefExpr, {bodyStmts}));
403
404 mInsertSemi = false; // Since we tamper with a CompoundStmt we signal _not_ to insert the usual semi
405 }
406
407 return;
408 }
409
410 SmallVector<Expr*, 16> args{mallocCall};
411 if(auto* ncCtorExpr = const_cast<CXXConstructExpr*>(stmt->getConstructExpr())) {
412 args.append(ncCtorExpr->arg_begin(), ncCtorExpr->arg_end());
413 }
414
415 InsertArg(Call(ctorName, args));
416}
417//-----------------------------------------------------------------------------
418
419void CfrontCodeGenerator::InsertArg(const CXXOperatorCallExpr* stmt)
420{
421 const auto* callee = stmt->getDirectCallee();
422
423 if(const auto* cxxCallee = dyn_cast_or_null<CXXMethodDecl>(callee); IsCopyOrMoveAssign(cxxCallee)) {
424 SmallVector<Expr*, 16> args{};
425
426 for(const auto& arg : stmt->arguments()) {
427 args.push_back(Ref(arg));
428 }
429
430 InsertArg(Call(callee, args));
431
432 } else {
433 InsertArg(dyn_cast_or_null<CallExpr>(stmt));
434 }
435}
436//-----------------------------------------------------------------------------
437
438static void InsertVtblPtr(const CXXMethodDecl* stmt, const CXXRecordDecl* cur, StmtsContainer& bodyStmts)
439{
440 if(cur->isPolymorphic() and (0 == cur->getNumBases())) {
441 auto* fieldDecl = CfrontCodeGenerator::VtableData().VtblPtrField(cur);
442 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(cur)));
443
444 // struct __mptr *__ptbl_vec__c___src_C_[]
446 auto* vtblArrayPos =
447 ArraySubscript(mkDeclRefExpr(vtablAr), GetGlobalVtablePos(stmt->getParent(), cur), fieldDecl->getType());
448
449 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, vtblArrayPos));
450
451 } else if(cur->isPolymorphic() and (0 < cur->getNumBases()) and (cur != stmt->getParent())) {
452 for(const auto& base : cur->bases()) {
453 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
454 }
455 }
456}
457//-----------------------------------------------------------------------------
458
460{
461 // Skip if he method is unused like assignment operators by default.
462 RETURN_IF(not stmt->isUsed() and
463 (IsCopyOrMoveAssign(stmt) or (not stmt->hasBody() and not isa<CXXConstructorDecl>(stmt))));
464
465 OutputFormatHelper initOutputFormatHelper{};
466 initOutputFormatHelper.SetIndent(mOutputFormatHelper, OutputFormatHelper::SkipIndenting::Yes);
467
468 auto recordDeclType = GetRecordDeclType(stmt);
469 if(stmt->isConst()) {
470 recordDeclType.addConst();
471 }
472
473 auto parentType = Ptr(recordDeclType);
474 auto* body = stmt->getBody();
475 StmtsContainer bodyStmts{};
476
477 auto retType = stmt->getReturnType();
478
479 auto processBaseClassesAndFields = [&](const CXXRecordDecl* parent) {
480 auto* thisOfParent = mkVarDeclRefExpr(kwInternalThis, parentType);
481
482 auto insertFields = [&](const RecordDecl* rd) {
483 for(auto* fieldDecl : rd->fields()) {
484 if(const auto* cxxRecordDecl = fieldDecl->getType()->getAsCXXRecordDecl()) {
485 // We don't need any checks like isDefaultConstructible. We would not reach this
486 // point in any other case.
487
488 auto lvalueRefType = GetGlobalAST().getLValueReferenceType(parentType);
489 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, lvalueRefType);
490 auto* rhsMemberExpr = AccessMember("__rhs"sv, fieldDecl, lvalueRefType);
491
492 // Add call to ctor
493 bodyStmts.AddBodyStmts(Call(GetSpecialMemberName(stmt, GetRecordDeclType(cxxRecordDecl)),
494 {Ref(lhsMemberExpr), Ref(rhsMemberExpr)}));
495
496 } else {
497 auto* rhsMemberExpr = AccessMember("__rhs"sv, fieldDecl, parentType);
498
499 bodyStmts.AddBodyStmts(Assign(thisOfParent, fieldDecl, rhsMemberExpr));
500 }
501 }
502 };
503
504 for(const auto& base : parent->bases()) {
505 const auto rd = base.getType()->getAsRecordDecl();
506
507 auto* lhsCast = StaticCast(GetRecordDeclType(rd), thisOfParent, true);
508 auto* rhsDeclRef = mkVarDeclRefExpr("__rhs"sv, parentType);
509 auto* rhsCast = StaticCast(GetRecordDeclType(rd), rhsDeclRef, true);
510
511 auto* callAssignBase = Call(GetSpecialMemberName(stmt, GetRecordDeclType(rd)), {lhsCast, rhsCast});
512
513 bodyStmts.AddBodyStmts(callAssignBase);
514 }
515
516 // insert own fields
517 insertFields(parent);
518 };
519
520 // Skip ctor for trivial types
521 if(const auto* ctorDecl = dyn_cast_or_null<CXXConstructorDecl>(stmt)) {
522 const auto* parent = stmt->getParent();
523
524 if(not stmt->doesThisDeclarationHaveABody()) {
525 if(IsCopyOrMoveCtor(ctorDecl)) {
526 if(const bool showSpecialMemberFunc{stmt->isUserProvided() or stmt->isExplicitlyDefaulted()};
527 not showSpecialMemberFunc) {
528 return;
529 }
530
531 processBaseClassesAndFields(parent);
532 }
533 } else if(ctorDecl->isDefaultConstructor()) {
534 auto insertFields = [&](const RecordDecl* rd) {
535 for(auto* fieldDecl : rd->fields()) {
536 if(auto* initializer = fieldDecl->getInClassInitializer();
537 initializer and fieldDecl->hasInClassInitializer()) {
538 const bool isConstructorExpr{isa<CXXConstructExpr>(initializer) or
539 isa<ExprWithCleanups>(initializer)};
540
541 if(not isConstructorExpr) {
542 auto* lhsMemberExpr = AccessMember(kwInternalThis, fieldDecl, Ptr(GetRecordDeclType(rd)));
543
544 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, fieldDecl, initializer));
545
546 } else {
547 bodyStmts.AddBodyStmts(CallConstructor(fieldDecl->getType(),
549 fieldDecl,
550 ArgsToExprVector(initializer),
551 DoCast::No,
552 AsReference::Yes));
553 }
554
555 } else if(const auto* cxxRecordDecl = fieldDecl->getType()->getAsCXXRecordDecl()) {
556 // We don't need any checks like isDefaultConstructible. We would not reach this
557 // point in any other cause.
558
559 if(auto lhsType = fieldDecl->getType(); HasCtor(lhsType)) {
560 bodyStmts.AddBodyStmts(CallConstructor(GetRecordDeclType(cxxRecordDecl),
561 Ptr(GetRecordDeclType(cxxRecordDecl)),
562 fieldDecl,
563 {},
564 DoCast::No,
565 AsReference::Yes));
566
567 } else {
568 bodyStmts.Add(
569 Comment(StrCat(GetName(*fieldDecl), " // trivial type, maybe uninitialized"sv)));
570 // Nothing to do here, we are looking at an uninitialized variable
571 }
572 }
573 }
574 };
575
576 for(const auto& base : parent->bases()) {
577 auto baseType = base.getType();
578
579 if(const auto* baseRd = baseType->getAsCXXRecordDecl();
580 baseRd and baseRd->hasNonTrivialDefaultConstructor()) {
581 bodyStmts.AddBodyStmts(CallConstructor(baseType, Ptr(baseType), nullptr, {}, DoCast::Yes));
582 }
583 }
584
585 // insert our vtable pointer
586 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
587
588 // in case of multi inheritance insert additional vtable pointers
589 for(const auto& base : parent->bases()) {
590 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
591 }
592
593 // insert own fields
594 insertFields(parent);
595
596 } else {
597 // user ctor
598 for(const auto* init : ctorDecl->inits()) {
599 auto* member = init->getMember();
600
601 if(not isa<CXXConstructExpr>(init->getInit())) {
602 if(not init->getAnyMember()) {
603 continue;
604 }
605
606 auto* lhsMemberExpr = AccessMember(kwInternalThis, member, Ptr(GetRecordDeclType(parent)));
607
608 bodyStmts.AddBodyStmts(Assign(lhsMemberExpr, member, init->getInit()));
609 continue;
610
611 } else if(init->isBaseInitializer()) {
612 bodyStmts.AddBodyStmts(init->getInit());
613 continue;
614 }
615
616 auto ctorType = member->getType();
617
618 auto* lhsMemberExpr = AccessMember(kwInternalThis, member, ctorType);
619
620 auto callParams{ArgsToExprVector(init->getInit())};
621 callParams.insert(callParams.begin(), Ref(lhsMemberExpr));
622
623 bodyStmts.AddBodyStmts(
624 Call(GetSpecialMemberName(stmt, GetRecordDeclType(ctorType->getAsRecordDecl())), callParams));
625 }
626
627 // insert our vtable pointer
628 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
629 // in case of multi inheritance insert additional vtable pointers
630 for(const auto& base : parent->bases()) {
631 InsertVtblPtr(stmt, base.getType()->getAsCXXRecordDecl(), bodyStmts);
632 }
633 }
634
635 if(body) {
636 bodyStmts.AddBodyStmts(body);
637 }
638
639 bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(ctorDecl->getType()))));
640
641 body = mkCompoundStmt({bodyStmts});
642 retType = parentType;
643
644 // copy and move assignment op
645 } else if(IsCopyOrMoveAssign(stmt)) {
646 if(not stmt->doesThisDeclarationHaveABody() or stmt->isDefaulted()) {
647
648 // we don't want the default generated body
649 bodyStmts.clear();
650
651 processBaseClassesAndFields(stmt->getParent());
652 } else if(body) {
653 bodyStmts.AddBodyStmts(body);
654 }
655
656 bodyStmts.AddBodyStmts(Return(mkVarDeclRefExpr(kwInternalThis, Ptr(stmt->getType()))));
657
658 body = mkCompoundStmt({bodyStmts});
659 retType = parentType;
660
661 } else if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(stmt)) {
662 // Based on: https://www.dre.vanderbilt.edu/~schmidt/PDF/C++-translation.pdf
663
664 if(not HasDtor(GetRecordDeclType(dtor->getParent()))) {
665 return;
666 }
667
668 InsertVtblPtr(stmt, stmt->getParent(), bodyStmts);
669
670 for(const auto& base : llvm::reverse(dtor->getParent()->bases())) {
671 if(not dtor->isVirtual()) {
672 continue;
673 }
674
675 InsertVtblPtr(stmt, dyn_cast_or_null<CXXRecordDecl>(base.getType()->getAsRecordDecl()), bodyStmts);
676 }
677
678 if(body) {
679 bodyStmts.AddBodyStmts(body);
680 }
681
682 for(const auto& base : llvm::reverse(dtor->getParent()->bases())) {
683 if(not dtor->isVirtual()) {
684 continue;
685 }
686
687 auto* lhsDeclRef = mkVarDeclRefExpr(kwInternalThis, Ptr(base.getType()));
688 auto* cast = Cast(lhsDeclRef, lhsDeclRef->getType());
689
690 bodyStmts.Add(
691 Call(GetSpecialMemberName(stmt, GetRecordDeclType(base.getType()->getAsRecordDecl())), {cast}));
692 }
693
694 body = mkCompoundStmt({bodyStmts});
695 }
696
697 params_store params{};
698 params.reserve(stmt->getNumParams() + 1);
699
700 if(not IsStaticStorageClass(stmt) and not stmt->isStatic()) {
701 params.emplace_back(kwInternalThis, parentType);
702 }
703
704 for(const auto& param : stmt->parameters()) {
705 std::string name{GetName(*param)};
706 auto type = param->getType();
707
708 // at least in case of a copy constructor modify the parameters
709 if((0 == name.length()) and
710 (IsCopyOrMoveCtor(dyn_cast_or_null<CXXConstructorDecl>(stmt)) or IsCopyOrMoveAssign(stmt))) {
711 name = "__rhs"sv;
712 type = Ptr(type.getNonReferenceType());
713 }
714
715 params.emplace_back(name, type);
716 }
717
718 auto* callSpecialMemberFn = Function(GetSpecialMemberName(stmt), retType, to_params_view(params));
719 callSpecialMemberFn->setInlineSpecified(stmt->isInlined());
720 callSpecialMemberFn->setStorageClass((stmt->isStatic() or IsStaticStorageClass(stmt)) ? SC_Static : SC_None);
721 callSpecialMemberFn->setBody(body);
722
723 InsertArg(callSpecialMemberFn);
724
726}
727//-----------------------------------------------------------------------------
728
729void CfrontCodeGenerator::FormatCast(const std::string_view,
730 const QualType& castDestType,
731 const Expr* subExpr,
732 const CastKind& kind)
733{
734 // C does not have a rvalue notation and we already transformed the temporary into an object. Skip the cast to &&.
735 // Ignore CK_UncheckedDerivedToBase which would lead to (A)c where neither A nor c is a pointer.
736 if(not castDestType->isRValueReferenceType() and not(CastKind::CK_UncheckedDerivedToBase == kind)) {
737 mOutputFormatHelper.Append("(", GetName(castDestType), ")");
738
739 // ARM p 221:
740 // C* pc = new C;
741 // B* pb = pc -> pc = (B*) ((char*)pc+delta(B))
742 if(is{kind}.any_of(CastKind::CK_DerivedToBase, CastKind::CK_BaseToDerived)) {
743 // We have to switch in case of a base to derived cast
744 auto [key,
745 sign] = [&]() -> std::pair<std::pair<const CXXRecordDecl*, const CXXRecordDecl*>, std::string_view> {
746 auto plainType = [](QualType t) {
747 if(const auto* pt = dyn_cast_or_null<PointerType>(t.getTypePtrOrNull())) {
748 return pt->getPointeeType()->getAsCXXRecordDecl();
749 }
750
751 return t->getAsCXXRecordDecl();
752 };
753
754 auto base = plainType(castDestType);
755 auto derived = plainType(subExpr->getType());
756
757 if((CastKind::CK_BaseToDerived == kind)) {
758 return {{base, derived}, "-"sv};
759 }
760
761 return {{derived, base}, "+"sv};
762 }();
763
764 if(auto off = mThisPointerOffset[key]) {
765 mOutputFormatHelper.Append("((char*)"sv);
766 InsertArg(subExpr);
767 mOutputFormatHelper.Append(sign, off, ")"sv);
768
769 return;
770 }
771 }
772 }
773
774 InsertArg(subExpr);
775}
776//-----------------------------------------------------------------------------
777
784//-----------------------------------------------------------------------------
785
786void CfrontCodeGenerator::InsertArg(const StaticAssertDecl* stmt)
787{
789
790 mOutputFormatHelper.Append("_Static_assert"sv);
791
792 WrapInParens([&] {
793 InsertArg(stmt->getAssertExpr());
794
795 if(stmt->getMessage()) {
797 InsertArg(stmt->getMessage());
798 }
799 });
800
802}
803//-----------------------------------------------------------------------------
804
805void CfrontCodeGenerator::InsertArg(const TypedefDecl* stmt)
806{
807 mOutputFormatHelper.AppendSemiNewLine(kwTypedefSpace, GetName(stmt->getUnderlyingType()), " "sv, GetName(*stmt));
809}
810//-----------------------------------------------------------------------------
811
812static void ProcessFields(CXXRecordDecl* recordDecl, const CXXRecordDecl* rd)
813{
814 RETURN_IF(not rd->hasDefinition())
815
816 auto AddField = [&](const FieldDecl* field) {
817 recordDecl->addDecl(mkFieldDecl(recordDecl, GetName(*field), field->getType()));
818 };
819
820 // Insert field from base classes
821 for(const auto& base : rd->bases()) {
822 // XXX: ignoring TemplateSpecializationType
823 if(const auto* rdBase = dyn_cast_or_null<CXXRecordDecl>(base.getType().getCanonicalType()->getAsRecordDecl())) {
824 ProcessFields(recordDecl, rdBase);
825 }
826 }
827
828 // insert vtable pointer if required
829 if(rd->isPolymorphic() and (rd->getNumBases() == 0)) {
830 recordDecl->addDecl(CfrontCodeGenerator::VtableData().VtblPtrField(rd));
831 }
832
833 // insert own fields
834 for(const auto* d : rd->fields()) {
835 AddField(d);
836 }
837
838 if(recordDecl->field_empty()) {
839 AddField(mkFieldDecl(recordDecl, "__dummy"sv, GetGlobalAST().CharTy));
840 }
841}
842//-----------------------------------------------------------------------------
843
844static std::string GetFirstPolymorphicBaseName(const RecordDecl* decl, const RecordDecl* to)
845{
846 std::string ret{GetName(*decl)};
847
848 if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() > 1) {
849 for(const auto& base : rdecl->bases()) {
850 if(const auto* rd = base.getType()->getAsRecordDecl(); rd == to) {
851 ret += GetFirstPolymorphicBaseName(rd, to);
852 break;
853 }
854 }
855 }
856
857 return ret;
858}
859//-----------------------------------------------------------------------------
860
861///! Find the first polymorphic base class.
862static const CXXRecordDecl* GetFirstPolymorphicBase(const RecordDecl* decl)
863{
864 if(const auto* rdecl = dyn_cast_or_null<CXXRecordDecl>(decl); rdecl->getNumBases() >= 1) {
865 for(const auto& base : rdecl->bases()) {
866 const auto* rd = base.getType()->getAsRecordDecl();
867
868 if(const auto* cxxRd = dyn_cast_or_null<CXXRecordDecl>(rd); not cxxRd or not cxxRd->isPolymorphic()) {
869 continue;
870 } else if(const CXXRecordDecl* ret = GetFirstPolymorphicBase(rd)) {
871 return ret;
872 }
873
874 break;
875 }
876 }
877
878 return dyn_cast_or_null<CXXRecordDecl>(decl);
879}
880//-----------------------------------------------------------------------------
881
882void CfrontCodeGenerator::InsertArg(const CXXRecordDecl* stmt)
883{
884 auto* recordDecl = Struct(GetName(*stmt));
885
886 if(stmt->hasDefinition() and stmt->isPolymorphic()) {
887 if(auto* itctx =
888 static_cast<ItaniumVTableContext*>(const_cast<ASTContext&>(GetGlobalAST()).getVTableContext())) {
889#if 0
890 // Get mangled RTTI name
891 auto* mc = const_cast<ASTContext&>(GetGlobalAST()).createMangleContext(nullptr);
892 SmallString<256> rttiName{};
893 llvm::raw_svector_ostream out(rttiName);
894 mc->mangleCXXRTTI(QualType(stmt->getTypeForDecl(), 0), out);
895 DPrint("name: %s\n", rttiName.c_str());
896#endif
897
898 SmallVector<Expr*, 16> mInitExprs{};
899 SmallVector<QualType, 5> baseList{};
900
901 if(stmt->getNumBases() == 0) {
902 baseList.push_back(GetRecordDeclType(stmt));
903 }
904
905 for(const auto& base : stmt->bases()) {
906 baseList.push_back(base.getType());
907 }
908
909 llvm::DenseMap<uint64_t, ThunkInfo> thunkMap{};
910 const VTableLayout& layout{itctx->getVTableLayout(stmt)};
911
912 for(const auto& [idx, thunk] : layout.vtable_thunks()) {
913 thunkMap[idx] = thunk;
914 }
915
916 unsigned clsIdx{};
917 unsigned funIdx{};
918 auto& vtblData = VtableData();
919
920 auto pushVtable = [&] {
921 if(funIdx) {
923
924 // struct __mptr __vtbl__A[] = {0, 0, 0, 0, 0, (__vptp)FunA, 0, 0, 0};
925 auto* thisRd = baseList[clsIdx - 1]->getAsCXXRecordDecl();
926 auto vtableName{StrCat("__vtbl_"sv, GetFirstPolymorphicBaseName(stmt, thisRd))};
927 auto* vtabl = Variable(vtableName, ContantArrayTy(vtblData.vtableRecordType, funIdx));
928 vtabl->setInit(InitList(mInitExprs, vtblData.vtableRecordType));
929
930 PushVtableEntry(stmt, thisRd, vtabl);
931
932 funIdx = 0;
933 }
934
935 mInitExprs.clear();
936 };
937
938 for(unsigned i = 0; const auto& vc : layout.vtable_components()) {
939 switch(vc.getKind()) {
940 case VTableComponent::CK_OffsetToTop: {
941 auto off = layout.getVTableOffset(clsIdx);
942 if(auto rem = (off % 4)) {
943 off += 4 - rem; // sometimes the value is misaligned. Align to 4 bytes
944 }
945
946 mThisPointerOffset[{stmt, baseList[clsIdx]->getAsCXXRecordDecl()}] = off * 4; // we need bytes
947
948 if(clsIdx >= 1) {
949 pushVtable();
950 }
951 ++clsIdx;
952 } break;
953
954 case VTableComponent::CK_RTTI:
955 break;
956
957 // Source: https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vtable-components
958 // The entries for virtual destructors are actually pairs of entries. The first destructor,
959 // called the complete object destructor, performs the destruction without calling delete() on
960 // the object. The second destructor, called the deleting destructor, calls delete() after
961 // destroying the object.
962 case VTableComponent::CK_CompleteDtorPointer:
963 break; // vc.getKind() == VTableComponent::CK_CompleteDtorPointer
964 case VTableComponent::CK_DeletingDtorPointer:
965 case VTableComponent::CK_FunctionPointer: {
966 auto* thunkOffset = [&] {
967 if(ThunkInfo thunk = thunkMap.lookup(i); not thunk.isEmpty() and not thunk.This.isEmpty()) {
968 return Int32(thunk.This.NonVirtual);
969 }
970
971 return Int32(0);
972 }();
973
974 const auto* md = dyn_cast_or_null<FunctionDecl>(vc.getFunctionDecl());
975
976 std::string name{};
977 if(md->isPureVirtual()) {
980
981 md = Function("__cxa_pure_virtual"sv, VoidTy(), params_vector{{kwInternalThis, VoidTy()}});
982
983 name = GetName(*md);
984 } else {
985 name = GetSpecialMemberName(md);
986 }
987
988 auto* reicast = ReinterpretCast(vtblData.vptpTypedef, mkVarDeclRefExpr(name, md->getType()));
989
990 mInitExprs.push_back(InitList({thunkOffset, Int32(0), reicast}, vtblData.vtableRecordType));
991
992 mVirtualFunctions[{md, {stmt, GetFirstPolymorphicBase(stmt)}}] = funIdx;
993
994 ++funIdx;
995 break;
996 }
997 default: break;
998 }
999
1000 ++i;
1001 }
1002
1003 pushVtable();
1004 }
1005 }
1006
1007 if(stmt->hasDefinition()) {
1008 ProcessFields(recordDecl, stmt);
1009 recordDecl->completeDefinition();
1010
1012 }
1013
1014 // use our freshly created recordDecl
1015 CodeGenerator::InsertArg(recordDecl);
1016
1017#if 0
1018 // TypedefDecl above is not called
1019 auto& ctx = GetGlobalAST();
1020 auto et = ctx.getElaboratedType(ElaboratedTypeKeyword::ETK_Struct, nullptr, GetRecordDeclType(recordDecl), nullptr);
1021 auto* typedefDecl = Typedef(GetName(*stmt),et);
1022 CodeGenerator::InsertArg(typedefDecl);
1023#endif
1024
1025 // insert member functions except for the special member functions and classes defined inside this class
1026 for(OnceTrue firstRecordDecl{}; const auto* d : stmt->decls()) {
1027 if((isa<CXXRecordDecl>(d) and firstRecordDecl) // skip the first record decl which are ourselves
1028 or (stmt->isLambda() and isa<CXXDestructorDecl>(d)) // skip dtor for lambdas
1029 or isa<FieldDecl>(d) // skip fields
1030 or isa<AccessSpecDecl>(d) // skip access specifiers
1031 ) {
1032 continue;
1033 }
1034
1035 // According to "Inside the C++ Object Model" a trivial and literal type has no ctor/dtor.
1036 if((stmt->isTrivial() and isa<CXXConstructorDecl>(d)) or
1037 (stmt->hasTrivialDestructor() and isa<CXXDestructorDecl>(d))) {
1038 continue;
1039 }
1040
1041 InsertArg(d);
1042 }
1043}
1044//-----------------------------------------------------------------------------
1045
1046void CfrontCodeGenerator::InsertArg(const CXXMemberCallExpr* stmt)
1047{
1048 if(const auto* me = dyn_cast_or_null<MemberExpr>(stmt->getCallee())) {
1049 auto* obj = me->getBase();
1050 const bool isPointer{obj->getType()->isPointerType()};
1051
1052 if(const bool isReference = IsReferenceType(dyn_cast_or_null<VarDecl>(obj->getReferencedDeclOfCallee()));
1053 not isPointer and not isReference) {
1054 obj = Ref(obj);
1055 }
1056
1057 if(const auto* matExpr = dyn_cast_or_null<MaterializeTemporaryExpr>(me->getBase())) {
1058 if(const auto* tmpExpr = dyn_cast_or_null<CXXBindTemporaryExpr>(matExpr->getSubExpr())) {
1059 if(const auto* tmpObjExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(tmpExpr->getSubExpr())) {
1060 obj = const_cast<CXXTemporaryObjectExpr*>(tmpObjExpr);
1061 }
1062 }
1063 }
1064
1065 auto* memDecl = me->getMemberDecl();
1066
1067 if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(obj->getType())) {
1068 if(const auto* dtor = dyn_cast_or_null<CXXDestructorDecl>(memDecl)) {
1069 // ignore the reference
1070 InsertArg(CallVecDtor(dyn_cast_or_null<UnaryOperator>(obj)->getSubExpr(), ar));
1071 return;
1072 }
1073 }
1074
1075 SmallVector<Expr*, 16> params{obj};
1076 auto* ncStmt = const_cast<CXXMemberCallExpr*>(stmt);
1077 params.append(ncStmt->arg_begin(), ncStmt->arg_end());
1078
1079 if(auto* md = dyn_cast_or_null<CXXMethodDecl>(memDecl); md and md->isVirtual()) {
1080 auto& vtblData = VtableData();
1081 auto* cls = md->getParent();
1082 auto vRecordDecl = GetFirstPolymorphicBase(cls);
1083 auto* vtblField = VtableData().VtblPtrField(vRecordDecl);
1084
1085 // -- cast to function signature: void Fun(struct X*)
1086
1087 auto destType = not isPointer ? Ptr(obj->getType()) : obj->getType();
1088 auto atype = isPointer ? obj->getType()->getPointeeType() : obj->getType();
1089 auto idx = mVirtualFunctions[{md, {atype->getAsCXXRecordDecl(), vRecordDecl}}];
1090
1091 // a->__vptr[1]; #1
1092 auto* accessVptr = AccessMember(Paren(obj), vtblField, true);
1093 auto* vtblArrayPos = ArraySubscript(accessVptr, idx, vtblField->getType());
1094
1095 auto* p = Paren(vtblArrayPos); // ( #1 ) #2
1096 auto* accessMemberF = AccessMember(p, vtblData.f, false); // #2.f #3
1097
1098 // (void (*)(struct X*) (#3)
1099 params_vector ps{{kwInternalThis, destType}};
1100 auto* funcPtrFuncDecl = Function("__dummy"sv, VoidTy(), ps);
1101 auto* reicast = ReinterpretCast(funcPtrFuncDecl->getType(), accessMemberF, true);
1102
1103 auto* p4 = Paren(reicast); // (#4)
1104 auto p5 = Dref(p4); // *#5
1105 auto* p6 = Paren(p5); // (#5) #6
1106
1107 // -- call with possible this pointer adjustment
1108
1109 auto* p7 = AccessMember(p, vtblData.d, false); // a->__vptr[1]; #7
1110 auto* p8 = ReinterpretCast(GetGlobalAST().CharTy, Paren(obj), true); // (#7) #8
1111
1112 auto* p9 = ReinterpretCast(destType, p8);
1113
1114 auto* p10 = Paren(p9);
1115 auto* p11 = Plus(p10, p7); // #7 + #8 #9
1116 auto* p12 = Paren(p11);
1117
1118 // Use the modified object parameter
1119 params[0] = p12;
1120 InsertArg(CallExpr::Create(GetGlobalAST(), p6, params, p6->getType(), VK_LValue, {}, {}));
1121
1122 } else {
1123 InsertArg(Call(GetSpecialMemberName(memDecl), params));
1124 }
1125
1126 } else {
1128 }
1129}
1130//-----------------------------------------------------------------------------
1131
1132void CfrontCodeGenerator::InsertArg(const FunctionDecl* stmt)
1133{
1134 if(not stmt->isMain()) {
1136 return;
1137 }
1138
1139 params_store params{};
1140 SmallVector<Expr*, 16> args{};
1141
1142 for(auto* param : stmt->parameters()) {
1143 params.emplace_back(GetName(*param), param->getType());
1144 args.push_back(mkDeclRefExpr(param));
1145 }
1146
1147 auto mainName{"main"sv};
1148 auto trampolinMainName{BuildInternalVarName(mainName)};
1149
1150 auto* intMain = Function(trampolinMainName, stmt->getReturnType(), to_params_view(params));
1151 intMain->setBody(stmt->getBody());
1152 intMain->setHasImplicitReturnZero(true);
1153
1154 InsertArg(intMain);
1156
1157 auto* mainRetVar = Variable("ret"sv, stmt->getReturnType());
1158 mainRetVar->setInit(Call(trampolinMainName, args));
1159
1160 auto* mainRetVarDeclStmt = mkDeclStmt(mainRetVar);
1161
1162 StmtsContainer bodyStmts{Call(cxaStart, {}), mainRetVarDeclStmt, Call(cxaAtExit, {}), Return(mainRetVar)};
1163
1164 auto* body = mkCompoundStmt({bodyStmts});
1165 auto* modMain = Function(mainName, stmt->getReturnType(), to_params_view(params));
1166 modMain->setBody(body);
1167
1168 CodeGenerator::InsertArg(modMain);
1169}
1170//-----------------------------------------------------------------------------
1171
1172void CfrontCodeGenerator::InsertArg(const CXXConstructExpr* stmt)
1173{
1174 if(P0315Visitor dt{*this}; not dt.TraverseType(stmt->getType())) {
1175 if(not mLambdaStack.empty()) {
1176 for(const auto& e : mLambdaStack) {
1177 RETURN_IF(LambdaCallerType::VarDecl == e.callerType());
1178 }
1179 }
1180 }
1181
1182 auto ctor = stmt->getConstructor();
1183 auto ctorName = GetSpecialMemberName(ctor);
1184 auto* vd = dyn_cast_or_null<VarDecl>(mLastDecl);
1185
1186#if 0
1187 // XXX: An expression like C c[4]{4,5,6} with C having a ctor does show up wrong at the moment.
1188 if(not ar) {
1189 ar = dyn_cast_or_null<ConstantArrayType>(vd->getType());
1190
1191 if(ar) {
1192 mLastStmt->dump();
1193 openScope = true;
1194 // mOutputFormatHelper.CloseScopeWithSemi();
1196 }
1197 }
1198#endif
1199
1200 auto InsertCallCtor = [&](Expr* varNameRef) {
1201 SmallVector<Expr*, 16> args{Cast(varNameRef, Ptr(stmt->getType()))};
1202
1203 for(int i = 0; auto* arg : stmt->arguments()) {
1204 if(IsCopyOrMoveCtor(ctor) or ctor->getParamDecl(i)->getType()->isReferenceType()) {
1205 args.push_back(Ref(arg));
1206
1207 } else {
1208 args.push_back(const_cast<Expr*>(arg));
1209 }
1210
1211 ++i;
1212 }
1213
1214 InsertArg(Call(ctorName, args));
1215 };
1216
1217 // For an array we need to call __vec_new
1218 if(const auto* ar = dyn_cast_or_null<ConstantArrayType>(stmt->getType())) {
1219 if(not HasCtor(ar->getElementType())) {
1220 mInsertSemi = false;
1221 return;
1222 }
1223
1224 InsertArg(CallVecCtor(ctorName, vd, ar->getElementType(), Int32(GetSize(ar))));
1225
1226 } else if(const auto* tmpObjectExpr = dyn_cast_or_null<CXXTemporaryObjectExpr>(stmt); vd and not tmpObjectExpr) {
1227 if(not HasCtor(vd->getType())) {
1228 mInsertSemi = false;
1229 } else {
1230 auto* varNameRef = Ref(mkDeclRefExpr(vd));
1231
1232 InsertCallCtor(varNameRef);
1233 }
1234
1235 } else if(tmpObjectExpr) {
1236 auto* varNameRef = Ref(mkVarDeclRefExpr(GetName(*tmpObjectExpr), stmt->getType()));
1237
1238 if(not HasCtor(stmt->getType())) {
1239 InsertArg(varNameRef);
1240 return;
1241 }
1242
1243 InsertCallCtor(varNameRef);
1244
1245 } else {
1247 stmt->getType(), Ptr(GetRecordDeclType(ctor)), nullptr, ArgsToExprVector(stmt), DoCast::Yes));
1248 }
1249}
1250//-----------------------------------------------------------------------------
1251
1252} // namespace clang::insights
const InsightsOptions & GetInsightsOptions()
Get the global C++ Insights options.
Definition Insights.cpp:37
const ASTContext & GetGlobalAST()
Get access to the ASTContext.
Definition Insights.cpp:71
constexpr std::string_view kwNull
constexpr std::string_view cxaStart
constexpr std::string_view kwInternalThis
constexpr std::string_view kwTypedefSpace
constexpr std::string_view cxaAtExit
#define RETURN_IF(cond)
! A helper inspired by https://github.com/Microsoft/wil/wiki/Error-handling-helpers
constexpr bool empty() const noexcept
Definition StackList.h:69
A special generator for coroutines. It is only activated, if -show-coroutines-transformation is given...
void InsertArg(const CXXThisExpr *) override
void InsertCXXMethodDecl(const CXXMethodDecl *, CodeGenerator::SkipBody) override
void FormatCast(const std::string_view, const QualType &, const Expr *, const CastKind &) override
void WrapInParens(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
virtual void InsertArg(const Decl *stmt)
OutputFormatHelper & mOutputFormatHelper
void AppendNewLine(const char c)
Same as Append but adds a newline after the last argument.
void Append(const char c)
Append a single character.
void SetIndent(const unsigned indent, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to indent.
void AppendSemiNewLine()
Append a semicolon and a newline.
! Find a LambdaExpr inside a Decltype
DeclStmt * mkDeclStmt(Dcls... dcls)
Definition ASTHelpers.h:91
BinaryOperator * Plus(Expr *var, Expr *assignExpr)
CXXReinterpretCastExpr * ReinterpretCast(QualType toType, const Expr *toExpr, bool makePointer)
CXXRecordDecl * Struct(std::string_view name)
FieldDecl * mkFieldDecl(DeclContext *dc, std::string_view name, QualType type)
params_vector to_params_view(params_store &params)
DeclRefExpr * mkDeclRefExpr(const ValueDecl *vd)
QualType Typedef(std::string_view name, QualType underlayingType)
std::vector< std::pair< std::string_view, QualType > > params_vector
Definition ASTHelpers.h:27
CallExpr * Call(const FunctionDecl *fd, ArrayRef< Expr * > params)
UnaryOperator * Ref(const Expr *e)
VarDecl * Variable(std::string_view name, QualType type, DeclContext *dc)
MemberExpr * AccessMember(const Expr *expr, const ValueDecl *vd, bool isArrow)
DeclRefExpr * mkVarDeclRefExpr(std::string_view name, QualType type)
static CallExpr * CallConstructor(QualType ctorType, DeclRefExpr *lhsDeclRef, Expr *lhsMemberExpr, ArrayRef< Expr * > callParams, DoCast doCast, AsReference asReference)
SmallVector< Expr *, 5 > ArgsToExprVector(const Expr *expr)
ArraySubscriptExpr * ArraySubscript(const Expr *lhs, uint64_t index, QualType type)
ReturnStmt * Return(Expr *stmt)
CXXStaticCastExpr * Cast(const Expr *toExpr, QualType toType)
CXXStaticCastExpr * CastToVoidFunPtr(std::string_view name)
Stmt * Comment(std::string_view comment)
ParenExpr * Paren(Expr *expr)
IfStmt * If(const Expr *condition, ArrayRef< Stmt * > bodyStmts)
BinaryOperator * Mul(Expr *lhs, Expr *rhs)
InitListExpr * InitList(ArrayRef< Expr * > initExprs, QualType t)
UnaryExprOrTypeTraitExpr * Sizeof(QualType toType)
QualType GetRecordDeclType(const CXXMethodDecl *md)
std::vector< std::pair< std::string, QualType > > params_store
Definition ASTHelpers.h:28
FunctionDecl * Function(std::string_view name, QualType returnType, const params_vector &parameters)
CompoundStmt * mkCompoundStmt(ArrayRef< Stmt * > bodyStmts, SourceLocation beginLoc, SourceLocation endLoc)
IntegerLiteral * Int32(uint64_t value)
QualType ContantArrayTy(QualType t, int size)
UnaryOperator * Dref(const Expr *stmt)
QualType Ptr(QualType srcType)
CXXStaticCastExpr * StaticCast(QualType toType, const Expr *toExpr, bool makePointer)
BinaryOperator * Assign(const VarDecl *var, Expr *assignExpr)
static auto * CallVecDelete(Expr *objectParam, QualType allocatedType)
uint64_t GetSize(const ConstantArrayType *arrayType)
@ HeaderStdlib
Track whether we need to insert <stdlib.h> in Cfront mode.
@ HeaderAssert
Track whether we need to insert <assert.h> in Cfront mode.
@ HeaderStddef
Track whether we need to insert <stddef.h> in Cfront mode.
void PushVtableEntry(const CXXRecordDecl *record, const CXXRecordDecl *recordB, VarDecl *decl)
int GetGlobalVtablePos(const CXXRecordDecl *record, const CXXRecordDecl *recordB)
static llvm::DenseMap< std::pair< const CXXRecordDecl *, const CXXRecordDecl * >, int > mThisPointerOffset
Store the this pointer offset from derived to base class.
std::string GetName(const NamedDecl &nd, const QualifiedName qualifiedName)
static void ProcessFields(CXXRecordDecl *recordDecl, const CXXRecordDecl *rd)
void DPrint(const char *fmt, const auto &... args)
Debug print which is disabled in release-mode.
Definition DPrint.h:71
std::string BuildInternalVarName(const std::string_view &varName)
static bool IsCopyOrMoveAssign(const CXXMethodDecl *stmt)
static bool HasDtor(QualType t)
static const CXXRecordDecl * GetFirstPolymorphicBase(const RecordDecl *decl)
! Find the first polymorphic base class.
static bool HasCtor(QualType t)
static void InsertVtblPtr(const CXXMethodDecl *stmt, const CXXRecordDecl *cur, StmtsContainer &bodyStmts)
static auto * CallVecDtor(Expr *objectParam, const ConstantArrayType *ar)
bool IsReferenceType(const ValueDecl *decl)
static auto * CallVecNewOrCtor(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr, std::string_view funName)
static std::string GetSpecialMemberName(const ValueDecl *vd, QualType type)
static auto * CallVecCtor(std::string_view ctorName, const VarDecl *objectParam, QualType allocatedType, Expr *arraySizeExpr)
static bool IsCopyOrMoveCtor(const CXXConstructorDecl *ctor)
bool IsStaticStorageClass(const CXXMethodDecl *md)
static std::string GetFirstPolymorphicBaseName(const RecordDecl *decl, const RecordDecl *to)
static auto * CallVecNew(std::string_view ctorName, Expr *objectParam, QualType allocatedType, Expr *arraySizeExpr)
static auto * CallVecDeleteOrDtor(Expr *objectParam, QualType allocatedType, std::string_view name, uint64_t size)
void EnableGlobalInsert(GlobalInserts idx)
Definition Insights.cpp:96
static FieldDecl * AddField(CoroutineASTData &astData, std::string_view name, QualType type)
std::string StrCat(const auto &... args)
FieldDecl * VtblPtrField(const CXXRecordDecl *parent)
! A helper type to have a container for ArrayRef
Definition ASTHelpers.h:64
Handy helper to avoid longish comparisons.
constexpr bool any_of(const auto &... ts) const