<commit_before>//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MainThreadCheckerRuntime.h"

#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/RegularExpression.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/NameLookup.h"
#include "swift/ClangImporter/ClangImporter.h"

using namespace lldb;
using namespace lldb_private;

MainThreadCheckerRuntime::~MainThreadCheckerRuntime() {
  Deactivate();
}

lldb::InstrumentationRuntimeSP
MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) {
  return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp));
}

void MainThreadCheckerRuntime::Initialize() {
  PluginManager::RegisterPlugin(
      GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.",
      CreateInstance, GetTypeStatic);
}

void MainThreadCheckerRuntime::Terminate() {
  PluginManager::UnregisterPlugin(CreateInstance);
}

lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() {
  return ConstString("MainThreadChecker");
}

lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() {
  return eInstrumentationRuntimeTypeMainThreadChecker;
}

const RegularExpression &
MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() {
  static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib"));
  return regex;
}

bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid(
    const lldb::ModuleSP module_sp) {
  static ConstString test_sym("__main_thread_checker_on_report");
  const Symbol *symbol =
      module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny);
  return symbol != nullptr;
}

static std::string TranslateObjCNameToSwiftName(std::string className,
                                                std::string selector,
                                                StackFrameSP swiftFrame) {
  if (className.empty() || selector.empty())
    return "";
  ModuleSP swiftModule = swiftFrame->GetFrameCodeAddress().GetModule();
  if (!swiftModule)
    return "";
  SwiftASTContext *ctx = llvm::dyn_cast_or_null<SwiftASTContext>(
      swiftModule->GetTypeSystemForLanguage(lldb::eLanguageTypeSwift));
  if (!ctx)
    return "";
  swift::ClangImporter *imp = ctx->GetClangImporter();
  if (!imp)
    return "";

  size_t numArguments = llvm::StringRef(selector).count(':');
  llvm::SmallVector<llvm::StringRef, 4> parts;
  llvm::StringRef(selector).split(parts, ":", /*MaxSplit*/ -1,
      /*KeepEmpty*/ false);

  llvm::SmallVector<swift::Identifier, 2> selectorIdentifiers;
  for (size_t i = 0; i < parts.size(); i++) {
    selectorIdentifiers.push_back(ctx->GetIdentifier(parts[i]));
  }

  class MyConsumer : public swift::VisibleDeclConsumer {
  public:
    swift::ObjCSelector selectorToLookup;
    swift::DeclName result;

    MyConsumer(swift::ObjCSelector selector) : selectorToLookup(selector) {}

    virtual void foundDecl(swift::ValueDecl *VD,
                           swift::DeclVisibilityKind Reason) {
      if (result)
        return; // Take the first result.
      swift::ClassDecl *cls = llvm::dyn_cast<swift::ClassDecl>(VD);
      if (!cls)
        return;
      auto funcs = cls->lookupDirect(selectorToLookup, true);
      if (funcs.size() == 0)
        return;

      // If the decl is actually an accessor, use the property name instead.
      swift::AbstractFunctionDecl *decl = funcs.front();
      if (auto func = llvm::dyn_cast<swift::FuncDecl>(decl)) {
        swift::DeclContext *funcCtx = func->getParent();
        // We need to loadAllMembers(), otherwise 'isAccessor' returns false.
        if (auto extension = llvm::dyn_cast<swift::ExtensionDecl>(funcCtx)) {
          extension->loadAllMembers();
        } else if (auto nominal =
                       llvm::dyn_cast<swift::NominalTypeDecl>(funcCtx)) {
          nominal->loadAllMembers();
        }

        if (func->isAccessor()) {
          result = func->getAccessorStorageDecl()->getFullName();
          return;
        }
      }

      result = decl->getFullName();
    }
  };

  MyConsumer consumer(swift::ObjCSelector(*ctx->GetASTContext(), numArguments,
                                          selectorIdentifiers));
  // FIXME(mracek): Switch to a new API that translates the Clang class name
  // to Swift class name, once this API exists. Now we assume they are the same.
  imp->lookupValue(ctx->GetIdentifier(className), consumer);

  if (!consumer.result)
    return "";
  llvm::SmallString<32> scratchSpace;
  return className + "." + consumer.result.getString(scratchSpace).str();
}

StructuredData::ObjectSP
MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
  ProcessSP process_sp = GetProcessSP();
  if (!process_sp)
    return StructuredData::ObjectSP();

  ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
  StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
  ModuleSP runtime_module_sp = GetRuntimeModuleSP();
  Target &target = process_sp->GetTarget();

  if (!frame_sp)
    return StructuredData::ObjectSP();

  RegisterContextSP regctx_sp = frame_sp->GetRegisterContext();
  if (!regctx_sp)
    return StructuredData::ObjectSP();

  const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1");
  if (!reginfo)
    return StructuredData::ObjectSP();

  uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0);
  if (!apiname_ptr)
    return StructuredData::ObjectSP();

  std::string apiName = "";
  Status read_error;
  target.ReadCStringFromMemory(apiname_ptr, apiName, read_error);
  if (read_error.Fail())
    return StructuredData::ObjectSP();

  std::string className = "";
  std::string selector = "";
  if (apiName.substr(0, 2) == "-[") {
    size_t spacePos = apiName.find(" ");
    if (spacePos != std::string::npos) {
      className = apiName.substr(2, spacePos - 2);
      selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2);
    }
  }

  // Gather the PCs of the user frames in the backtrace.
  StructuredData::Array *trace = new StructuredData::Array();
  auto trace_sp = StructuredData::ObjectSP(trace);
  StackFrameSP responsible_frame;
  for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
    StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I);
    Address addr = frame->GetFrameCodeAddress();
    if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
      continue;

    // The first non-runtime frame is responsible for the bug.
    if (!responsible_frame)
      responsible_frame = frame;

    // First frame in stacktrace should point to a real PC, not return address.
    if (I != 0 && trace->GetSize() == 0) {
      addr.Slide(-1);
    }

    lldb::addr_t PC = addr.GetLoadAddress(&target);
    trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
  }

  if (responsible_frame) {
    if (responsible_frame->GetLanguage() == eLanguageTypeSwift) {
      std::string swiftApiName =
          TranslateObjCNameToSwiftName(className, selector, responsible_frame);
      if (swiftApiName != "")
        apiName = swiftApiName;
    }
  }

  auto *d = new StructuredData::Dictionary();
  auto dict_sp = StructuredData::ObjectSP(d);
  d->AddStringItem("instrumentation_class", "MainThreadChecker");
  d->AddStringItem("api_name", apiName);
  d->AddStringItem("class_name", className);
  d->AddStringItem("selector", selector);
  d->AddStringItem("description",
                   apiName + " must be used from main thread only");
  d->AddIntegerItem("tid", thread_sp->GetIndexID());
  d->AddItem("trace", trace_sp);
  return dict_sp;
}

bool MainThreadCheckerRuntime::NotifyBreakpointHit(
    void *baton, StoppointCallbackContext *context, user_id_t break_id,
    user_id_t break_loc_id) {
  assert(baton && "null baton");
  if (!baton)
    return false; //< false => resume execution.

  MainThreadCheckerRuntime *const instance =
      static_cast<MainThreadCheckerRuntime *>(baton);

  ProcessSP process_sp = instance->GetProcessSP();
  ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
  if (!process_sp || !thread_sp ||
      process_sp != context->exe_ctx_ref.GetProcessSP())
    return false;

  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
    return false;

  StructuredData::ObjectSP report =
      instance->RetrieveReportData(context->exe_ctx_ref);

  if (report) {
    std::string description = report->GetAsDictionary()
                                ->GetValueForKey("description")
                                ->GetAsString()
                                ->GetValue();
    thread_sp->SetStopInfo(
        InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
            *thread_sp, description, report));
    return true;
  }

  return false;
}

