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

#include <mutex>
#include <utility>
#include <vector>

#include "lldb/Core/Module.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/DataFormatters/StringPrinter.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolFile.h"
#include "lldb/Symbol/GoASTContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Target.h"

#include "Plugins/ExpressionParser/Go/GoUserExpression.h"
#include "Plugins/SymbolFile/DWARF/DWARFASTParserGo.h"

using namespace lldb;

namespace lldb_private
{
class GoArray;
class GoFunction;
class GoStruct;

class GoType
{
  public:
    enum
    {
        KIND_BOOL = 1,
        KIND_INT = 2,
        KIND_INT8 = 3,
        KIND_INT16 = 4,
        KIND_INT32 = 5,
        KIND_INT64 = 6,
        KIND_UINT = 7,
        KIND_UINT8 = 8,
        KIND_UINT16 = 9,
        KIND_UINT32 = 10,
        KIND_UINT64 = 11,
        KIND_UINTPTR = 12,
        KIND_FLOAT32 = 13,
        KIND_FLOAT64 = 14,
        KIND_COMPLEX64 = 15,
        KIND_COMPLEX128 = 16,
        KIND_ARRAY = 17,
        KIND_CHAN = 18,
        KIND_FUNC = 19,
        KIND_INTERFACE = 20,
        KIND_MAP = 21,
        KIND_PTR = 22,
        KIND_SLICE = 23,
        KIND_STRING = 24,
        KIND_STRUCT = 25,
        KIND_UNSAFEPOINTER = 26,
        KIND_LLDB_VOID, // Extension for LLDB, not used by go runtime.
        KIND_MASK = (1 << 5) - 1,
        KIND_DIRECT_IFACE = 1 << 5
    };
    GoType(int kind, const ConstString &name)
        : m_kind(kind & KIND_MASK)
        , m_name(name)
    {
        if (m_kind == KIND_FUNC)
            m_kind = KIND_FUNC;
    }
    virtual ~GoType() {}

    int
    GetGoKind() const
    {
        return m_kind;
    }
    const ConstString &
    GetName() const
    {
        return m_name;
    }
    virtual CompilerType
    GetElementType() const
    {
        return CompilerType();
    }

    bool
    IsTypedef() const
    {
        switch (m_kind)
        {
            case KIND_CHAN:
            case KIND_MAP:
            case KIND_INTERFACE:
                return true;
            default:
                return false;
        }
    }

    GoArray *GetArray();
    GoFunction *GetFunction();
    GoStruct *GetStruct();

  private:
    int m_kind;
    ConstString m_name;
    GoType(const GoType &) = delete;
    const GoType &operator=(const GoType &) = delete;
};

class GoElem : public GoType
{
  public:
    GoElem(int kind, const ConstString &name, const CompilerType &elem)
        : GoType(kind, name)
        , m_elem(elem)
    {
    }
    virtual CompilerType
    GetElementType() const
    {
        return m_elem;
    }

  private:
    // TODO: should we store this differently?
    CompilerType m_elem;

    GoElem(const GoElem &) = delete;
    const GoElem &operator=(const GoElem &) = delete;
};

class GoArray : public GoElem
{
  public:
    GoArray(const ConstString &name, uint64_t length, const CompilerType &elem)
        : GoElem(KIND_ARRAY, name, elem)
        , m_length(length)
    {
    }

    uint64_t
    GetLength() const
    {
        return m_length;
    }

  private:
    uint64_t m_length;
    GoArray(const GoArray &) = delete;
    const GoArray &operator=(const GoArray &) = delete;
};

class GoFunction : public GoType
{
  public:
    GoFunction(const ConstString &name, bool is_variadic)
        : GoType(KIND_FUNC, name)
        , m_is_variadic(is_variadic)
    {
    }

    bool
    IsVariadic() const
    {
        return m_is_variadic;
    }

  private:
    bool m_is_variadic;
    GoFunction(const GoFunction &) = delete;
    const GoFunction &operator=(const GoFunction &) = delete;
};

class GoStruct : public GoType
{
  public:
    struct Field
    {
        Field(const ConstString &name, const CompilerType &type, uint64_t offset)
            : m_name(name)
            , m_type(type)
            , m_byte_offset(offset)
        {
        }
        ConstString m_name;
        CompilerType m_type;
        uint64_t m_byte_offset;
    };

    GoStruct(int kind, const ConstString &name, int64_t byte_size)
        : GoType(kind == 0 ? KIND_STRUCT : kind, name), m_is_complete(false), m_byte_size(byte_size)
    {
    }

    uint32_t
    GetNumFields() const
    {
        return m_fields.size();
    }

    const Field *
    GetField(uint32_t i) const
    {
        if (i < m_fields.size())
            return &m_fields[i];
        return nullptr;
    }

    void
    AddField(const ConstString &name, const CompilerType &type, uint64_t offset)
    {
        m_fields.push_back(Field(name, type, offset));
    }

    bool
    IsComplete() const
    {
        return m_is_complete;
    }

    void
    SetComplete()
    {
        m_is_complete = true;
    }

    int64_t
    GetByteSize() const
    {
        return m_byte_size;
    }

  private:
    bool m_is_complete;
    int64_t m_byte_size;
    std::vector<Field> m_fields;

    GoStruct(const GoStruct &) = delete;
    const GoStruct &operator=(const GoStruct &) = delete;
};

GoArray *
GoType::GetArray()
{
    if (m_kind == KIND_ARRAY)
    {
        return static_cast<GoArray *>(this);
    }
    return nullptr;
}

GoFunction *
GoType::GetFunction()
{
    if (m_kind == KIND_FUNC)
    {
        return static_cast<GoFunction *>(this);
    }
    return nullptr;
}

GoStruct *
GoType::GetStruct()
{
    switch (m_kind)
    {
        case KIND_STRING:
        case KIND_STRUCT:
        case KIND_SLICE:
            return static_cast<GoStruct *>(this);
    }
    return nullptr;
}
} // namespace lldb_private
using namespace lldb_private;

