CodeGenerator.h
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 #ifndef INSIGHTS_CODE_GENERATOR_H
9 #define INSIGHTS_CODE_GENERATOR_H
10 
11 #include "clang/AST/ASTContext.h"
12 #include "clang/Rewrite/Core/Rewriter.h"
13 #include "llvm/ADT/APInt.h"
14 
15 #include <optional>
16 
17 #include "ClangCompat.h"
18 #include "InsightsStaticStrings.h"
19 #include "InsightsStrongTypes.h"
20 #include "InsightsUtility.h"
21 #include "OutputFormatHelper.h"
22 #include "StackList.h"
23 //-----------------------------------------------------------------------------
24 
25 namespace clang::insights {
26 
27 void PushVtableEntry(const CXXRecordDecl*, const CXXRecordDecl*, VarDecl* decl);
28 int GetGlobalVtablePos(const CXXRecordDecl*, const CXXRecordDecl*);
29 
31 {
32  std::string mComment{};
33 
34 public:
35  CppInsightsCommentStmt(std::string_view comment)
36  : Stmt{NoStmtClass}
37  , mComment{comment}
38  {
39  }
40 
41  std::string_view Comment() const { return mComment; }
42 
43  static bool classof(const Stmt* T) { return T->getStmtClass() == NoStmtClass; }
44 
45  child_range children()
46  {
47  static child_iterator iter{};
48  return {iter, iter};
49  }
50  const_child_range children() const
51  {
52  static const_child_iterator iter{};
53  return {iter, iter};
54  }
55 };
56 
58 {
59  STRONG_BOOL(FuncStart);
60 
61  const VarDecl* item{};
62  FuncStart funcStart{FuncStart::No};
63  int scope{};
64 };
65 
67 {
68  inline static int scopeCounter{};
69 
70  SmallVector<LifetimeEntry, 10> objects{};
71 
72  void InsertDtorCall(const VarDecl* decl, OutputFormatHelper& ofm);
73 
74 public:
75  void Add(const VarDecl* decl);
76  void AddExtended(const VarDecl* decl, const ValueDecl* extending);
77 
78  LifetimeEntry& top() { return objects.back(); }
79 
80  void removeTop();
81  void StartScope(bool funcStart);
82  bool Return(OutputFormatHelper& ofm);
83  bool EndScope(OutputFormatHelper& ofm, bool clear);
84 };
85 
86 /// \brief More or less the heart of C++ Insights.
87 ///
88 /// This is the place where nearly all of the transformations happen. This class knows the needed types and how to
89 /// generated code from them.
91 {
92 protected:
94  const Stmt* mLastStmt{};
95  const Expr* mLastExpr{}; // special case for assignments to class member
96 
97 public:
98  const Decl* mLastDecl{};
99 
100 protected:
102  friend class CodeGeneratorVariant;
103 
105 
106  enum class LambdaCallerType
107  {
108  VarDecl,
109  InitCapture,
110  CallExpr,
113  LambdaExpr,
114  ReturnStmt,
117  TemplateHead,
118  Decltype,
119  };
120 
121  class LambdaHelper : public StackListEntry<LambdaHelper>
122  {
123  public:
124  LambdaHelper(const LambdaCallerType lambdaCallerType, OutputFormatHelper& outputFormatHelper)
125  : mLambdaCallerType{lambdaCallerType}
126  , mCurrentVarDeclPos{outputFormatHelper.CurrentPos()}
127  , mOutputFormatHelper{outputFormatHelper}
128  {
129  mLambdaOutputFormatHelper.SetIndent(mOutputFormatHelper);
130  }
131 
132  void finish()
133  {
134  if(not mLambdaOutputFormatHelper.empty()) {
135  mOutputFormatHelper.InsertAt(mCurrentVarDeclPos, mLambdaOutputFormatHelper);
136  }
137  }
138 
139  OutputFormatHelper& buffer() { return mLambdaOutputFormatHelper; }
140 
141  std::string& inits() { return mInits; }
142 
143  void insertInits(OutputFormatHelper& outputFormatHelper)
144  {
145  if(not mInits.empty()) {
146  outputFormatHelper.Append(mInits);
147  mInits.clear();
148  }
149  }
150 
151  LambdaCallerType callerType() const { return mLambdaCallerType; }
152  bool insertName() const { return (LambdaCallerType::Decltype != mLambdaCallerType) or mForceName; }
153 
154  void setInsertName(bool b) { mForceName = b; }
155 
156  private:
157  const LambdaCallerType mLambdaCallerType;
158  const size_t mCurrentVarDeclPos;
159  OutputFormatHelper& mOutputFormatHelper;
160  OutputFormatHelper mLambdaOutputFormatHelper{};
161  std::string mInits{};
162  bool mForceName{};
163  };
164  //-----------------------------------------------------------------------------
165 
167 
168  STRONG_BOOL(LambdaInInitCapture); ///! Signal whether we are processing a lambda created and assigned to an init
169  /// capture of another lambda.
170 
172  ProcessingPrimaryTemplate); ///! We do not want to transform a primary template which contains a Coroutine.
173 
174  constexpr CodeGenerator(OutputFormatHelper& _outputFormatHelper,
175  LambdaStackType& lambdaStack,
176  LambdaInInitCapture lambdaInitCapture,
177  ProcessingPrimaryTemplate processingPrimaryTemplate)
178  : mOutputFormatHelper{_outputFormatHelper}
179  , mLambdaStack{lambdaStack}
180  , mLambdaInitCapture{lambdaInitCapture}
181  , mProcessingPrimaryTemplate{processingPrimaryTemplate}
182  {
183  }
184 
185 public:
186  explicit constexpr CodeGenerator(OutputFormatHelper& _outputFormatHelper)
187  : CodeGenerator{_outputFormatHelper, mLambdaStackThis, ProcessingPrimaryTemplate::No}
188  {
189  }
190 
191  constexpr CodeGenerator(OutputFormatHelper& _outputFormatHelper, LambdaInInitCapture lambdaInitCapture)
192  : CodeGenerator{_outputFormatHelper, mLambdaStackThis, lambdaInitCapture, ProcessingPrimaryTemplate::No}
193  {
194  }
195 
196  constexpr CodeGenerator(OutputFormatHelper& _outputFormatHelper,
197  LambdaStackType& lambdaStack,
198  ProcessingPrimaryTemplate processingPrimaryTemplate)
199  : CodeGenerator{_outputFormatHelper, lambdaStack, LambdaInInitCapture::No, processingPrimaryTemplate}
200  {
201  }
202 
203  virtual ~CodeGenerator() = default;
204 
205 #define IGNORED_DECL(type) \
206  virtual void InsertArg(const type*) {}
207 #define IGNORED_STMT(type) \
208  virtual void InsertArg(const type*) {}
209 #define SUPPORTED_DECL(type) virtual void InsertArg(const type* stmt);
210 #define SUPPORTED_STMT(type) virtual void InsertArg(const type* stmt);
211 
212 #include "CodeGeneratorTypes.h"
213 
214  virtual void InsertArg(const Decl* stmt);
215  virtual void InsertArg(const Stmt* stmt);
216 
217  template<typename T>
218  void InsertTemplateArgs(const T& t)
219  {
220  if constexpr(std::is_same_v<T, FunctionDecl>) {
221  if(const auto* tmplArgs = t.getTemplateSpecializationArgs()) {
222  InsertTemplateArgs(*tmplArgs);
223  }
224  } else if constexpr(std::is_same_v<T, VarTemplateSpecializationDecl>) {
225  InsertTemplateArgs(t.getTemplateArgs());
226 
227  } else if constexpr(requires { t.template_arguments(); }) {
228  if constexpr(std::is_same_v<DeclRefExpr, T>) {
229  if(0 == t.getNumTemplateArgs()) {
230  return;
231  }
232  }
233 
234  InsertTemplateArgs(t.template_arguments());
235 
236  } else if constexpr(requires { t.asArray(); }) {
237  InsertTemplateArgs(t.asArray());
238  }
239  }
240 
241  void InsertTemplateArgs(const ClassTemplateSpecializationDecl& clsTemplateSpe);
242 
243  /// \brief Insert the code for a FunctionDecl.
244  ///
245  /// This inserts the code of a FunctionDecl (and everything which is derived from one). It takes care of
246  /// CXXMethodDecl's access modifier as well as things like constexpr, noexcept, static and more.
247  ///
248  /// @param decl The FunctionDecl to process.
249  /// @param skipAccess Show or hide access modifiers (public, private, protected). The default is to show them.
250  /// @param cxxInheritedCtorDecl If not null, the type and name of this decl is used for the parameters.
251  void InsertFunctionNameWithReturnType(const FunctionDecl& decl,
252  const CXXConstructorDecl* cxxInheritedCtorDecl = nullptr);
253 
254  template<typename T>
255  void InsertTemplateArgs(const ArrayRef<T>& array)
256  {
258 
259  ForEachArg(array, [&](const auto& arg) { InsertTemplateArg(arg); });
260 
261  /* put as space between to closing brackets: >> -> > > */
262  if(mOutputFormatHelper.GetString().back() == '>') {
264  }
265 
267  }
268 
269  void InsertAttributes(const Decl*);
270  void InsertAttributes(const Decl::attr_range&);
271  void InsertAttribute(const Attr&);
272 
273  void InsertTemplateArg(const TemplateArgument& arg);
274 
275  STRONG_BOOL(TemplateParamsOnly); ///! Skip template, type constraints and class/typename.
276  void InsertTemplateParameters(const TemplateParameterList& list,
277  const TemplateParamsOnly templateParamsOnly = TemplateParamsOnly::No);
278 
279  void StartLifetimeScope();
280  void LifetimeAddExtended(const VarDecl*, const ValueDecl*);
281  void EndLifetimeScope();
282 
283 protected:
284  virtual bool InsertVarDecl(const VarDecl*) { return true; }
285  virtual bool SkipSpaceAfterVarDecl() { return false; }
286  virtual bool InsertComma() { return false; }
287  virtual bool InsertSemi() { return true; }
288  virtual bool InsertNamespace() const { return false; }
289 
290  /// \brief Show casts to xvalues independent from the show all casts option.
291  ///
292  /// This helps showing xvalue casts in structured bindings.
293  virtual bool ShowXValueCasts() const { return false; }
294 
295  void HandleTemplateParameterPack(const ArrayRef<TemplateArgument>& args);
296  void HandleCompoundStmt(const CompoundStmt* stmt);
297  /// \brief Show what is behind a local static variable.
298  ///
299  /// [stmt.dcl] p4: Initialization of a block-scope variable with static storage duration is thread-safe since C++11.
300  /// Regardless of that, as long as it is a non-trivally construct and destructable class the compiler adds code to
301  /// track the initialization state. Reference:
302  /// - www.opensource.apple.com/source/libcppabi/libcppabi-14/src/cxa_guard.cxx
303  void HandleLocalStaticNonTrivialClass(const VarDecl* stmt);
304 
305  virtual void FormatCast(const std::string_view castName,
306  const QualType& CastDestType,
307  const Expr* SubExpr,
308  const CastKind& castKind);
309 
310  void ForEachArg(const auto& arguments, auto&& lambda) { mOutputFormatHelper.ForEachArg(arguments, lambda); }
311 
312  void InsertArgWithParensIfNeeded(const Stmt* stmt);
313  void InsertSuffix(const QualType& type);
314 
315  void InsertTemplateArg(const TemplateArgumentLoc& arg) { InsertTemplateArg(arg.getArgument()); }
316  bool InsertLambdaStaticInvoker(const CXXMethodDecl* cxxMethodDecl);
317 
318  STRONG_BOOL(InsertInline);
319 
320  void InsertConceptConstraint(const llvm::SmallVectorImpl<const Expr*>& constraints,
321  const InsertInline insertInline);
322  void InsertConceptConstraint(const FunctionDecl* tmplDecl);
323  void InsertConceptConstraint(const VarDecl* varDecl);
324  void InsertConceptConstraint(const TemplateParameterList& tmplDecl);
325 
326  void InsertTemplate(const FunctionTemplateDecl*, bool withSpec);
327 
328  void InsertQualifierAndNameWithTemplateArgs(const DeclarationName& declName, const auto* stmt)
329  {
330  InsertQualifierAndName(declName, stmt->getQualifier(), stmt->hasTemplateKeyword());
331 
332  if(stmt->getNumTemplateArgs()) {
333  InsertTemplateArgs(*stmt);
334  } else if(stmt->hasExplicitTemplateArgs()) {
335  // we have empty templates arguments, but angle brackets provided by the user
336  mOutputFormatHelper.Append("<>"sv);
337  }
338  }
339 
340  void InsertQualifierAndName(const DeclarationName& declName,
341  const NestedNameSpecifier* qualifier,
342  const bool hasTemplateKeyword);
343 
344  /// For a special case, when a LambdaExpr occurs in a Constructor from an
345  /// in class initializer, there is a need for a more narrow scope for the \c LAMBDA_SCOPE_HELPER.
346  void InsertCXXMethodHeader(const CXXMethodDecl* stmt, OutputFormatHelper& initOutputFormatHelper);
347 
348  void InsertTemplateGuardBegin(const FunctionDecl* stmt);
349  void InsertTemplateGuardEnd(const FunctionDecl* stmt);
350 
351  /// \brief Insert \c template<> to introduce a template specialization.
352  void InsertTemplateSpecializationHeader(const Decl&);
353 
354  void InsertTemplateArgsObjectParam(const ArrayRef<TemplateArgument>& array);
355  void InsertTemplateArgsObjectParam(const TemplateParamObjectDecl& param);
356 
357  void InsertNamespace(const NestedNameSpecifier* namespaceSpecifier);
358  void ParseDeclContext(const DeclContext* Ctx);
359 
360  STRONG_BOOL(SkipBody);
361  virtual void InsertCXXMethodDecl(const CXXMethodDecl* stmt, SkipBody skipBody);
362  void InsertMethodBody(const FunctionDecl* stmt, const size_t posBeforeFunc);
363 
364  /// \brief Generalized function to insert either a \c CXXConstructExpr or \c CXXUnresolvedConstructExpr
365  template<typename T>
366  void InsertConstructorExpr(const T* stmt);
367 
368  /// \brief Check whether or not this statement will add curlys or parentheses and add them only if required.
369  void InsertCurlysIfRequired(const Stmt* stmt);
370 
371  void InsertIfOrSwitchInitVariables(same_as_any_of<const IfStmt, const SwitchStmt> auto* stmt);
372 
373  void InsertInstantiationPoint(const SourceManager& sm, const SourceLocation& instLoc, std::string_view text = {});
374 
375  STRONG_BOOL(AddNewLineAfter);
376 
377  void WrapInCompoundIfNeeded(const Stmt* stmt, const AddNewLineAfter addNewLineAfter);
378 
379  STRONG_BOOL(AddSpaceAtTheEnd);
380 
381  enum class BraceKind
382  {
383  Parens,
384  Curlys
385  };
386 
387  void WrapInParens(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd = AddSpaceAtTheEnd::No);
388 
389  void WrapInParensIfNeeded(bool needsParens,
390  void_func_ref lambda,
391  const AddSpaceAtTheEnd addSpaceAtTheEnd = AddSpaceAtTheEnd::No);
392 
393  void WrapInCurliesIfNeeded(bool needsParens,
394  void_func_ref lambda,
395  const AddSpaceAtTheEnd addSpaceAtTheEnd = AddSpaceAtTheEnd::No);
396 
397  void WrapInCurlys(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd = AddSpaceAtTheEnd::No);
398 
399  void WrapInParensOrCurlys(const BraceKind curlys,
400  void_func_ref lambda,
401  const AddSpaceAtTheEnd addSpaceAtTheEnd = AddSpaceAtTheEnd::No);
402 
403  void UpdateCurrentPos(std::optional<size_t>& pos) { pos = mOutputFormatHelper.CurrentPos(); }
404 
405  static std::string_view GetBuiltinTypeSuffix(const BuiltinType::Kind& kind);
406 
408  {
409  public:
411  OutputFormatHelper& outputFormatHelper,
412  const LambdaCallerType lambdaCallerType);
413 
415 
416  private:
417  LambdaStackType& mStack;
418  LambdaHelper mHelper;
419 
420  OutputFormatHelper& GetBuffer(OutputFormatHelper& outputFormatHelper) const;
421  };
422 
423  void HandleLambdaExpr(const LambdaExpr* stmt, LambdaHelper& lambdaHelper);
424  static std::string FillConstantArray(const ConstantArrayType* ct, const std::string& value, const uint64_t startAt);
425  static std::string GetValueOfValueInit(const QualType& t);
426 
427  bool InsideDecltype() const;
428 
431 
432  STRONG_BOOL(SkipVarDecl);
433  STRONG_BOOL(UseCommaInsteadOfSemi);
434  STRONG_BOOL(NoEmptyInitList);
435  STRONG_BOOL(ShowConstantExprValue);
436  LambdaInInitCapture mLambdaInitCapture{LambdaInInitCapture::No};
437 
438  ShowConstantExprValue mShowConstantExprValue{ShowConstantExprValue::No};
439  SkipVarDecl mSkipVarDecl{SkipVarDecl::No};
440  UseCommaInsteadOfSemi mUseCommaInsteadOfSemi{UseCommaInsteadOfSemi::No};
441  NoEmptyInitList mNoEmptyInitList{
442  NoEmptyInitList::No}; //!< At least in case if a requires-clause containing T{} we don't want to get T{{}}.
443  const LambdaExpr* mLambdaExpr{};
444  static constexpr auto MAX_FILL_VALUES_FOR_ARRAYS{
445  uint64_t{100}}; //!< This is the upper limit of elements which will be shown for an array when filled by \c
446  //!< FillConstantArray.
447  std::optional<size_t> mCurrentVarDeclPos{}; //!< The position in mOutputFormatHelper where a potential
448  //!< std::initializer_list expansion must be inserted.
449  std::optional<size_t> mCurrentCallExprPos{}; //!< The position in mOutputFormatHelper where a potential
450  //!< std::initializer_list expansion must be inserted.
451  std::optional<size_t> mCurrentReturnPos{}; //!< The position in mOutputFormatHelper from a return where a
452  //!< potential std::initializer_list expansion must be inserted.
453  std::optional<size_t> mCurrentFieldPos{}; //!< The position in mOutputFormatHelper in a class where where a
454  //!< potential std::initializer_list expansion must be inserted.
456  nullptr}; //!< Helper output buffer for std::initializer_list expansion.
457  bool mRequiresImplicitReturnZero{}; //!< Track whether this is a function with an imlpicit return 0.
458  bool mSkipSemi{};
459  ProcessingPrimaryTemplate mProcessingPrimaryTemplate{};
460  static inline std::map<std::string, bool> mSeenDecls{};
461 };
462 //-----------------------------------------------------------------------------
463 
464 class LambdaCodeGenerator final : public CodeGenerator
465 {
466 public:
468 
470  void InsertArg(const CXXThisExpr* stmt) override;
471 
473 };
474 //-----------------------------------------------------------------------------
475 
476 /*
477  * \brief Special case to generate the inits of e.g. a \c ForStmt.
478  *
479  * This class is a specialization to handle cases where we can have multiple init statements to the same variable and
480  * hence need only one time the \c VarDecl. An example a for-loops:
481 \code
482 for(int x=2, y=3, z=4; i < x; ++i) {}
483 \endcode
484  */
486 {
487 public:
488  explicit MultiStmtDeclCodeGenerator(OutputFormatHelper& _outputFormatHelper,
489  LambdaStackType& lambdaStack,
490  bool insertVarDecl)
491  : CodeGenerator{_outputFormatHelper, lambdaStack, ProcessingPrimaryTemplate::No}
492  , mInsertVarDecl{insertVarDecl}
493  , mInsertComma{}
494  {
495  }
496 
497  // Insert the semi after the last declaration. This implies that this class always requires its own scope.
499 
501 
502 protected:
503  OnceTrue mInsertVarDecl{}; //! Insert the \c VarDecl only once.
504  OnceFalse mInsertComma{}; //! Insert the comma after we have generated the first \c VarDecl and we are about to
505  //! insert another one.
506 
507  bool InsertVarDecl(const VarDecl*) override { return mInsertVarDecl; }
508  bool InsertComma() override { return mInsertComma; }
509  bool InsertSemi() override { return false; }
510 };
511 //-----------------------------------------------------------------------------
512 
514 {
515  CXXRecordDecl* mFrameType{};
516  FieldDecl* mResumeFnField{};
517  FieldDecl* mDestroyFnField{};
518  FieldDecl* mPromiseField{};
519  FieldDecl* mSuspendIndexField{};
522  DeclRefExpr* mFrameAccessDeclRef{};
523  MemberExpr* mSuspendIndexAccess{};
525  std::vector<const CXXThisExpr*> mThisExprs{};
526 };
527 
528 ///
529 /// \brief A special generator for coroutines. It is only activated, if \c -show-coroutines-transformation is given as a
530 /// command line option.
532 {
533 public:
534  explicit CoroutinesCodeGenerator(OutputFormatHelper& _outputFormatHelper, const size_t posBeforeFunc)
535  : CoroutinesCodeGenerator{_outputFormatHelper, posBeforeFunc, {}, {}, {}}
536  {
537  }
538 
539  explicit CoroutinesCodeGenerator(OutputFormatHelper& _outputFormatHelper,
540  const size_t posBeforeFunc,
541  std::string_view fsmName,
542  size_t suspendsCount,
543  CoroutineASTData data)
544  : CodeGenerator{_outputFormatHelper}
545  , mPosBeforeFunc{posBeforeFunc}
546  , mSuspendsCount{suspendsCount}
547  , mFSMName{fsmName}
548  , mASTData{data}
549  {
550  }
551 
552  ~CoroutinesCodeGenerator() override;
553 
555 
556  void InsertArg(const ImplicitCastExpr* stmt) override;
557  void InsertArg(const CallExpr* stmt) override;
558  void InsertArg(const CXXRecordDecl* stmt) override;
559  void InsertArg(const OpaqueValueExpr* stmt) override;
560 
561  void InsertArg(const CoroutineBodyStmt* stmt) override;
562  void InsertArg(const CoroutineSuspendExpr* stmt) override;
563  void InsertArg(const CoreturnStmt* stmt) override;
564 
565  void InsertCoroutine(const FunctionDecl& fd, const CoroutineBodyStmt* body);
566 
567  std::string GetFrameName() const { return mFrameName; }
568 
569 protected:
570  bool InsertVarDecl(const VarDecl* vd) override { return mInsertVarDecl or (vd and vd->isStaticLocal()); }
571  bool SkipSpaceAfterVarDecl() override { return not mInsertVarDecl; }
572 
573 private:
574  enum class eState
575  {
576  Invalid,
577  InitialSuspend,
578  Body,
579  FinalSuspend,
580  };
581 
582  eState mState{};
583  const size_t mPosBeforeFunc;
584  size_t mPosBeforeSuspendExpr{};
585  size_t mSuspendsCount{};
586  size_t mSuspendsCounter{};
587  bool mInsertVarDecl{true};
588  bool mSupressCasts{};
589  bool mSupressRecordDecls{};
590  std::string mFrameName{};
591  std::string mFSMName{};
592  CoroutineASTData mASTData{};
593  llvm::DenseMap<const Stmt*, bool> mBinaryExprs{};
594  static inline llvm::DenseMap<const Expr*, std::pair<const DeclRefExpr*, std::string>>
595  mOpaqueValues{}; ///! Keeps track of the current set of opaque value
596 
597  QualType GetFrameType() const { return QualType(mASTData.mFrameType->getTypeForDecl(), 0); }
598  QualType GetFramePointerType() const;
599 
600  std::string BuildResumeLabelName(int) const;
601  FieldDecl* AddField(std::string_view name, QualType type);
602 
603  void InsertArgWithNull(const Stmt* stmt);
604 };
605 //-----------------------------------------------------------------------------
606 
607 ///
608 /// \brief A special generator for coroutines. It is only activated, if \c -show-coroutines-transformation is given as a
609 /// command line option.
610 class CfrontCodeGenerator final : public CodeGenerator
611 {
612  ///! A mapping for the pair method decl - derived-to-base-class to index in the vtable.
613  static inline llvm::DenseMap<std::pair<const Decl*, std::pair<const CXXRecordDecl*, const CXXRecordDecl*>>, int>
614  mVirtualFunctions{};
615  bool mInsertSemi{true}; // We need to for int* p = new{5};
616 
617 public:
618  using CodeGenerator::CodeGenerator;
619 
620  using CodeGenerator::InsertArg;
621 
622  void InsertArg(const CXXThisExpr*) override;
623  void InsertArg(const CXXDeleteExpr*) override;
624  void InsertArg(const CXXNewExpr*) override;
625  void InsertArg(const CXXOperatorCallExpr*) override;
626  void InsertArg(const CXXNullPtrLiteralExpr*) override;
627  void InsertArg(const StaticAssertDecl*) override;
628  void InsertArg(const CXXRecordDecl*) override;
629  void InsertArg(const CXXMemberCallExpr*) override;
630  void InsertArg(const CXXConstructExpr*) override;
631  void InsertArg(const FunctionDecl* stmt) override;
632  void InsertArg(const TypedefDecl* stmt) override;
633 
634  void InsertCXXMethodDecl(const CXXMethodDecl*, CodeGenerator::SkipBody) override;
635 
636  void FormatCast(const std::string_view, const QualType&, const Expr*, const CastKind&) override;
637 
639  {
641 
642  // struct __mptr *__ptbl_vec__c___src_C_[]
643  VarDecl* VtblArrayVar(int size);
644  FieldDecl* VtblPtrField(const CXXRecordDecl* parent);
645 
646  QualType vptpTypedef; // typedef int (*__vptp)();
647 
648  /*
649 struct __mptr
650 {
651  short d;
652  short i;
653  __vptp f;
654 };
655 */
656  CXXRecordDecl* vtableRecorDecl;
658  FieldDecl* d;
659  FieldDecl* f;
660  };
661 
662  static CfrontVtableData& VtableData();
663 
664 protected:
665  bool InsertSemi() override { return std::exchange(mInsertSemi, true); }
666 };
667 //-----------------------------------------------------------------------------
668 
669 ///
670 /// \brief A special container which creates either a \c CodeGenerator or a \c CfrontCodeGenerator depending on the
671 /// command line options.
673 {
674  union CodeGenerators
675  {
676  CodeGenerator cg;
677  CfrontCodeGenerator cfcg;
678 
679  CodeGenerators(OutputFormatHelper& _outputFormatHelper,
680  CodeGenerator::LambdaStackType& lambdaStack,
681  CodeGenerator::ProcessingPrimaryTemplate processingPrimaryTemplate);
682  CodeGenerators(OutputFormatHelper& _outputFormatHelper, CodeGenerator::LambdaInInitCapture lambdaInitCapture);
683 
684  ~CodeGenerators();
685  } cgs;
686 
687  CodeGenerator* cg;
688  OutputFormatHelper& ofm;
689 
690  void Set();
691 
692 public:
694  : CodeGeneratorVariant{_outputFormatHelper, CodeGenerator::LambdaInInitCapture::No}
695  {
696  }
697 
699  CodeGenerator::LambdaStackType& lambdaStack,
700  CodeGenerator::ProcessingPrimaryTemplate processingPrimaryTemplate)
701  : cgs{_outputFormatHelper, lambdaStack, processingPrimaryTemplate}
702  , ofm{_outputFormatHelper}
703  , cg{}
704  {
705  Set();
706  }
707 
708  CodeGeneratorVariant(OutputFormatHelper& _outputFormatHelper, CodeGenerator::LambdaInInitCapture lambdaInitCapture)
709  : cgs{_outputFormatHelper, lambdaInitCapture}
710  , ofm{_outputFormatHelper}
711  , cg{}
712  {
713  Set();
714  }
715 
716  CodeGenerator* operator->() { return cg; }
717 };
718 //-----------------------------------------------------------------------------
719 
720 } // namespace clang::insights
721 
722 #endif /* INSIGHTS_CODE_GENERATOR_H */
llvm::function_ref< void()> void_func_ref
A special generator for coroutines. It is only activated, if -show-coroutines-transformation is given...
void insertInits(OutputFormatHelper &outputFormatHelper)
LambdaHelper(const LambdaCallerType lambdaCallerType, OutputFormatHelper &outputFormatHelper)
LambdaScopeHandler(LambdaStackType &stack, OutputFormatHelper &outputFormatHelper, const LambdaCallerType lambdaCallerType)
More or less the heart of C++ Insights.
Definition: CodeGenerator.h:91
STRONG_BOOL(LambdaInInitCapture)
void InsertFunctionNameWithReturnType(const FunctionDecl &decl, const CXXConstructorDecl *cxxInheritedCtorDecl=nullptr)
Insert the code for a FunctionDecl.
void WrapInParensIfNeeded(bool needsParens, void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
void WrapInCompoundIfNeeded(const Stmt *stmt, const AddNewLineAfter addNewLineAfter)
static std::map< std::string, bool > mSeenDecls
void HandleCompoundStmt(const CompoundStmt *stmt)
void InsertQualifierAndNameWithTemplateArgs(const DeclarationName &declName, const auto *stmt)
void WrapInParens(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
LambdaInInitCapture mLambdaInitCapture
static std::string FillConstantArray(const ConstantArrayType *ct, const std::string &value, const uint64_t startAt)
void InsertTemplateArg(const TemplateArgumentLoc &arg)
virtual void InsertArg(const Decl *stmt)
void InsertTemplateSpecializationHeader(const Decl &)
Insert template<> to introduce a template specialization.
void WrapInCurlys(void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
virtual bool InsertVarDecl(const VarDecl *)
constexpr CodeGenerator(OutputFormatHelper &_outputFormatHelper, LambdaStackType &lambdaStack, ProcessingPrimaryTemplate processingPrimaryTemplate)
constexpr CodeGenerator(OutputFormatHelper &_outputFormatHelper, LambdaInInitCapture lambdaInitCapture)
const LambdaExpr * mLambdaExpr
constexpr CodeGenerator(OutputFormatHelper &_outputFormatHelper, LambdaStackType &lambdaStack, LambdaInInitCapture lambdaInitCapture, ProcessingPrimaryTemplate processingPrimaryTemplate)
! We do not want to transform a primary template which contains a Coroutine.
void InsertInstantiationPoint(const SourceManager &sm, const SourceLocation &instLoc, std::string_view text={})
Inserts the instantiation point of a template.
ProcessingPrimaryTemplate mProcessingPrimaryTemplate
void InsertTemplateArgs(const T &t)
std::optional< size_t > mCurrentVarDeclPos
void InsertAttribute(const Attr &)
OutputFormatHelper * mOutputFormatHelperOutside
Helper output buffer for std::initializer_list expansion.
void HandleLambdaExpr(const LambdaExpr *stmt, LambdaHelper &lambdaHelper)
void WrapInCurliesIfNeeded(bool needsParens, void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
void InsertTemplateGuardEnd(const FunctionDecl *stmt)
static std::string GetValueOfValueInit(const QualType &t)
STRONG_BOOL(TemplateParamsOnly)
void LifetimeAddExtended(const VarDecl *, const ValueDecl *)
STRONG_BOOL(ProcessingPrimaryTemplate)
void HandleLocalStaticNonTrivialClass(const VarDecl *stmt)
Show what is behind a local static variable.
virtual void FormatCast(const std::string_view castName, const QualType &CastDestType, const Expr *SubExpr, const CastKind &castKind)
std::optional< size_t > mCurrentCallExprPos
virtual void InsertCXXMethodDecl(const CXXMethodDecl *stmt, SkipBody skipBody)
void InsertTemplateParameters(const TemplateParameterList &list, const TemplateParamsOnly templateParamsOnly=TemplateParamsOnly::No)
! Skip template, type constraints and class/typename.
void HandleTemplateParameterPack(const ArrayRef< TemplateArgument > &args)
void InsertIfOrSwitchInitVariables(same_as_any_of< const IfStmt, const SwitchStmt > auto *stmt)
STRONG_BOOL(UseCommaInsteadOfSemi)
void UpdateCurrentPos(std::optional< size_t > &pos)
bool InsertLambdaStaticInvoker(const CXXMethodDecl *cxxMethodDecl)
virtual ~CodeGenerator()=default
void InsertTemplateGuardBegin(const FunctionDecl *stmt)
LambdaStackType & mLambdaStack
void InsertConceptConstraint(const llvm::SmallVectorImpl< const Expr * > &constraints, const InsertInline insertInline)
virtual bool InsertNamespace() const
void ForEachArg(const auto &arguments, auto &&lambda)
void InsertQualifierAndName(const DeclarationName &declName, const NestedNameSpecifier *qualifier, const bool hasTemplateKeyword)
NoEmptyInitList mNoEmptyInitList
At least in case if a requires-clause containing T{} we don't want to get T{{}}.
std::optional< size_t > mCurrentReturnPos
void InsertMethodBody(const FunctionDecl *stmt, const size_t posBeforeFunc)
bool mRequiresImplicitReturnZero
Track whether this is a function with an imlpicit return 0.
void InsertConstructorExpr(const T *stmt)
Generalized function to insert either a CXXConstructExpr or CXXUnresolvedConstructExpr.
void InsertArgWithParensIfNeeded(const Stmt *stmt)
static constexpr auto MAX_FILL_VALUES_FOR_ARRAYS
void WrapInParensOrCurlys(const BraceKind curlys, void_func_ref lambda, const AddSpaceAtTheEnd addSpaceAtTheEnd=AddSpaceAtTheEnd::No)
UseCommaInsteadOfSemi mUseCommaInsteadOfSemi
std::optional< size_t > mCurrentFieldPos
void InsertTemplateArg(const TemplateArgument &arg)
void InsertSuffix(const QualType &type)
STRONG_BOOL(ShowConstantExprValue)
void InsertAttributes(const Decl *)
virtual bool SkipSpaceAfterVarDecl()
void InsertCurlysIfRequired(const Stmt *stmt)
Check whether or not this statement will add curlys or parentheses and add them only if required.
OutputFormatHelper & mOutputFormatHelper
void InsertTemplate(const FunctionTemplateDecl *, bool withSpec)
constexpr CodeGenerator(OutputFormatHelper &_outputFormatHelper)
void InsertCXXMethodHeader(const CXXMethodDecl *stmt, OutputFormatHelper &initOutputFormatHelper)
void InsertTemplateArgs(const ArrayRef< T > &array)
STRONG_BOOL(AddSpaceAtTheEnd)
LifetimeTracker mLifeTimeTracker
Definition: CodeGenerator.h:93
void InsertTemplateArgsObjectParam(const ArrayRef< TemplateArgument > &array)
virtual bool ShowXValueCasts() const
Show casts to xvalues independent from the show all casts option.
static std::string_view GetBuiltinTypeSuffix(const BuiltinType::Kind &kind)
ShowConstantExprValue mShowConstantExprValue
void ParseDeclContext(const DeclContext *Ctx)
A special container which creates either a CodeGenerator or a CfrontCodeGenerator depending on the co...
CodeGeneratorVariant(OutputFormatHelper &_outputFormatHelper, CodeGenerator::LambdaStackType &lambdaStack, CodeGenerator::ProcessingPrimaryTemplate processingPrimaryTemplate)
CodeGeneratorVariant(OutputFormatHelper &_outputFormatHelper, CodeGenerator::LambdaInInitCapture lambdaInitCapture)
CodeGeneratorVariant(OutputFormatHelper &_outputFormatHelper)
A special generator for coroutines. It is only activated, if -show-coroutines-transformation is given...
bool InsertVarDecl(const VarDecl *vd) override
CoroutinesCodeGenerator(OutputFormatHelper &_outputFormatHelper, const size_t posBeforeFunc)
CoroutinesCodeGenerator(OutputFormatHelper &_outputFormatHelper, const size_t posBeforeFunc, std::string_view fsmName, size_t suspendsCount, CoroutineASTData data)
const_child_range children() const
Definition: CodeGenerator.h:50
CppInsightsCommentStmt(std::string_view comment)
Definition: CodeGenerator.h:35
std::string_view Comment() const
Definition: CodeGenerator.h:41
static bool classof(const Stmt *T)
Definition: CodeGenerator.h:43
virtual void InsertArg(const Decl *stmt)
bool EndScope(OutputFormatHelper &ofm, bool clear)
void Add(const VarDecl *decl)
bool Return(OutputFormatHelper &ofm)
void AddExtended(const VarDecl *decl, const ValueDecl *extending)
OnceFalse mInsertComma
Insert the VarDecl only once.
MultiStmtDeclCodeGenerator(OutputFormatHelper &_outputFormatHelper, LambdaStackType &lambdaStack, bool insertVarDecl)
bool InsertVarDecl(const VarDecl *) override
The C++ Insights formatter.
void ForEachArg(const auto &arguments, auto &&lambda)
Append a argument list to the buffer.
void Append(const char c)
Append a single character.
bool empty() const
Check whether the buffer is empty.
void SetIndent(const unsigned indent, const SkipIndenting skipIndenting=SkipIndenting::No)
Set the indent level of this class to indent.
std::string & GetString()
Returns a reference to the underlying string buffer.
size_t CurrentPos() const
Returns the current position in the output buffer.
void InsertAt(const size_t atPos, std::string_view data)
Insert a string before the position atPos.
void PushVtableEntry(const CXXRecordDecl *record, const CXXRecordDecl *recordB, VarDecl *decl)
int GetGlobalVtablePos(const CXXRecordDecl *record, const CXXRecordDecl *recordB)
static FieldDecl * AddField(CoroutineASTData &astData, std::string_view name, QualType type)
Base class for StackList.
Definition: StackList.h:8
std::vector< const CXXThisExpr * > mThisExprs
Definition: CodeGenerator.h:58
STRONG_BOOL(FuncStart)
FuncStart funcStart
Definition: CodeGenerator.h:62
int scope
Definition: CodeGenerator.h:63
const VarDecl * item
Definition: CodeGenerator.h:61