Skip to content

Commit fe42b28

Browse files
committed
it works
demangling mostly works fix dots printing works add tests add conformance to AnyKeyPath implement SPI subscripts fully work comments use cross platform image inspection remove unnecessary comment fix fix issues add conditional conformance add types try to fix the api-digester test cr feedback: move impls behind flag, remove addChain(), switch statement, fallthrough instead of if-elses, move import cr feedback: refactor switch statement fix #ifdef reindent, cr feedback: removes manual memory management fix missing whitespace fix typo fix indentation issues switch to regexes checks should test in on all platforms print types in subscripts add test for empty subscript Update test/api-digester/stability-stdlib-abi-without-asserts.test Co-authored-by: Xiaodi Wu <[email protected]> add commas fix failing test fix stdlib annotation cr feedback: remove global, refactor ifdef cr feedback: switch back to manual memory management switch to 5.8 macro add new weakly linked functions to the allowlist fix one more failing test more cr feedback more cr feedback
1 parent 9affc33 commit fe42b28

File tree

7 files changed

+343
-84
lines changed

7 files changed

+343
-84
lines changed

include/swift/Demangling/Demangle.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -649,6 +649,11 @@ ManglingErrorOr<const char *> mangleNodeAsObjcCString(NodePointer node,
649649
std::string nodeToString(NodePointer Root,
650650
const DemangleOptions &Options = DemangleOptions());
651651

652+
/// Transforms a mangled key path accessor thunk helper
653+
/// into the identfier/subscript that would be used to invoke it in swift code.
654+
std::string keyPathSourceString(const char *MangledName,
655+
size_t MangledNameLength);
656+
652657
/// A class for printing to a std::string.
653658
class DemanglerPrinter {
654659
public:

lib/Demangling/NodePrinter.cpp

Lines changed: 142 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,14 @@
1414
//
1515
//===----------------------------------------------------------------------===//
1616

17+
#include "swift/AST/Ownership.h"
1718
#include "swift/Basic/STLExtras.h"
1819
#include "swift/Demangling/Demangle.h"
19-
#include "swift/AST/Ownership.h"
2020
#include "swift/Strings.h"
2121
#include <cassert>
2222
#include <cstdio>
2323
#include <cstdlib>
24+
#include <vector>
2425

2526
using namespace swift;
2627
using namespace Demangle;
@@ -3211,6 +3212,146 @@ void NodePrinter::printEntityType(NodePointer Entity, NodePointer type,
32113212
}
32123213
}
32133214

3215+
NodePointer
3216+
matchSequenceOfKinds(NodePointer start,
3217+
std::vector<std::tuple<Node::Kind, size_t>> pattern) {
3218+
if (start != nullptr) {
3219+
NodePointer current = start;
3220+
size_t idx = 0;
3221+
while (idx < pattern.size()) {
3222+
std::tuple<Node::Kind, size_t> next = pattern[idx];
3223+
idx += 1;
3224+
NodePointer nextChild = current->getChild(std::get<1>(next));
3225+
if (nextChild != nullptr && nextChild->getKind() == std::get<0>(next)) {
3226+
current = nextChild;
3227+
} else {
3228+
return nullptr;
3229+
}
3230+
}
3231+
if (idx == pattern.size()) {
3232+
return current;
3233+
} else {
3234+
return nullptr;
3235+
}
3236+
} else {
3237+
return nullptr;
3238+
}
3239+
}
3240+
3241+
std::string Demangle::keyPathSourceString(const char *MangledName,
3242+
size_t MangledNameLength) {
3243+
std::string invalid = "";
3244+
std::string unlabelledArg = "_: ";
3245+
Context ctx;
3246+
NodePointer root =
3247+
ctx.demangleSymbolAsNode(StringRef(MangledName, MangledNameLength));
3248+
if (!root)
3249+
return invalid;
3250+
if (root->getNumChildren() >= 1) {
3251+
NodePointer firstChild = root->getChild(0);
3252+
if (firstChild->getKind() == Node::Kind::KeyPathGetterThunkHelper) {
3253+
NodePointer child = firstChild->getChild(0);
3254+
switch (child->getKind()) {
3255+
case Node::Kind::Subscript: {
3256+
std::string subscriptText = "subscript(";
3257+
std::vector<std::string> argumentTypeNames;
3258+
// Multiple arguments case
3259+
NodePointer argList = matchSequenceOfKinds(
3260+
child, {
3261+
std::make_pair(Node::Kind::Type, 2),
3262+
std::make_pair(Node::Kind::FunctionType, 0),
3263+
std::make_pair(Node::Kind::ArgumentTuple, 0),
3264+
std::make_pair(Node::Kind::Type, 0),
3265+
std::make_pair(Node::Kind::Tuple, 0),
3266+
});
3267+
if (argList != nullptr) {
3268+
size_t numArgumentTypes = argList->getNumChildren();
3269+
size_t idx = 0;
3270+
while (idx < numArgumentTypes) {
3271+
NodePointer argumentType = argList->getChild(idx);
3272+
idx += 1;
3273+
if (argumentType->getKind() == Node::Kind::TupleElement) {
3274+
argumentType =
3275+
argumentType->getChild(0)->getChild(0)->getChild(1);
3276+
if (argumentType->getKind() == Node::Kind::Identifier) {
3277+
argumentTypeNames.push_back(
3278+
std::string(argumentType->getText()));
3279+
continue;
3280+
}
3281+
}
3282+
argumentTypeNames.push_back("<Unknown>");
3283+
}
3284+
} else {
3285+
// Case where there is a single argument
3286+
argList = matchSequenceOfKinds(
3287+
child, {
3288+
std::make_pair(Node::Kind::Type, 2),
3289+
std::make_pair(Node::Kind::FunctionType, 0),
3290+
std::make_pair(Node::Kind::ArgumentTuple, 0),
3291+
std::make_pair(Node::Kind::Type, 0),
3292+
});
3293+
if (argList != nullptr) {
3294+
argumentTypeNames.push_back(
3295+
std::string(argList->getChild(0)->getChild(1)->getText()));
3296+
}
3297+
}
3298+
child = child->getChild(1);
3299+
size_t idx = 0;
3300+
// There is an argument label:
3301+
if (child != nullptr) {
3302+
if (child->getKind() == Node::Kind::LabelList) {
3303+
size_t numChildren = child->getNumChildren();
3304+
if (numChildren == 0) {
3305+
subscriptText += unlabelledArg + argumentTypeNames[0];
3306+
} else {
3307+
while (idx < numChildren) {
3308+
Node *argChild = child->getChild(idx);
3309+
idx += 1;
3310+
if (argChild->getKind() == Node::Kind::Identifier) {
3311+
subscriptText += std::string(argChild->getText()) + ": " +
3312+
argumentTypeNames[idx - 1];
3313+
if (idx != numChildren) {
3314+
subscriptText += ", ";
3315+
}
3316+
} else if (argChild->getKind() ==
3317+
Node::Kind::FirstElementMarker ||
3318+
argChild->getKind() == Node::Kind::VariadicMarker) {
3319+
subscriptText += unlabelledArg + argumentTypeNames[idx - 1];
3320+
}
3321+
}
3322+
}
3323+
}
3324+
} else {
3325+
subscriptText += unlabelledArg + argumentTypeNames[0];
3326+
}
3327+
return subscriptText + ")";
3328+
}
3329+
case Node::Kind::Variable: {
3330+
child = child->getChild(1);
3331+
if (child == nullptr) {
3332+
return invalid;
3333+
}
3334+
if (child->getKind() == Node::Kind::PrivateDeclName) {
3335+
child = child->getChild(1);
3336+
if (child == nullptr) {
3337+
return invalid;
3338+
}
3339+
if (child->getKind() == Node::Kind::Identifier) {
3340+
return std::string(child->getText());
3341+
}
3342+
} else if (child->getKind() == Node::Kind::Identifier) {
3343+
return std::string(child->getText());
3344+
}
3345+
break;
3346+
}
3347+
default:
3348+
return invalid;
3349+
}
3350+
}
3351+
}
3352+
return invalid;
3353+
}
3354+
32143355
std::string Demangle::nodeToString(NodePointer root,
32153356
const DemangleOptions &options) {
32163357
if (!root)

stdlib/public/core/KeyPath.swift

Lines changed: 111 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -3711,73 +3711,121 @@ internal func _instantiateKeyPathBuffer(
37113711
}
37123712
}
37133713

3714-
@_silgen_name("swift_keypath_dladdr")
3715-
internal func keypath_dladdr(_: UnsafeRawPointer) -> UnsafePointer<CChar>
3716-
3717-
fileprivate func dynamicLibraryAddress(of pointer: UnsafeRawPointer) -> String {
3718-
String(cString: keypath_dladdr(pointer))
3714+
#if SWIFT_ENABLE_REFLECTION
3715+
3716+
@_silgen_name("swift_keyPath_dladdr")
3717+
fileprivate func keypath_dladdr(_: UnsafeRawPointer) -> UnsafePointer<CChar>?
3718+
3719+
@_silgen_name("swift_keyPathSourceString")
3720+
fileprivate func demangle(
3721+
name: UnsafePointer<CChar>
3722+
) -> UnsafeMutablePointer<CChar>?
3723+
3724+
fileprivate func dynamicLibraryAddress<Base, Leaf>(
3725+
of pointer: ComputedAccessorsPtr,
3726+
_: Base.Type,
3727+
_ leaf: Leaf.Type
3728+
) -> String {
3729+
let getter: ComputedAccessorsPtr.Getter<Base, Leaf> = pointer.getter()
3730+
let pointer = unsafeBitCast(getter, to: UnsafeRawPointer.self)
3731+
if let cString = keypath_dladdr(UnsafeRawPointer(pointer)) {
3732+
if let demangled = demangle(name: cString)
3733+
.map({ pointer in
3734+
defer {
3735+
pointer.deallocate()
3736+
}
3737+
return String(cString: pointer)
3738+
}) {
3739+
return demangled
3740+
}
3741+
}
3742+
return "<computed \(pointer) (\(leaf))>"
37193743
}
37203744

3721-
extension KeyPath: CustomDebugStringConvertible {
3722-
3723-
public var debugDescription: String {
3724-
// TODO: For perf, we could use a local growable buffer instead of Any (see comment above)
3725-
var description = "\\\(String(describing: Root.self))."
3726-
return withBuffer {
3727-
var buffer = $0
3728-
if buffer.data.isEmpty {
3729-
_internalInvariantFailure("key path has no components")
3730-
return description
3745+
#endif
3746+
3747+
@available(SwiftStdlib 5.8, *)
3748+
extension AnyKeyPath: CustomDebugStringConvertible {
3749+
3750+
#if SWIFT_ENABLE_REFLECTION
3751+
@available(SwiftStdlib 5.8, *)
3752+
public var debugDescription: String {
3753+
var description = "\\\(String(describing: Self.rootType))"
3754+
return withBuffer {
3755+
var buffer = $0
3756+
if buffer.data.isEmpty {
3757+
_internalInvariantFailure("key path has no components")
3758+
}
3759+
var valueType: Any.Type = Self.rootType
3760+
while true {
3761+
let (rawComponent, optNextType) = buffer.next()
3762+
let hasEnded = optNextType == nil
3763+
let nextType = optNextType ?? Self.valueType
3764+
switch rawComponent.value {
3765+
case .optionalForce, .optionalWrap, .optionalChain:
3766+
break
3767+
default:
3768+
description.append(".")
3769+
}
3770+
switch rawComponent.value {
3771+
case .class(let offset),
3772+
.struct(let offset):
3773+
let count = _getRecursiveChildCount(valueType)
3774+
let index = (0..<count)
3775+
.first(where: { i in
3776+
_getChildOffset(
3777+
valueType,
3778+
index: i
3779+
) == offset
3780+
})
3781+
if let index = index {
3782+
var field = _FieldReflectionMetadata()
3783+
_ = _getChildMetadata(
3784+
valueType,
3785+
index: index,
3786+
fieldMetadata: &field
3787+
)
3788+
defer {
3789+
field.freeFunc?(field.name)
37313790
}
3732-
while true {
3733-
let (rawComponent, optNextType) = buffer.next()
3734-
let valueType = optNextType ?? Value.self
3735-
let isLast = optNextType == nil
3736-
func name(for offset: Int) -> String {
3737-
let count = _getRecursiveChildCount(valueType)
3738-
for i in 0..<count {
3739-
if _getChildOffset(
3740-
valueType,
3741-
index: i
3742-
) == offset {
3743-
var field = _FieldReflectionMetadata()
3744-
_ = _getChildMetadata(
3745-
valueType,
3746-
index: i,
3747-
fieldMetadata: &field
3748-
)
3749-
defer {
3750-
field.freeFunc?(field.name)
3751-
}
3752-
return String(cString: field.name)
3753-
}
3754-
}
3755-
_internalInvariantFailure("Type Metadata doesn't have a field with an offset matching the one in this keypath segment")
3756-
return ""
3757-
}
3758-
func name(for pointer: UnsafeRawPointer) -> String {
3759-
dynamicLibraryAddress(of: pointer)
3760-
}
3761-
switch rawComponent.value {
3762-
case .class(let offset):
3763-
description.append(name(for: offset))
3764-
case .get(_, let accessors, let argument):
3765-
description.append(name(for: accessors.getterPtr))
3766-
case .mutatingGetSet(_, let accessors, _):
3767-
description.append(name(for: accessors.getterPtr))
3768-
case .nonmutatingGetSet(_, let accessors, let argument):
3769-
description.append(name(for: accessors.getterPtr))
3770-
case .optionalChain, .optionalWrap:
3771-
description.append("?")
3772-
case .optionalForce:
3773-
description.append("!")
3774-
case .struct(let offset):
3775-
description.append(name(for: offset))
3776-
}
3777-
description.append(".")
3791+
description.append(String(cString: field.name))
3792+
} else {
3793+
description.append("<offset \(offset) (\(nextType))>")
3794+
}
3795+
case .get(_, let accessors, _),
3796+
.nonmutatingGetSet(_, let accessors, _),
3797+
.mutatingGetSet(_, let accessors, _):
3798+
func project<Base>(base: Base.Type) -> String {
3799+
func project2<Leaf>(leaf: Leaf.Type) -> String {
3800+
dynamicLibraryAddress(
3801+
of: accessors,
3802+
base,
3803+
leaf
3804+
)
37783805
}
3779-
return description
3806+
return _openExistential(nextType, do: project2)
3807+
}
3808+
description.append(
3809+
_openExistential(valueType, do: project)
3810+
)
3811+
case .optionalChain, .optionalWrap:
3812+
description.append("?")
3813+
case .optionalForce:
3814+
description.append("!")
3815+
}
3816+
if hasEnded {
3817+
break
37803818
}
3819+
valueType = nextType
3820+
}
3821+
return description
37813822
}
3782-
3823+
}
3824+
#else
3825+
@available(SwiftStdlib 5.8, *)
3826+
public var debugDescription: String {
3827+
"(value cannot be printed without reflection)"
3828+
}
3829+
#endif
3830+
37833831
}

0 commit comments

Comments
 (0)