GoASTContext::GoASTContext()
    : TypeSystem(eKindGo)
    , m_pointer_byte_size(0)
    , m_int_byte_size(0)
    , m_types(new TypeMap)
{
}
GoASTContext::~GoASTContext()
{
}

//------------------------------------------------------------------
// PluginInterface functions
//------------------------------------------------------------------

ConstString
GoASTContext::GetPluginNameStatic()
{
    return ConstString("go");
}

ConstString
GoASTContext::GetPluginName()
{
    return GoASTContext::GetPluginNameStatic();
}

uint32_t
GoASTContext::GetPluginVersion()
{
    return 1;
}

lldb::TypeSystemSP
GoASTContext::CreateInstance (lldb::LanguageType language, Module *module, Target *target)
{
    if (language == eLanguageTypeGo)
    {
        ArchSpec arch;
        std::shared_ptr<GoASTContext> go_ast_sp;
        if (module)
        {
            arch = module->GetArchitecture();
            go_ast_sp = std::shared_ptr<GoASTContext>(new GoASTContext);
        }
        else if (target)
        {
            arch = target->GetArchitecture();
            go_ast_sp = std::shared_ptr<GoASTContextForExpr>(new GoASTContextForExpr(target->shared_from_this()));
        }

        if (arch.IsValid())
        {
            go_ast_sp->SetAddressByteSize(arch.GetAddressByteSize());
            return go_ast_sp;
        }
    }
    return lldb::TypeSystemSP();
}

void
GoASTContext::EnumerateSupportedLanguages(std::set<lldb::LanguageType> &languages_for_types, std::set<lldb::LanguageType> &languages_for_expressions)
{
    static std::vector<lldb::LanguageType> s_supported_languages_for_types({
        lldb::eLanguageTypeGo});
    
    static std::vector<lldb::LanguageType> s_supported_languages_for_expressions({});
    
    languages_for_types.insert(s_supported_languages_for_types.begin(), s_supported_languages_for_types.end());
    languages_for_expressions.insert(s_supported_languages_for_expressions.begin(), s_supported_languages_for_expressions.end());
}


void
GoASTContext::Initialize()
{
    PluginManager::RegisterPlugin (GetPluginNameStatic(),
                                   "AST context plug-in",
                                   CreateInstance,
                                   EnumerateSupportedLanguages);
}

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


//----------------------------------------------------------------------
// Tests
//----------------------------------------------------------------------

bool
GoASTContext::IsArrayType(lldb::opaque_compiler_type_t type, CompilerType *element_type, uint64_t *size, bool *is_incomplete)
{
    if (element_type)
        element_type->Clear();
    if (size)
        *size = 0;
    if (is_incomplete)
        *is_incomplete = false;
    GoArray *array = static_cast<GoType *>(type)->GetArray();
    if (array)
    {
        if (size)
            *size = array->GetLength();
        if (element_type)
            *element_type = array->GetElementType();
        return true;
    }
    return false;
}

bool
GoASTContext::IsVectorType(lldb::opaque_compiler_type_t type, CompilerType *element_type, uint64_t *size)
{
    if (element_type)
        element_type->Clear();
    if (size)
        *size = 0;
    return false;
}

bool
GoASTContext::IsAggregateType(lldb::opaque_compiler_type_t type)
{
    int kind = static_cast<GoType *>(type)->GetGoKind();
    if (kind < GoType::KIND_ARRAY)
        return false;
    if (kind == GoType::KIND_PTR)
        return false;
    if (kind == GoType::KIND_CHAN)
        return false;
    if (kind == GoType::KIND_MAP)
        return false;
    if (kind == GoType::KIND_STRING)
        return false;
    if (kind == GoType::KIND_UNSAFEPOINTER)
        return false;
    return true;
}

bool
GoASTContext::IsBeingDefined(lldb::opaque_compiler_type_t type)
{
    return false;
}

bool
GoASTContext::IsCharType(lldb::opaque_compiler_type_t type)
{
    // Go's DWARF doesn't distinguish between rune and int32.
    return false;
}

bool
GoASTContext::IsCompleteType(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return false;
    GoType *t = static_cast<GoType *>(type);
    if (GoStruct *s = t->GetStruct())
        return s->IsComplete();
    if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR)
        return t->GetElementType().IsCompleteType();
    return true;
}

bool
GoASTContext::IsConst(lldb::opaque_compiler_type_t type)
{
    return false;
}

bool
GoASTContext::IsCStringType(lldb::opaque_compiler_type_t type, uint32_t &length)
{
    return false;
}

bool
GoASTContext::IsDefined(lldb::opaque_compiler_type_t type)
{
    return type != nullptr;
}

bool
GoASTContext::IsFloatingPointType(lldb::opaque_compiler_type_t type, uint32_t &count, bool &is_complex)
{
    int kind = static_cast<GoType *>(type)->GetGoKind();
    if (kind >= GoType::KIND_FLOAT32 && kind <= GoType::KIND_COMPLEX128)
    {
        if (kind >= GoType::KIND_COMPLEX64)
        {
            is_complex = true;
            count = 2;
        }
        else
        {
            is_complex = false;
            count = 1;
        }
        return true;
    }
    count = 0;
    is_complex = false;
    return false;
}

bool
GoASTContext::IsFunctionType(lldb::opaque_compiler_type_t type, bool *is_variadic_ptr)
{
    GoFunction *func = static_cast<GoType *>(type)->GetFunction();
    if (func)
    {
        if (is_variadic_ptr)
            *is_variadic_ptr = func->IsVariadic();
        return true;
    }
    if (is_variadic_ptr)
        *is_variadic_ptr = false;
    return false;
}

uint32_t
GoASTContext::IsHomogeneousAggregate(lldb::opaque_compiler_type_t type, CompilerType *base_type_ptr)
{
    return false;
}

size_t
GoASTContext::GetNumberOfFunctionArguments(lldb::opaque_compiler_type_t type)
{
    return 0;
}

CompilerType
GoASTContext::GetFunctionArgumentAtIndex(lldb::opaque_compiler_type_t type, const size_t index)
{
    return CompilerType();
}

