//===-- TypeFormat.cpp ----------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/DataFormatters/TypeFormat.h"




#include "lldb/lldb-enumerations.h"
#include "lldb/lldb-public.h"

#include "lldb/Core/DumpDataExtractor.h"
#include "lldb/DataFormatters/FormatManager.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/TypeList.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/DataExtractor.h"
#include "lldb/Utility/StreamString.h"

using namespace lldb;
using namespace lldb_private;

TypeFormatImpl::TypeFormatImpl(const Flags &flags)
    : m_flags(flags), m_my_revision(0) {}

TypeFormatImpl::~TypeFormatImpl() {}

TypeFormatImpl_Format::TypeFormatImpl_Format(lldb::Format f,
                                             const TypeFormatImpl::Flags &flags)
    : TypeFormatImpl(flags), m_format(f) {}

TypeFormatImpl_Format::~TypeFormatImpl_Format() {}

bool TypeFormatImpl_Format::FormatObject(ValueObject *valobj,
                                         std::string &dest) const {
  if (!valobj)
    return false;
  if (valobj->CanProvideValue()) {
    Value &value(valobj->GetValue());
    const Value::ContextType context_type = value.GetContextType();
    ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
    DataExtractor data;

    if (context_type == Value::eContextTypeRegisterInfo) {
      const RegisterInfo *reg_info = value.GetRegisterInfo();
      if (reg_info) {
        Status error;
        valobj->GetData(data, error);
        if (error.Fail())
          return false;

        StreamString reg_sstr;
        DumpDataExtractor(data, &reg_sstr, 0, GetFormat(), reg_info->byte_size,
                          1, UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0,
                          exe_ctx.GetBestExecutionContextScope());
        dest = reg_sstr.GetString();
      }
    } else {
      CompilerType compiler_type = value.GetCompilerType();
      if (compiler_type) {
        // put custom bytes to display in the DataExtractor to override the
        // default value logic
        if (GetFormat() == eFormatCString) {
          lldb_private::Flags type_flags(compiler_type.GetTypeInfo(
              nullptr)); // disambiguate w.r.t. TypeFormatImpl::Flags
          if (type_flags.Test(eTypeIsPointer) &&
              !type_flags.Test(eTypeIsObjC)) {
            // if we are dumping a pointer as a c-string, get the pointee data
            // as a string
            TargetSP target_sp(valobj->GetTargetSP());
            if (target_sp) {
              size_t max_len = target_sp->GetMaximumSizeOfStringSummary();
              Status error;
              DataBufferSP buffer_sp(new DataBufferHeap(max_len + 1, 0));
              Address address(valobj->GetPointerValue());
              if (target_sp->ReadCStringFromMemory(
                      address, (char *)buffer_sp->GetBytes(), max_len, error) &&
                  error.Success())
                data.SetData(buffer_sp);
            }
          }
        } else {
          Status error;
          valobj->GetData(data, error);
          if (error.Fail())
            return false;
        }

        ExecutionContextScope *exe_scope =
            exe_ctx.GetBestExecutionContextScope();
        llvm::Optional<uint64_t> size = compiler_type.GetByteSize(exe_scope);
        if (!size)
          return false;
        StreamString sstr;
        compiler_type.DumpTypeValue(
            &sstr,                          // The stream to use for display
            GetFormat(),                    // Format to display this type with
            data,                           // Data to extract from
            0,                              // Byte offset into "m_data"
            *size,                          // Byte size of item in "m_data"
            valobj->GetBitfieldBitSize(),   // Bitfield bit size
            valobj->GetBitfieldBitOffset(), // Bitfield bit offset
            exe_scope);
        // Given that we do not want to set the ValueObject's m_error for a
        // formatting error (or else we wouldn't be able to reformat until a
        // next update), an empty string is treated as a "false" return from
        // here, but that's about as severe as we get
        // CompilerType::DumpTypeValue() should always return something, even
        // if that something is an error message
        dest = sstr.GetString();
      }
    }
    return !dest.empty();
  } else
    return false;
}

std::string TypeFormatImpl_Format::GetDescription() {
  StreamString sstr;
  sstr.Printf("%s%s%s%s", FormatManager::GetFormatAsCString(GetFormat()),
              Cascades() ? "" : " (not cascading)",
              SkipsPointers() ? " (skip pointers)" : "",
              SkipsReferences() ? " (skip references)" : "");
  return sstr.GetString();
}

TypeFormatImpl_EnumType::TypeFormatImpl_EnumType(
    ConstString type_name, const TypeFormatImpl::Flags &flags)
    : TypeFormatImpl(flags), m_enum_type(type_name), m_types() {}

TypeFormatImpl_EnumType::~TypeFormatImpl_EnumType() {}

bool TypeFormatImpl_EnumType::FormatObject(ValueObject *valobj,
                                           std::string &dest) const {
  dest.clear();
  if (!valobj)
    return false;
  if (!valobj->CanProvideValue())
    return false;
  ProcessSP process_sp;
  TargetSP target_sp;
  void *valobj_key = (process_sp = valobj->GetProcessSP()).get();
  if (!valobj_key)
    valobj_key = (target_sp = valobj->GetTargetSP()).get();
  else
    target_sp = process_sp->GetTarget().shared_from_this();
  if (!valobj_key)
    return false;
  auto iter = m_types.find(valobj_key), end = m_types.end();
  CompilerType valobj_enum_type;
  if (iter == end) {
    // probably a redundant check
    if (!target_sp)
      return false;
    const ModuleList &images(target_sp->GetImages());
    TypeList types;
    llvm::DenseSet<lldb_private::SymbolFile *> searched_symbol_files;
    images.FindTypes(nullptr, m_enum_type, false, UINT32_MAX,
                     searched_symbol_files, types);
    if (types.Empty())
      return false;
    for (lldb::TypeSP type_sp : types.Types()) {
      if (!type_sp)
        continue;
      if ((type_sp->GetForwardCompilerType().GetTypeInfo() &
           eTypeIsEnumeration) == eTypeIsEnumeration) {
        valobj_enum_type = type_sp->GetFullCompilerType();
        m_types.emplace(valobj_key, valobj_enum_type);
        break;
      }
    }
  } else
    valobj_enum_type = iter->second;
  if (!valobj_enum_type.IsValid())
    return false;
  DataExtractor data;
  Status error;
  valobj->GetData(data, error);
  if (error.Fail())
    return false;
  ExecutionContext exe_ctx(valobj->GetExecutionContextRef());
  StreamString sstr;
  valobj_enum_type.DumpTypeValue(&sstr, lldb::eFormatEnum, data, 0,
                                 data.GetByteSize(), 0, 0,
                                 exe_ctx.GetBestExecutionContextScope());
  if (!sstr.GetString().empty())
    dest = sstr.GetString();
  return !dest.empty();
}

std::string TypeFormatImpl_EnumType::GetDescription() {
  StreamString sstr;
  sstr.Printf("as type %s%s%s%s", m_enum_type.AsCString("<invalid type>"),
              Cascades() ? "" : " (not cascading)",
              SkipsPointers() ? " (skip pointers)" : "",
              SkipsReferences() ? " (skip references)" : "");
  return sstr.GetString();
}