void MainThreadCheckerRuntime::Activate() {
  if (IsActive())
    return;

  ProcessSP process_sp = GetProcessSP();
  if (!process_sp)
    return;

  ModuleSP runtime_module_sp = GetRuntimeModuleSP();

  ConstString symbol_name("__main_thread_checker_on_report");
  const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
      symbol_name, eSymbolTypeCode);

  if (symbol == nullptr)
    return;

  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
    return;

  Target &target = process_sp->GetTarget();
  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);

  if (symbol_address == LLDB_INVALID_ADDRESS)
    return;

  Breakpoint *breakpoint =
      process_sp->GetTarget()
          .CreateBreakpoint(symbol_address, /*internal=*/true,
                            /*hardware=*/false)
          .get();
  breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this,
                          true);
  breakpoint->SetBreakpointKind("main-thread-checker-report");
  SetBreakpointID(breakpoint->GetID());

  SetActive(true);
}

void MainThreadCheckerRuntime::Deactivate() {
  SetActive(false);

  auto BID = GetBreakpointID();
  if (BID == LLDB_INVALID_BREAK_ID)
    return;

  if (ProcessSP process_sp = GetProcessSP()) {
    process_sp->GetTarget().RemoveBreakpointByID(BID);
    SetBreakpointID(LLDB_INVALID_BREAK_ID);
  }
}

