diff options
Diffstat (limited to 'source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp')
| -rw-r--r-- | source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp | 620 | 
1 files changed, 497 insertions, 123 deletions
diff --git a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 72c33fec8105c..d1a3c0dea8253 100644 --- a/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -11,13 +11,18 @@  // C++ Includes  // Other libraries and framework includes  #include "clang/AST/ASTContext.h" +#include "clang/AST/ASTDiagnostic.h"  #include "clang/AST/ExternalASTSource.h" +#include "clang/Basic/DiagnosticIDs.h"  #include "clang/Basic/FileManager.h"  #include "clang/Basic/SourceLocation.h"  #include "clang/Basic/TargetInfo.h" -#include "clang/Basic/Version.h" +#include "clang/Basic/Version.h"   #include "clang/CodeGen/CodeGenAction.h"  #include "clang/CodeGen/ModuleBuilder.h" +#include "clang/Edit/Commit.h" +#include "clang/Edit/EditsReceiver.h" +#include "clang/Edit/EditedSource.h"  #include "clang/Frontend/CompilerInstance.h"  #include "clang/Frontend/CompilerInvocation.h"  #include "clang/Frontend/FrontendActions.h" @@ -28,6 +33,7 @@  #include "clang/Lex/Preprocessor.h"  #include "clang/Parse/ParseAST.h"  #include "clang/Rewrite/Frontend/FrontendActions.h" +#include "clang/Rewrite/Core/Rewriter.h"  #include "clang/Sema/SemaConsumer.h"  #include "clang/StaticAnalyzer/Frontend/FrontendActions.h" @@ -37,7 +43,11 @@  #include "llvm/Support/FileSystem.h"  #include "llvm/Support/TargetSelect.h" +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wglobal-constructors"  #include "llvm/ExecutionEngine/MCJIT.h" +#pragma clang diagnostic pop +  #include "llvm/IR/LLVMContext.h"  #include "llvm/IR/Module.h"  #include "llvm/Support/ErrorHandling.h" @@ -48,6 +58,7 @@  // Project includes  #include "ClangExpressionParser.h" +#include "ClangDiagnostic.h"  #include "ClangASTSource.h"  #include "ClangExpressionHelper.h" @@ -65,17 +76,21 @@  #include "lldb/Core/Stream.h"  #include "lldb/Core/StreamFile.h"  #include "lldb/Core/StreamString.h" -#include "lldb/Expression/IRExecutionUnit.h" +#include "lldb/Core/StringList.h"  #include "lldb/Expression/IRDynamicChecks.h" +#include "lldb/Expression/IRExecutionUnit.h"  #include "lldb/Expression/IRInterpreter.h"  #include "lldb/Host/File.h"  #include "lldb/Host/HostInfo.h"  #include "lldb/Symbol/ClangASTContext.h"  #include "lldb/Symbol/SymbolVendor.h"  #include "lldb/Target/ExecutionContext.h" +#include "lldb/Target/Language.h"  #include "lldb/Target/ObjCLanguageRuntime.h"  #include "lldb/Target/Process.h"  #include "lldb/Target/Target.h" +#include "lldb/Target/ThreadPlanCallFunction.h" +#include "lldb/Utility/LLDBAssert.h"  using namespace clang;  using namespace llvm; @@ -85,21 +100,6 @@ using namespace lldb_private;  // Utility Methods for Clang  //===----------------------------------------------------------------------===// -std::string GetBuiltinIncludePath(const char *Argv0) { -    SmallString<128> P(llvm::sys::fs::getMainExecutable( -        Argv0, (void *)(intptr_t) GetBuiltinIncludePath)); - -    if (!P.empty()) { -        llvm::sys::path::remove_filename(P); // Remove /clang from foo/bin/clang -        llvm::sys::path::remove_filename(P); // Remove /bin   from foo/bin - -        // Get foo/lib/clang/<version>/include -        llvm::sys::path::append(P, "lib", "clang", CLANG_VERSION_STRING, -                                "include"); -    } - -    return P.str(); -}  class ClangExpressionParser::LLDBPreprocessorCallbacks : public PPCallbacks  { @@ -154,6 +154,100 @@ public:      }  }; +class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer +{ +public: +    ClangDiagnosticManagerAdapter() : m_passthrough(new clang::TextDiagnosticBuffer) {} + +    ClangDiagnosticManagerAdapter(const std::shared_ptr<clang::TextDiagnosticBuffer> &passthrough) +        : m_passthrough(passthrough) +    { +    } + +    void +    ResetManager(DiagnosticManager *manager = nullptr) +    { +        m_manager = manager; +    } + +    void +    HandleDiagnostic(DiagnosticsEngine::Level DiagLevel, const clang::Diagnostic &Info) +    { +        if (m_manager) +        { +            llvm::SmallVector<char, 32> diag_str; +            Info.FormatDiagnostic(diag_str); +            diag_str.push_back('\0'); +            const char *data = diag_str.data(); + +            lldb_private::DiagnosticSeverity severity; +            bool make_new_diagnostic = true; +             +            switch (DiagLevel) +            { +                case DiagnosticsEngine::Level::Fatal: +                case DiagnosticsEngine::Level::Error: +                    severity = eDiagnosticSeverityError; +                    break; +                case DiagnosticsEngine::Level::Warning: +                    severity = eDiagnosticSeverityWarning; +                    break; +                case DiagnosticsEngine::Level::Remark: +                case DiagnosticsEngine::Level::Ignored: +                    severity = eDiagnosticSeverityRemark; +                    break; +                case DiagnosticsEngine::Level::Note: +                    m_manager->AppendMessageToDiagnostic(data); +                    make_new_diagnostic = false; +            } +            if (make_new_diagnostic) +            { +                ClangDiagnostic *new_diagnostic = new ClangDiagnostic(data, severity, Info.getID()); +                m_manager->AddDiagnostic(new_diagnostic); +                 +                // Don't store away warning fixits, since the compiler doesn't have enough +                // context in an expression for the warning to be useful. +                // FIXME: Should we try to filter out FixIts that apply to our generated +                // code, and not the user's expression? +                if (severity == eDiagnosticSeverityError) +                { +                    size_t num_fixit_hints = Info.getNumFixItHints(); +                    for (size_t i = 0; i < num_fixit_hints; i++) +                    { +                        const clang::FixItHint &fixit = Info.getFixItHint(i); +                        if (!fixit.isNull()) +                            new_diagnostic->AddFixitHint(fixit); +                    } +                } +            } +        } +         +        m_passthrough->HandleDiagnostic(DiagLevel, Info); +    } + +    void +    FlushDiagnostics(DiagnosticsEngine &Diags) +    { +        m_passthrough->FlushDiagnostics(Diags); +    } + +    DiagnosticConsumer * +    clone(DiagnosticsEngine &Diags) const +    { +        return new ClangDiagnosticManagerAdapter(m_passthrough); +    } + +    clang::TextDiagnosticBuffer * +    GetPassthrough() +    { +        return m_passthrough.get(); +    } + +private: +    DiagnosticManager *m_manager = nullptr; +    std::shared_ptr<clang::TextDiagnosticBuffer> m_passthrough; +}; +  //===----------------------------------------------------------------------===//  // Implementation of ClangExpressionParser  //===----------------------------------------------------------------------===// @@ -166,37 +260,78 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      m_code_generator (),      m_pp_callbacks(nullptr)  { +    Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); + +    // We can't compile expressions without a target.  So if the exe_scope is null or doesn't have a target, +    // then we just need to get out of here.  I'll lldb_assert and not make any of the compiler objects since +    // I can't return errors directly from the constructor.  Further calls will check if the compiler was made and +    // bag out if it wasn't. +     +    if (!exe_scope) +    { +        lldb_assert(exe_scope, "Can't make an expression parser with a null scope.", __FUNCTION__, __FILE__, __LINE__); +        return; +    } +     +    lldb::TargetSP target_sp; +    target_sp = exe_scope->CalculateTarget(); +    if (!target_sp) +    { +        lldb_assert(exe_scope, "Can't make an expression parser with a null target.", __FUNCTION__, __FILE__, __LINE__); +        return; +    } +          // 1. Create a new compiler instance.      m_compiler.reset(new CompilerInstance()); +    lldb::LanguageType frame_lang = expr.Language(); // defaults to lldb::eLanguageTypeUnknown +    bool overridden_target_opts = false; +    lldb_private::LanguageRuntime *lang_rt = nullptr; -    // 2. Install the target. +    std::string abi; +    ArchSpec target_arch; +    target_arch = target_sp->GetArchitecture(); -    lldb::TargetSP target_sp; -    if (exe_scope) -        target_sp = exe_scope->CalculateTarget(); +    const auto target_machine = target_arch.GetMachine(); + +    // If the expression is being evaluated in the context of an existing +    // stack frame, we introspect to see if the language runtime is available. +     +    lldb::StackFrameSP frame_sp = exe_scope->CalculateStackFrame(); +    lldb::ProcessSP process_sp = exe_scope->CalculateProcess(); +     +    // Make sure the user hasn't provided a preferred execution language +    // with `expression --language X -- ...` +    if (frame_sp && frame_lang == lldb::eLanguageTypeUnknown) +        frame_lang = frame_sp->GetLanguage(); + +    if (process_sp && frame_lang != lldb::eLanguageTypeUnknown) +    { +        lang_rt = process_sp->GetLanguageRuntime(frame_lang); +        if (log) +            log->Printf("Frame has language of type %s", Language::GetNameForLanguageType(frame_lang)); +    } -    // TODO: figure out what to really do when we don't have a valid target. -    // Sometimes this will be ok to just use the host target triple (when we -    // evaluate say "2+3", but other expressions like breakpoint conditions -    // and other things that _are_ target specific really shouldn't just be -    // using the host triple. This needs to be fixed in a better way. -    if (target_sp && target_sp->GetArchitecture().IsValid()) +    // 2. Configure the compiler with a set of default options that are appropriate +    // for most situations. +    if (target_arch.IsValid())      { -        std::string triple = target_sp->GetArchitecture().GetTriple().str(); +        std::string triple = target_arch.GetTriple().str();          m_compiler->getTargetOpts().Triple = triple; +        if (log) +            log->Printf("Using %s as the target triple", m_compiler->getTargetOpts().Triple.c_str());      }      else      { +        // If we get here we don't have a valid target and just have to guess. +        // Sometimes this will be ok to just use the host target triple (when we evaluate say "2+3", but other +        // expressions like breakpoint conditions and other things that _are_ target specific really shouldn't just be +        // using the host triple. In such a case the language runtime should expose an overridden options set (3), +        // below.          m_compiler->getTargetOpts().Triple = llvm::sys::getDefaultTargetTriple(); +        if (log) +            log->Printf("Using default target triple of %s", m_compiler->getTargetOpts().Triple.c_str());      } - -    if (target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86 || -        target_sp->GetArchitecture().GetMachine() == llvm::Triple::x86_64) -    { -        m_compiler->getTargetOpts().Features.push_back("+sse"); -        m_compiler->getTargetOpts().Features.push_back("+sse2"); -    } - +    // Now add some special fixes for known architectures:      // Any arm32 iOS environment, but not on arm64      if (m_compiler->getTargetOpts().Triple.find("arm64") == std::string::npos &&          m_compiler->getTargetOpts().Triple.find("arm") != std::string::npos && @@ -204,17 +339,60 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      {          m_compiler->getTargetOpts().ABI = "apcs-gnu";      } +    // Supported subsets of x86 +    if (target_machine == llvm::Triple::x86 || +        target_machine == llvm::Triple::x86_64) +    { +        m_compiler->getTargetOpts().Features.push_back("+sse"); +        m_compiler->getTargetOpts().Features.push_back("+sse2"); +    } -    m_compiler->createDiagnostics(); +    // Set the target CPU to generate code for. +    // This will be empty for any CPU that doesn't really need to make a special CPU string. +    m_compiler->getTargetOpts().CPU = target_arch.GetClangTargetCPU(); -    // Create the target instance. -    m_compiler->setTarget(TargetInfo::CreateTargetInfo( -        m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts)); +    // Set the target ABI +    abi = GetClangTargetABI(target_arch); +    if (!abi.empty()) +        m_compiler->getTargetOpts().ABI = abi; -    assert (m_compiler->hasTarget()); +    // 3. Now allow the runtime to provide custom configuration options for the target. +    // In this case, a specialized language runtime is available and we can query it for extra options. +    // For 99% of use cases, this will not be needed and should be provided when basic platform detection is not enough. +    if (lang_rt) +        overridden_target_opts = lang_rt->GetOverrideExprOptions(m_compiler->getTargetOpts()); + +    if (overridden_target_opts) +        if (log) +        { +            log->Debug("Using overridden target options for the expression evaluation"); + +            auto opts = m_compiler->getTargetOpts(); +            log->Debug("Triple: '%s'", opts.Triple.c_str()); +            log->Debug("CPU: '%s'", opts.CPU.c_str()); +            log->Debug("FPMath: '%s'", opts.FPMath.c_str()); +            log->Debug("ABI: '%s'", opts.ABI.c_str()); +            log->Debug("LinkerVersion: '%s'", opts.LinkerVersion.c_str()); +            StringList::LogDump(log, opts.FeaturesAsWritten, "FeaturesAsWritten"); +            StringList::LogDump(log, opts.Features, "Features"); +            StringList::LogDump(log, opts.Reciprocals, "Reciprocals"); +        } + +    // 4. Create and install the target on the compiler. +    m_compiler->createDiagnostics(); +    auto target_info = TargetInfo::CreateTargetInfo(m_compiler->getDiagnostics(), m_compiler->getInvocation().TargetOpts); +    if (log) +    { +        log->Printf("Using SIMD alignment: %d", target_info->getSimdDefaultAlign()); +        log->Printf("Target datalayout string: '%s'", target_info->getDataLayout().getStringRepresentation().c_str()); +        log->Printf("Target ABI: '%s'", target_info->getABI().str().c_str()); +        log->Printf("Target vector alignment: %d", target_info->getMaxVectorAlign()); +    } +    m_compiler->setTarget(target_info); -    // 3. Set options. +    assert (m_compiler->hasTarget()); +    // 5. Set language options.      lldb::LanguageType language = expr.Language();      switch (language) @@ -242,7 +420,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      case lldb::eLanguageTypeC_plus_plus_14:          m_compiler->getLangOpts().CPlusPlus11 = true;          m_compiler->getHeaderSearchOpts().UseLibcxx = true; -        // fall thru ... +        LLVM_FALLTHROUGH;      case lldb::eLanguageTypeC_plus_plus_03:          m_compiler->getLangOpts().CPlusPlus = true;          // FIXME: the following language option is a temporary workaround, @@ -277,10 +455,6 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      // information.      m_compiler->getLangOpts().SpellChecking = false; -    lldb::ProcessSP process_sp; -    if (exe_scope) -        process_sp = exe_scope->CalculateProcess(); -      if (process_sp && m_compiler->getLangOpts().ObjC1)      {          if (process_sp->GetObjCLanguageRuntime()) @@ -305,9 +479,9 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      m_compiler->getCodeGenOpts().DisableFPElim = true;      m_compiler->getCodeGenOpts().OmitLeafFramePointer = false;      if (generate_debug_info) -        m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::FullDebugInfo); +        m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::FullDebugInfo);      else -        m_compiler->getCodeGenOpts().setDebugInfo(CodeGenOptions::NoDebugInfo); +        m_compiler->getCodeGenOpts().setDebugInfo(codegenoptions::NoDebugInfo);      // Disable some warnings.      m_compiler->getDiagnostics().setSeverityForGroup(clang::diag::Flavor::WarningOrError, @@ -321,11 +495,11 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,      // created. This complexity should be lifted elsewhere.      m_compiler->getTarget().adjust(m_compiler->getLangOpts()); -    // 4. Set up the diagnostic buffer for reporting errors +    // 6. Set up the diagnostic buffer for reporting errors -    m_compiler->getDiagnostics().setClient(new clang::TextDiagnosticBuffer); +    m_compiler->getDiagnostics().setClient(new ClangDiagnosticManagerAdapter); -    // 5. Set up the source management objects inside the compiler +    // 7. Set up the source management objects inside the compiler      clang::FileSystemOptions file_system_options;      m_file_manager.reset(new clang::FileManager(file_system_options)); @@ -344,7 +518,7 @@ ClangExpressionParser::ClangExpressionParser (ExecutionContextScope *exe_scope,          m_compiler->getPreprocessor().addPPCallbacks(std::move(pp_callbacks));      } -    // 6. Most of this we get from the CompilerInstance, but we +    // 8. Most of this we get from the CompilerInstance, but we      // also want to give the context an ExternalASTSource.      m_selector_table.reset(new SelectorTable());      m_builtin_context.reset(new Builtin::Context()); @@ -387,37 +561,38 @@ ClangExpressionParser::~ClangExpressionParser()  }  unsigned -ClangExpressionParser::Parse (Stream &stream) +ClangExpressionParser::Parse(DiagnosticManager &diagnostic_manager)  { -    TextDiagnosticBuffer *diag_buf = static_cast<TextDiagnosticBuffer*>(m_compiler->getDiagnostics().getClient()); +    ClangDiagnosticManagerAdapter *adapter = +        static_cast<ClangDiagnosticManagerAdapter *>(m_compiler->getDiagnostics().getClient()); +    clang::TextDiagnosticBuffer *diag_buf = adapter->GetPassthrough(); +    diag_buf->FlushDiagnostics(m_compiler->getDiagnostics()); -    diag_buf->FlushDiagnostics (m_compiler->getDiagnostics()); +    adapter->ResetManager(&diagnostic_manager);      const char *expr_text = m_expr.Text(); -    clang::SourceManager &SourceMgr = m_compiler->getSourceManager(); +    clang::SourceManager &source_mgr = m_compiler->getSourceManager();      bool created_main_file = false; -    if (m_compiler->getCodeGenOpts().getDebugInfo() == CodeGenOptions::FullDebugInfo) +    if (m_compiler->getCodeGenOpts().getDebugInfo() == codegenoptions::FullDebugInfo)      { -        std::string temp_source_path; -          int temp_fd = -1;          llvm::SmallString<PATH_MAX> result_path;          FileSpec tmpdir_file_spec;          if (HostInfo::GetLLDBPath(lldb::ePathTypeLLDBTempSystemDir, tmpdir_file_spec))          {              tmpdir_file_spec.AppendPathComponent("lldb-%%%%%%.expr"); -            temp_source_path = tmpdir_file_spec.GetPath(); +            std::string temp_source_path = tmpdir_file_spec.GetPath();              llvm::sys::fs::createUniqueFile(temp_source_path, temp_fd, result_path);          }          else          {              llvm::sys::fs::createTemporaryFile("lldb", "expr", temp_fd, result_path);          } -         +          if (temp_fd != -1)          { -            lldb_private::File file (temp_fd, true); +            lldb_private::File file(temp_fd, true);              const size_t expr_text_len = strlen(expr_text);              size_t bytes_written = expr_text_len;              if (file.Write(expr_text, bytes_written).Success()) @@ -425,9 +600,8 @@ ClangExpressionParser::Parse (Stream &stream)                  if (bytes_written == expr_text_len)                  {                      file.Close(); -                    SourceMgr.setMainFileID(SourceMgr.createFileID( -                        m_file_manager->getFile(result_path), -                        SourceLocation(), SrcMgr::C_User)); +                    source_mgr.setMainFileID(source_mgr.createFileID(m_file_manager->getFile(result_path), +                                                                     SourceLocation(), SrcMgr::C_User));                      created_main_file = true;                  }              } @@ -437,7 +611,7 @@ ClangExpressionParser::Parse (Stream &stream)      if (!created_main_file)      {          std::unique_ptr<MemoryBuffer> memory_buffer = MemoryBuffer::getMemBufferCopy(expr_text, __FUNCTION__); -        SourceMgr.setMainFileID(SourceMgr.createFileID(std::move(memory_buffer))); +        source_mgr.setMainFileID(source_mgr.createFileID(std::move(memory_buffer)));      }      diag_buf->BeginSourceFile(m_compiler->getLangOpts(), &m_compiler->getPreprocessor()); @@ -462,58 +636,147 @@ ClangExpressionParser::Parse (Stream &stream)      diag_buf->EndSourceFile(); -    TextDiagnosticBuffer::const_iterator diag_iterator; +    unsigned num_errors = diag_buf->getNumErrors(); -    int num_errors = 0; -          if (m_pp_callbacks && m_pp_callbacks->hasErrors())      {          num_errors++; -         -        stream.PutCString(m_pp_callbacks->getErrorString().c_str()); +        diagnostic_manager.PutCString(eDiagnosticSeverityError, "while importing modules:"); +        diagnostic_manager.AppendMessageToDiagnostic(m_pp_callbacks->getErrorString().c_str());      } -    for (diag_iterator = diag_buf->warn_begin(); -         diag_iterator != diag_buf->warn_end(); -         ++diag_iterator) -        stream.Printf("warning: %s\n", (*diag_iterator).second.c_str()); +    if (!num_errors) +    { +        if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) +        { +            diagnostic_manager.Printf(eDiagnosticSeverityError, "Couldn't infer the type of a variable"); +            num_errors++; +        } +    } -    for (diag_iterator = diag_buf->err_begin(); -         diag_iterator != diag_buf->err_end(); -         ++diag_iterator) +    if (!num_errors)      { -        num_errors++; -        stream.Printf("error: %s\n", (*diag_iterator).second.c_str()); +        type_system_helper->CommitPersistentDecls();      } -    for (diag_iterator = diag_buf->note_begin(); -         diag_iterator != diag_buf->note_end(); -         ++diag_iterator) -        stream.Printf("note: %s\n", (*diag_iterator).second.c_str()); +    adapter->ResetManager(); -    if (!num_errors) +    return num_errors; +} + +std::string +ClangExpressionParser::GetClangTargetABI (const ArchSpec &target_arch) +{ +    std::string abi; +  +    if(target_arch.IsMIPS())      { -        if (type_system_helper->DeclMap() && !type_system_helper->DeclMap()->ResolveUnknownTypes()) +       switch (target_arch.GetFlags () & ArchSpec::eMIPSABI_mask) +       { +       case ArchSpec::eMIPSABI_N64: +            abi = "n64"; break; +       case ArchSpec::eMIPSABI_N32: +            abi = "n32"; break; +       case ArchSpec::eMIPSABI_O32: +            abi = "o32"; break; +       default: +              break; +       } +    } +    return abi; +} + +bool +ClangExpressionParser::RewriteExpression(DiagnosticManager &diagnostic_manager) +{ +    clang::SourceManager &source_manager = m_compiler->getSourceManager(); +    clang::edit::EditedSource editor(source_manager, m_compiler->getLangOpts(), nullptr); +    clang::edit::Commit commit(editor); +    clang::Rewriter rewriter(source_manager, m_compiler->getLangOpts()); +     +    class RewritesReceiver : public edit::EditsReceiver { +      Rewriter &rewrite; + +    public: +      RewritesReceiver(Rewriter &in_rewrite) : rewrite(in_rewrite) { } + +      void insert(SourceLocation loc, StringRef text) override { +        rewrite.InsertText(loc, text); +      } +      void replace(CharSourceRange range, StringRef text) override { +        rewrite.ReplaceText(range.getBegin(), rewrite.getRangeSize(range), text); +      } +    }; +     +    RewritesReceiver rewrites_receiver(rewriter); +     +    const DiagnosticList &diagnostics = diagnostic_manager.Diagnostics(); +    size_t num_diags = diagnostics.size(); +    if (num_diags == 0) +        return false; +     +    for (const Diagnostic *diag : diagnostic_manager.Diagnostics()) +    { +        const ClangDiagnostic *diagnostic = llvm::dyn_cast<ClangDiagnostic>(diag); +        if (diagnostic && diagnostic->HasFixIts())          { -            stream.Printf("error: Couldn't infer the type of a variable\n"); -            num_errors++; +             for (const FixItHint &fixit : diagnostic->FixIts()) +             { +                // This is cobbed from clang::Rewrite::FixItRewriter. +                if (fixit.CodeToInsert.empty()) +                { +                  if (fixit.InsertFromRange.isValid()) +                  { +                      commit.insertFromRange(fixit.RemoveRange.getBegin(), +                                             fixit.InsertFromRange, /*afterToken=*/false, +                                             fixit.BeforePreviousInsertions); +                  } +                  else +                    commit.remove(fixit.RemoveRange); +                } +                else +                { +                  if (fixit.RemoveRange.isTokenRange() || +                      fixit.RemoveRange.getBegin() != fixit.RemoveRange.getEnd()) +                    commit.replace(fixit.RemoveRange, fixit.CodeToInsert); +                  else +                    commit.insert(fixit.RemoveRange.getBegin(), fixit.CodeToInsert, +                                /*afterToken=*/false, fixit.BeforePreviousInsertions); +                } +            }          }      } +     +    // FIXME - do we want to try to propagate specific errors here? +    if (!commit.isCommitable()) +        return false; +    else if (!editor.commit(commit)) +        return false; +     +    // Now play all the edits, and stash the result in the diagnostic manager. +    editor.applyRewrites(rewrites_receiver); +    RewriteBuffer &main_file_buffer = rewriter.getEditBuffer(source_manager.getMainFileID()); -    return num_errors; +    std::string fixed_expression; +    llvm::raw_string_ostream out_stream(fixed_expression); +     +    main_file_buffer.write(out_stream); +    out_stream.flush(); +    diagnostic_manager.SetFixedExpression(fixed_expression); +     +    return true;  }  static bool FindFunctionInModule (ConstString &mangled_name,                                    llvm::Module *module,                                    const char *orig_name)  { -    for (llvm::Module::iterator fi = module->getFunctionList().begin(), fe = module->getFunctionList().end(); -         fi != fe; -         ++fi) +    for (const auto &func : module->getFunctionList())      { -        if (fi->getName().str().find(orig_name) != std::string::npos) +        const StringRef &name = func.getName(); +        if (name.find(orig_name) != StringRef::npos)          { -            mangled_name.SetCString(fi->getName().str().c_str()); +            mangled_name.SetString(name);              return true;          }      } @@ -521,7 +784,7 @@ static bool FindFunctionInModule (ConstString &mangled_name,      return false;  } -Error +lldb_private::Error  ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,                                              lldb::addr_t &func_end,                                              lldb::IRExecutionUnitSP &execution_unit_sp, @@ -533,7 +796,7 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,  	func_end = LLDB_INVALID_ADDRESS;      Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS)); -    Error err; +    lldb_private::Error err;      std::unique_ptr<llvm::Module> llvm_module_ap (m_code_generator->ReleaseModule()); @@ -544,26 +807,65 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,          return err;      } -    // Find the actual name of the function (it's often mangled somehow) -      ConstString function_name; -    if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName())) +    if (execution_policy != eExecutionPolicyTopLevel)      { -        err.SetErrorToGenericError(); -        err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); -        return err; +        // Find the actual name of the function (it's often mangled somehow) + +        if (!FindFunctionInModule(function_name, llvm_module_ap.get(), m_expr.FunctionName())) +        { +            err.SetErrorToGenericError(); +            err.SetErrorStringWithFormat("Couldn't find %s() in the module", m_expr.FunctionName()); +            return err; +        } +        else +        { +            if (log) +                log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); +        }      } -    else + +    SymbolContext sc; + +    if (lldb::StackFrameSP frame_sp = exe_ctx.GetFrameSP()) +    { +        sc = frame_sp->GetSymbolContext(lldb::eSymbolContextEverything); +    } +    else if (lldb::TargetSP target_sp = exe_ctx.GetTargetSP()) +    { +        sc.target_sp = target_sp; +    } + +    LLVMUserExpression::IRPasses custom_passes;      { +        auto lang = m_expr.Language();          if (log) -            log->Printf("Found function %s for %s", function_name.AsCString(), m_expr.FunctionName()); +            log->Printf("%s - Currrent expression language is %s\n", __FUNCTION__, +                        Language::GetNameForLanguageType(lang)); + +        if (lang != lldb::eLanguageTypeUnknown) +        { +            auto runtime = exe_ctx.GetProcessSP()->GetLanguageRuntime(lang); +            if (runtime) +                runtime->GetIRPasses(custom_passes); +        } +    } + +    if (custom_passes.EarlyPasses) +    { +        if (log) +            log->Printf("%s - Running Early IR Passes from LanguageRuntime on expression module '%s'", __FUNCTION__, +                        m_expr.FunctionName()); + +        custom_passes.EarlyPasses->run(*llvm_module_ap);      }      execution_unit_sp.reset(new IRExecutionUnit (m_llvm_context, // handed off here                                                   llvm_module_ap, // handed off here                                                   function_name,                                                   exe_ctx.GetTargetSP(), +                                                 sc,                                                   m_compiler->getTargetOpts().Features));      ClangExpressionHelper *type_system_helper = dyn_cast<ClangExpressionHelper>(m_expr.GetTypeSystemHelper()); @@ -576,20 +878,28 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,          if (target)              error_stream = target->GetDebugger().GetErrorFile().get(); -        IRForTarget ir_for_target(decl_map, -                                  m_expr.NeedsVariableResolution(), -                                  *execution_unit_sp, -                                  error_stream, +        IRForTarget ir_for_target(decl_map, m_expr.NeedsVariableResolution(), *execution_unit_sp, error_stream,                                    function_name.AsCString());          bool ir_can_run = ir_for_target.runOnModule(*execution_unit_sp->GetModule()); -        Error interpret_error;          Process *process = exe_ctx.GetProcessPtr(); -        bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); -        can_interpret = IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), interpret_error, interpret_function_calls); +        if (execution_policy != eExecutionPolicyAlways && execution_policy != eExecutionPolicyTopLevel) +        { +            lldb_private::Error interpret_error; + +            bool interpret_function_calls = !process ? false : process->CanInterpretFunctionCalls(); +            can_interpret = +                IRInterpreter::CanInterpret(*execution_unit_sp->GetModule(), *execution_unit_sp->GetFunction(), +                                            interpret_error, interpret_function_calls); +            if (!can_interpret && execution_policy == eExecutionPolicyNever) +            { +                err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); +                return err; +            } +        }          if (!ir_can_run)          { @@ -597,19 +907,21 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,              return err;          } -        if (!can_interpret && execution_policy == eExecutionPolicyNever) +        if (!process && execution_policy == eExecutionPolicyAlways)          { -            err.SetErrorStringWithFormat("Can't run the expression locally: %s", interpret_error.AsCString()); +            err.SetErrorString("Expression needed to run in the target, but the target can't be run");              return err;          } -        if (!process && execution_policy == eExecutionPolicyAlways) +        if (!process && execution_policy == eExecutionPolicyTopLevel)          { -            err.SetErrorString("Expression needed to run in the target, but the target can't be run"); +            err.SetErrorString( +                "Top-level code needs to be inserted into a runnable target, but the target can't be run");              return err;          } -        if (execution_policy == eExecutionPolicyAlways || !can_interpret) +        if (execution_policy == eExecutionPolicyAlways || +            (execution_policy != eExecutionPolicyTopLevel && !can_interpret))          {              if (m_expr.NeedsValidation() && process)              { @@ -617,14 +929,14 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,                  {                      DynamicCheckerFunctions *dynamic_checkers = new DynamicCheckerFunctions(); -                    StreamString install_errors; +                    DiagnosticManager install_diagnostics; -                    if (!dynamic_checkers->Install(install_errors, exe_ctx)) +                    if (!dynamic_checkers->Install(install_diagnostics, exe_ctx))                      { -                        if (install_errors.GetString().empty()) -                            err.SetErrorString ("couldn't install checkers, unknown error"); +                        if (install_diagnostics.Diagnostics().size()) +                            err.SetErrorString("couldn't install checkers, unknown error");                          else -                            err.SetErrorString (install_errors.GetString().c_str()); +                            err.SetErrorString(install_diagnostics.GetString().c_str());                          return err;                      } @@ -637,14 +949,28 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,                  IRDynamicChecks ir_dynamic_checks(*process->GetDynamicCheckers(), function_name.AsCString()); -                if (!ir_dynamic_checks.runOnModule(*execution_unit_sp->GetModule())) +                llvm::Module *module = execution_unit_sp->GetModule(); +                if (!module || !ir_dynamic_checks.runOnModule(*module))                  {                      err.SetErrorToGenericError();                      err.SetErrorString("Couldn't add dynamic checks to the expression");                      return err;                  } + +                if (custom_passes.LatePasses) +                { +                    if (log) +                        log->Printf("%s - Running Late IR Passes from LanguageRuntime on expression module '%s'", +                                    __FUNCTION__, m_expr.FunctionName()); + +                    custom_passes.LatePasses->run(*module); +                }              } +        } +        if (execution_policy == eExecutionPolicyAlways || execution_policy == eExecutionPolicyTopLevel || +            !can_interpret) +        {              execution_unit_sp->GetRunnableInfo(err, func_addr, func_end);          }      } @@ -655,3 +981,51 @@ ClangExpressionParser::PrepareForExecution (lldb::addr_t &func_addr,      return err;  } + +lldb_private::Error +ClangExpressionParser::RunStaticInitializers (lldb::IRExecutionUnitSP &execution_unit_sp, +                                              ExecutionContext &exe_ctx) +{ +    lldb_private::Error err; +     +    lldbassert(execution_unit_sp.get()); +    lldbassert(exe_ctx.HasThreadScope()); +     +    if (!execution_unit_sp.get()) +    { +        err.SetErrorString ("can't run static initializers for a NULL execution unit"); +        return err; +    } +     +    if (!exe_ctx.HasThreadScope()) +    { +        err.SetErrorString ("can't run static initializers without a thread"); +        return err; +    } +     +    std::vector<lldb::addr_t> static_initializers; +     +    execution_unit_sp->GetStaticInitializers(static_initializers); +     +    for (lldb::addr_t static_initializer : static_initializers) +    { +        EvaluateExpressionOptions options; +                 +        lldb::ThreadPlanSP call_static_initializer(new ThreadPlanCallFunction(exe_ctx.GetThreadRef(), +                                                                              Address(static_initializer), +                                                                              CompilerType(), +                                                                              llvm::ArrayRef<lldb::addr_t>(), +                                                                              options)); +         +        DiagnosticManager execution_errors; +        lldb::ExpressionResults results = exe_ctx.GetThreadRef().GetProcess()->RunThreadPlan(exe_ctx, call_static_initializer, options, execution_errors); +         +        if (results != lldb::eExpressionCompleted) +        { +            err.SetErrorStringWithFormat ("couldn't run static initializer: %s", execution_errors.GetString().c_str()); +            return err; +        } +    } +     +    return err; +}  | 