bool
GoASTContext::IsFunctionPointerType(lldb::opaque_compiler_type_t type)
{
    return IsFunctionType(type);
}

bool
GoASTContext::IsBlockPointerType (lldb::opaque_compiler_type_t type, CompilerType *function_pointer_type_ptr)
{
    return false;
}

bool
GoASTContext::IsIntegerType(lldb::opaque_compiler_type_t type, bool &is_signed)
{
    is_signed = false;
    // TODO: Is bool an integer?
    if (type)
    {
        int kind = static_cast<GoType *>(type)->GetGoKind();
        if (kind <= GoType::KIND_UINTPTR)
        {
            is_signed = (kind != GoType::KIND_BOOL) & (kind <= GoType::KIND_INT64);
            return true;
        }
    }
    return false;
}

bool
GoASTContext::IsPolymorphicClass(lldb::opaque_compiler_type_t type)
{
    return false;
}

bool
GoASTContext::IsPossibleDynamicType(lldb::opaque_compiler_type_t type,
                                    CompilerType *target_type, // Can pass NULL
                                    bool check_cplusplus, bool check_objc)
{
    if (target_type)
        target_type->Clear();
    if (type)
        return static_cast<GoType *>(type)->GetGoKind() == GoType::KIND_INTERFACE;
    return false;
}

bool
GoASTContext::IsRuntimeGeneratedType(lldb::opaque_compiler_type_t type)
{
    return false;
}

bool
GoASTContext::IsPointerType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type)
{
    if (!type)
        return false;
    GoType *t = static_cast<GoType *>(type);
    if (pointee_type)
    {
        *pointee_type = t->GetElementType();
    }
    switch (t->GetGoKind())
    {
        case GoType::KIND_PTR:
        case GoType::KIND_UNSAFEPOINTER:
        case GoType::KIND_CHAN:
        case GoType::KIND_MAP:
            // TODO: is function a pointer?
            return true;
        default:
            return false;
    }
}

bool
GoASTContext::IsPointerOrReferenceType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type)
{
    return IsPointerType(type, pointee_type);
}

bool
GoASTContext::IsReferenceType(lldb::opaque_compiler_type_t type, CompilerType *pointee_type, bool *is_rvalue)
{
    return false;
}

bool
GoASTContext::IsScalarType(lldb::opaque_compiler_type_t type)
{
    return !IsAggregateType(type);
}

bool
GoASTContext::IsTypedefType(lldb::opaque_compiler_type_t type)
{
    if (type)
        return static_cast<GoType *>(type)->IsTypedef();
    return false;
}

bool
GoASTContext::IsVoidType(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return false;
    return static_cast<GoType *>(type)->GetGoKind() == GoType::KIND_LLDB_VOID;
}

bool
GoASTContext::SupportsLanguage (lldb::LanguageType language)
{
    return language == eLanguageTypeGo;
}

//----------------------------------------------------------------------
// Type Completion
//----------------------------------------------------------------------

bool
GoASTContext::GetCompleteType(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return false;
    GoType *t = static_cast<GoType *>(type);
    if (t->IsTypedef() || t->GetGoKind() == GoType::KIND_PTR || t->GetArray())
        return t->GetElementType().GetCompleteType();
    if (GoStruct *s = t->GetStruct())
    {
        if (s->IsComplete())
            return true;
        CompilerType compiler_type(this, s);
        SymbolFile *symbols = GetSymbolFile();
        return symbols && symbols->CompleteType(compiler_type);
    }
    return true;
}

//----------------------------------------------------------------------
// AST related queries
//----------------------------------------------------------------------

uint32_t
GoASTContext::GetPointerByteSize()
{
    return m_pointer_byte_size;
}

//----------------------------------------------------------------------
// Accessors
//----------------------------------------------------------------------

ConstString
GoASTContext::GetTypeName(lldb::opaque_compiler_type_t type)
{
    if (type)
        return static_cast<GoType *>(type)->GetName();
    return ConstString();
}

uint32_t
GoASTContext::GetTypeInfo(lldb::opaque_compiler_type_t type, CompilerType *pointee_or_element_compiler_type)
{
    if (pointee_or_element_compiler_type)
        pointee_or_element_compiler_type->Clear();
    if (!type)
        return 0;
    GoType *t = static_cast<GoType *>(type);
    if (pointee_or_element_compiler_type)
        *pointee_or_element_compiler_type = t->GetElementType();
    int kind = t->GetGoKind();
    if (kind == GoType::KIND_ARRAY)
        return eTypeHasChildren | eTypeIsArray;
    if (kind < GoType::KIND_ARRAY)
    {
        uint32_t builtin_type_flags = eTypeIsBuiltIn | eTypeHasValue;
        if (kind < GoType::KIND_FLOAT32)
        {
            builtin_type_flags |= eTypeIsInteger | eTypeIsScalar;
            if (kind >= GoType::KIND_INT && kind <= GoType::KIND_INT64)
                builtin_type_flags |= eTypeIsSigned;
        }
        else
        {
            builtin_type_flags |= eTypeIsFloat;
            if (kind < GoType::KIND_COMPLEX64)
                builtin_type_flags |= eTypeIsComplex;
            else
                builtin_type_flags |= eTypeIsScalar;
        }
        return builtin_type_flags;
    }
    if (kind == GoType::KIND_STRING)
        return eTypeHasValue | eTypeIsBuiltIn;
    if (kind == GoType::KIND_FUNC)
        return eTypeIsFuncPrototype | eTypeHasValue;
    if (IsPointerType(type))
        return eTypeIsPointer | eTypeHasValue | eTypeHasChildren;
    if (kind == GoType::KIND_LLDB_VOID)
        return 0;
    return eTypeHasChildren | eTypeIsStructUnion;
}

lldb::TypeClass
GoASTContext::GetTypeClass(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return eTypeClassInvalid;
    int kind = static_cast<GoType *>(type)->GetGoKind();
    if (kind == GoType::KIND_FUNC)
        return eTypeClassFunction;
    if (IsPointerType(type))
        return eTypeClassPointer;
    if (kind < GoType::KIND_COMPLEX64)
        return eTypeClassBuiltin;
    if (kind <= GoType::KIND_COMPLEX128)
        return eTypeClassComplexFloat;
    if (kind == GoType::KIND_LLDB_VOID)
        return eTypeClassInvalid;
    return eTypeClassStruct;
}

