Added a SemaConsumer that transforms the ASTs for
an expression, adding code to put the value of the
last expression (if there is one) into a variable
and write the address of that variable to a global
pointer.


git-svn-id: https://llvm.org/svn/llvm-project/llvdb/trunk@107419 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Expression/ClangExpression.cpp b/source/Expression/ClangExpression.cpp
index b249584..fc8cebe 100644
--- a/source/Expression/ClangExpression.cpp
+++ b/source/Expression/ClangExpression.cpp
@@ -38,6 +38,7 @@
 #include "clang/Frontend/VerifyDiagnosticsClient.h"
 #include "clang/Lex/Preprocessor.h"
 #include "clang/Sema/ParseAST.h"
+#include "clang/Sema/SemaConsumer.h"
 #include "llvm/ExecutionEngine/ExecutionEngine.h"
 #include "llvm/ExecutionEngine/JIT.h"
 #include "llvm/Module.h"
@@ -53,6 +54,7 @@
 #include "lldb/Core/Log.h"
 #include "lldb/Expression/ClangExpression.h"
 #include "lldb/Expression/ClangASTSource.h"
+#include "lldb/Expression/ClangResultSynthesizer.h"
 #include "lldb/Expression/ClangStmtVisitor.h"
 #include "lldb/Symbol/ClangASTContext.h"
 #include "lldb/Expression/RecordingMemoryManager.h"
@@ -279,19 +281,23 @@
 }
 
 unsigned
-ClangExpression::ParseExpression (const char *expr_text, Stream &stream)
+ClangExpression::ParseExpression (const char *expr_text,
+                                  Stream &stream,
+                                  bool add_result_var)
 {
     // HACK: for now we have to make a function body around our expression
     // since there is no way to parse a single expression line in LLVM/Clang.
-    std::string func_expr("void ___clang_expr()\n{\n\t");
+    std::string func_expr("extern \"C\" void ___clang_expr()\n{\n\t");
     func_expr.append(expr_text);
     func_expr.append(";\n}");
-    return ParseBareExpression (func_expr, stream);
+    return ParseBareExpression (func_expr, stream, add_result_var);
 
 }
 
 unsigned
-ClangExpression::ParseBareExpression (llvm::StringRef expr_text, Stream &stream)
+ClangExpression::ParseBareExpression (llvm::StringRef expr_text, 
+                                      Stream &stream,
+                                      bool add_result_var)
 {
     Mutex::Locker locker(GetClangMutex ());
 
@@ -354,7 +360,17 @@
     // - CodeGeneration ASTConsumer (include/clang/ModuleBuilder.h), which will be passed in when you call...
     // - Call clang::ParseAST (in lib/Sema/ParseAST.cpp) to parse the buffer. The CodeGenerator will generate code for __dbg_expr.
     // - Once ParseAST completes, you can grab the llvm::Module from the CodeGenerator, which will have an llvm::Function you can hand off to the JIT.
-    ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext());
+    
+    if (add_result_var)
+    {
+        ClangResultSynthesizer result_synthesizer(m_code_generator_ptr);
+        ParseAST(m_clang_ap->getPreprocessor(), &result_synthesizer, m_clang_ap->getASTContext());
+    }
+    else 
+    {
+        ParseAST(m_clang_ap->getPreprocessor(), m_code_generator_ptr, m_clang_ap->getASTContext());
+    }
+
     
     text_diagnostic_buffer.EndSourceFile();
 
@@ -413,7 +429,6 @@
     return num_errors;
 }
 
-
 static FrontendAction *
 CreateFrontendAction(CompilerInstance &CI)
 {
@@ -471,41 +486,42 @@
         return 1;
     }
     