lldb::ThreadCollectionSP
MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo(
    StructuredData::ObjectSP info) {
  ThreadCollectionSP threads;
  threads.reset(new ThreadCollection());

  ProcessSP process_sp = GetProcessSP();

  if (info->GetObjectForDotSeparatedPath("instrumentation_class")
      ->GetStringValue() != "MainThreadChecker")
    return threads;

  std::vector<lldb::addr_t> PCs;
  auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
  trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
    PCs.push_back(PC->GetAsInteger()->GetValue());
    return true;
  });

  if (PCs.empty())
    return threads;

  StructuredData::ObjectSP thread_id_obj =
      info->GetObjectForDotSeparatedPath("tid");
  tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;

  uint32_t stop_id = 0;
  bool stop_id_is_valid = false;
  HistoryThread *history_thread =
      new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
  ThreadSP new_thread_sp(history_thread);

  // Save this in the Process' ExtendedThreadList so a strong pointer
  // retains the object
  process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
  threads->AddThread(new_thread_sp);

  return threads;
}
<commit_msg>Update for the changes to Swift accessor declarations (Swift PR #13866).<commit_after>//===-- MainThreadCheckerRuntime.cpp ----------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "MainThreadCheckerRuntime.h"

#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Variable.h"
#include "lldb/Symbol/VariableList.h"
#include "lldb/Target/InstrumentationRuntimeStopInfo.h"
#include "lldb/Target/RegisterContext.h"
#include "lldb/Target/SectionLoadList.h"
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Utility/RegularExpression.h"
#include "Plugins/Process/Utility/HistoryThread.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/NameLookup.h"
#include "swift/ClangImporter/ClangImporter.h"

using namespace lldb;
using namespace lldb_private;

MainThreadCheckerRuntime::~MainThreadCheckerRuntime() {
  Deactivate();
}

lldb::InstrumentationRuntimeSP
MainThreadCheckerRuntime::CreateInstance(const lldb::ProcessSP &process_sp) {
  return InstrumentationRuntimeSP(new MainThreadCheckerRuntime(process_sp));
}

void MainThreadCheckerRuntime::Initialize() {
  PluginManager::RegisterPlugin(
      GetPluginNameStatic(), "MainThreadChecker instrumentation runtime plugin.",
      CreateInstance, GetTypeStatic);
}

void MainThreadCheckerRuntime::Terminate() {
  PluginManager::UnregisterPlugin(CreateInstance);
}

lldb_private::ConstString MainThreadCheckerRuntime::GetPluginNameStatic() {
  return ConstString("MainThreadChecker");
}

lldb::InstrumentationRuntimeType MainThreadCheckerRuntime::GetTypeStatic() {
  return eInstrumentationRuntimeTypeMainThreadChecker;
}

const RegularExpression &
MainThreadCheckerRuntime::GetPatternForRuntimeLibrary() {
  static RegularExpression regex(llvm::StringRef("libMainThreadChecker.dylib"));
  return regex;
}

bool MainThreadCheckerRuntime::CheckIfRuntimeIsValid(
    const lldb::ModuleSP module_sp) {
  static ConstString test_sym("__main_thread_checker_on_report");
  const Symbol *symbol =
      module_sp->FindFirstSymbolWithNameAndType(test_sym, lldb::eSymbolTypeAny);
  return symbol != nullptr;
}

static std::string TranslateObjCNameToSwiftName(std::string className,
                                                std::string selector,
                                                StackFrameSP swiftFrame) {
  if (className.empty() || selector.empty())
    return "";
  ModuleSP swiftModule = swiftFrame->GetFrameCodeAddress().GetModule();
  if (!swiftModule)
    return "";
  SwiftASTContext *ctx = llvm::dyn_cast_or_null<SwiftASTContext>(
      swiftModule->GetTypeSystemForLanguage(lldb::eLanguageTypeSwift));
  if (!ctx)
    return "";
  swift::ClangImporter *imp = ctx->GetClangImporter();
  if (!imp)
    return "";

  size_t numArguments = llvm::StringRef(selector).count(':');
  llvm::SmallVector<llvm::StringRef, 4> parts;
  llvm::StringRef(selector).split(parts, ":", /*MaxSplit*/ -1,
      /*KeepEmpty*/ false);

  llvm::SmallVector<swift::Identifier, 2> selectorIdentifiers;
  for (size_t i = 0; i < parts.size(); i++) {
    selectorIdentifiers.push_back(ctx->GetIdentifier(parts[i]));
  }

  class MyConsumer : public swift::VisibleDeclConsumer {
  public:
    swift::ObjCSelector selectorToLookup;
    swift::DeclName result;

    MyConsumer(swift::ObjCSelector selector) : selectorToLookup(selector) {}

    virtual void foundDecl(swift::ValueDecl *VD,
                           swift::DeclVisibilityKind Reason) {
      if (result)
        return; // Take the first result.
      swift::ClassDecl *cls = llvm::dyn_cast<swift::ClassDecl>(VD);
      if (!cls)
        return;
      auto funcs = cls->lookupDirect(selectorToLookup, true);
      if (funcs.size() == 0)
        return;

      // If the decl is actually an accessor, use the property name instead.
      swift::AbstractFunctionDecl *decl = funcs.front();
      if (auto func = llvm::dyn_cast<swift::FuncDecl>(decl)) {
        swift::DeclContext *funcCtx = func->getParent();
        // We need to loadAllMembers(), otherwise 'isAccessor' returns false.
        if (auto extension = llvm::dyn_cast<swift::ExtensionDecl>(funcCtx)) {
          extension->loadAllMembers();
        } else if (auto nominal =
                       llvm::dyn_cast<swift::NominalTypeDecl>(funcCtx)) {
          nominal->loadAllMembers();
        }

        if (auto accessor = llvm::dyn_cast<swift::AccessorDecl>(func)) {
          result = accessor->getStorage()->getFullName();
          return;
        }
      }

      result = decl->getFullName();
    }
  };

  MyConsumer consumer(swift::ObjCSelector(*ctx->GetASTContext(), numArguments,
                                          selectorIdentifiers));
  // FIXME(mracek): Switch to a new API that translates the Clang class name
  // to Swift class name, once this API exists. Now we assume they are the same.
  imp->lookupValue(ctx->GetIdentifier(className), consumer);

  if (!consumer.result)
    return "";
  llvm::SmallString<32> scratchSpace;
  return className + "." + consumer.result.getString(scratchSpace).str();
}

StructuredData::ObjectSP
MainThreadCheckerRuntime::RetrieveReportData(ExecutionContextRef exe_ctx_ref) {
  ProcessSP process_sp = GetProcessSP();
  if (!process_sp)
    return StructuredData::ObjectSP();

  ThreadSP thread_sp = exe_ctx_ref.GetThreadSP();
  StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
  ModuleSP runtime_module_sp = GetRuntimeModuleSP();
  Target &target = process_sp->GetTarget();

  if (!frame_sp)
    return StructuredData::ObjectSP();

  RegisterContextSP regctx_sp = frame_sp->GetRegisterContext();
  if (!regctx_sp)
    return StructuredData::ObjectSP();

  const RegisterInfo *reginfo = regctx_sp->GetRegisterInfoByName("arg1");
  if (!reginfo)
    return StructuredData::ObjectSP();

  uint64_t apiname_ptr = regctx_sp->ReadRegisterAsUnsigned(reginfo, 0);
  if (!apiname_ptr)
    return StructuredData::ObjectSP();

  std::string apiName = "";
  Status read_error;
  target.ReadCStringFromMemory(apiname_ptr, apiName, read_error);
  if (read_error.Fail())
    return StructuredData::ObjectSP();

  std::string className = "";
  std::string selector = "";
  if (apiName.substr(0, 2) == "-[") {
    size_t spacePos = apiName.find(" ");
    if (spacePos != std::string::npos) {
      className = apiName.substr(2, spacePos - 2);
      selector = apiName.substr(spacePos + 1, apiName.length() - spacePos - 2);
    }
  }

  // Gather the PCs of the user frames in the backtrace.
  StructuredData::Array *trace = new StructuredData::Array();
  auto trace_sp = StructuredData::ObjectSP(trace);
  StackFrameSP responsible_frame;
  for (unsigned I = 0; I < thread_sp->GetStackFrameCount(); ++I) {
    StackFrameSP frame = thread_sp->GetStackFrameAtIndex(I);
    Address addr = frame->GetFrameCodeAddress();
    if (addr.GetModule() == runtime_module_sp) // Skip PCs from the runtime.
      continue;

    // The first non-runtime frame is responsible for the bug.
    if (!responsible_frame)
      responsible_frame = frame;

    // First frame in stacktrace should point to a real PC, not return address.
    if (I != 0 && trace->GetSize() == 0) {
      addr.Slide(-1);
    }

    lldb::addr_t PC = addr.GetLoadAddress(&target);
    trace->AddItem(StructuredData::ObjectSP(new StructuredData::Integer(PC)));
  }

  if (responsible_frame) {
    if (responsible_frame->GetLanguage() == eLanguageTypeSwift) {
      std::string swiftApiName =
          TranslateObjCNameToSwiftName(className, selector, responsible_frame);
      if (swiftApiName != "")
        apiName = swiftApiName;
    }
  }

  auto *d = new StructuredData::Dictionary();
  auto dict_sp = StructuredData::ObjectSP(d);
  d->AddStringItem("instrumentation_class", "MainThreadChecker");
  d->AddStringItem("api_name", apiName);
  d->AddStringItem("class_name", className);
  d->AddStringItem("selector", selector);
  d->AddStringItem("description",
                   apiName + " must be used from main thread only");
  d->AddIntegerItem("tid", thread_sp->GetIndexID());
  d->AddItem("trace", trace_sp);
  return dict_sp;
}

bool MainThreadCheckerRuntime::NotifyBreakpointHit(
    void *baton, StoppointCallbackContext *context, user_id_t break_id,
    user_id_t break_loc_id) {
  assert(baton && "null baton");
  if (!baton)
    return false; //< false => resume execution.

  MainThreadCheckerRuntime *const instance =
      static_cast<MainThreadCheckerRuntime *>(baton);

  ProcessSP process_sp = instance->GetProcessSP();
  ThreadSP thread_sp = context->exe_ctx_ref.GetThreadSP();
  if (!process_sp || !thread_sp ||
      process_sp != context->exe_ctx_ref.GetProcessSP())
    return false;

  if (process_sp->GetModIDRef().IsLastResumeForUserExpression())
    return false;

  StructuredData::ObjectSP report =
      instance->RetrieveReportData(context->exe_ctx_ref);

  if (report) {
    std::string description = report->GetAsDictionary()
                                ->GetValueForKey("description")
                                ->GetAsString()
                                ->GetValue();
    thread_sp->SetStopInfo(
        InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData(
            *thread_sp, description, report));
    return true;
  }

  return false;
}

void MainThreadCheckerRuntime::Activate() {
  if (IsActive())
    return;

  ProcessSP process_sp = GetProcessSP();
  if (!process_sp)
    return;

  ModuleSP runtime_module_sp = GetRuntimeModuleSP();

  ConstString symbol_name("__main_thread_checker_on_report");
  const Symbol *symbol = runtime_module_sp->FindFirstSymbolWithNameAndType(
      symbol_name, eSymbolTypeCode);

  if (symbol == nullptr)
    return;

  if (!symbol->ValueIsAddress() || !symbol->GetAddressRef().IsValid())
    return;

  Target &target = process_sp->GetTarget();
  addr_t symbol_address = symbol->GetAddressRef().GetOpcodeLoadAddress(&target);

  if (symbol_address == LLDB_INVALID_ADDRESS)
    return;

  Breakpoint *breakpoint =
      process_sp->GetTarget()
          .CreateBreakpoint(symbol_address, /*internal=*/true,
                            /*hardware=*/false)
          .get();
  breakpoint->SetCallback(MainThreadCheckerRuntime::NotifyBreakpointHit, this,
                          true);
  breakpoint->SetBreakpointKind("main-thread-checker-report");
  SetBreakpointID(breakpoint->GetID());

  SetActive(true);
}

void MainThreadCheckerRuntime::Deactivate() {
  SetActive(false);

  auto BID = GetBreakpointID();
  if (BID == LLDB_INVALID_BREAK_ID)
    return;

  if (ProcessSP process_sp = GetProcessSP()) {
    process_sp->GetTarget().RemoveBreakpointByID(BID);
    SetBreakpointID(LLDB_INVALID_BREAK_ID);
  }
}

lldb::ThreadCollectionSP
MainThreadCheckerRuntime::GetBacktracesFromExtendedStopInfo(
    StructuredData::ObjectSP info) {
  ThreadCollectionSP threads;
  threads.reset(new ThreadCollection());

  ProcessSP process_sp = GetProcessSP();

  if (info->GetObjectForDotSeparatedPath("instrumentation_class")
      ->GetStringValue() != "MainThreadChecker")
    return threads;

  std::vector<lldb::addr_t> PCs;
  auto trace = info->GetObjectForDotSeparatedPath("trace")->GetAsArray();
  trace->ForEach([&PCs](StructuredData::Object *PC) -> bool {
    PCs.push_back(PC->GetAsInteger()->GetValue());
    return true;
  });

  if (PCs.empty())
    return threads;

  StructuredData::ObjectSP thread_id_obj =
      info->GetObjectForDotSeparatedPath("tid");
  tid_t tid = thread_id_obj ? thread_id_obj->GetIntegerValue() : 0;

  uint32_t stop_id = 0;
  bool stop_id_is_valid = false;
  HistoryThread *history_thread =
      new HistoryThread(*process_sp, tid, PCs, stop_id, stop_id_is_valid);
  ThreadSP new_thread_sp(history_thread);

  // Save this in the Process' ExtendedThreadList so a strong pointer
  // retains the object
  process_sp->GetExtendedThreadList().AddThread(new_thread_sp);
  threads->AddThread(new_thread_sp);

  return threads;
}
<|endoftext|>


<commit_before>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view information solvers widget
//==============================================================================

#include "cellmlfileruntime.h"
#include "corecliutils.h"
#include "singlecellviewinformationsolverswidget.h"
#include "singlecellviewplugin.h"
#include "singlecellviewsimulation.h"

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewInformationSolversWidgetData::SingleCellViewInformationSolversWidgetData(const QMap<QString, SolverInterface *> &pSolversInterfaces,
                                                                                Core::Property *pSolversProperty,
                                                                                Core::Property *pSolversListProperty,
                                                                                const QMap<QString, Core::Properties> &pSolversProperties) :
    mSolversInterfaces(pSolversInterfaces),
    mSolversProperty(pSolversProperty),
    mSolversListProperty(pSolversListProperty),
    mSolversProperties(pSolversProperties)
{
}

//==============================================================================

QMap<QString, SolverInterface *> SingleCellViewInformationSolversWidgetData::solversInterfaces() const
{
    // Return our solvers interfaces

    return mSolversInterfaces;
}

//==============================================================================

Core::Property * SingleCellViewInformationSolversWidgetData::solversProperty() const
{
    // Return our solvers property

    return mSolversProperty;
}

//==============================================================================

Core::Property * SingleCellViewInformationSolversWidgetData::solversListProperty() const
{
    // Return our solvers list property

    return mSolversListProperty;
}

//==============================================================================

QMap<QString, Core::Properties> SingleCellViewInformationSolversWidgetData::solversProperties() const
{
    // Return our solvers properties

    return mSolversProperties;
}

//==============================================================================

SingleCellViewInformationSolversWidget::SingleCellViewInformationSolversWidget(SingleCellViewPlugin *pPlugin,
                                                                               QWidget *pParent) :
    PropertyEditorWidget(true, pParent),
    mDescriptions(QMap<Core::Property *, Descriptions>())
{
    // Remove all our properties

    removeAllProperties();

    // Add properties for our different solvers

    mOdeSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Ode);
    mDaeSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Dae);
    mNlaSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Nla);

    // Show/hide the relevant properties

    if (mOdeSolverData)
        doSolverChanged(mOdeSolverData, mOdeSolverData->solversListProperty()->value());

    if (mDaeSolverData)
        doSolverChanged(mDaeSolverData, mDaeSolverData->solversListProperty()->value());

    if (mNlaSolverData)
        doSolverChanged(mNlaSolverData, mNlaSolverData->solversListProperty()->value());

    // Expand all our properties

    expandAll();

    // Keep track of changes to list properties

    connect(this, SIGNAL(propertyChanged(Core::Property *)),
            this, SLOT(solverChanged(Core::Property *)));
}