lldb::BasicType
GoASTContext::GetBasicTypeEnumeration(lldb::opaque_compiler_type_t type)
{
    ConstString name = GetTypeName(type);
    if (name)
    {
        typedef UniqueCStringMap<lldb::BasicType> TypeNameToBasicTypeMap;
        static TypeNameToBasicTypeMap g_type_map;
        static std::once_flag g_once_flag;
        std::call_once(g_once_flag, [](){
            // "void"
            g_type_map.Append(ConstString("void").GetCString(), eBasicTypeVoid);
            // "int"
            g_type_map.Append(ConstString("int").GetCString(), eBasicTypeInt);
            g_type_map.Append(ConstString("uint").GetCString(), eBasicTypeUnsignedInt);
            
            // Miscellaneous
            g_type_map.Append(ConstString("bool").GetCString(), eBasicTypeBool);

            // Others. Should these map to C types?
            g_type_map.Append(ConstString("byte").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("uint8").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("uint16").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("uint32").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("uint64").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("int8").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("int16").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("int32").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("int64").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("float32").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("float64").GetCString(), eBasicTypeOther);
            g_type_map.Append(ConstString("uintptr").GetCString(), eBasicTypeOther);

            g_type_map.Sort();
        });
        
        return g_type_map.Find(name.GetCString(), eBasicTypeInvalid);
    }
    return eBasicTypeInvalid;
}

lldb::LanguageType
GoASTContext::GetMinimumLanguage(lldb::opaque_compiler_type_t type)
{
    return lldb::eLanguageTypeGo;
}

unsigned
GoASTContext::GetTypeQualifiers(lldb::opaque_compiler_type_t type)
{
    return 0;
}

//----------------------------------------------------------------------
// Creating related types
//----------------------------------------------------------------------

CompilerType
GoASTContext::GetArrayElementType(lldb::opaque_compiler_type_t type, uint64_t *stride)
{
    GoArray *array = static_cast<GoType *>(type)->GetArray();
    if (array)
    {
        if (stride)
        {
            *stride = array->GetElementType().GetByteSize(nullptr);
        }
        return array->GetElementType();
    }
    return CompilerType();
}

CompilerType
GoASTContext::GetCanonicalType(lldb::opaque_compiler_type_t type)
{
    GoType *t = static_cast<GoType *>(type);
    if (t->IsTypedef())
        return t->GetElementType();
    return CompilerType(this, type);
}

CompilerType
GoASTContext::GetFullyUnqualifiedType(lldb::opaque_compiler_type_t type)
{
    return CompilerType(this, type);
}

// Returns -1 if this isn't a function of if the function doesn't have a prototype
// Returns a value >= 0 if there is a prototype.
int
GoASTContext::GetFunctionArgumentCount(lldb::opaque_compiler_type_t type)
{
    return GetNumberOfFunctionArguments(type);
}

CompilerType
GoASTContext::GetFunctionArgumentTypeAtIndex(lldb::opaque_compiler_type_t type, size_t idx)
{
    return GetFunctionArgumentAtIndex(type, idx);
}

CompilerType
GoASTContext::GetFunctionReturnType(lldb::opaque_compiler_type_t type)
{
    CompilerType result;
    if (type)
    {
        GoType *t = static_cast<GoType *>(type);
        if (t->GetGoKind() == GoType::KIND_FUNC)
            result = t->GetElementType();
    }
    return result;
}

size_t
GoASTContext::GetNumMemberFunctions(lldb::opaque_compiler_type_t type)
{
    return 0;
}

TypeMemberFunctionImpl
GoASTContext::GetMemberFunctionAtIndex(lldb::opaque_compiler_type_t type, size_t idx)
{
    return TypeMemberFunctionImpl();
}

CompilerType
GoASTContext::GetNonReferenceType(lldb::opaque_compiler_type_t type)
{
    return CompilerType(this, type);
}

CompilerType
GoASTContext::GetPointeeType(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return CompilerType();
    return static_cast<GoType *>(type)->GetElementType();
}

CompilerType
GoASTContext::GetPointerType(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return CompilerType();
    ConstString type_name = GetTypeName(type);
    ConstString pointer_name(std::string("*") + type_name.GetCString());
    GoType *pointer = (*m_types)[pointer_name].get();
    if (pointer == nullptr)
    {
        pointer = new GoElem(GoType::KIND_PTR, pointer_name, CompilerType(this, type));
        (*m_types)[pointer_name].reset(pointer);
    }
    return CompilerType(this, pointer);
}

// If the current object represents a typedef type, get the underlying type
CompilerType
GoASTContext::GetTypedefedType(lldb::opaque_compiler_type_t type)
{
    if (IsTypedefType(type))
        return static_cast<GoType *>(type)->GetElementType();
    return CompilerType();
}

//----------------------------------------------------------------------
// Create related types using the current type's AST
//----------------------------------------------------------------------
CompilerType
GoASTContext::GetBasicTypeFromAST(lldb::BasicType basic_type)
{
    return CompilerType();
}

CompilerType
GoASTContext::GetBuiltinTypeForEncodingAndBitSize (lldb::Encoding encoding,
                                                   size_t bit_size)
{
    return CompilerType();
}


//----------------------------------------------------------------------
// Exploring the type
//----------------------------------------------------------------------

