Skip to content

[lldb] Add unittests for SwiftLanguageRuntime demangling functions #9422

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,24 +83,26 @@ static bool IsSwiftAsyncFunctionSymbol(swift::Demangle::NodePointer node) {
return false;
if (hasChild(node, Node::Kind::AsyncSuspendResumePartialFunction))
return false;

// Peel off layers over top of Function nodes.
switch (node->getFirstChild()->getKind()) {
case Node::Kind::Static:
case Node::Kind::ExplicitClosure:
// Peel off a Static node. If it exists, there will be a single instance and a
// top level node.
if (node->getFirstChild()->getKind() == Node::Kind::Static)
node = node->getFirstChild();
break;
default:
break;
}

return childAtPath(node,
{Node::Kind::Function, Node::Kind::Type,
Node::Kind::FunctionType, Node::Kind::AsyncAnnotation}) ||
childAtPath(node,
{Node::Kind::Function, Node::Kind::Type,
Node::Kind::DependentGenericType, Node::Kind::Type,
Node::Kind::FunctionType, Node::Kind::AsyncAnnotation});
// Get the ExplicitClosure or Function node.
// For nested closures in Swift, the demangle tree is inverted: the
// inner-most closure is the top-most ExplicitClosure node.
NodePointer func_node = [&] {
if (NodePointer func = childAtPath(node, Node::Kind::Function))
return func;
return childAtPath(node, Node::Kind::ExplicitClosure);
}();

return childAtPath(func_node, {Node::Kind::Type, Node::Kind::FunctionType,
Node::Kind::AsyncAnnotation}) ||
childAtPath(func_node,
{Node::Kind::Type, Node::Kind::DependentGenericType,
Node::Kind::Type, Node::Kind::FunctionType,
Node::Kind::AsyncAnnotation});
}

bool SwiftLanguageRuntime::IsSwiftAsyncFunctionSymbol(StringRef name) {
Expand Down
1 change: 1 addition & 0 deletions lldb/unittests/Symbol/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
set(SWIFT_SOURCES
TestSwiftASTContext.cpp
TestTypeSystemSwiftTypeRef.cpp
TestSwiftDemangler.cpp
)
set(SWIFT_LIBS
lldbPluginTypeSystemSwift
Expand Down
87 changes: 87 additions & 0 deletions lldb/unittests/Symbol/TestSwiftDemangler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
#include "gtest/gtest.h"

#include "Plugins/LanguageRuntime/Swift/SwiftLanguageRuntime.h"

using namespace lldb;
using namespace lldb_private;
using namespace llvm;
static constexpr auto IsSwiftMangledName =
SwiftLanguageRuntime::IsSwiftMangledName;
static constexpr auto IsAnySwiftAsyncFunctionSymbol = [](StringRef name) {
return SwiftLanguageRuntime::IsAnySwiftAsyncFunctionSymbol(name);
};

TEST(TestSwiftDemangleAsyncNames, BasicAsync) {
// "sayBasic" == a basic async function
// "sayGeneric" == a generic async function
SmallVector<StringRef> basic_funclets = {
"$s1a8sayBasicyySSYaF",
"$s1a8sayBasicyySSYaFTY0_",
"$s1a8sayBasicyySSYaFTQ1_",
"$s1a8sayBasicyySSYaFTY2_",
};
SmallVector<StringRef> generic_funclets = {
"$s1a10sayGenericyyxYalF",
"$s1a10sayGenericyyxYalFTY0_",
"$s1a10sayGenericyyxYalFTQ1_",
"$s1a10sayGenericyyxYalFTY2_",
};
for (StringRef async_name :
llvm::concat<StringRef>(basic_funclets, generic_funclets)) {
EXPECT_TRUE(IsSwiftMangledName(async_name)) << async_name;
EXPECT_TRUE(IsAnySwiftAsyncFunctionSymbol(async_name)) << async_name;
}
}

TEST(TestSwiftDemangleAsyncNames, ClosureAsync) {
// These are all async closures
SmallVector<StringRef> nested1_funclets = {
// Nesting level 1: a closure inside a function.
"$s1a8sayHelloyyYaFyypYacfU_", "$s1a8sayHelloyyYaFyypYacfU_TY0_",
"$s1a8sayHelloyyYaFyypYacfU_TQ1_", "$s1a8sayHelloyyYaFyypYacfU_TY2_",
"$s1a8sayHelloyyYaFyypYacfU_TQ3_", "$s1a8sayHelloyyYaFyypYacfU_TY4_",
"$s1a8sayHelloyyYaFyypYacfU_TQ5_", "$s1a8sayHelloyyYaFyypYacfU_TY6_"};
SmallVector<StringRef> nested2_funclets1 = {
// Nesting level 2: a closure inside a closure.
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU_TY0_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU_TQ1_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU_TY2_",
};
SmallVector<StringRef> nested2_funclets2 = {
// Nesting level 2: another closure, same level as the previous one.
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU0_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU0_TY0_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU0_TQ1_",
"$s1a8sayHelloyyYaFyypYacfU_yypYacfU0_TY2_",
};
SmallVector<StringRef> nested2_funclets_top_not_async = {
// Also nesting level 2: but this time, the top level function is _not_
// async!
"$s1a18myNonAsyncFunctionyyFyyYacfU_SiypYacfU_SSypYacfU0_",
"$s1a18myNonAsyncFunctionyyFyyYacfU_SiypYacfU_SSypYacfU0_TY0_",
"$s1a18myNonAsyncFunctionyyFyyYacfU_SiypYacfU_SSypYacfU0_TQ1_",
"$s1a18myNonAsyncFunctionyyFyyYacfU_SiypYacfU_SSypYacfU0_TY2_"};

for (StringRef async_name : llvm::concat<StringRef>(
nested1_funclets, nested2_funclets1, nested2_funclets2,
nested2_funclets_top_not_async)) {
EXPECT_TRUE(IsSwiftMangledName(async_name)) << async_name;
EXPECT_TRUE(IsAnySwiftAsyncFunctionSymbol(async_name)) << async_name;
}
}

TEST(TestSwiftDemangleAsyncNames, StaticAsync) {
// static async functions
SmallVector<StringRef> async_names = {
"$s1a6StructV9sayStaticyySSYaFZ"
"$s1a6StructV9sayStaticyySSYaFZTY0_",
"$s1a6StructV9sayStaticyySSYaFZTQ1_",
"$s1a6StructV9sayStaticyySSYaFZTY2_",
};

for (StringRef async_name : async_names) {
EXPECT_TRUE(IsSwiftMangledName(async_name)) << async_name;
EXPECT_TRUE(IsAnySwiftAsyncFunctionSymbol(async_name)) << async_name;
}
}