-    llvm::Module::iterator fi;
-            
-    for (fi = module->begin();
-         fi != module->end();
-         ++fi)
+    llvm::Function* function = module->getFunction(StringRef("___clang_expr"));
+    
+    if (!function)
     {
-        llvm::Function &function = *fi;
-                
         if (log)
-            log->Printf("IR for %s:", function.getName().str().c_str());
+            log->Printf("Couldn't find ___clang_expr() in the module");
+        
+        return 1;
+    }
+            
+    if (log)
+        log->Printf("IR for %s:", function->getName().str().c_str());
+            
+    llvm::Function::iterator bbi;
+            
+    for (bbi = function->begin();
+         bbi != function->end();
+         ++bbi)
+    {
+        llvm::BasicBlock &bb = *bbi;
                 
-        llvm::Function::iterator bbi;
+        llvm::BasicBlock::iterator ii;
                 
-        for (bbi = function.begin();
-             bbi != function.end();
-             ++bbi)
+        for (ii = bb.begin();
+             ii != bb.end();
+             ++ii)
         {
-            llvm::BasicBlock &bb = *bbi;
-                    
-            llvm::BasicBlock::iterator ii;
-                    
-            for (ii = bb.begin();
-                 ii != bb.end();
-                 ++ii)
-            {
-                llvm::Instruction &inst = *ii;
-                
-                std::string s;
-                llvm::raw_string_ostream os(s);
-                
-                inst.print(os);
-                
-                if (log)
-                    log->Printf("  %s", s.c_str());
-            }
+            llvm::Instruction &inst = *ii;
+            
+            std::string s;
+            llvm::raw_string_ostream os(s);
+            
+            inst.print(os);
+            
+            if (log)
+                log->Printf("  %s", s.c_str());
         }
     }
     
