1292932Sdim//===-- ASTResultSynthesizer.cpp --------------------------------*- C++ -*-===//
2292932Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6292932Sdim//
7292932Sdim//===----------------------------------------------------------------------===//
8292932Sdim
9292932Sdim#include "ASTResultSynthesizer.h"
10292932Sdim
11292932Sdim#include "ClangPersistentVariables.h"
12292932Sdim
13309124Sdim#include "lldb/Symbol/ClangASTContext.h"
14309124Sdim#include "lldb/Symbol/ClangASTImporter.h"
15309124Sdim#include "lldb/Target/Target.h"
16309124Sdim#include "lldb/Utility/LLDBAssert.h"
17321369Sdim#include "lldb/Utility/Log.h"
18292932Sdim#include "stdlib.h"
19292932Sdim#include "clang/AST/ASTContext.h"
20292932Sdim#include "clang/AST/Decl.h"
21292932Sdim#include "clang/AST/DeclCXX.h"
22292932Sdim#include "clang/AST/DeclGroup.h"
23292932Sdim#include "clang/AST/DeclObjC.h"
24292932Sdim#include "clang/AST/Expr.h"
25292932Sdim#include "clang/AST/Stmt.h"
26292932Sdim#include "clang/Parse/Parser.h"
27292932Sdim#include "clang/Sema/SemaDiagnostic.h"
28292932Sdim#include "llvm/Support/Casting.h"
29292932Sdim#include "llvm/Support/raw_ostream.h"
30292932Sdim
31292932Sdimusing namespace llvm;
32292932Sdimusing namespace clang;
33292932Sdimusing namespace lldb_private;
34292932Sdim
35314564SdimASTResultSynthesizer::ASTResultSynthesizer(ASTConsumer *passthrough,
36314564Sdim                                           bool top_level, Target &target)
37353358Sdim    : m_ast_context(nullptr), m_passthrough(passthrough),
38353358Sdim      m_passthrough_sema(nullptr), m_target(target), m_sema(nullptr),
39353358Sdim      m_top_level(top_level) {
40314564Sdim  if (!m_passthrough)
41314564Sdim    return;
42292932Sdim
43314564Sdim  m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
44292932Sdim}
45292932Sdim
46314564SdimASTResultSynthesizer::~ASTResultSynthesizer() {}
47292932Sdim
48314564Sdimvoid ASTResultSynthesizer::Initialize(ASTContext &Context) {
49314564Sdim  m_ast_context = &Context;
50292932Sdim
51314564Sdim  if (m_passthrough)
52314564Sdim    m_passthrough->Initialize(Context);
53292932Sdim}
54292932Sdim
55314564Sdimvoid ASTResultSynthesizer::TransformTopLevelDecl(Decl *D) {
56314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
57292932Sdim
58314564Sdim  if (NamedDecl *named_decl = dyn_cast<NamedDecl>(D)) {
59314564Sdim    if (log && log->GetVerbose()) {
60314564Sdim      if (named_decl->getIdentifier())
61360784Sdim        LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
62360784Sdim                  named_decl->getIdentifier()->getNameStart());
63314564Sdim      else if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D))
64360784Sdim        LLDB_LOGF(log, "TransformTopLevelDecl(%s)",
65360784Sdim                  method_decl->getSelector().getAsString().c_str());
66314564Sdim      else
67360784Sdim        LLDB_LOGF(log, "TransformTopLevelDecl(<complex>)");
68314564Sdim    }
69292932Sdim
70314564Sdim    if (m_top_level) {
71314564Sdim      RecordPersistentDecl(named_decl);
72292932Sdim    }
73314564Sdim  }
74292932Sdim
75314564Sdim  if (LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D)) {
76314564Sdim    RecordDecl::decl_iterator decl_iterator;
77292932Sdim
78314564Sdim    for (decl_iterator = linkage_spec_decl->decls_begin();
79314564Sdim         decl_iterator != linkage_spec_decl->decls_end(); ++decl_iterator) {
80314564Sdim      TransformTopLevelDecl(*decl_iterator);
81292932Sdim    }
82314564Sdim  } else if (!m_top_level) {
83314564Sdim    if (ObjCMethodDecl *method_decl = dyn_cast<ObjCMethodDecl>(D)) {
84314564Sdim      if (m_ast_context &&
85314564Sdim          !method_decl->getSelector().getAsString().compare("$__lldb_expr:")) {
86314564Sdim        RecordPersistentTypes(method_decl);
87314564Sdim        SynthesizeObjCMethodResult(method_decl);
88314564Sdim      }
89314564Sdim    } else if (FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D)) {
90344779Sdim      // When completing user input the body of the function may be a nullptr.
91344779Sdim      if (m_ast_context && function_decl->hasBody() &&
92314564Sdim          !function_decl->getNameInfo().getAsString().compare("$__lldb_expr")) {
93314564Sdim        RecordPersistentTypes(function_decl);
94314564Sdim        SynthesizeFunctionResult(function_decl);
95314564Sdim      }
96292932Sdim    }
97314564Sdim  }
98292932Sdim}
99292932Sdim
100314564Sdimbool ASTResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D) {
101314564Sdim  DeclGroupRef::iterator decl_iterator;
102292932Sdim
103314564Sdim  for (decl_iterator = D.begin(); decl_iterator != D.end(); ++decl_iterator) {
104314564Sdim    Decl *decl = *decl_iterator;
105292932Sdim
106314564Sdim    TransformTopLevelDecl(decl);
107314564Sdim  }
108292932Sdim
109314564Sdim  if (m_passthrough)
110314564Sdim    return m_passthrough->HandleTopLevelDecl(D);
111314564Sdim  return true;
112292932Sdim}
113292932Sdim
114314564Sdimbool ASTResultSynthesizer::SynthesizeFunctionResult(FunctionDecl *FunDecl) {
115314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
116292932Sdim
117314564Sdim  if (!m_sema)
118314564Sdim    return false;
119292932Sdim
120314564Sdim  FunctionDecl *function_decl = FunDecl;
121292932Sdim
122314564Sdim  if (!function_decl)
123314564Sdim    return false;
124292932Sdim
125314564Sdim  if (log && log->GetVerbose()) {
126314564Sdim    std::string s;
127314564Sdim    raw_string_ostream os(s);
128292932Sdim
129314564Sdim    function_decl->print(os);
130292932Sdim
131314564Sdim    os.flush();
132292932Sdim
133360784Sdim    LLDB_LOGF(log, "Untransformed function AST:\n%s", s.c_str());
134314564Sdim  }
135292932Sdim
136314564Sdim  Stmt *function_body = function_decl->getBody();
137314564Sdim  CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
138292932Sdim
139314564Sdim  bool ret = SynthesizeBodyResult(compound_stmt, function_decl);
140292932Sdim
141314564Sdim  if (log && log->GetVerbose()) {
142314564Sdim    std::string s;
143314564Sdim    raw_string_ostream os(s);
144292932Sdim
145314564Sdim    function_decl->print(os);
146292932Sdim
147314564Sdim    os.flush();
148292932Sdim
149360784Sdim    LLDB_LOGF(log, "Transformed function AST:\n%s", s.c_str());
150314564Sdim  }
151292932Sdim
152314564Sdim  return ret;
153292932Sdim}
154292932Sdim
155314564Sdimbool ASTResultSynthesizer::SynthesizeObjCMethodResult(
156314564Sdim    ObjCMethodDecl *MethodDecl) {
157314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
158292932Sdim
159314564Sdim  if (!m_sema)
160314564Sdim    return false;
161292932Sdim
162314564Sdim  if (!MethodDecl)
163314564Sdim    return false;
164292932Sdim
165314564Sdim  if (log && log->GetVerbose()) {
166314564Sdim    std::string s;
167314564Sdim    raw_string_ostream os(s);
168292932Sdim
169314564Sdim    MethodDecl->print(os);
170292932Sdim
171314564Sdim    os.flush();
172292932Sdim
173360784Sdim    LLDB_LOGF(log, "Untransformed method AST:\n%s", s.c_str());
174314564Sdim  }
175292932Sdim
176314564Sdim  Stmt *method_body = MethodDecl->getBody();
177292932Sdim
178314564Sdim  if (!method_body)
179314564Sdim    return false;
180292932Sdim
181314564Sdim  CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(method_body);
182292932Sdim
183314564Sdim  bool ret = SynthesizeBodyResult(compound_stmt, MethodDecl);
184292932Sdim
185314564Sdim  if (log && log->GetVerbose()) {
186314564Sdim    std::string s;
187314564Sdim    raw_string_ostream os(s);
188292932Sdim
189314564Sdim    MethodDecl->print(os);
190292932Sdim
191314564Sdim    os.flush();
192292932Sdim
193360784Sdim    LLDB_LOGF(log, "Transformed method AST:\n%s", s.c_str());
194314564Sdim  }
195292932Sdim
196314564Sdim  return ret;
197292932Sdim}
198292932Sdim
199314564Sdimbool ASTResultSynthesizer::SynthesizeBodyResult(CompoundStmt *Body,
200314564Sdim                                                DeclContext *DC) {
201314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
202292932Sdim
203314564Sdim  ASTContext &Ctx(*m_ast_context);
204292932Sdim
205314564Sdim  if (!Body)
206314564Sdim    return false;
207292932Sdim
208314564Sdim  if (Body->body_empty())
209314564Sdim    return false;
210292932Sdim
211314564Sdim  Stmt **last_stmt_ptr = Body->body_end() - 1;
212314564Sdim  Stmt *last_stmt = *last_stmt_ptr;
213292932Sdim
214314564Sdim  while (dyn_cast<NullStmt>(last_stmt)) {
215314564Sdim    if (last_stmt_ptr != Body->body_begin()) {
216314564Sdim      last_stmt_ptr--;
217314564Sdim      last_stmt = *last_stmt_ptr;
218314564Sdim    } else {
219314564Sdim      return false;
220292932Sdim    }
221314564Sdim  }
222292932Sdim
223314564Sdim  Expr *last_expr = dyn_cast<Expr>(last_stmt);
224292932Sdim
225314564Sdim  if (!last_expr)
226314564Sdim    // No auxiliary variable necessary; expression returns void
227314564Sdim    return true;
228292932Sdim
229314564Sdim  // In C++11, last_expr can be a LValueToRvalue implicit cast.  Strip that off
230341825Sdim  // if that's the case.
231292932Sdim
232314564Sdim  do {
233314564Sdim    ImplicitCastExpr *implicit_cast = dyn_cast<ImplicitCastExpr>(last_expr);
234292932Sdim
235314564Sdim    if (!implicit_cast)
236314564Sdim      break;
237292932Sdim
238314564Sdim    if (implicit_cast->getCastKind() != CK_LValueToRValue)
239314564Sdim      break;
240292932Sdim
241314564Sdim    last_expr = implicit_cast->getSubExpr();
242353358Sdim  } while (false);
243292932Sdim
244314564Sdim  // is_lvalue is used to record whether the expression returns an assignable
245341825Sdim  // Lvalue or an Rvalue.  This is relevant because they are handled
246341825Sdim  // differently.
247314564Sdim  //
248314564Sdim  // For Lvalues
249314564Sdim  //
250314564Sdim  //   - In AST result synthesis (here!) the expression E is transformed into an
251314564Sdim  //   initialization
252314564Sdim  //     T *$__lldb_expr_result_ptr = &E.
253314564Sdim  //
254314564Sdim  //   - In structure allocation, a pointer-sized slot is allocated in the
255314564Sdim  //   struct that is to be
256314564Sdim  //     passed into the expression.
257314564Sdim  //
258314564Sdim  //   - In IR transformations, reads and writes to $__lldb_expr_result_ptr are
259314564Sdim  //   redirected at
260314564Sdim  //     an entry in the struct ($__lldb_arg) passed into the expression.
261314564Sdim  //     (Other persistent
262314564Sdim  //     variables are treated similarly, having been materialized as
263314564Sdim  //     references, but in those
264314564Sdim  //     cases the value of the reference itself is never modified.)
265314564Sdim  //
266314564Sdim  //   - During materialization, $0 (the result persistent variable) is ignored.
267314564Sdim  //
268314564Sdim  //   - During dematerialization, $0 is marked up as a load address with value
269314564Sdim  //   equal to the
270314564Sdim  //     contents of the structure entry.
271314564Sdim  //
272314564Sdim  // For Rvalues
273314564Sdim  //
274314564Sdim  //   - In AST result synthesis the expression E is transformed into an
275314564Sdim  //   initialization
276314564Sdim  //     static T $__lldb_expr_result = E.
277314564Sdim  //
278314564Sdim  //   - In structure allocation, a pointer-sized slot is allocated in the
279314564Sdim  //   struct that is to be
280314564Sdim  //     passed into the expression.
281314564Sdim  //
282314564Sdim  //   - In IR transformations, an instruction is inserted at the beginning of
283314564Sdim  //   the function to
284314564Sdim  //     dereference the pointer resident in the slot.  Reads and writes to
285314564Sdim  //     $__lldb_expr_result
286314564Sdim  //     are redirected at that dereferenced version.  Guard variables for the
287314564Sdim  //     static variable
288314564Sdim  //     are excised.
289314564Sdim  //
290314564Sdim  //   - During materialization, $0 (the result persistent variable) is
291314564Sdim  //   populated with the location
292314564Sdim  //     of a newly-allocated area of memory.
293314564Sdim  //
294314564Sdim  //   - During dematerialization, $0 is ignored.
295292932Sdim
296341825Sdim  bool is_lvalue = last_expr->getValueKind() == VK_LValue &&
297341825Sdim                   last_expr->getObjectKind() == OK_Ordinary;
298292932Sdim
299314564Sdim  QualType expr_qual_type = last_expr->getType();
300314564Sdim  const clang::Type *expr_type = expr_qual_type.getTypePtr();
301292932Sdim
302314564Sdim  if (!expr_type)
303314564Sdim    return false;
304292932Sdim
305314564Sdim  if (expr_type->isVoidType())
306314564Sdim    return true;
307292932Sdim
308314564Sdim  if (log) {
309314564Sdim    std::string s = expr_qual_type.getAsString();
310292932Sdim
311360784Sdim    LLDB_LOGF(log, "Last statement is an %s with type: %s",
312360784Sdim              (is_lvalue ? "lvalue" : "rvalue"), s.c_str());
313314564Sdim  }
314292932Sdim
315353358Sdim  clang::VarDecl *result_decl = nullptr;
316292932Sdim
317314564Sdim  if (is_lvalue) {
318314564Sdim    IdentifierInfo *result_ptr_id;
319292932Sdim
320314564Sdim    if (expr_type->isFunctionType())
321314564Sdim      result_ptr_id =
322314564Sdim          &Ctx.Idents.get("$__lldb_expr_result"); // functions actually should
323314564Sdim                                                  // be treated like function
324314564Sdim                                                  // pointers
325314564Sdim    else
326314564Sdim      result_ptr_id = &Ctx.Idents.get("$__lldb_expr_result_ptr");
327292932Sdim
328314564Sdim    m_sema->RequireCompleteType(SourceLocation(), expr_qual_type,
329314564Sdim                                clang::diag::err_incomplete_type);
330292932Sdim
331314564Sdim    QualType ptr_qual_type;
332292932Sdim
333353358Sdim    if (expr_qual_type->getAs<ObjCObjectType>() != nullptr)
334314564Sdim      ptr_qual_type = Ctx.getObjCObjectPointerType(expr_qual_type);
335314564Sdim    else
336314564Sdim      ptr_qual_type = Ctx.getPointerType(expr_qual_type);
337292932Sdim
338314564Sdim    result_decl =
339314564Sdim        VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(),
340353358Sdim                        result_ptr_id, ptr_qual_type, nullptr, SC_Static);
341292932Sdim
342314564Sdim    if (!result_decl)
343314564Sdim      return false;
344292932Sdim
345314564Sdim    ExprResult address_of_expr =
346314564Sdim        m_sema->CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, last_expr);
347314564Sdim    if (address_of_expr.get())
348314564Sdim      m_sema->AddInitializerToDecl(result_decl, address_of_expr.get(), true);
349292932Sdim    else
350314564Sdim      return false;
351314564Sdim  } else {
352314564Sdim    IdentifierInfo &result_id = Ctx.Idents.get("$__lldb_expr_result");
353292932Sdim
354353358Sdim    result_decl =
355353358Sdim        VarDecl::Create(Ctx, DC, SourceLocation(), SourceLocation(), &result_id,
356353358Sdim                        expr_qual_type, nullptr, SC_Static);
357292932Sdim
358314564Sdim    if (!result_decl)
359314564Sdim      return false;
360292932Sdim
361314564Sdim    m_sema->AddInitializerToDecl(result_decl, last_expr, true);
362314564Sdim  }
363292932Sdim
364314564Sdim  DC->addDecl(result_decl);
365292932Sdim
366314564Sdim  ///////////////////////////////
367314564Sdim  // call AddInitializerToDecl
368314564Sdim  //
369292932Sdim
370314564Sdim  // m_sema->AddInitializerToDecl(result_decl, last_expr);
371292932Sdim
372314564Sdim  /////////////////////////////////
373314564Sdim  // call ConvertDeclToDeclGroup
374314564Sdim  //
375292932Sdim
376314564Sdim  Sema::DeclGroupPtrTy result_decl_group_ptr;
377292932Sdim
378314564Sdim  result_decl_group_ptr = m_sema->ConvertDeclToDeclGroup(result_decl);
379292932Sdim
380314564Sdim  ////////////////////////
381314564Sdim  // call ActOnDeclStmt
382314564Sdim  //
383292932Sdim
384314564Sdim  StmtResult result_initialization_stmt_result(m_sema->ActOnDeclStmt(
385314564Sdim      result_decl_group_ptr, SourceLocation(), SourceLocation()));
386292932Sdim
387314564Sdim  ////////////////////////////////////////////////
388314564Sdim  // replace the old statement with the new one
389314564Sdim  //
390292932Sdim
391360784Sdim  *last_stmt_ptr = static_cast<Stmt *>(result_initialization_stmt_result.get());
392292932Sdim
393314564Sdim  return true;
394292932Sdim}
395292932Sdim
396314564Sdimvoid ASTResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx) {
397314564Sdim  if (m_passthrough)
398314564Sdim    m_passthrough->HandleTranslationUnit(Ctx);
399292932Sdim}
400292932Sdim
401314564Sdimvoid ASTResultSynthesizer::RecordPersistentTypes(DeclContext *FunDeclCtx) {
402314564Sdim  typedef DeclContext::specific_decl_iterator<TypeDecl> TypeDeclIterator;
403292932Sdim
404314564Sdim  for (TypeDeclIterator i = TypeDeclIterator(FunDeclCtx->decls_begin()),
405314564Sdim                        e = TypeDeclIterator(FunDeclCtx->decls_end());
406314564Sdim       i != e; ++i) {
407314564Sdim    MaybeRecordPersistentType(*i);
408314564Sdim  }
409292932Sdim}
410292932Sdim
411314564Sdimvoid ASTResultSynthesizer::MaybeRecordPersistentType(TypeDecl *D) {
412314564Sdim  if (!D->getIdentifier())
413314564Sdim    return;
414292932Sdim
415314564Sdim  StringRef name = D->getName();
416292932Sdim
417314564Sdim  if (name.size() == 0 || name[0] != '$')
418314564Sdim    return;
419292932Sdim
420314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
421292932Sdim
422314564Sdim  ConstString name_cs(name.str().c_str());
423292932Sdim
424360784Sdim  LLDB_LOGF(log, "Recording persistent type %s\n", name_cs.GetCString());
425292932Sdim
426314564Sdim  m_decls.push_back(D);
427309124Sdim}
428292932Sdim
429314564Sdimvoid ASTResultSynthesizer::RecordPersistentDecl(NamedDecl *D) {
430314564Sdim  lldbassert(m_top_level);
431309124Sdim
432314564Sdim  if (!D->getIdentifier())
433314564Sdim    return;
434309124Sdim
435314564Sdim  StringRef name = D->getName();
436309124Sdim
437314564Sdim  if (name.size() == 0)
438314564Sdim    return;
439309124Sdim
440314564Sdim  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
441309124Sdim
442314564Sdim  ConstString name_cs(name.str().c_str());
443309124Sdim
444360784Sdim  LLDB_LOGF(log, "Recording persistent decl %s\n", name_cs.GetCString());
445309124Sdim
446314564Sdim  m_decls.push_back(D);
447292932Sdim}
448292932Sdim
449314564Sdimvoid ASTResultSynthesizer::CommitPersistentDecls() {
450360784Sdim  auto *state =
451360784Sdim      m_target.GetPersistentExpressionStateForLanguage(lldb::eLanguageTypeC);
452360784Sdim  if (!state)
453360784Sdim    return;
454360784Sdim
455360784Sdim  auto *persistent_vars = llvm::cast<ClangPersistentVariables>(state);
456360784Sdim  ClangASTContext *scratch_ctx = ClangASTContext::GetScratch(m_target);
457360784Sdim
458314564Sdim  for (clang::NamedDecl *decl : m_decls) {
459314564Sdim    StringRef name = decl->getName();
460314564Sdim    ConstString name_cs(name.str().c_str());
461309124Sdim
462314564Sdim    Decl *D_scratch = m_target.GetClangASTImporter()->DeportDecl(
463360784Sdim        &scratch_ctx->getASTContext(), decl);
464309124Sdim
465314564Sdim    if (!D_scratch) {
466314564Sdim      Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EXPRESSIONS));
467309124Sdim
468314564Sdim      if (log) {
469314564Sdim        std::string s;
470314564Sdim        llvm::raw_string_ostream ss(s);
471314564Sdim        decl->dump(ss);
472314564Sdim        ss.flush();
473309124Sdim
474360784Sdim        LLDB_LOGF(log, "Couldn't commit persistent  decl: %s\n", s.c_str());
475314564Sdim      }
476309124Sdim
477314564Sdim      continue;
478314564Sdim    }
479309124Sdim
480314564Sdim    if (NamedDecl *NamedDecl_scratch = dyn_cast<NamedDecl>(D_scratch))
481360784Sdim      persistent_vars->RegisterPersistentDecl(name_cs, NamedDecl_scratch,
482360784Sdim                                              scratch_ctx);
483314564Sdim  }
484309124Sdim}
485309124Sdim
486314564Sdimvoid ASTResultSynthesizer::HandleTagDeclDefinition(TagDecl *D) {
487314564Sdim  if (m_passthrough)
488314564Sdim    m_passthrough->HandleTagDeclDefinition(D);
489292932Sdim}
490292932Sdim
491314564Sdimvoid ASTResultSynthesizer::CompleteTentativeDefinition(VarDecl *D) {
492314564Sdim  if (m_passthrough)
493314564Sdim    m_passthrough->CompleteTentativeDefinition(D);
494292932Sdim}
495292932Sdim
496314564Sdimvoid ASTResultSynthesizer::HandleVTable(CXXRecordDecl *RD) {
497314564Sdim  if (m_passthrough)
498314564Sdim    m_passthrough->HandleVTable(RD);
499292932Sdim}
500292932Sdim
501314564Sdimvoid ASTResultSynthesizer::PrintStats() {
502314564Sdim  if (m_passthrough)
503314564Sdim    m_passthrough->PrintStats();
504292932Sdim}
505292932Sdim
506314564Sdimvoid ASTResultSynthesizer::InitializeSema(Sema &S) {
507314564Sdim  m_sema = &S;
508292932Sdim
509314564Sdim  if (m_passthrough_sema)
510314564Sdim    m_passthrough_sema->InitializeSema(S);
511292932Sdim}
512292932Sdim
513314564Sdimvoid ASTResultSynthesizer::ForgetSema() {
514353358Sdim  m_sema = nullptr;
515292932Sdim
516314564Sdim  if (m_passthrough_sema)
517314564Sdim    m_passthrough_sema->ForgetSema();
518292932Sdim}
519