blob: db84d001eeca1af601aa7e06632f2c6c303bee93 [file] [log] [blame]
//===----------------------------------------------------------------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/Basic/Lazy.h"
#include "swift/Runtime/Reflection.h"
#include "swift/Runtime/Casting.h"
#include "swift/Runtime/Config.h"
#include "swift/Runtime/HeapObject.h"
#include "swift/Runtime/Metadata.h"
#include "swift/Runtime/Enum.h"
#include "swift/Runtime/Unreachable.h"
#include "swift/Demangling/Demangle.h"
#include "swift/Runtime/Debug.h"
#include "swift/Runtime/Portability.h"
#include "Private.h"
#include "WeakReference.h"
#include "llvm/Support/Compiler.h"
#include <cassert>
#include <cinttypes>
#include <cstdio>
#include <cstring>
#include <new>
#include <string>
#include <tuple>
#if SWIFT_OBJC_INTEROP
#include "swift/Runtime/ObjCBridge.h"
#include "SwiftObject.h"
#include <Foundation/Foundation.h>
#include <objc/objc.h>
#include <objc/runtime.h>
#endif
#if defined(_WIN32)
#include <stdarg.h>
namespace {
int asprintf(char **strp, const char *fmt, ...) {
va_list argp0, argp1;
va_start(argp0, fmt);
va_copy(argp1, argp0);
int length = _vscprintf(fmt, argp0);
*strp = reinterpret_cast<char *>(malloc(length + 1));
if (*strp == nullptr)
return -1;
length = _vsnprintf(*strp, length, fmt, argp1);
va_end(argp0);
va_end(argp1);
return length;
}
char *strndup(const char *s, size_t n) {
size_t length = std::min(strlen(s), n);
char *buffer = reinterpret_cast<char *>(malloc(length + 1));
if (buffer == nullptr)
return buffer;
strncpy(buffer, s, length);
buffer[length] = '\0';
return buffer;
}
}
#endif
using namespace swift;
#if SWIFT_OBJC_INTEROP
// Declare the debugQuickLookObject selector.
@interface DeclareSelectors
- (id)debugQuickLookObject;
@end
#endif
namespace {
/// The layout of Any.
using Any = OpaqueExistentialContainer;
// Swift assumes Any is returned in memory.
// Use AnyReturn to guarantee that even on architectures
// where Any would be returned in registers.
struct AnyReturn {
Any any;
AnyReturn(Any a) : any(a) { }
operator Any() { return any; }
~AnyReturn() { }
};
static std::tuple<const Metadata *, OpaqueValue *>
unwrapExistential(const Metadata *T, OpaqueValue *Value) {
// If the value is an existential container, look through it to reflect the
// contained value.
// TODO: Should look through existential metatypes too, but it doesn't
// really matter yet since we don't have any special mirror behavior for
// concrete metatypes yet.
while (T->getKind() == MetadataKind::Existential) {
auto *existential
= static_cast<const ExistentialTypeMetadata *>(T);
// Unwrap the existential container.
T = existential->getDynamicType(Value);
Value = existential->projectValue(Value);
// Existential containers can end up nested in some cases due to generic
// abstraction barriers. Repeat in case we have a nested existential.
}
return std::make_tuple(T, Value);
}
static bool loadSpecialReferenceStorage(OpaqueValue *fieldData,
const FieldType fieldType,
Any *outValue) {
// isWeak() implies a reference type via Sema.
if (!fieldType.isWeak())
return false;
auto type = fieldType.getType();
assert(type->getKind() == MetadataKind::Optional);
auto *weakField = reinterpret_cast<WeakReference *>(fieldData);
auto *strongValue = swift_unknownObjectWeakLoadStrong(weakField);
// Now that we have a strong reference, we need to create a temporary buffer
// from which to copy the whole value, which might be a native class-bound
// existential, which means we also need to copy n witness tables, for
// however many protocols are in the protocol composition. For example, if we
// are copying a:
// weak var myWeakProperty : (Protocol1 & Protocol2)?
// then we need to copy three values:
// - the instance
// - the witness table for Protocol1
// - the witness table for Protocol2
auto *weakContainer =
reinterpret_cast<WeakClassExistentialContainer *>(fieldData);
// Create a temporary existential where we can put the strong reference.
// The allocateBuffer value witness requires a ValueBuffer to own the
// allocated storage.
ValueBuffer temporaryBuffer;
auto *temporaryValue = reinterpret_cast<ClassExistentialContainer *>(
type->allocateBufferIn(&temporaryBuffer));
// Now copy the entire value out of the parent, which will include the
// witness tables.
temporaryValue->Value = strongValue;
auto valueWitnessesSize = type->getValueWitnesses()->getSize() -
sizeof(WeakClassExistentialContainer);
memcpy(temporaryValue->getWitnessTables(), weakContainer->getWitnessTables(),
valueWitnessesSize);
outValue->Type = type;
auto *opaqueValueAddr = type->allocateBoxForExistentialIn(&outValue->Buffer);
type->vw_initializeWithCopy(opaqueValueAddr,
reinterpret_cast<OpaqueValue *>(temporaryValue));
type->deallocateBufferIn(&temporaryBuffer);
return true;
}
// Abstract base class for reflection implementations.
struct ReflectionMirrorImpl {
const Metadata *type;
OpaqueValue *value;
virtual char displayStyle() = 0;
virtual intptr_t count() = 0;
virtual AnyReturn subscript(intptr_t index, const char **outName,
void (**outFreeFunc)(const char *)) = 0;
virtual const char *enumCaseName() { return nullptr; }
#if SWIFT_OBJC_INTEROP
virtual id quickLookObject() { return nil; }
#endif
virtual ~ReflectionMirrorImpl() {}
};
// Implementation for tuples.
struct TupleImpl : ReflectionMirrorImpl {
char displayStyle() {
return 't';
}
intptr_t count() {
auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
return Tuple->NumElements;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
auto *Tuple = static_cast<const TupleTypeMetadata *>(type);
if (i < 0 || (size_t)i > Tuple->NumElements)
swift::crash("Swift mirror subscript bounds check failure");
// Determine whether there is a label.
bool hasLabel = false;
if (const char *labels = Tuple->Labels) {
const char *space = strchr(labels, ' ');
for (intptr_t j = 0; j != i && space; ++j) {
labels = space + 1;
space = strchr(labels, ' ');
}
// If we have a label, create it.
if (labels && space && labels != space) {
*outName = strndup(labels, space - labels);
hasLabel = true;
}
}
if (!hasLabel) {
// The name is the stringized element number '.0'.
char *str;
asprintf(&str, ".%" PRIdPTR, i);
*outName = str;
}
*outFreeFunc = [](const char *str) { free(const_cast<char *>(str)); };
// Get the nth element.
auto &elt = Tuple->getElement(i);
auto *bytes = reinterpret_cast<const char *>(value);
auto *eltData = reinterpret_cast<const OpaqueValue *>(bytes + elt.Offset);
Any result;
result.Type = elt.Type;
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(eltData));
return AnyReturn(result);
}
};
struct swift_closure {
void *fptr;
HeapObject *context;
};
SWIFT_RUNTIME_STDLIB_API SWIFT_CC(swift) swift_closure
MANGLE_SYM(s20_playgroundPrintHookySScSgvg)();
static bool _shouldReportMissingReflectionMetadataWarnings() {
// Missing metadata warnings noise up playground sessions and aren't really
// actionable in playground contexts. If we're running in a playground,
// suppress warnings.
//
// Guesstimate whether we're in a playground by looking at the
// _playgroundPrintHook variable in the standard library, which is set during
// playground execution.
auto hook = MANGLE_SYM(s20_playgroundPrintHookySScSgvg)();
if (hook.fptr) {
swift_release(hook.context);
return false;
} else {
return true;
}
}
/// Raise a warning about reflection metadata that could not be found
/// at runtime. This is usually mostly harmless, but it's good to alert
/// users that it happens.
static void
missing_reflection_metadata_warning(const char *fmt, ...) {
bool shouldWarn =
SWIFT_LAZY_CONSTANT(_shouldReportMissingReflectionMetadataWarnings());
if (!shouldWarn)
return;
va_list args;
va_start(args, fmt);
warningv(0, fmt, args);
}
static std::pair<StringRef /*name*/, FieldType /*fieldInfo*/>
getFieldAt(const Metadata *base, unsigned index) {
using namespace reflection;
// If we failed to find the field descriptor metadata for the type, fall
// back to returning an empty tuple as a standin.
auto failedToFindMetadata = [&]() -> std::pair<StringRef, FieldType> {
auto typeName = swift_getTypeName(base, /*qualified*/ true);
missing_reflection_metadata_warning(
"warning: the Swift runtime found no field metadata for "
"type '%*s' that claims to be reflectable. Its fields will show up as "
"'unknown' in Mirrors\n",
(int)typeName.length, typeName.data);
return {"unknown",
FieldType()
.withType(TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {}))
.withIndirect(false)
.withWeak(false)};
};
auto *baseDesc = base->getTypeContextDescriptor();
if (!baseDesc)
return failedToFindMetadata();
auto *fields = baseDesc->Fields.get();
if (!fields)
return failedToFindMetadata();
const FieldDescriptor &descriptor = *fields;
auto &field = descriptor.getFields()[index];
auto name = field.getFieldName(0);
// Enum cases don't always have types.
if (!field.hasMangledTypeName())
return {name, FieldType().withIndirect(field.isIndirectCase())};
std::vector<const ContextDescriptor *> descriptorPath;
{
const auto *parent = reinterpret_cast<
const ContextDescriptor *>(baseDesc);
while (parent) {
if (parent->isGeneric())
descriptorPath.push_back(parent);
parent = parent->Parent.get();
}
}
auto typeName = field.getMangledTypeName(0);
auto typeInfo = _getTypeByMangledName(
typeName,
[&](unsigned depth, unsigned index) -> const Metadata * {
if (depth >= descriptorPath.size())
return nullptr;
unsigned currentDepth = 0;
unsigned flatIndex = index;
const ContextDescriptor *currentContext = descriptorPath.back();
for (const auto *context : llvm::reverse(descriptorPath)) {
if (currentDepth >= depth)
break;
flatIndex += context->getNumGenericParams();
currentContext = context;
++currentDepth;
}
if (index >= currentContext->getNumGenericParams())
return nullptr;
return base->getGenericArgs()[flatIndex];
});
// Complete the type metadata before returning it to the caller.
if (typeInfo) {
typeInfo = TypeInfo(swift_checkMetadataState(MetadataState::Complete,
typeInfo).Value,
typeInfo.getReferenceOwnership());
}
// If demangling the type failed, pretend it's an empty type instead with
// a log message.
if (typeInfo == nullptr) {
typeInfo = TypeInfo(&METADATA_SYM(EMPTY_TUPLE_MANGLING), {});
missing_reflection_metadata_warning(
"warning: the Swift runtime was unable to demangle the type "
"of field '%*s'. the mangled type name is '%*s'. this field will "
"show up as an empty tuple in Mirrors\n",
(int)name.size(), name.data(),
(int)typeName.size(), typeName.data());
}
return {name, FieldType()
.withType(typeInfo)
.withIndirect(field.isIndirectCase())
.withWeak(typeInfo.isWeak())};
}
// Implementation for structs.
struct StructImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Struct = static_cast<const StructMetadata *>(type);
const auto &Description = Struct->getDescription();
return Description->isReflectable();
}
char displayStyle() {
return 's';
}
intptr_t count() {
if (!isReflectable()) {
return 0;
}
auto *Struct = static_cast<const StructMetadata *>(type);
return Struct->getDescription()->NumFields;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
auto *Struct = static_cast<const StructMetadata *>(type);
if (i < 0 || (size_t)i > Struct->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// Load the offset from its respective vector.
auto fieldOffset = Struct->getFieldOffsets()[i];
Any result;
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "indirect struct fields not implemented");
*outName = name.data();
*outFreeFunc = nullptr;
auto *bytes = reinterpret_cast<char*>(value);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
if (!didLoad) {
result.Type = fieldInfo.getType();
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(fieldData));
}
return AnyReturn(result);
}
};
// Implementation for enums.
struct EnumImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Enum = static_cast<const EnumMetadata *>(type);
const auto &Description = Enum->getDescription();
return Description->isReflectable();
}
const char *getInfo(unsigned *tagPtr = nullptr,
const Metadata **payloadTypePtr = nullptr,
bool *indirectPtr = nullptr) {
// 'tag' is in the range [0..NumElements-1].
unsigned tag = type->vw_getEnumTag(value);
StringRef name;
FieldType info;
std::tie(name, info) = getFieldAt(type, tag);
const Metadata *payloadType = info.getType();
bool indirect = info.isIndirect();
if (tagPtr)
*tagPtr = tag;
if (payloadTypePtr)
*payloadTypePtr = payloadType;
if (indirectPtr)
*indirectPtr = indirect;
return name.data();
}
char displayStyle() {
return 'e';
}
intptr_t count() {
if (!isReflectable()) {
return 0;
}
const Metadata *payloadType;
getInfo(nullptr, &payloadType, nullptr);
return (payloadType != nullptr) ? 1 : 0;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
unsigned tag;
const Metadata *payloadType;
bool indirect;
auto *caseName = getInfo(&tag, &payloadType, &indirect);
// Copy the enum payload into a box
const Metadata *boxType = (indirect ? &METADATA_SYM(Bo).base : payloadType);
BoxPair pair = swift_allocBox(boxType);
type->vw_destructiveProjectEnumData(const_cast<OpaqueValue *>(value));
boxType->vw_initializeWithCopy(pair.buffer, const_cast<OpaqueValue *>(value));
type->vw_destructiveInjectEnumTag(const_cast<OpaqueValue *>(value), tag);
value = pair.buffer;
// If the payload is indirect, we need to jump through the box to get it.
if (indirect) {
const HeapObject *owner = *reinterpret_cast<HeapObject * const *>(value);
value = swift_projectBox(const_cast<HeapObject *>(owner));
}
*outName = caseName;
*outFreeFunc = nullptr;
Any result;
result.Type = payloadType;
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(value));
swift_release(pair.object);
return AnyReturn(result);
}
const char *enumCaseName() {
if (!isReflectable()) {
return nullptr;
}
return getInfo();
}
};
// Implementation for classes.
struct ClassImpl : ReflectionMirrorImpl {
bool isReflectable() {
const auto *Class = static_cast<const ClassMetadata *>(type);
const auto &Description = Class->getDescription();
return Description->isReflectable();
}
char displayStyle() {
return 'c';
}
intptr_t count() {
if (!isReflectable())
return 0;
auto *Clas = static_cast<const ClassMetadata*>(type);
auto count = Clas->getDescription()->NumFields;
return count;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
auto *Clas = static_cast<const ClassMetadata*>(type);
if (i < 0 || (size_t)i > Clas->getDescription()->NumFields)
swift::crash("Swift mirror subscript bounds check failure");
// FIXME: If the class has ObjC heritage, get the field offset using the ObjC
// metadata, because we don't update the field offsets in the face of
// resilient base classes.
uintptr_t fieldOffset;
if (usesNativeSwiftReferenceCounting(Clas)) {
fieldOffset = Clas->getFieldOffsets()[i];
} else {
#if SWIFT_OBJC_INTEROP
Ivar *ivars = class_copyIvarList((Class)Clas, nullptr);
fieldOffset = ivar_getOffset(ivars[i]);
free(ivars);
#else
swift::crash("Object appears to be Objective-C, but no runtime.");
#endif
}
Any result;
StringRef name;
FieldType fieldInfo;
std::tie(name, fieldInfo) = getFieldAt(type, i);
assert(!fieldInfo.isIndirect() && "class indirect properties not implemented");
auto *bytes = *reinterpret_cast<char * const *>(value);
auto *fieldData = reinterpret_cast<OpaqueValue *>(bytes + fieldOffset);
*outName = name.data();
*outFreeFunc = nullptr;
bool didLoad = loadSpecialReferenceStorage(fieldData, fieldInfo, &result);
if (!didLoad) {
result.Type = fieldInfo.getType();
auto *opaqueValueAddr = result.Type->allocateBoxForExistentialIn(&result.Buffer);
result.Type->vw_initializeWithCopy(opaqueValueAddr,
const_cast<OpaqueValue *>(fieldData));
}
return AnyReturn(result);
}
#if SWIFT_OBJC_INTEROP
id quickLookObject() {
id object = [*reinterpret_cast<const id *>(value) retain];
if ([object respondsToSelector:@selector(debugQuickLookObject)]) {
id quickLookObject = [object debugQuickLookObject];
[quickLookObject retain];
[object release];
return quickLookObject;
}
return object;
}
#endif
};
#if SWIFT_OBJC_INTEROP
// Implementation for ObjC classes.
struct ObjCClassImpl : ClassImpl {
intptr_t count() {
// ObjC makes no guarantees about the state of ivars, so we can't safely
// introspect them in the general case.
return 0;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
swift::crash("Cannot get children of Objective-C objects.");
}
};
#endif
// Implementation for metatypes.
struct MetatypeImpl : ReflectionMirrorImpl {
char displayStyle() {
return '\0';
}
intptr_t count() {
return 0;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
swift::crash("Metatypes have no children.");
}
};
// Implementation for opaque types.
struct OpaqueImpl : ReflectionMirrorImpl {
char displayStyle() {
return '\0';
}
intptr_t count() {
return 0;
}
AnyReturn subscript(intptr_t i, const char **outName,
void (**outFreeFunc)(const char *)) {
swift::crash("Opaque types have no children.");
}
};
template<typename F>
auto call(OpaqueValue *passedValue, const Metadata *T, const Metadata *passedType,
const F &f) -> decltype(f(nullptr))
{
const Metadata *type;
OpaqueValue *value;
std::tie(type, value) = unwrapExistential(T, passedValue);
if (passedType != nullptr) {
type = passedType;
}
auto call = [&](ReflectionMirrorImpl *impl) {
impl->type = type;
impl->value = value;
auto result = f(impl);
return result;
};
auto callClass = [&] {
if (passedType == nullptr) {
// Get the runtime type of the object.
const void *obj = *reinterpret_cast<const void * const *>(value);
auto isa = _swift_getClass(obj);
// Look through artificial subclasses.
while (isa->isTypeMetadata() && isa->isArtificialSubclass()) {
isa = isa->Superclass;
}
passedType = isa;
}
#if SWIFT_OBJC_INTEROP
// If this is a pure ObjC class, reflect it using ObjC's runtime facilities.
// ForeignClass (e.g. CF classes) manifests as a NULL class object.
auto *classObject = passedType->getClassObject();
if (classObject == nullptr || !classObject->isTypeMetadata()) {
ObjCClassImpl impl;
return call(&impl);
}
#endif
// Otherwise, use the native Swift facilities.
ClassImpl impl;
return call(&impl);
};
switch (type->getKind()) {
case MetadataKind::Tuple: {
TupleImpl impl;
return call(&impl);
}
case MetadataKind::Struct: {
StructImpl impl;
return call(&impl);
}
case MetadataKind::Enum:
case MetadataKind::Optional: {
EnumImpl impl;
return call(&impl);
}
case MetadataKind::ObjCClassWrapper:
case MetadataKind::ForeignClass:
case MetadataKind::Class: {
return callClass();
}
case MetadataKind::Metatype:
case MetadataKind::ExistentialMetatype: {
MetatypeImpl impl;
return call(&impl);
}
case MetadataKind::Opaque: {
#if SWIFT_OBJC_INTEROP
// If this is the Builtin.UnknownObject type, use the dynamic type of the
// object reference.
if (type == &METADATA_SYM(BO).base) {
return callClass();
}
#endif
// If this is the Builtin.NativeObject type, and the heap object is a
// class instance, use the dynamic type of the object reference.
if (type == &METADATA_SYM(Bo).base) {
const HeapObject *obj
= *reinterpret_cast<const HeapObject * const*>(value);
if (obj->metadata->getKind() == MetadataKind::Class) {
return callClass();
}
}
LLVM_FALLTHROUGH;
}
/// TODO: Implement specialized mirror witnesses for all kinds.
default:
break;
// Types can't have these kinds.
case MetadataKind::HeapLocalVariable:
case MetadataKind::HeapGenericLocalVariable:
case MetadataKind::ErrorObject:
swift::crash("Swift mirror lookup failure");
}
// If we have an unknown kind of type, or a type without special handling,
// treat it as opaque.
OpaqueImpl impl;
return call(&impl);
}
} // end anonymous namespace
// func _getNormalizedType<T>(_: T, type: Any.Type) -> Any.Type
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const Metadata *swift_reflectionMirror_normalizedType(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) { return impl->type; });
}
// func _getChildCount<T>(_: T, type: Any.Type) -> Int
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
intptr_t swift_reflectionMirror_count(OpaqueValue *value,
const Metadata *type,
const Metadata *T) {
return call(value, T, type, [](ReflectionMirrorImpl *impl) {
return impl->count();
});
}
// We intentionally use a non-POD return type with this entry point to give
// it an indirect return ABI for compatibility with Swift.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreturn-type-c-linkage"
// func _getChild<T>(
// of: T,
// type: Any.Type,
// index: Int,
// outName: UnsafeMutablePointer<UnsafePointer<CChar>?>,
// outFreeFunc: UnsafeMutablePointer<NameFreeFunc?>
// ) -> Any
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
AnyReturn swift_reflectionMirror_subscript(OpaqueValue *value, const Metadata *type,
intptr_t index,
const char **outName,
void (**outFreeFunc)(const char *),
const Metadata *T) {
return call(value, T, type, [&](ReflectionMirrorImpl *impl) {
return impl->subscript(index, outName, outFreeFunc);
});
}
#pragma clang diagnostic pop
// func _getDisplayStyle<T>(_: T) -> CChar
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
char swift_reflectionMirror_displayStyle(OpaqueValue *value, const Metadata *T) {
return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->displayStyle(); });
}
// func _getEnumCaseName<T>(_ value: T) -> UnsafePointer<CChar>?
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const char *swift_EnumCaseName(OpaqueValue *value, const Metadata *T) {
return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->enumCaseName(); });
}
// func _opaqueSummary(_ metadata: Any.Type) -> UnsafePointer<CChar>?
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
const char *swift_OpaqueSummary(const Metadata *T) {
switch (T->getKind()) {
case MetadataKind::Class:
case MetadataKind::Struct:
case MetadataKind::Enum:
case MetadataKind::Optional:
case MetadataKind::Metatype:
return nullptr;
case MetadataKind::Opaque:
return "(Opaque Value)";
case MetadataKind::Tuple:
return "(Tuple)";
case MetadataKind::Function:
return "(Function)";
case MetadataKind::Existential:
return "(Existential)";
case MetadataKind::ObjCClassWrapper:
return "(Objective-C Class Wrapper)";
case MetadataKind::ExistentialMetatype:
return "(Existential Metatype)";
case MetadataKind::ForeignClass:
return "(Foreign Class)";
case MetadataKind::HeapLocalVariable:
return "(Heap Local Variable)";
case MetadataKind::HeapGenericLocalVariable:
return "(Heap Generic Local Variable)";
case MetadataKind::ErrorObject:
return "(ErrorType Object)";
default:
return "(Unknown)";
}
}
#if SWIFT_OBJC_INTEROP
// func _getQuickLookObject<T>(_: T) -> AnyObject?
SWIFT_CC(swift) SWIFT_RUNTIME_STDLIB_API
id swift_reflectionMirror_quickLookObject(OpaqueValue *value, const Metadata *T) {
return call(value, T, nullptr, [](ReflectionMirrorImpl *impl) { return impl->quickLookObject(); });
}
#endif