uint64_t
GoASTContext::GetBitSize(lldb::opaque_compiler_type_t type, ExecutionContextScope *exe_scope)
{
    if (!type)
        return 0;
    if (!GetCompleteType(type))
        return 0;
    GoType *t = static_cast<GoType *>(type);
    GoArray *array = nullptr;
    switch (t->GetGoKind())
    {
        case GoType::KIND_BOOL:
        case GoType::KIND_INT8:
        case GoType::KIND_UINT8:
            return 8;
        case GoType::KIND_INT16:
        case GoType::KIND_UINT16:
            return 16;
        case GoType::KIND_INT32:
        case GoType::KIND_UINT32:
        case GoType::KIND_FLOAT32:
            return 32;
        case GoType::KIND_INT64:
        case GoType::KIND_UINT64:
        case GoType::KIND_FLOAT64:
        case GoType::KIND_COMPLEX64:
            return 64;
        case GoType::KIND_COMPLEX128:
            return 128;
        case GoType::KIND_INT:
        case GoType::KIND_UINT:
            return m_int_byte_size * 8;
        case GoType::KIND_UINTPTR:
        case GoType::KIND_FUNC: // I assume this is a pointer?
        case GoType::KIND_CHAN:
        case GoType::KIND_PTR:
        case GoType::KIND_UNSAFEPOINTER:
        case GoType::KIND_MAP:
            return m_pointer_byte_size * 8;
        case GoType::KIND_ARRAY:
            array = t->GetArray();
            return array->GetLength() * array->GetElementType().GetBitSize(exe_scope);
        case GoType::KIND_INTERFACE:
            return t->GetElementType().GetBitSize(exe_scope);
        case GoType::KIND_SLICE:
        case GoType::KIND_STRING:
        case GoType::KIND_STRUCT:
            return t->GetStruct()->GetByteSize() * 8;
        default:
            assert(false);
    }
    return 0;
}

lldb::Encoding
GoASTContext::GetEncoding(lldb::opaque_compiler_type_t type, uint64_t &count)
{
    count = 1;
    bool is_signed;
    if (IsIntegerType(type, is_signed))
        return is_signed ? lldb::eEncodingSint : eEncodingUint;
    bool is_complex;
    uint32_t complex_count;
    if (IsFloatingPointType(type, complex_count, is_complex))
    {
        count = complex_count;
        return eEncodingIEEE754;
    }
    if (IsPointerType(type))
        return eEncodingUint;
    return eEncodingInvalid;
}

lldb::Format
GoASTContext::GetFormat(lldb::opaque_compiler_type_t type)
{
    if (!type)
        return eFormatDefault;
    switch (static_cast<GoType *>(type)->GetGoKind())
    {
        case GoType::KIND_BOOL:
            return eFormatBoolean;
        case GoType::KIND_INT:
        case GoType::KIND_INT8:
        case GoType::KIND_INT16:
        case GoType::KIND_INT32:
        case GoType::KIND_INT64:
            return eFormatDecimal;
        case GoType::KIND_UINT:
        case GoType::KIND_UINT8:
        case GoType::KIND_UINT16:
        case GoType::KIND_UINT32:
        case GoType::KIND_UINT64:
            return eFormatUnsigned;
        case GoType::KIND_FLOAT32:
        case GoType::KIND_FLOAT64:
            return eFormatFloat;
        case GoType::KIND_COMPLEX64:
        case GoType::KIND_COMPLEX128:
            return eFormatComplexFloat;
        case GoType::KIND_UINTPTR:
        case GoType::KIND_CHAN:
        case GoType::KIND_PTR:
        case GoType::KIND_MAP:
        case GoType::KIND_UNSAFEPOINTER:
            return eFormatHex;
        case GoType::KIND_STRING:
            return eFormatCString;
        case GoType::KIND_ARRAY:
        case GoType::KIND_INTERFACE:
        case GoType::KIND_SLICE:
        case GoType::KIND_STRUCT:
        default:
            // Don't know how to display this.
            return eFormatBytes;
    }
}

size_t
GoASTContext::GetTypeBitAlign(lldb::opaque_compiler_type_t type)
{
    return 0;
}

uint32_t
GoASTContext::GetNumChildren(lldb::opaque_compiler_type_t type, bool omit_empty_base_classes)
{
    if (!type || !GetCompleteType(type))
        return 0;
    GoType *t = static_cast<GoType *>(type);
    if (t->GetGoKind() == GoType::KIND_PTR)
    {
        CompilerType elem = t->GetElementType();
        if (elem.IsAggregateType())
            return elem.GetNumChildren(omit_empty_base_classes);
        return 1;
    }
    else if (GoArray *array = t->GetArray())
    {
        return array->GetLength();
    }
    else if (t->IsTypedef())
    {
        return t->GetElementType().GetNumChildren(omit_empty_base_classes);
    }

    return GetNumFields(type);
}

uint32_t
GoASTContext::GetNumFields(lldb::opaque_compiler_type_t type)
{
    if (!type || !GetCompleteType(type))
        return 0;
    GoType *t = static_cast<GoType *>(type);
    if (t->IsTypedef())
        return t->GetElementType().GetNumFields();
    GoStruct *s = t->GetStruct();
    if (s)
        return s->GetNumFields();
    return 0;
}

CompilerType
GoASTContext::GetFieldAtIndex(lldb::opaque_compiler_type_t type, size_t idx, std::string &name, uint64_t *bit_offset_ptr,
                              uint32_t *bitfield_bit_size_ptr, bool *is_bitfield_ptr)
{
    if (bit_offset_ptr)
        *bit_offset_ptr = 0;
    if (bitfield_bit_size_ptr)
        *bitfield_bit_size_ptr = 0;
    if (is_bitfield_ptr)
        *is_bitfield_ptr = false;

    if (!type || !GetCompleteType(type))
        return CompilerType();

    GoType *t = static_cast<GoType *>(type);
    if (t->IsTypedef())
        return t->GetElementType().GetFieldAtIndex(idx, name, bit_offset_ptr, bitfield_bit_size_ptr, is_bitfield_ptr);

    GoStruct *s = t->GetStruct();
    if (s)
    {
        const auto *field = s->GetField(idx);
        if (field)
        {
            name = field->m_name.GetStringRef();
            if (bit_offset_ptr)
                *bit_offset_ptr = field->m_byte_offset * 8;
            return field->m_type;
        }
    }
    return CompilerType();
}