//==============================================================================

SingleCellViewInformationSolversWidget::~SingleCellViewInformationSolversWidget()
{
    // Delete some internal objects

    delete mOdeSolverData;
    delete mDaeSolverData;
    delete mNlaSolverData;
}

//==============================================================================

void SingleCellViewInformationSolversWidget::retranslateUi()
{
    // Update our property names

    if (mOdeSolverData) {
        mOdeSolverData->solversProperty()->setName(tr("ODE solver"));
        mOdeSolverData->solversListProperty()->setName(tr("Name"));

        mOdeSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    if (mDaeSolverData) {
        mDaeSolverData->solversProperty()->setName(tr("DAE solver"));
        mDaeSolverData->solversListProperty()->setName(tr("Name"));

        mDaeSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    if (mNlaSolverData) {
        mNlaSolverData->solversProperty()->setName(tr("NLA solver"));
        mNlaSolverData->solversListProperty()->setName(tr("Name"));

        mNlaSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    // Update the name of our various properties, should they have a description
    // associated with them
    // Note: this is effectively to have the description of our solvers'
    //       properties properly updated...

    foreach (Core::Property *property, properties()) {
        if (mDescriptions.contains(property)) {
            // The property has a description associated with it, so retrieve
            // the version, if any, which corresponds to our current locale

            Descriptions descriptions = mDescriptions.value(property);
            QString description = descriptions.value(Core::locale());

            if (description.isEmpty()) {
                // No description exists for the current locale, so retrieve the
                // English description (which, hopefully, exists)

                description = descriptions.value("en");
            }

            // Set the name of the property to the description

            property->setName(description);
        }
    }

    // Default retranslation
    // Note: we must do it last since we set the empty list value of some
    //       properties above...

    PropertyEditorWidget::retranslateUi();
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::addSolverProperties(const SolverInterfaces &pSolverInterfaces,
                                                                                const Solver::Type &pSolverType)
{
    // Make sure that we have at least one solver interface

    if (pSolverInterfaces.isEmpty())
        return 0;

    // Retrieve the name of the solvers which type is the one in which we are
    // interested

    QMap<QString, SolverInterface *> solversInterfaces = QMap<QString, SolverInterface *>();
    Core::Property *solversProperty = 0;
    Core::Property *solversListProperty = 0;
    QStringList solversNames = QStringList();
    QMap<QString, Core::Properties> solversProperties = QMap<QString, Core::Properties>();

    foreach (SolverInterface *solverInterface, pSolverInterfaces) {
        if (solverInterface->solverType() == pSolverType) {
            // Keep track of the solver's interface

            solversInterfaces.insert(solverInterface->solverName(), solverInterface);

            // Keep track of the solver's name

            solversNames << solverInterface->solverName();

            // Add our solvers section property and list property for our
            // solvers, if needed

            if (!solversProperty) {
                solversProperty = addSectionProperty();

                solversListProperty = addListProperty(solversProperty);
            }

            // Add the solver's properties

            Core::Property *property;
            Core::Properties properties = Core::Properties();

            foreach (const Solver::Property &solverInterfaceProperty,
                     solverInterface->solverProperties()) {
                // Add the solver's property and set its default value

                switch (solverInterfaceProperty.type()) {
                case Solver::Property::Boolean:
                    property = addBooleanProperty(solverInterfaceProperty.defaultValue().toBool(),
                                                  solversProperty);

                    break;
                case Solver::Property::Integer:
                    property = addIntegerProperty(solverInterfaceProperty.defaultValue().toInt(),
                                                  solversProperty);

                    break;
                case Solver::Property::Double:
                    property = addDoubleProperty(solverInterfaceProperty.defaultValue().toDouble(),
                                                 solversProperty);

                    break;
                case Solver::Property::List:
                    property = addListProperty(solverInterfaceProperty.listValues(),
                                               solverInterfaceProperty.defaultValue().toString(),
                                               solversProperty);

                    break;
                }

                property->setId(solverInterfaceProperty.id());

                // Make the property editable

                property->setEditable(true);

                // Set the solver's property's 'unit', if needed

                if (solverInterfaceProperty.hasVoiUnit())
                    property->setUnit("???");
                    // Note: to assign a non-empty string to our unit item is
                    //       just a way for us to make sure that the property's
                    //       will get initialised (see setPropertiesUnit())...

                // Keep track of the solver's property

                properties << property;

                // Keep track of the solver's property's descriptions

                mDescriptions.insert(property, solverInterfaceProperty.descriptions());
            }

            // Keep track of the solver's properties

            solversProperties.insert(solverInterface->solverName(), properties);
        }
    }

    // Check whether we have at least one solver

    if (solversListProperty) {
        // We have a solvers list property, which means that we have at least
        // one solver, so sort our list

        solversNames.sort();

        // Assign the list of solvers to our list property

        solversListProperty->setListValues(solversNames);

        // Create and return our solver data

        return new SingleCellViewInformationSolversWidgetData(solversInterfaces,
                                                              solversProperty,
                                                              solversListProperty,
                                                              solversProperties);
    } else {
        return 0;
    }
}

//==============================================================================

void SingleCellViewInformationSolversWidget::setPropertiesUnit(SingleCellViewInformationSolversWidgetData *pSolverData,
                                                               const QString &pVoiUnit)
{
    // Make sure that we have some solver's data

    if (!pSolverData)
        return;

    // Go through the solvers' properties and set the unit of the relevant ones

    foreach (const Core::Properties &properties, pSolverData->solversProperties())
        foreach (Core::Property *property, properties)
            if (!property->unit().isEmpty())
                property->setUnit(pVoiUnit);
}

//==============================================================================

void SingleCellViewInformationSolversWidget::initialize(SingleCellViewSimulation *pSimulation)
{
    // Make sure that the CellML file runtime is valid

    if (pSimulation->runtime()->isValid()) {
        // Show/hide the ODE/DAE/NLA solver information

        if (mOdeSolverData)
            mOdeSolverData->solversProperty()->setVisible(pSimulation->runtime()->needOdeSolver());

        if (mDaeSolverData)
            mDaeSolverData->solversProperty()->setVisible(pSimulation->runtime()->needDaeSolver());

        if (mNlaSolverData)
            mNlaSolverData->solversProperty()->setVisible(pSimulation->runtime()->needNlaSolver());
    }

    // Set the unit of our different properties, if needed

    QString voiUnit = pSimulation->runtime()->variableOfIntegration()->unit();

    setPropertiesUnit(mOdeSolverData, voiUnit);
    setPropertiesUnit(mDaeSolverData, voiUnit);
    setPropertiesUnit(mNlaSolverData, voiUnit);

    // Initialise our simulation's NLA solver's properties, so that we can then
    // properly reset our simulation the first time round

    if (mNlaSolverData) {
        pSimulation->data()->setNlaSolverName(mNlaSolverData->solversListProperty()->value(), false);

        foreach (Core::Property *property, mNlaSolverData->solversProperties().value(pSimulation->data()->nlaSolverName())) {
            pSimulation->data()->addNlaSolverProperty(property->id(),
                                                      (property->type() == Core::Property::Integer)?
                                                          property->integerValue():
                                                          property->doubleValue(),
                                                      false);
        }
    }
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::odeSolvers() const
{
    // Return the available ODE solvers, if any

    return mOdeSolverData?mOdeSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::daeSolvers() const
{
    // Return the available DAE solvers, if any

    return mDaeSolverData?mDaeSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::nlaSolvers() const
{
    // Return the available NLA solvers, if any

    return mNlaSolverData?mNlaSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::odeSolverData() const
{
    // Return our ODE solver data

    return mOdeSolverData;
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::daeSolverData() const
{
    // Return our DAE solver data

    return mDaeSolverData;
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::nlaSolverData() const
{
    // Return our NLA solver data

    return mNlaSolverData;
}

//==============================================================================

void SingleCellViewInformationSolversWidget::updateSolverGui(SingleCellViewInformationSolversWidgetData *pSolverData)
{
    // Make sure that we have some solver data

    if (!pSolverData)
        return;

    // Update our solver properties visibility

    QString solverName = pSolverData->solversListProperty()->value();
    SolverInterface *solverInterface = pSolverData->solversInterfaces().value(solverName);
    Core::Properties solverProperties = pSolverData->solversProperties().value(solverName);

    // Retrieve our solver properties values

    QMap<QString, QString> solverPropertiesValues = QMap<QString, QString>();

    foreach (Core::Property *solverProperty, solverProperties)
        solverPropertiesValues.insert(solverProperty->id(),solverProperty->value());

    // Ask our solver interface to tell us about the visibility of its
    // properties based on their values

    QMap<QString, bool> solverPropertiesVisibility = solverInterface->solverPropertiesVisibility(solverPropertiesValues);

    // Update the visilibity of our solver properties
    // Note: if there is no visibility information for a given solver property,
    //       then it means that it should be visible...

    foreach (Core::Property *solverProperty, solverProperties)
        solverProperty->setVisible(solverPropertiesVisibility.value(solverProperty->id(), true));
}

//==============================================================================

void SingleCellViewInformationSolversWidget::updateGui(SingleCellViewInformationSolversWidgetData *pSolverData)
{
    // Update our solver(s) properties visibility

    if (mOdeSolverData && (!pSolverData || (pSolverData == mOdeSolverData)))
        updateSolverGui(mOdeSolverData);

    if (mDaeSolverData && (!pSolverData || (pSolverData == mDaeSolverData)))
        updateSolverGui(mDaeSolverData);

    if (mNlaSolverData && (!pSolverData || (pSolverData == mNlaSolverData)))
        updateSolverGui(mNlaSolverData);
}

//==============================================================================

void SingleCellViewInformationSolversWidget::doSolverChanged(SingleCellViewInformationSolversWidgetData *pSolverData,
                                                             const QString &pSolverName)
{
    // Make sure that we have some solver data

    if (!pSolverData)
        return;

    // Go through the different properties for the given type of solver and
    // show/hide whatever needs showing/hiding

    for (auto solverProperties = pSolverData->solversProperties().constBegin(),
              solverPropertiesEnd = pSolverData->solversProperties().constEnd();
         solverProperties != solverPropertiesEnd; ++solverProperties) {
        bool solverPropertiesVisible = !solverProperties.key().compare(pSolverName);

        foreach (Core::Property *solverProperty, solverProperties.value())
            solverProperty->setVisible(solverPropertiesVisible);
    }
}

//==============================================================================

void SingleCellViewInformationSolversWidget::solverChanged(Core::Property *pProperty)
{
    // Try, for the ODE/DAE/NLA solvers list property, to handle the change in
    // the list property
    // Note: the ODE/DAE/NLA solvers list property is our first property, hence
    //       we make sure that its row number is equal to zero (in case there is
    //       one or several other list properties, as is the case for the CVODE
    //       and IDA solvers)...

    if (!pProperty->row()) {
        doSolverChanged((mOdeSolverData && (pProperty == mOdeSolverData->solversListProperty()))?
                            mOdeSolverData:
                            (mDaeSolverData && (pProperty == mDaeSolverData->solversListProperty()))?
                                mDaeSolverData:
                                mNlaSolverData,
                        pProperty->value());
    }
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<commit_msg>Some minor cleaning up [ci skip].<commit_after>/*******************************************************************************

Licensed to the OpenCOR team under one or more contributor license agreements.
See the NOTICE.txt file distributed with this work for additional information
regarding copyright ownership. The OpenCOR team licenses this file to you under
the Apache License, Version 2.0 (the "License"); you may not use this file
except in compliance with the License. You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed
under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
CONDITIONS OF ANY KIND, either express or implied. See the License for the
specific language governing permissions and limitations under the License.

*******************************************************************************/

//==============================================================================
// Single cell view information solvers widget
//==============================================================================

#include "cellmlfileruntime.h"
#include "corecliutils.h"
#include "singlecellviewinformationsolverswidget.h"
#include "singlecellviewplugin.h"
#include "singlecellviewsimulation.h"

//==============================================================================

namespace OpenCOR {
namespace SingleCellView {

//==============================================================================

SingleCellViewInformationSolversWidgetData::SingleCellViewInformationSolversWidgetData(const QMap<QString, SolverInterface *> &pSolversInterfaces,
                                                                                Core::Property *pSolversProperty,
                                                                                Core::Property *pSolversListProperty,
                                                                                const QMap<QString, Core::Properties> &pSolversProperties) :
    mSolversInterfaces(pSolversInterfaces),
    mSolversProperty(pSolversProperty),
    mSolversListProperty(pSolversListProperty),
    mSolversProperties(pSolversProperties)
{
}

//==============================================================================

QMap<QString, SolverInterface *> SingleCellViewInformationSolversWidgetData::solversInterfaces() const
{
    // Return our solvers interfaces

    return mSolversInterfaces;
}

//==============================================================================

Core::Property * SingleCellViewInformationSolversWidgetData::solversProperty() const
{
    // Return our solvers property

    return mSolversProperty;
}

//==============================================================================

Core::Property * SingleCellViewInformationSolversWidgetData::solversListProperty() const
{
    // Return our solvers list property

    return mSolversListProperty;
}

//==============================================================================

QMap<QString, Core::Properties> SingleCellViewInformationSolversWidgetData::solversProperties() const
{
    // Return our solvers properties

    return mSolversProperties;
}

//==============================================================================

SingleCellViewInformationSolversWidget::SingleCellViewInformationSolversWidget(SingleCellViewPlugin *pPlugin,
                                                                               QWidget *pParent) :
    PropertyEditorWidget(true, pParent),
    mDescriptions(QMap<Core::Property *, Descriptions>())
{
    // Remove all our properties

    removeAllProperties();

    // Add properties for our different solvers

    mOdeSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Ode);
    mDaeSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Dae);
    mNlaSolverData = addSolverProperties(pPlugin->solverInterfaces(), Solver::Nla);

    // Show/hide the relevant properties

    if (mOdeSolverData)
        doSolverChanged(mOdeSolverData, mOdeSolverData->solversListProperty()->value());

    if (mDaeSolverData)
        doSolverChanged(mDaeSolverData, mDaeSolverData->solversListProperty()->value());

    if (mNlaSolverData)
        doSolverChanged(mNlaSolverData, mNlaSolverData->solversListProperty()->value());

    // Expand all our properties

    expandAll();

    // Keep track of changes to list properties

    connect(this, SIGNAL(propertyChanged(Core::Property *)),
            this, SLOT(solverChanged(Core::Property *)));
}

//==============================================================================

SingleCellViewInformationSolversWidget::~SingleCellViewInformationSolversWidget()
{
    // Delete some internal objects

    delete mOdeSolverData;
    delete mDaeSolverData;
    delete mNlaSolverData;
}

//==============================================================================

void SingleCellViewInformationSolversWidget::retranslateUi()
{
    // Update our property names

    if (mOdeSolverData) {
        mOdeSolverData->solversProperty()->setName(tr("ODE solver"));
        mOdeSolverData->solversListProperty()->setName(tr("Name"));

        mOdeSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    if (mDaeSolverData) {
        mDaeSolverData->solversProperty()->setName(tr("DAE solver"));
        mDaeSolverData->solversListProperty()->setName(tr("Name"));

        mDaeSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    if (mNlaSolverData) {
        mNlaSolverData->solversProperty()->setName(tr("NLA solver"));
        mNlaSolverData->solversListProperty()->setName(tr("Name"));

        mNlaSolverData->solversListProperty()->setEmptyListValue(tr("None available"));
    }

    // Update the name of our various properties, should they have a description
    // associated with them
    // Note: this is effectively to have the description of our solvers'
    //       properties properly updated...

    foreach (Core::Property *property, properties()) {
        if (mDescriptions.contains(property)) {
            // The property has a description associated with it, so retrieve
            // the version, if any, which corresponds to our current locale

            Descriptions descriptions = mDescriptions.value(property);
            QString description = descriptions.value(Core::locale());

            if (description.isEmpty()) {
                // No description exists for the current locale, so retrieve the
                // English description (which, hopefully, exists)

                description = descriptions.value("en");
            }

            // Set the name of the property to the description

            property->setName(description);
        }
    }

    // Default retranslation
    // Note: we must do it last since we set the empty list value of some
    //       properties above...

    PropertyEditorWidget::retranslateUi();
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::addSolverProperties(const SolverInterfaces &pSolverInterfaces,
                                                                                const Solver::Type &pSolverType)
{
    // Make sure that we have at least one solver interface

    if (pSolverInterfaces.isEmpty())
        return 0;

    // Retrieve the name of the solvers which type is the one in which we are
    // interested

    QMap<QString, SolverInterface *> solversInterfaces = QMap<QString, SolverInterface *>();
    Core::Property *solversProperty = 0;
    Core::Property *solversListProperty = 0;
    QStringList solversNames = QStringList();
    QMap<QString, Core::Properties> solversProperties = QMap<QString, Core::Properties>();

    foreach (SolverInterface *solverInterface, pSolverInterfaces) {
        if (solverInterface->solverType() == pSolverType) {
            // Keep track of the solver's interface

            solversInterfaces.insert(solverInterface->solverName(), solverInterface);

            // Keep track of the solver's name

            solversNames << solverInterface->solverName();

            // Add our solvers section property and list property for our
            // solvers, if needed

            if (!solversProperty) {
                solversProperty = addSectionProperty();

                solversListProperty = addListProperty(solversProperty);
            }

            // Add the solver's properties

            Core::Property *property = 0;
            Core::Properties properties = Core::Properties();

            foreach (const Solver::Property &solverInterfaceProperty,
                     solverInterface->solverProperties()) {
                // Add the solver's property and set its default value

                switch (solverInterfaceProperty.type()) {
                case Solver::Property::Boolean:
                    property = addBooleanProperty(solverInterfaceProperty.defaultValue().toBool(),
                                                  solversProperty);

                    break;
                case Solver::Property::Integer:
                    property = addIntegerProperty(solverInterfaceProperty.defaultValue().toInt(),
                                                  solversProperty);

                    break;
                case Solver::Property::Double:
                    property = addDoubleProperty(solverInterfaceProperty.defaultValue().toDouble(),
                                                 solversProperty);

                    break;
                case Solver::Property::List:
                    property = addListProperty(solverInterfaceProperty.listValues(),
                                               solverInterfaceProperty.defaultValue().toString(),
                                               solversProperty);

                    break;
                }

                property->setId(solverInterfaceProperty.id());

                // Make the property editable

                property->setEditable(true);

                // Set the solver's property's 'unit', if needed

                if (solverInterfaceProperty.hasVoiUnit())
                    property->setUnit("???");
                    // Note: to assign a non-empty string to our unit item is
                    //       just a way for us to make sure that the property's
                    //       will get initialised (see setPropertiesUnit())...

                // Keep track of the solver's property

                properties << property;

                // Keep track of the solver's property's descriptions

                mDescriptions.insert(property, solverInterfaceProperty.descriptions());
            }

            // Keep track of the solver's properties

            solversProperties.insert(solverInterface->solverName(), properties);
        }
    }

    // Check whether we have at least one solver

    if (solversListProperty) {
        // We have a solvers list property, which means that we have at least
        // one solver, so sort our list

        solversNames.sort();

        // Assign the list of solvers to our list property

        solversListProperty->setListValues(solversNames);

        // Create and return our solver data

        return new SingleCellViewInformationSolversWidgetData(solversInterfaces,
                                                              solversProperty,
                                                              solversListProperty,
                                                              solversProperties);
    } else {
        return 0;
    }
}

//==============================================================================

void SingleCellViewInformationSolversWidget::setPropertiesUnit(SingleCellViewInformationSolversWidgetData *pSolverData,
                                                               const QString &pVoiUnit)
{
    // Make sure that we have some solver's data

    if (!pSolverData)
        return;

    // Go through the solvers' properties and set the unit of the relevant ones

    foreach (const Core::Properties &properties, pSolverData->solversProperties())
        foreach (Core::Property *property, properties)
            if (!property->unit().isEmpty())
                property->setUnit(pVoiUnit);
}

//==============================================================================

void SingleCellViewInformationSolversWidget::initialize(SingleCellViewSimulation *pSimulation)
{
    // Make sure that the CellML file runtime is valid

    if (pSimulation->runtime()->isValid()) {
        // Show/hide the ODE/DAE/NLA solver information

        if (mOdeSolverData)
            mOdeSolverData->solversProperty()->setVisible(pSimulation->runtime()->needOdeSolver());

        if (mDaeSolverData)
            mDaeSolverData->solversProperty()->setVisible(pSimulation->runtime()->needDaeSolver());

        if (mNlaSolverData)
            mNlaSolverData->solversProperty()->setVisible(pSimulation->runtime()->needNlaSolver());
    }

    // Set the unit of our different properties, if needed

    QString voiUnit = pSimulation->runtime()->variableOfIntegration()->unit();

    setPropertiesUnit(mOdeSolverData, voiUnit);
    setPropertiesUnit(mDaeSolverData, voiUnit);
    setPropertiesUnit(mNlaSolverData, voiUnit);

    // Initialise our simulation's NLA solver's properties, so that we can then
    // properly reset our simulation the first time round

    if (mNlaSolverData) {
        pSimulation->data()->setNlaSolverName(mNlaSolverData->solversListProperty()->value(), false);

        foreach (Core::Property *property, mNlaSolverData->solversProperties().value(pSimulation->data()->nlaSolverName())) {
            pSimulation->data()->addNlaSolverProperty(property->id(),
                                                      (property->type() == Core::Property::Integer)?
                                                          property->integerValue():
                                                          property->doubleValue(),
                                                      false);
        }
    }
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::odeSolvers() const
{
    // Return the available ODE solvers, if any

    return mOdeSolverData?mOdeSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::daeSolvers() const
{
    // Return the available DAE solvers, if any

    return mDaeSolverData?mDaeSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

QStringList SingleCellViewInformationSolversWidget::nlaSolvers() const
{
    // Return the available NLA solvers, if any

    return mNlaSolverData?mNlaSolverData->solversListProperty()->listValues():QStringList();
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::odeSolverData() const
{
    // Return our ODE solver data

    return mOdeSolverData;
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::daeSolverData() const
{
    // Return our DAE solver data

    return mDaeSolverData;
}

//==============================================================================

SingleCellViewInformationSolversWidgetData * SingleCellViewInformationSolversWidget::nlaSolverData() const
{
    // Return our NLA solver data

    return mNlaSolverData;
}

//==============================================================================

void SingleCellViewInformationSolversWidget::updateSolverGui(SingleCellViewInformationSolversWidgetData *pSolverData)
{
    // Make sure that we have some solver data

    if (!pSolverData)
        return;

    // Update our solver properties visibility

    QString solverName = pSolverData->solversListProperty()->value();
    SolverInterface *solverInterface = pSolverData->solversInterfaces().value(solverName);
    Core::Properties solverProperties = pSolverData->solversProperties().value(solverName);

    // Retrieve our solver properties values

    QMap<QString, QString> solverPropertiesValues = QMap<QString, QString>();

    foreach (Core::Property *solverProperty, solverProperties)
        solverPropertiesValues.insert(solverProperty->id(),solverProperty->value());

    // Ask our solver interface to tell us about the visibility of its
    // properties based on their values

    QMap<QString, bool> solverPropertiesVisibility = solverInterface->solverPropertiesVisibility(solverPropertiesValues);

    // Update the visilibity of our solver properties
    // Note: if there is no visibility information for a given solver property,
    //       then it means that it should be visible...

    foreach (Core::Property *solverProperty, solverProperties)
        solverProperty->setVisible(solverPropertiesVisibility.value(solverProperty->id(), true));
}

//==============================================================================

void SingleCellViewInformationSolversWidget::updateGui(SingleCellViewInformationSolversWidgetData *pSolverData)
{
    // Update our solver(s) properties visibility

    if (mOdeSolverData && (!pSolverData || (pSolverData == mOdeSolverData)))
        updateSolverGui(mOdeSolverData);

    if (mDaeSolverData && (!pSolverData || (pSolverData == mDaeSolverData)))
        updateSolverGui(mDaeSolverData);

    if (mNlaSolverData && (!pSolverData || (pSolverData == mNlaSolverData)))
        updateSolverGui(mNlaSolverData);
}

//==============================================================================

void SingleCellViewInformationSolversWidget::doSolverChanged(SingleCellViewInformationSolversWidgetData *pSolverData,
                                                             const QString &pSolverName)
{
    // Make sure that we have some solver data

    if (!pSolverData)
        return;

    // Go through the different properties for the given type of solver and
    // show/hide whatever needs showing/hiding

    for (auto solverProperties = pSolverData->solversProperties().constBegin(),
              solverPropertiesEnd = pSolverData->solversProperties().constEnd();
         solverProperties != solverPropertiesEnd; ++solverProperties) {
        bool solverPropertiesVisible = !solverProperties.key().compare(pSolverName);

        foreach (Core::Property *solverProperty, solverProperties.value())
            solverProperty->setVisible(solverPropertiesVisible);
    }
}

//==============================================================================

void SingleCellViewInformationSolversWidget::solverChanged(Core::Property *pProperty)
{
    // Try, for the ODE/DAE/NLA solvers list property, to handle the change in
    // the list property
    // Note: the ODE/DAE/NLA solvers list property is our first property, hence
    //       we make sure that its row number is equal to zero (in case there is
    //       one or several other list properties, as is the case for the CVODE
    //       and IDA solvers)...

    if (!pProperty->row()) {
        doSolverChanged((mOdeSolverData && (pProperty == mOdeSolverData->solversListProperty()))?
                            mOdeSolverData:
                            (mDaeSolverData && (pProperty == mDaeSolverData->solversListProperty()))?
                                mDaeSolverData:
                                mNlaSolverData,
                        pProperty->value());
    }
}

//==============================================================================

}   // namespace SingleCellView
}   // namespace OpenCOR

//==============================================================================
// End of file
//==============================================================================
<|endoftext|>


<commit_before>#include <iostream>

#include <type_traits>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <amgcl/relaxation/runtime.hpp>
#include <amgcl/coarsening/runtime.hpp>
#include <amgcl/solver/runtime.hpp>
#include <amgcl/make_solver.hpp>
#include <amgcl/amg.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/adapter/crs_tuple.hpp>

#include "amgcl.h"

#ifdef AMGCL_PROFILING
#include <amgcl/profiler.hpp>
namespace amgcl {
    profiler<> prof;
}
#endif

//---------------------------------------------------------------------------
typedef amgcl::backend::builtin<double>           Backend;
typedef amgcl::amg<Backend, amgcl::runtime::coarsening::wrapper, amgcl::runtime::relaxation::wrapper> AMG;
typedef amgcl::runtime::solver::wrapper<Backend>  ISolver;
typedef amgcl::make_solver<AMG, ISolver>          Solver;
typedef boost::property_tree::ptree               Params;

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_params_create() {
    return static_cast<amgclHandle>( new Params() );
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_seti(amgclHandle prm, const char *name, int value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_setf(amgclHandle prm, const char *name, float value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_sets(amgclHandle prm, const char *name, const char *value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_read_json(amgclHandle prm, const char *fname) {
    read_json(fname, *static_cast<Params*>(prm));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_destroy(amgclHandle prm) {
    delete static_cast<Params*>(prm);
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_precond_create(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr, ptr + n + 1),
            boost::make_iterator_range(col, col + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new AMG(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new AMG(A));
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_precond_create_f(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto ptr_c = boost::make_transform_iterator(ptr, [](int i){ return i - 1; });
    auto col_c = boost::make_transform_iterator(col, [](int i){ return i - 1; });

    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr_c, ptr_c + n + 1),
            boost::make_iterator_range(col_c, col_c + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new AMG(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new AMG(A));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_apply(amgclHandle handle, const double *rhs, double *x)
{
    AMG *amg = static_cast<AMG*>(handle);

    size_t n = amgcl::backend::rows(amg->system_matrix());

    boost::iterator_range<double*> x_range =
        boost::make_iterator_range(x, x + n);

    amg->apply(boost::make_iterator_range(rhs, rhs + n), x_range);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_report(amgclHandle handle) {
    std::cout << *static_cast<AMG*>(handle) << std::endl;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_destroy(amgclHandle handle) {
    delete static_cast<AMG*>(handle);
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_solver_create(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr, ptr + n + 1),
            boost::make_iterator_range(col, col + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new Solver(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new Solver(A));
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_solver_create_f(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto ptr_c = boost::make_transform_iterator(ptr, [](int i){ return i - 1; });
    auto col_c = boost::make_transform_iterator(col, [](int i){ return i - 1; });

    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr_c, ptr_c + n + 1),
            boost::make_iterator_range(col_c, col_c + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new Solver(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new Solver(A));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_report(amgclHandle handle) {
    std::cout << static_cast<Solver*>(handle)->precond() << std::endl;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_destroy(amgclHandle handle) {
    delete static_cast<Solver*>(handle);
}

//---------------------------------------------------------------------------
conv_info STDCALL amgcl_solver_solve(
        amgclHandle handle,
        const double *rhs,
        double *x
        )
{
    Solver *slv = static_cast<Solver*>(handle);

    size_t n = slv->size();

    conv_info cnv;

    boost::iterator_range<double*> x_range = boost::make_iterator_range(x, x + n);

    std::tie(cnv.iterations, cnv.residual) = (*slv)(
            boost::make_iterator_range(rhs, rhs + n), x_range
            );

    return cnv;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_solve_f(
        amgclHandle handle,
        const double *rhs,
        double *x,
        conv_info *cnv
        )
{
    *cnv = amgcl_solver_solve(handle, rhs, x);
}

//---------------------------------------------------------------------------
conv_info STDCALL amgcl_solver_solve_mtx(
        amgclHandle handle,
        int    const * A_ptr,
        int    const * A_col,
        double const * A_val,
        const double *rhs,
        double *x
        )
{
    Solver *slv = static_cast<Solver*>(handle);

    size_t n = slv->size();

    conv_info cnv;

    boost::iterator_range<double*> x_range = boost::make_iterator_range(x, x + n);

    std::tie(cnv.iterations, cnv.residual) = (*slv)(
            std::make_tuple(
                n,
                boost::make_iterator_range(A_ptr, A_ptr + n),
                boost::make_iterator_range(A_col, A_col + A_ptr[n]),
                boost::make_iterator_range(A_val, A_val + A_ptr[n])
                ),
            boost::make_iterator_range(rhs, rhs + n), x_range
            );

    return cnv;
}
<commit_msg>Fix off-by-one error in lib/amgcl.cpp<commit_after>#include <iostream>

#include <type_traits>
#include <boost/iterator/transform_iterator.hpp>
#include <boost/range/iterator_range.hpp>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>

#include <amgcl/relaxation/runtime.hpp>
#include <amgcl/coarsening/runtime.hpp>
#include <amgcl/solver/runtime.hpp>
#include <amgcl/make_solver.hpp>
#include <amgcl/amg.hpp>
#include <amgcl/backend/builtin.hpp>
#include <amgcl/adapter/crs_tuple.hpp>

#include "amgcl.h"

#ifdef AMGCL_PROFILING
#include <amgcl/profiler.hpp>
namespace amgcl {
    profiler<> prof;
}
#endif

//---------------------------------------------------------------------------
typedef amgcl::backend::builtin<double>           Backend;
typedef amgcl::amg<Backend, amgcl::runtime::coarsening::wrapper, amgcl::runtime::relaxation::wrapper> AMG;
typedef amgcl::runtime::solver::wrapper<Backend>  ISolver;
typedef amgcl::make_solver<AMG, ISolver>          Solver;
typedef boost::property_tree::ptree               Params;

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_params_create() {
    return static_cast<amgclHandle>( new Params() );
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_seti(amgclHandle prm, const char *name, int value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_setf(amgclHandle prm, const char *name, float value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_sets(amgclHandle prm, const char *name, const char *value) {
    static_cast<Params*>(prm)->put(name, value);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_read_json(amgclHandle prm, const char *fname) {
    read_json(fname, *static_cast<Params*>(prm));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_params_destroy(amgclHandle prm) {
    delete static_cast<Params*>(prm);
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_precond_create(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr, ptr + n + 1),
            boost::make_iterator_range(col, col + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new AMG(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new AMG(A));
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_precond_create_f(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto ptr_c = boost::make_transform_iterator(ptr, [](int i){ return i - 1; });
    auto col_c = boost::make_transform_iterator(col, [](int i){ return i - 1; });

    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr_c, ptr_c + n + 1),
            boost::make_iterator_range(col_c, col_c + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new AMG(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new AMG(A));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_apply(amgclHandle handle, const double *rhs, double *x)
{
    AMG *amg = static_cast<AMG*>(handle);

    size_t n = amgcl::backend::rows(amg->system_matrix());

    boost::iterator_range<double*> x_range =
        boost::make_iterator_range(x, x + n);

    amg->apply(boost::make_iterator_range(rhs, rhs + n), x_range);
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_report(amgclHandle handle) {
    std::cout << *static_cast<AMG*>(handle) << std::endl;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_precond_destroy(amgclHandle handle) {
    delete static_cast<AMG*>(handle);
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_solver_create(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr, ptr + n + 1),
            boost::make_iterator_range(col, col + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new Solver(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new Solver(A));
}

//---------------------------------------------------------------------------
amgclHandle STDCALL amgcl_solver_create_f(
        int           n,
        const int    *ptr,
        const int    *col,
        const double *val,
        amgclHandle   prm
        )
{
    auto ptr_c = boost::make_transform_iterator(ptr, [](int i){ return i - 1; });
    auto col_c = boost::make_transform_iterator(col, [](int i){ return i - 1; });

    auto A = std::make_tuple(n,
            boost::make_iterator_range(ptr_c, ptr_c + n + 1),
            boost::make_iterator_range(col_c, col_c + ptr[n]),
            boost::make_iterator_range(val, val + ptr[n])
            );

    if (prm)
        return static_cast<amgclHandle>(new Solver(A, *static_cast<Params*>(prm)));
    else
        return static_cast<amgclHandle>(new Solver(A));
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_report(amgclHandle handle) {
    std::cout << static_cast<Solver*>(handle)->precond() << std::endl;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_destroy(amgclHandle handle) {
    delete static_cast<Solver*>(handle);
}

//---------------------------------------------------------------------------
conv_info STDCALL amgcl_solver_solve(
        amgclHandle handle,
        const double *rhs,
        double *x
        )
{
    Solver *slv = static_cast<Solver*>(handle);

    size_t n = slv->size();

    conv_info cnv;

    boost::iterator_range<double*> x_range = boost::make_iterator_range(x, x + n);

    std::tie(cnv.iterations, cnv.residual) = (*slv)(
            boost::make_iterator_range(rhs, rhs + n), x_range
            );

    return cnv;
}

//---------------------------------------------------------------------------
void STDCALL amgcl_solver_solve_f(
        amgclHandle handle,
        const double *rhs,
        double *x,
        conv_info *cnv
        )
{
    *cnv = amgcl_solver_solve(handle, rhs, x);
}

//---------------------------------------------------------------------------
conv_info STDCALL amgcl_solver_solve_mtx(
        amgclHandle handle,
        int    const * A_ptr,
        int    const * A_col,
        double const * A_val,
        const double *rhs,
        double *x
        )
{
    Solver *slv = static_cast<Solver*>(handle);

    size_t n = slv->size();

    conv_info cnv;

    boost::iterator_range<double*> x_range = boost::make_iterator_range(x, x + n);

    std::tie(cnv.iterations, cnv.residual) = (*slv)(
            std::make_tuple(
                n,
                boost::make_iterator_range(A_ptr, A_ptr + n + 1),
                boost::make_iterator_range(A_col, A_col + A_ptr[n]),
                boost::make_iterator_range(A_val, A_val + A_ptr[n])
                ),
            boost::make_iterator_range(rhs, rhs + n), x_range
            );

    return cnv;
}
<|endoftext|>


<commit_before><commit_msg>acmacs::chart::SelectedAntigens and SelectedSera<commit_after><|endoftext|>


<commit_before><commit_msg>Create 1216 - Getline One.cpp<commit_after><|endoftext|>