* Copyright (c) 2025-2026 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string_view>
#include "gtest/gtest.h"
#include "test/utils/asm_test.h"
class NameManglingAsmTest : public ::test::utils::AsmTest {
public:
void CheckUsingFunctionInstanceTable(std::string_view input, std::string_view expectedName)
{
SetCurrentProgram(input);
auto result = GetFunction(expectedName, program_->functionInstanceTable);
ASSERT_NE(result, nullptr);
}
void CheckUsingRecordTable(std::string_view input, std::string_view expectedName)
{
SetCurrentProgram(input);
auto result = GetRecord(expectedName, program_);
ASSERT_NE(result, nullptr);
}
void CheckPropertyUsingRecordTable(std::string_view input, std::string_view expectedRecordName,
[[maybe_unused]] std::string_view expectedPropName)
{
SetCurrentProgram(input);
auto result = GetRecord(expectedRecordName, program_);
ASSERT_NE(result, nullptr);
bool found = false;
for (auto &it : result->fieldList) {
std::string name = expectedRecordName.data() + std::string(".") + it.name;
if (name == expectedPropName) {
found = true;
break;
}
}
ASSERT_NE(found, false);
}
};
TEST_F(NameManglingAsmTest, asyncFunctionNameGen)
{
std::string_view input = R"(
async function TestFunc0() {}
async function TestFunc1(i: int | undefined) {}
async function TestFunc2(i: int | undefined, j: number | undefined) {}
)";
SetCurrentProgram(input);
auto result0 = GetFunction("dummy.ETSGLOBAL.%%async-TestFunc0:std.core.Promise;", program_->functionStaticTable);
ASSERT_NE(result0, nullptr);
auto result1 =
GetFunction("dummy.ETSGLOBAL.%%async-TestFunc1:std.core.Int;std.core.Promise;", program_->functionStaticTable);
ASSERT_NE(result1, nullptr);
auto result2 = GetFunction("dummy.ETSGLOBAL.%%async-TestFunc2:std.core.Int;std.core.Double;std.core.Promise;",
program_->functionStaticTable);
ASSERT_NE(result2, nullptr);
}
TEST_F(NameManglingAsmTest, asyncMethodNameGen)
{
std::string_view input = R"(
class TestClass {
async testMethod0() {}
async testMethod1(i: int | undefined) {}
async testMethod2(i: int | undefined, j: number | undefined) {}
}
)";
CheckUsingFunctionInstanceTable(input, "dummy.TestClass.%%async-testMethod0:std.core.Promise;");
CheckUsingFunctionInstanceTable(input, "dummy.TestClass.%%async-testMethod1:std.core.Int;std.core.Promise;");
CheckUsingFunctionInstanceTable(
input, "dummy.TestClass.%%async-testMethod2:std.core.Int;std.core.Double;std.core.Promise;");
}
TEST_F(NameManglingAsmTest, interfaceGetterNameGen)
{
std::string_view input = R"(
interface TestInterface {
get testMember() : string;
}
)";
std::string_view expectedGeneratedName = "dummy.TestInterface.%%get-testMember:std.core.String;";
CheckUsingFunctionInstanceTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, classGetterNameGen)
{
std::string_view input = R"(
class TestClass {
get testMember(): string {
return "hello world";
}
}
)";
std::string_view expectedGeneratedName = "dummy.TestClass.%%get-testMember:std.core.String;";
CheckUsingFunctionInstanceTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, partialClassNameGen)
{
std::string_view input = R"(
class TestClass {
maybeNullMember: string | undefined = undefined;
}
function testFunc(a0: Partial<TestClass>) {
if (a0.maybeNullMember != undefined) {
console.log("the member is: " + a0.maybeNullMember)
} else {
console.log("all of the members on the argument are null")
}
}
let a: Partial<TestClass> = {}
testFunc(a)
)";
std::string_view expectedGeneratedName = "dummy.%%partial-TestClass";
CheckUsingRecordTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, partialClassFromNamespaceNameGen)
{
std::string_view input = R"(
namespace TestNamespace {
export class ClassInNamespace {
className: String | undefined = undefined;
}
}
function exampleFunc(a0: Partial<TestNamespace.ClassInNamespace>) {
if (a0.className != undefined) {
console.log("className is: " + a0.className)
}
}
let testVar: Partial<TestNamespace.ClassInNamespace> = {
className: "ClassInNamespace"
}
exampleFunc(testVar);
)";
std::string_view expectedGeneratedName = "dummy.TestNamespace.%%partial-ClassInNamespace";
CheckUsingRecordTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, partialInterfaceNameGen)
{
std::string_view input = R"(
interface Book {
title: String;
description: String;
}
function exampleFunc(a0: Partial<Book>) {
if (a0.title != undefined) {
console.log("The title is: " + a0.title);
}
if (a0.description != undefined) {
console.log("The description is: " + a0.description);
}
}
let myBook: Partial<Book> = {
title: "The title",
description: "Some kind of a description"
}
exampleFunc(myBook);
)";
std::string_view expectedGeneratedName = "dummy.%%partial-Book";
CheckUsingRecordTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, partialInterfaceFromNamespaceNameGen)
{
std::string_view input = R"(
namespace TestNamespace {
export interface TestInterface {
title: String
description: String
}
}
function exampleFunc(a0: Partial<TestNamespace.TestInterface>) {
if (a0.title != undefined) {
console.log("title is: " + a0.title)
}
if (a0.description != undefined) {
console.log("description is: " + a0.description)
}
}
let testVar: Partial<TestNamespace.TestInterface> = {
title: "The title",
description: "Some kind of a description"
}
exampleFunc(testVar);
)";
std::string_view expectedGeneratedName = "dummy.TestNamespace.%%partial-TestInterface";
CheckUsingRecordTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, propertyNameGen)
{
std::string_view input = R"(
interface TestInterface {
testMember: String;
}
class TestClass implements TestInterface {
testMember = "Hello world";
}
)";
SetCurrentProgram(input);
std::string_view expectedRecordName = "dummy.TestClass";
std::string_view expectedPropName = "dummy.TestClass.testMember";
CheckPropertyUsingRecordTable(input, expectedRecordName, expectedPropName);
}
TEST_F(NameManglingAsmTest, interfaceSetterNameGen)
{
std::string_view input = R"(
interface TestInterface {
set testMember(a0: String)
}
)";
std::string_view expectedGeneratedName = "dummy.TestInterface.%%set-testMember:std.core.String;void;";
CheckUsingFunctionInstanceTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, classSetterNameGen)
{
std::string_view input = R"(
interface TestClass {
set testMember(a0: String)
}
)";
std::string_view expectedGeneratedName = "dummy.TestClass.%%set-testMember:std.core.String;void;";
CheckUsingFunctionInstanceTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, lambdaNameGen)
{
std::string_view input = R"(
let lambdaFunc = (): void => {}
)";
std::string_view expectedGeneratedName = "dummy.%%lambda-lambda_invoke-0";
CheckUsingRecordTable(input, expectedGeneratedName);
}
TEST_F(NameManglingAsmTest, unionPropMethodNameGen)
{
std::string_view input = R"(
class TestClassA {
propMethod(): void {
console.log("hello world");
}
}
class TestClassB {
propMethod(): void {
console.log("hello world");
}
}
function foo(a0: TestClassA | TestClassB) {
a0.propMethod();
}
let myVar = new TestClassA()
foo(myVar)
)";
std::string_view expectedRecordName = "dummy.%%union_prop-TestClassA|TestClassB";
CheckUsingRecordTable(input, expectedRecordName);
std::string_view expectedMethodName = "dummy.%%union_prop-TestClassA|TestClassB.propMethod:void;";
CheckUsingFunctionInstanceTable(input, expectedMethodName);
}
TEST_F(NameManglingAsmTest, unionPropMemberNameGen)
{
std::string_view input = R"(
class TestClass {
testMethod(): void {
console.log("hello world")
}
}
class TestClassA {
prop = new TestClass()
}
class TestClassB {
prop = new TestClass()
}
function foo(a0: TestClassA | TestClassB) {
let tmpVar = a0.prop
tmpVar.testMethod()
}
let myVar = new TestClassA()
foo(myVar)
)";
std::string_view expectedRecordName = "dummy.%%union_prop-TestClassA|TestClassB";
CheckUsingRecordTable(input, expectedRecordName);
std::string_view expectedPropName = "dummy.%%union_prop-TestClassA|TestClassB.prop";
CheckPropertyUsingRecordTable(input, expectedRecordName, expectedPropName);
}