CompilerType
GoASTContext::GetChildCompilerTypeAtIndex(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, size_t idx, bool transparent_pointers,
                                          bool omit_empty_base_classes, bool ignore_array_bounds, std::string &child_name,
                                          uint32_t &child_byte_size, int32_t &child_byte_offset,
                                          uint32_t &child_bitfield_bit_size, uint32_t &child_bitfield_bit_offset,
                                          bool &child_is_base_class, bool &child_is_deref_of_parent, ValueObject *valobj, uint64_t &language_flags)
{
    child_name.clear();
    child_byte_size = 0;
    child_byte_offset = 0;
    child_bitfield_bit_size = 0;
    child_bitfield_bit_offset = 0;
    child_is_base_class = false;
    child_is_deref_of_parent = false;
    language_flags = 0;

    if (!type || !GetCompleteType(type))
        return CompilerType();

    GoType *t = static_cast<GoType *>(type);
    if (t->GetStruct())
    {
        uint64_t bit_offset;
        CompilerType ret = GetFieldAtIndex(type, idx, child_name, &bit_offset, nullptr, nullptr);
        child_byte_size = ret.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : nullptr);
        child_byte_offset = bit_offset / 8;
        return ret;
    }
    else if (t->GetGoKind() == GoType::KIND_PTR)
    {
        CompilerType pointee = t->GetElementType();
        if (!pointee.IsValid() || pointee.IsVoidType())
            return CompilerType();
        if (transparent_pointers && pointee.IsAggregateType())
        {
            bool tmp_child_is_deref_of_parent = false;
            return pointee.GetChildCompilerTypeAtIndex(exe_ctx, idx, transparent_pointers, omit_empty_base_classes,
                                                    ignore_array_bounds, child_name, child_byte_size, child_byte_offset,
                                                    child_bitfield_bit_size, child_bitfield_bit_offset,
                                                       child_is_base_class, tmp_child_is_deref_of_parent, valobj, language_flags);
        }
        else
        {
            child_is_deref_of_parent = true;
            const char *parent_name = valobj ? valobj->GetName().GetCString() : NULL;
            if (parent_name)
            {
                child_name.assign(1, '*');
                child_name += parent_name;
            }

            // We have a pointer to an simple type
            if (idx == 0 && pointee.GetCompleteType())
            {
                child_byte_size = pointee.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
                child_byte_offset = 0;
                return pointee;
            }
        }
    }
    else if (GoArray *a = t->GetArray())
    {
        if (ignore_array_bounds || idx < a->GetLength())
        {
            CompilerType element_type = a->GetElementType();
            if (element_type.GetCompleteType())
            {
                char element_name[64];
                ::snprintf(element_name, sizeof(element_name), "[%zu]", idx);
                child_name.assign(element_name);
                child_byte_size = element_type.GetByteSize(exe_ctx ? exe_ctx->GetBestExecutionContextScope() : NULL);
                child_byte_offset = (int32_t)idx * (int32_t)child_byte_size;
                return element_type;
            }
        }
    }
    else if (t->IsTypedef())
    {
        return t->GetElementType().GetChildCompilerTypeAtIndex(
            exe_ctx, idx, transparent_pointers, omit_empty_base_classes, ignore_array_bounds, child_name,
            child_byte_size, child_byte_offset, child_bitfield_bit_size, child_bitfield_bit_offset, child_is_base_class,
            child_is_deref_of_parent, valobj, language_flags);
    }
    return CompilerType();
}

// Lookup a child given a name. This function will match base class names
// and member member names in "clang_type" only, not descendants.
uint32_t
GoASTContext::GetIndexOfChildWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes)
{
    if (!type || !GetCompleteType(type))
        return UINT_MAX;

    GoType *t = static_cast<GoType *>(type);
    GoStruct *s = t->GetStruct();
    if (s)
    {
        for (uint32_t i = 0; i < s->GetNumFields(); ++i)
        {
            const GoStruct::Field *f = s->GetField(i);
            if (f->m_name.GetStringRef() == name)
                return i;
        }
    }
    else if (t->GetGoKind() == GoType::KIND_PTR || t->IsTypedef())
    {
        return t->GetElementType().GetIndexOfChildWithName(name, omit_empty_base_classes);
    }
    return UINT_MAX;
}

// Lookup a child member given a name. This function will match member names
// only and will descend into "clang_type" children in search for the first
// member in this class, or any base class that matches "name".
// TODO: Return all matches for a given name by returning a vector<vector<uint32_t>>
// so we catch all names that match a given child name, not just the first.
size_t
GoASTContext::GetIndexOfChildMemberWithName(lldb::opaque_compiler_type_t type, const char *name, bool omit_empty_base_classes,
                                            std::vector<uint32_t> &child_indexes)
{
    uint32_t index = GetIndexOfChildWithName(type, name, omit_empty_base_classes);
    if (index == UINT_MAX)
        return 0;
    child_indexes.push_back(index);
    return 1;
}

// Converts "s" to a floating point value and place resulting floating
// point bytes in the "dst" buffer.
size_t
GoASTContext::ConvertStringToFloatValue(lldb::opaque_compiler_type_t type, const char *s, uint8_t *dst, size_t dst_size)
{
    assert(false);
    return 0;
}
//----------------------------------------------------------------------
// Dumping types
//----------------------------------------------------------------------
#define DEPTH_INCREMENT 2