diff --git a/source/Expression/ClangResultSynthesizer.cpp b/source/Expression/ClangResultSynthesizer.cpp
new file mode 100644
index 0000000..3a5769b
--- /dev/null
+++ b/source/Expression/ClangResultSynthesizer.cpp
@@ -0,0 +1,341 @@
+//===-- ClangResultSynthesizer.cpp ------------------------------*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "stdlib.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Decl.h"
+#include "clang/AST/DeclCXX.h"
+#include "clang/AST/DeclGroup.h"
+#include "clang/AST/Expr.h"
+#include "clang/AST/Stmt.h"
+#include "clang/Parse/Action.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Parse/Scope.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/raw_ostream.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Expression/ClangResultSynthesizer.h"
+
+using namespace llvm;
+using namespace clang;
+using namespace lldb_private;
+
+ClangResultSynthesizer::ClangResultSynthesizer(ASTConsumer *passthrough) :
+    m_passthrough(passthrough),
+    m_passthrough_sema(NULL),
+    m_sema(NULL),
+    m_ast_context(NULL)
+{
+    if (!m_passthrough)
+        return;
+    
+    m_passthrough_sema = dyn_cast<SemaConsumer>(passthrough);
+}
+
+ClangResultSynthesizer::~ClangResultSynthesizer()
+{
+}
+
+void
+ClangResultSynthesizer::Initialize(ASTContext &Context) 
+{
+    m_ast_context = &Context;
+    
+    if (m_passthrough)
+        m_passthrough->Initialize(Context);
+}
+
+void
+ClangResultSynthesizer::TransformTopLevelDecl(Decl* D)
+{
+    LinkageSpecDecl *linkage_spec_decl = dyn_cast<LinkageSpecDecl>(D);
+    
+    if (linkage_spec_decl)
+    {
+        RecordDecl::decl_iterator decl_iterator;
+        
+        for (decl_iterator = linkage_spec_decl->decls_begin();
+             decl_iterator != linkage_spec_decl->decls_end();
+             ++decl_iterator)
+        {
+            TransformTopLevelDecl(*decl_iterator);
+        }
+    }
+    
+    FunctionDecl *function_decl = dyn_cast<FunctionDecl>(D);
+    
+    if (m_ast_context &&
+        function_decl &&
+        !strcmp(function_decl->getNameAsCString(),
+                "___clang_expr"))
+    {
+        SynthesizeResult(*m_ast_context, function_decl);
+    }
+}
+
+void 
+ClangResultSynthesizer::HandleTopLevelDecl(DeclGroupRef D)
+{
+    DeclGroupRef::iterator decl_iterator;
+    
+    for (decl_iterator = D.begin();
+         decl_iterator != D.end();
+         ++decl_iterator)
+    {
+        Decl *decl = *decl_iterator;
+        
+        TransformTopLevelDecl(decl);
+    }
+    
+    if (m_passthrough)
+        m_passthrough->HandleTopLevelDecl(D);
+}
+
+bool 
+ClangResultSynthesizer::SynthesizeResult (ASTContext &Ctx,
+                                          FunctionDecl *FunDecl)
+{
+    Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
+    
+    if (!m_sema)
+        return false;
+
+    FunctionDecl *function_decl = FunDecl;
+    
+    if (!function_decl)
+        return false;
+    
+    Stmt *function_body = function_decl->getBody();
+    CompoundStmt *compound_stmt = dyn_cast<CompoundStmt>(function_body);
+    
+    if (!compound_stmt)
+        return false;
+    
+    if (compound_stmt->body_empty())
+        return false;
+    
+    Stmt **last_stmt_ptr = compound_stmt->body_end() - 1;
+    Stmt *last_stmt = *last_stmt_ptr;
+    
+    Expr *last_expr = dyn_cast<Expr>(last_stmt);
+    
+    if (!last_expr)
+        // No auxiliary variable necessary; expression returns void
+        return true;
+    
+    QualType expr_qual_type = last_expr->getType();
+    clang::Type *expr_type = expr_qual_type.getTypePtr();
+    
+    if (!expr_type)
+        return false;
+    
+    if (expr_type->isVoidType())
+        return true;
+    
+    if (log)
+    {
+        std::string s = expr_qual_type.getAsString();
+        
+        log->Printf("Last statement's type: %s", s.c_str());
+    }
+    
+    IdentifierInfo &result_id = Ctx.Idents.get("___clang_expr_result");
+    
+    DeclContext *decl_context = function_decl->getDeclContext();
+    
+    clang::VarDecl *result_decl = VarDecl::Create(Ctx, 
+                                                  function_decl, 
+                                                  SourceLocation(), 
+                                                  &result_id, 
+                                                  expr_qual_type, 
+                                                  NULL, 
+                                                  VarDecl::Static, 
+                                                  VarDecl::Static);
+    
+    if (!result_decl)
+        return false;
+    
+    function_decl->addDecl(result_decl);
+    
+    ///////////////////////////////
+    // call AddInitializerToDecl
+    //
+    
+    Parser::DeclPtrTy result_decl_ptr;
+    result_decl_ptr.set(result_decl);
+    
+    m_action->AddInitializerToDecl(result_decl_ptr, Parser::ExprArg(*m_action, last_expr));
+    
+    /////////////////////////////////
+    // call ConvertDeclToDeclGroup
+    //
+    
+    Parser::DeclGroupPtrTy result_decl_group_ptr;
+    
+    result_decl_group_ptr = m_action->ConvertDeclToDeclGroup(result_decl_ptr);
+    
+    ////////////////////////
+    // call ActOnDeclStmt
+    //
+    
+    Parser::OwningStmtResult result_initialization_stmt_result(m_action->ActOnDeclStmt(result_decl_group_ptr,
+                                                                                       SourceLocation(),
+                                                                                       SourceLocation()));
+    
+    
+    ///////////////////////////////////////////////
+    // Synthesize external void pointer variable
+    //
+    
+    IdentifierInfo &result_ptr_id = Ctx.Idents.get("___clang_expr_result_ptr");
+    
+    clang::VarDecl *result_ptr_decl = VarDecl::Create(Ctx,
+                                                      decl_context,
+                                                      SourceLocation(),
+                                                      &result_ptr_id,
+                                                      Ctx.VoidPtrTy,
+                                                      NULL,
+                                                      VarDecl::Extern,
+                                                      VarDecl::Extern);
+    
+    /////////////////////////////////////////////
+    // Build a DeclRef for the result variable
+    //
+    
+    DeclRefExpr *result_decl_ref_expr = DeclRefExpr::Create(Ctx,
+                                                            NULL,
+                                                            SourceRange(),
+                                                            result_decl,
+                                                            SourceLocation(),
+                                                            expr_qual_type);
+    
+    ///////////////////////
+    // call ActOnUnaryOp
+    //
+    
+    Scope my_scope(NULL, (Scope::BlockScope | Scope::FnScope | Scope::DeclScope));
+    
+    Parser::DeclPtrTy result_ptr_decl_ptr;
+    result_ptr_decl_ptr.set(result_ptr_decl);
+        
+    Parser::OwningExprResult addressof_expr_result(m_action->ActOnUnaryOp(&my_scope,
+                                                                          SourceLocation(),
+                                                                          tok::amp,
+                                                                          Parser::ExprArg(*m_action, result_decl_ref_expr)));
+    
+    ////////////////////////////////////////////
+    // Build a DeclRef for the result pointer
+    //
+    
+    DeclRefExpr *result_ptr_decl_ref_expr = DeclRefExpr::Create(Ctx,
+                                                                NULL,
+                                                                SourceRange(),
+                                                                result_ptr_decl,
+                                                                SourceLocation(),
+                                                                Ctx.VoidPtrTy);
+    
+    ////////////////////////
+    // call ActOnBinaryOp
+    //
+    
+    Parser::OwningExprResult assignment_expr_result(m_action->ActOnBinOp(&my_scope,
+                                                                         SourceLocation(),
+                                                                         tok::equal,
+                                                                         Parser::ExprArg(*m_action, result_ptr_decl_ref_expr),
+                                                                         Parser::ExprArg(*m_action, addressof_expr_result.take())));
+    
+    ////////////////////////////
+    // call ActOnCompoundStmt
+    //
+    
+    void *stmts[2];
+    
+    stmts[0] = result_initialization_stmt_result.take();
+    stmts[1] = assignment_expr_result.take();
+    
+    Parser::OwningStmtResult compound_stmt_result(m_action->ActOnCompoundStmt(SourceLocation(), 
+                                                                              SourceLocation(), 
+                                                                              Parser::MultiStmtArg(*m_action, stmts, 2), 
+                                                                              false));
+    
+    ////////////////////////////////////////////////
+    // replace the old statement with the new one
+    //
+    
+    *last_stmt_ptr = reinterpret_cast<Stmt*>(compound_stmt_result.take());
+
+    if (log)
+    {
+        std::string s;
+        raw_string_ostream os(s);
+        
+        function_decl->print(os);
+        
+        os.flush();
+        
+        log->Printf("Transformed function AST:\n%s", s.c_str());
+    }
+    
+    return true;
+}
+
+void
+ClangResultSynthesizer::HandleTranslationUnit(ASTContext &Ctx)
+{    
+    if (m_passthrough)
+        m_passthrough->HandleTranslationUnit(Ctx);
+}
+
+void 
+ClangResultSynthesizer::HandleTagDeclDefinition(TagDecl *D)
+{
+    if (m_passthrough)
+        m_passthrough->HandleTagDeclDefinition(D);
+}
+
+void
+ClangResultSynthesizer::CompleteTentativeDefinition(VarDecl *D)
+{
+    if (m_passthrough)
+        m_passthrough->CompleteTentativeDefinition(D);
+}
+
+void 
+ClangResultSynthesizer::HandleVTable(CXXRecordDecl *RD, bool DefinitionRequired) 
+{
+    if (m_passthrough)
+        m_passthrough->HandleVTable(RD, DefinitionRequired);
+}
+
+void
+ClangResultSynthesizer::PrintStats() 
+{
+    if (m_passthrough)
+        m_passthrough->PrintStats();
+}
+
+void
+ClangResultSynthesizer::InitializeSema(Sema &S)
+{
+    m_sema = &S;
+    m_action = reinterpret_cast<Action*>(m_sema);
+    
+    if (m_passthrough_sema)
+        m_passthrough_sema->InitializeSema(S);
+}
+
+void 
+ClangResultSynthesizer::ForgetSema() 
+{
+    m_sema = NULL;
+    m_action = NULL;
+    
+    if (m_passthrough_sema)
+        m_passthrough_sema->ForgetSema();
+}