void
GoASTContext::DumpValue(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s, lldb::Format format,
                        const DataExtractor &data, lldb::offset_t data_byte_offset, size_t data_byte_size,
                        uint32_t bitfield_bit_size, uint32_t bitfield_bit_offset, bool show_types, bool show_summary,
                        bool verbose, uint32_t depth)
{
    if (IsTypedefType(type))
        type = GetTypedefedType(type).GetOpaqueQualType();
    if (!type)
        return;
    GoType *t = static_cast<GoType *>(type);
    
    if (GoStruct *st = t->GetStruct())
    {
        if (GetCompleteType(type))
        {
            uint32_t field_idx = 0;
            for (auto* field = st->GetField(field_idx); field != nullptr; field_idx++)
            {
                // Print the starting squiggly bracket (if this is the
                // first member) or comma (for member 2 and beyond) for
                // the struct/union/class member.
                if (field_idx == 0)
                    s->PutChar('{');
                else
                    s->PutChar(',');
                
                // Indent
                s->Printf("\n%*s", depth + DEPTH_INCREMENT, "");
                
                // Print the member type if requested
                if (show_types)
                {
                    ConstString field_type_name = field->m_type.GetTypeName();
                    s->Printf("(%s) ", field_type_name.AsCString());
                }
                // Print the member name and equal sign
                s->Printf("%s = ", field->m_name.AsCString());
                
                
                // Dump the value of the member
                CompilerType field_type = field->m_type;
                field_type.DumpValue (exe_ctx,
                                         s,                              // Stream to dump to
                                         field_type.GetFormat(),         // The format with which to display the member
                                         data,                           // Data buffer containing all bytes for this type
                                         data_byte_offset + field->m_byte_offset,// Offset into "data" where to grab value from
                                         field->m_type.GetByteSize(exe_ctx->GetBestExecutionContextScope()),      // Size of this type in bytes
                                         0,                              // Bitfield bit size
                                         0,                              // Bitfield bit offset
                                         show_types,                     // Boolean indicating if we should show the variable types
                                         show_summary,                   // Boolean indicating if we should show a summary for the current type
                                         verbose,                        // Verbose output?
                                         depth + DEPTH_INCREMENT);       // Scope depth for any types that have children
            }

            // Indent the trailing squiggly bracket
            if (field_idx > 0)
                s->Printf("\n%*s}", depth, "");
            
        }
    }
    
    if (GoArray *a = t->GetArray()) {
        CompilerType element_clang_type = a->GetElementType();
        lldb::Format element_format = element_clang_type.GetFormat();
        uint32_t element_byte_size = element_clang_type.GetByteSize(exe_ctx->GetBestExecutionContextScope());
        
        uint64_t element_idx;
        for (element_idx = 0; element_idx < a->GetLength(); ++element_idx)
        {
            // Print the starting squiggly bracket (if this is the
            // first member) or comman (for member 2 and beyong) for
            // the struct/union/class member.
            if (element_idx == 0)
                s->PutChar('{');
            else
                s->PutChar(',');
            
            // Indent and print the index
            s->Printf("\n%*s[%" PRIu64 "] ", depth + DEPTH_INCREMENT, "", element_idx);
            
            // Figure out the field offset within the current struct/union/class type
            uint64_t element_offset = element_idx * element_byte_size;
            
            // Dump the value of the member
            element_clang_type.DumpValue (exe_ctx,
                                          s,                              // Stream to dump to
                                          element_format,                 // The format with which to display the element
                                          data,                           // Data buffer containing all bytes for this type
                                          data_byte_offset + element_offset,// Offset into "data" where to grab value from
                                          element_byte_size,              // Size of this type in bytes
                                          0,                              // Bitfield bit size
                                          0,                              // Bitfield bit offset
                                          show_types,                     // Boolean indicating if we should show the variable types
                                          show_summary,                   // Boolean indicating if we should show a summary for the current type
                                          verbose,                        // Verbose output?
                                          depth + DEPTH_INCREMENT);       // Scope depth for any types that have children
        }
        
        // Indent the trailing squiggly bracket
        if (element_idx > 0)
            s->Printf("\n%*s}", depth, "");
    }
    
    if (show_summary)
        DumpSummary (type, exe_ctx, s, data, data_byte_offset, data_byte_size);
}

bool
GoASTContext::DumpTypeValue(lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format, const DataExtractor &data,
                            lldb::offset_t byte_offset, size_t byte_size, uint32_t bitfield_bit_size,
                            uint32_t bitfield_bit_offset, ExecutionContextScope *exe_scope)
{
    if (!type)
        return false;
    if (IsAggregateType(type))
    {
        return false;
    }
    else
    {
        GoType *t = static_cast<GoType *>(type);
        if (t->IsTypedef())
        {
            CompilerType typedef_compiler_type = t->GetElementType();
            if (format == eFormatDefault)
                format = typedef_compiler_type.GetFormat();
            uint64_t typedef_byte_size = typedef_compiler_type.GetByteSize(exe_scope);

            return typedef_compiler_type.DumpTypeValue(
                s,
                format,              // The format with which to display the element
                data,                // Data buffer containing all bytes for this type
                byte_offset,         // Offset into "data" where to grab value from
                typedef_byte_size,   // Size of this type in bytes
                bitfield_bit_size,   // Size in bits of a bitfield value, if zero don't treat as a bitfield
                bitfield_bit_offset, // Offset in bits of a bitfield value if bitfield_bit_size != 0
                exe_scope);
        }

        uint32_t item_count = 1;
        // A few formats, we might need to modify our size and count for depending
        // on how we are trying to display the value...
        switch (format)
        {
            default:
            case eFormatBoolean:
            case eFormatBinary:
            case eFormatComplex:
            case eFormatCString: // NULL terminated C strings
            case eFormatDecimal:
            case eFormatEnum:
            case eFormatHex:
            case eFormatHexUppercase:
            case eFormatFloat:
            case eFormatOctal:
            case eFormatOSType:
            case eFormatUnsigned:
            case eFormatPointer:
            case eFormatVectorOfChar:
            case eFormatVectorOfSInt8:
            case eFormatVectorOfUInt8:
            case eFormatVectorOfSInt16:
            case eFormatVectorOfUInt16:
            case eFormatVectorOfSInt32:
            case eFormatVectorOfUInt32:
            case eFormatVectorOfSInt64:
            case eFormatVectorOfUInt64:
            case eFormatVectorOfFloat32:
            case eFormatVectorOfFloat64:
            case eFormatVectorOfUInt128:
                break;

            case eFormatChar:
            case eFormatCharPrintable:
            case eFormatCharArray:
            case eFormatBytes:
            case eFormatBytesWithASCII:
                item_count = byte_size;
                byte_size = 1;
                break;

            case eFormatUnicode16:
                item_count = byte_size / 2;
                byte_size = 2;
                break;

            case eFormatUnicode32:
                item_count = byte_size / 4;
                byte_size = 4;
                break;
        }
        return data.Dump(s, byte_offset, format, byte_size, item_count, UINT32_MAX, LLDB_INVALID_ADDRESS,
                         bitfield_bit_size, bitfield_bit_offset, exe_scope);
    }
    return 0;
}

void
GoASTContext::DumpSummary(lldb::opaque_compiler_type_t type, ExecutionContext *exe_ctx, Stream *s, const DataExtractor &data,
                          lldb::offset_t data_offset, size_t data_byte_size)
{
    if (type && GoType::KIND_STRING == static_cast<GoType *>(type)->GetGoKind())
    {
        // TODO(ribrdb): read length and data
    }
}

void
GoASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type)
{
    // Dump to stdout
    StreamFile s (stdout, false);
    DumpTypeDescription (type, &s);
}

void
GoASTContext::DumpTypeDescription(lldb::opaque_compiler_type_t type, Stream *s)
{
    if (!type)
        return;
    ConstString name = GetTypeName(type);
    GoType *t = static_cast<GoType *>(type);
    
    if (GoStruct *st = t->GetStruct())
    {
        if (GetCompleteType(type))
        {
            if (NULL == strchr(name.AsCString(), '{'))
                s->Printf("type %s ", name.AsCString());
            s->PutCString("struct {");
            if (st->GetNumFields() == 0) {
                s->PutChar('}');
                return;
            }
            s->IndentMore();
            uint32_t field_idx = 0;
            for (auto* field = st->GetField(field_idx); field != nullptr; field_idx++)
            {
                s->PutChar('\n');
                s->Indent();
                s->Printf("%s %s", field->m_name.AsCString(), field->m_type.GetTypeName().AsCString());
            }
            s->IndentLess();
            s->PutChar('\n');
            s->Indent("}");
            return;
        }
    }

    s->PutCString(name.AsCString());
}

CompilerType
GoASTContext::CreateArrayType(const ConstString &name, const CompilerType &element_type, uint64_t length)
{
    GoType *type = new GoArray(name, length, element_type);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

CompilerType
GoASTContext::CreateBaseType(int go_kind, const lldb_private::ConstString &name, uint64_t byte_size)
{
    if (go_kind == GoType::KIND_UINT || go_kind == GoType::KIND_INT)
        m_int_byte_size = byte_size;
    GoType *type = new GoType(go_kind, name);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

CompilerType
GoASTContext::CreateTypedefType(int kind, const ConstString &name, CompilerType impl)
{
    GoType *type = new GoElem(kind, name, impl);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

CompilerType
GoASTContext::CreateVoidType(const lldb_private::ConstString &name)
{
    GoType *type = new GoType(GoType::KIND_LLDB_VOID, name);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

CompilerType
GoASTContext::CreateStructType(int kind, const lldb_private::ConstString &name, uint32_t byte_size)
{
    GoType *type = new GoStruct(kind, name, byte_size);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

void
GoASTContext::AddFieldToStruct(const lldb_private::CompilerType &struct_type, const lldb_private::ConstString &name,
                               const lldb_private::CompilerType &field_type, uint32_t byte_offset)
{
    if (!struct_type)
        return;
    GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(struct_type.GetTypeSystem());
    if (!ast)
        return;
    GoType *type = static_cast<GoType *>(struct_type.GetOpaqueQualType());
    if (GoStruct *s = type->GetStruct())
        s->AddField(name, field_type, byte_offset);
}

void
GoASTContext::CompleteStructType(const lldb_private::CompilerType &struct_type)
{
    if (!struct_type)
        return;
    GoASTContext *ast = llvm::dyn_cast_or_null<GoASTContext>(struct_type.GetTypeSystem());
    if (!ast)
        return;
    GoType *type = static_cast<GoType *>(struct_type.GetOpaqueQualType());
    if (GoStruct *s = type->GetStruct())
        s->SetComplete();
}

CompilerType
GoASTContext::CreateFunctionType(const lldb_private::ConstString &name, CompilerType *params, size_t params_count,
                                 bool is_variadic)
{
    GoType *type = new GoFunction(name, is_variadic);
    (*m_types)[name].reset(type);
    return CompilerType(this, type);
}

bool
GoASTContext::IsGoString(const lldb_private::CompilerType &type)
{
    if (!type.IsValid() || !llvm::dyn_cast_or_null<GoASTContext>(type.GetTypeSystem()))
        return false;
    return GoType::KIND_STRING == static_cast<GoType *>(type.GetOpaqueQualType())->GetGoKind();
}

bool
GoASTContext::IsGoSlice(const lldb_private::CompilerType &type)
{
    if (!type.IsValid() || !llvm::dyn_cast_or_null<GoASTContext>(type.GetTypeSystem()))
        return false;
    return GoType::KIND_SLICE == static_cast<GoType *>(type.GetOpaqueQualType())->GetGoKind();
}

bool
GoASTContext::IsGoInterface(const lldb_private::CompilerType &type)
{
    if (!type.IsValid() || !llvm::dyn_cast_or_null<GoASTContext>(type.GetTypeSystem()))
        return false;
    return GoType::KIND_INTERFACE == static_cast<GoType *>(type.GetOpaqueQualType())->GetGoKind();
}

bool
GoASTContext::IsPointerKind(uint8_t kind)
{
    return (kind & GoType::KIND_MASK) == GoType::KIND_PTR;
}

bool
GoASTContext::IsDirectIface(uint8_t kind)
{
    return (kind & GoType::KIND_DIRECT_IFACE) == GoType::KIND_DIRECT_IFACE;
}

DWARFASTParser *
GoASTContext::GetDWARFParser()
{
    if (!m_dwarf_ast_parser_ap)
        m_dwarf_ast_parser_ap.reset(new DWARFASTParserGo(*this));
    return m_dwarf_ast_parser_ap.get();
}

UserExpression *
GoASTContextForExpr::GetUserExpression(const char *expr, const char *expr_prefix, lldb::LanguageType language,
                                       Expression::ResultType desired_type, const EvaluateExpressionOptions &options)
{
    TargetSP target = m_target_wp.lock();
    if (target)
        return new GoUserExpression(*target, expr, expr_prefix, language, desired_type, options);
    return nullptr;
}
