From 4b6415fac1e7007dd1b123ae9078b5535938f099 Mon Sep 17 00:00:00 2001 From: yp9522 Date: Tue, 5 Aug 2025 14:09:16 +0800 Subject: [PATCH 1/2] Lsp supports arkts mixed scene jumping Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICR7HR Signed-off-by: yp9522 --- ets2panda/bindings/native/src/lsp.cpp | 72 ++++++++++ .../src/common/Es2pandaNativeModule.ts | 104 ++++++++++++++ ets2panda/bindings/src/common/types.ts | 31 +++- ets2panda/bindings/src/lsp/lsp_helper.ts | 45 +++++- ets2panda/lsp/include/api.h | 9 ++ ets2panda/lsp/include/get_node.h | 9 ++ ets2panda/lsp/src/api.cpp | 54 +++++++ ets2panda/lsp/src/get_node.cpp | 136 ++++++++++++++++++ ets2panda/test/unit/lsp/CMakeLists.txt | 11 ++ .../test/unit/lsp/get_node_interface_test.cpp | 114 +++++++++++++++ .../lsp/get_node_member_expression_test.cpp | 92 ++++++++++++ ets2panda/test/unit/lsp/get_node_test.cpp | 70 ++++++++- .../unit/lsp/get_node_type_namespace_test.cpp | 129 +++++++++++++++++ 13 files changed, 870 insertions(+), 6 deletions(-) create mode 100755 ets2panda/test/unit/lsp/get_node_interface_test.cpp create mode 100755 ets2panda/test/unit/lsp/get_node_member_expression_test.cpp create mode 100755 ets2panda/test/unit/lsp/get_node_type_namespace_test.cpp diff --git a/ets2panda/bindings/native/src/lsp.cpp b/ets2panda/bindings/native/src/lsp.cpp index f1b1468bba..c8d3e54300 100644 --- a/ets2panda/bindings/native/src/lsp.cpp +++ b/ets2panda/bindings/native/src/lsp.cpp @@ -1817,6 +1817,22 @@ KNativePointer impl_getClassDefinition(KNativePointer astNodePtr, KStringPtr &no } TS_INTEROP_2(getClassDefinition, KNativePointer, KNativePointer, KStringPtr) +KNativePointer impl_getClassProperty(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getClassProperty(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getClassProperty, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getProperty(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getProperty(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getProperty, KNativePointer, KNativePointer, KStringPtr) + KNativePointer impl_getIdentifier(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) { auto ast = reinterpret_cast(astNodePtr); @@ -1859,6 +1875,38 @@ KNativePointer impl_getKindByNodeInfo(KNativePointer nodeInfo) } TS_INTEROP_1(getKindByNodeInfo, KNativePointer, KNativePointer) +KNativePointer impl_getMethodDefinition(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getMethodDefinition(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getMethodDefinition, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getTsEnumDeclaration(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getTsEnumDeclaration(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getTsEnumDeclaration, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getTsEnumMember(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getTsEnumMember(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getTsEnumMember, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getMemberExpression(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getMemberExpression(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getMemberExpression, KNativePointer, KNativePointer, KStringPtr) + KNativePointer impl_getDefinitionDataFromNode(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) { auto ast = reinterpret_cast(astNodePtr); @@ -1887,3 +1935,27 @@ KNativePointer impl_getColAndLineByOffset(KStringPtr &sourceCodePtr, KInt offset return new std::pair(impl->getColAndLineByOffset(sourceCodePtr.Data(), offset)); } TS_INTEROP_2(getColAndLineByOffset, KNativePointer, KStringPtr, KInt) + +KNativePointer impl_getTsInterfaceDeclaration(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getTsInterfaceDeclaration(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getTsInterfaceDeclaration, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getTsModuleDeclaration(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getTsModuleDeclaration(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getTsModuleDeclaration, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getTsTypeAliasDeclaration(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getTsTypeAliasDeclaration(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getTsTypeAliasDeclaration, KNativePointer, KNativePointer, KStringPtr) diff --git a/ets2panda/bindings/src/common/Es2pandaNativeModule.ts b/ets2panda/bindings/src/common/Es2pandaNativeModule.ts index 4b83ee5c55..9d8434a4f4 100644 --- a/ets2panda/bindings/src/common/Es2pandaNativeModule.ts +++ b/ets2panda/bindings/src/common/Es2pandaNativeModule.ts @@ -1025,6 +1025,110 @@ export class Es2pandaNativeModule { _getIdentifier(astNode: KPtr, nodeName: String): KPtr { throw new Error('Not implemented'); } + + _getMemberExpression(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getCallExpression(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getNewExpression(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getSuperExpression(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsTypeReference(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getFunctionDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getVariableDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getVariableDeclarator(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getMethodDefinition(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getClassProperty(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getProperty(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getImportDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getImportSpecifier(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getImportDefaultSpecifier(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getImportNamespaceSpecifier(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getExportAllDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getExportDefaultDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getExportNamedDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getExportSpecifier(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsModuleDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsInterfaceDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsTypeAliasDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsEnumDeclaration(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsEnumMember(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsFunctionType(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } + + _getTsClassImplements(astNode: KPtr, nodeName: String): KPtr { + throw new Error('Not implemented'); + } } export function initEs2panda(): Es2pandaNativeModule { diff --git a/ets2panda/bindings/src/common/types.ts b/ets2panda/bindings/src/common/types.ts index 48a339bea6..3a62d9b778 100644 --- a/ets2panda/bindings/src/common/types.ts +++ b/ets2panda/bindings/src/common/types.ts @@ -234,7 +234,36 @@ export interface TextDocumentChangeInfo { export enum AstNodeType { UNKNOWN, IDENTIFIER, - CLASS_DEFINITION + MEMBER_EXPRESSION, + CALL_EXPRESSION, + NEW_EXPRESSION, + SUPER_EXPRESSION, + TS_TYPE_REFERENCE, + // 语句 + CLASS_DEFINITION, + FUNCTION_DECLARATION, + VARIABLE_DECLARATION, + VARIABLE_DECLARATOR, + METHOD_DEFINITION, + CLASS_PROPERTY, + PROPERTY, + // 导入导出(import/export)待确认是否需要? + IMPORT_DECLARATION, + IMPORT_SPECIFIER, + IMPORT_DEFAULT_SPECIFIER, + IMPORT_NAMESPACE_SPECIFIER, + EXPORT_ALL_DECLARATION, + EXPORT_DEFAULT_DECLARATION, + EXPORT_NAMED_DECLARATION, + EXPORT_SPECIFIER, + TS_MODULE_DECLARATION, + // 类型定义 + TS_INTERFACE_DECLARATION, + TS_TYPE_ALIAS_DECLARATION, + TS_ENUM_DECLARATION, + TS_ENUM_MEMBER, + TS_FUNCTION_TYPE, + TS_CLASS_IMPLEMENTS, } export interface NodeInfo { name: string; diff --git a/ets2panda/bindings/src/lsp/lsp_helper.ts b/ets2panda/bindings/src/lsp/lsp_helper.ts index af1ddb06c9..5aa15f89cf 100644 --- a/ets2panda/bindings/src/lsp/lsp_helper.ts +++ b/ets2panda/bindings/src/lsp/lsp_helper.ts @@ -110,6 +110,7 @@ export class Lsp { private pathConfig: PathConfig; private lspDriverHelper = new LspDriverHelper(); private declFileMap: Record = {}; // Map + private typeAliasMap: Partial KPointer>> = {}; constructor(pathConfig: PathConfig, getContentCallback?: (filePath: string) => string, modules?: ModuleDescriptor[]) { initBuildEnv(); @@ -131,6 +132,8 @@ export class Lsp { this.defaultBuildConfig = Object.values(this.buildConfigs)[0]; PluginDriver.getInstance().initPlugins(this.defaultBuildConfig); this.initDeclFile(); + // 创建节点类型映射 + this.initTypeAliasMap(); } // Partially update for new file @@ -241,6 +244,39 @@ export class Lsp { } } + private initTypeAliasMap(): void { + this.typeAliasMap = { + [AstNodeType.IDENTIFIER]: global.es2panda._getIdentifier, + [AstNodeType.MEMBER_EXPRESSION]: global.es2panda._getMemberExpression, + [AstNodeType.CALL_EXPRESSION]: global.es2panda._getCallExpression, + [AstNodeType.NEW_EXPRESSION]: global.es2panda._getNewExpression, + [AstNodeType.SUPER_EXPRESSION]: global.es2panda._getSuperExpression, + [AstNodeType.TS_TYPE_REFERENCE]: global.es2panda._getTsTypeReference, + [AstNodeType.CLASS_DEFINITION]: global.es2panda._getClassDefinition, + [AstNodeType.FUNCTION_DECLARATION]: global.es2panda._getFunctionDeclaration, + [AstNodeType.VARIABLE_DECLARATION]: global.es2panda._getVariableDeclaration, + [AstNodeType.VARIABLE_DECLARATOR]: global.es2panda._getVariableDeclarator, + [AstNodeType.METHOD_DEFINITION]: global.es2panda._getMethodDefinition, + [AstNodeType.CLASS_PROPERTY]: global.es2panda._getClassProperty, + [AstNodeType.PROPERTY]: global.es2panda._getProperty, + [AstNodeType.IMPORT_DECLARATION]: global.es2panda._getImportDeclaration, + [AstNodeType.IMPORT_SPECIFIER]: global.es2panda._getImportSpecifier, + [AstNodeType.IMPORT_DEFAULT_SPECIFIER]: global.es2panda._getImportDefaultSpecifier, + [AstNodeType.IMPORT_NAMESPACE_SPECIFIER]: global.es2panda._getImportNamespaceSpecifier, + [AstNodeType.EXPORT_ALL_DECLARATION]: global.es2panda._getExportAllDeclaration, + [AstNodeType.EXPORT_DEFAULT_DECLARATION]: global.es2panda._getExportDefaultDeclaration, + [AstNodeType.EXPORT_NAMED_DECLARATION]: global.es2panda._getExportNamedDeclaration, + [AstNodeType.EXPORT_SPECIFIER]: global.es2panda._getExportSpecifier, + [AstNodeType.TS_MODULE_DECLARATION]: global.es2panda._getTsModuleDeclaration, + [AstNodeType.TS_INTERFACE_DECLARATION]: global.es2panda._getTsInterfaceDeclaration, + [AstNodeType.TS_TYPE_ALIAS_DECLARATION]: global.es2panda._getTsTypeAliasDeclaration, + [AstNodeType.TS_ENUM_DECLARATION]: global.es2panda._getTsEnumDeclaration, + [AstNodeType.TS_ENUM_MEMBER]: global.es2panda._getTsEnumMember, + [AstNodeType.TS_FUNCTION_TYPE]: global.es2panda._getTsFunctionType, + [AstNodeType.TS_CLASS_IMPLEMENTS]: global.es2panda._getTsClassImplements, + }; + } + updateDeclFile(filePath: string): void { if (!Object.prototype.hasOwnProperty.call(this.moduleInfos, filePath)) { return; @@ -296,10 +332,11 @@ export class Lsp { try { nodeInfos.forEach((nodeInfo) => { currentNodeName = nodeInfo.name; - if (nodeInfo.kind === AstNodeType.CLASS_DEFINITION) { - astNode = global.es2panda._getClassDefinition(astNode, currentNodeName); - } else if (nodeInfo.kind === AstNodeType.IDENTIFIER) { - astNode = global.es2panda._getIdentifier(astNode, currentNodeName); + const handler = this.typeAliasMap[nodeInfo.kind]; + if (handler) { + astNode = handler(astNode, currentNodeName); + } else { + console.warn(`No handler found for node type: ${nodeInfo.kind}`); } }); } finally { diff --git a/ets2panda/lsp/include/api.h b/ets2panda/lsp/include/api.h index ae40a5db5b..abe5e46356 100644 --- a/ets2panda/lsp/include/api.h +++ b/ets2panda/lsp/include/api.h @@ -563,7 +563,16 @@ typedef struct LSPAPI { es2panda_AstNode *(*getProgramAst)(es2panda_Context *context); std::vector (*getNodeInfosByDefinitionData)(es2panda_Context *context, size_t position); es2panda_AstNode *(*getClassDefinition)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getClassProperty)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getProperty)(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *(*getIdentifier)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getMethodDefinition)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getTsEnumDeclaration)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getTsEnumMember)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getTsInterfaceDeclaration)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getTsTypeAliasDeclaration)(es2panda_AstNode *astNode, const std::string &nodeType); + es2panda_AstNode *(*getTsModuleDeclaration)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getMemberExpression)(es2panda_AstNode *astNode, const std::string &nodeName); DefinitionInfo (*getDefinitionDataFromNode)(es2panda_AstNode *astNode, const std::string &nodeName); } LSPAPI; CAPI_EXPORT LSPAPI const *GetImpl(); diff --git a/ets2panda/lsp/include/get_node.h b/ets2panda/lsp/include/get_node.h index b2c63afacb..e3d6a1a237 100644 --- a/ets2panda/lsp/include/get_node.h +++ b/ets2panda/lsp/include/get_node.h @@ -22,6 +22,15 @@ namespace ark::es2panda::lsp { es2panda_AstNode *GetProgramAstImpl(es2panda_Context *context); es2panda_AstNode *GetClassDefinitionImpl(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *GetIdentifierImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetMethodDefinitionImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetTsEnumDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetTsEnumMemberImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetTsInterfaceDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetTsTypeAliasDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeType); +es2panda_AstNode *GetTsModuleDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetMemberExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetClassPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName); } // namespace ark::es2panda::lsp #endif \ No newline at end of file diff --git a/ets2panda/lsp/src/api.cpp b/ets2panda/lsp/src/api.cpp index 12f2d1905a..d2b6d4627f 100644 --- a/ets2panda/lsp/src/api.cpp +++ b/ets2panda/lsp/src/api.cpp @@ -508,11 +508,56 @@ es2panda_AstNode *GetClassDefinition(es2panda_AstNode *astNode, const std::strin return GetClassDefinitionImpl(astNode, nodeName); } +es2panda_AstNode *GetClassProperty(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetClassPropertyImpl(astNode, nodeName); +} + +es2panda_AstNode *GetProperty(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetPropertyImpl(astNode, nodeName); +} + es2panda_AstNode *GetIdentifier(es2panda_AstNode *astNode, const std::string &nodeName) { return GetIdentifierImpl(astNode, nodeName); } +es2panda_AstNode *GetMethodDefinition(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetMethodDefinitionImpl(astNode, nodeName); +} + +es2panda_AstNode *GetTsEnumDeclaration(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetTsEnumDeclarationImpl(astNode, nodeName); +} + +es2panda_AstNode *GetTsEnumMember(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetTsEnumMemberImpl(astNode, nodeName); +} + +es2panda_AstNode *GetTsInterfaceDeclaration(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetTsInterfaceDeclarationImpl(astNode, nodeName); +} + +es2panda_AstNode *GetTsTypeAliasDeclaration(es2panda_AstNode *astNode, const std::string &nodeType) +{ + return GetTsTypeAliasDeclarationImpl(astNode, nodeType); +} + +es2panda_AstNode *GetTsModuleDeclaration(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetTsModuleDeclarationImpl(astNode, nodeName); +} + +es2panda_AstNode *GetMemberExpression(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetMemberExpressionImpl(astNode, nodeName); +} + DefinitionInfo GetDefinitionDataFromNode(es2panda_AstNode *astNode, const std::string &nodeName) { DefinitionInfo result; @@ -586,7 +631,16 @@ LSPAPI g_lspImpl = {GetDefinitionAtPosition, GetProgramAst, GetNodeInfosByDefinitionData, GetClassDefinition, + GetClassProperty, + GetProperty, GetIdentifier, + GetMethodDefinition, + GetTsEnumDeclaration, + GetTsEnumMember, + GetTsInterfaceDeclaration, + GetTsTypeAliasDeclaration, + GetTsModuleDeclaration, + GetMemberExpression, GetDefinitionDataFromNode}; } // namespace ark::es2panda::lsp diff --git a/ets2panda/lsp/src/get_node.cpp b/ets2panda/lsp/src/get_node.cpp index fa9ea5fea6..d00c70fc5d 100644 --- a/ets2panda/lsp/src/get_node.cpp +++ b/ets2panda/lsp/src/get_node.cpp @@ -40,6 +40,31 @@ es2panda_AstNode *GetClassDefinitionImpl(es2panda_AstNode *astNode, const std::s return reinterpret_cast(targetNode); } +es2panda_AstNode *GetClassPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsClassProperty() && std::string(childNode->AsClassProperty()->Id()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsProperty() && + std::string(childNode->AsProperty()->Key()->AsIdentifier()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + es2panda_AstNode *GetIdentifierImpl(es2panda_AstNode *astNode, const std::string &nodeName) { if (astNode == nullptr) { @@ -52,4 +77,115 @@ es2panda_AstNode *GetIdentifierImpl(es2panda_AstNode *astNode, const std::string return reinterpret_cast(targetNode); } +es2panda_AstNode *GetMethodDefinitionImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsMethodDefinition() && + std::string(childNode->AsMethodDefinition()->Function()->Id()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetTsEnumDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsTSEnumDeclaration() && + std::string(childNode->AsTSEnumDeclaration()->Key()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetTsEnumMemberImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsTSEnumMember() && + std::string(childNode->AsTSEnumMember()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetTsInterfaceDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsTSInterfaceDeclaration() && + std::string(childNode->AsTSInterfaceDeclaration()->Id()->Name()) == nodeName; + }); + + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetTsTypeAliasDeclarationImpl(es2panda_AstNode *astNode, const std::string &typeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&typeName](ir::AstNode *childNode) { + return childNode->IsTSTypeAliasDeclaration() && + std::string(childNode->AsTSTypeAliasDeclaration()->Id()->Name()) == typeName; + }); + return reinterpret_cast(targetNode); +} + +es2panda_AstNode *GetTsModuleDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsTSModuleDeclaration() && + std::string(childNode->AsTSModuleDeclaration()->AsIdentifier()->Name()) == nodeName; + }); + return reinterpret_cast(targetNode); +} + +bool findMenberExpression(ir::AstNode *childNode, const std::string &nodeName) +{ + if (childNode->IsMemberExpression()) { + auto memberExpr = childNode->AsMemberExpression(); + + std::string propertyName = memberExpr->Property()->ToString(); + if (propertyName != nodeName) { + return false; + } + if (memberExpr->HasMemberKind(ir::MemberExpressionKind::PROPERTY_ACCESS)) { + return true; + } + if (memberExpr->HasMemberKind(ir::MemberExpressionKind::ELEMENT_ACCESS)) { + return true; + } + return false; + } + return false; +} + +es2panda_AstNode *GetMemberExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName) +{ + if (astNode == nullptr) { + return nullptr; + } + auto ast = reinterpret_cast(astNode); + auto targetNode = + ast->FindChild([&nodeName](ir::AstNode *childNode) { return findMenberExpression(childNode, nodeName); }); + return reinterpret_cast(targetNode); +} } // namespace ark::es2panda::lsp \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/CMakeLists.txt b/ets2panda/test/unit/lsp/CMakeLists.txt index c2fef459b4..5ead62e468 100644 --- a/ets2panda/test/unit/lsp/CMakeLists.txt +++ b/ets2panda/test/unit/lsp/CMakeLists.txt @@ -317,7 +317,18 @@ ets2panda_add_gtest(lsp_api_get_definition_from_node_test CPP_SOURCES get_definition_from_node_test.cpp ) +ets2panda_add_gtest(lsp_api_get_node_member_expression_test CPP_SOURCES + get_node_member_expression_test.cpp +) ets2panda_add_gtest(lsp_api_test_constructor_for_derived_need_super_call CPP_SOURCES constructor_for_derived_need_super_call_test.cpp +) + +ets2panda_add_gtest(lsp_api_get_node_interface_test CPP_SOURCES + get_node_interface_test.cpp +) + +ets2panda_add_gtest(lsp_api_get_node_type_namespace_test CPP_SOURCES + get_node_type_namespace_test.cpp ) \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/get_node_interface_test.cpp b/ets2panda/test/unit/lsp/get_node_interface_test.cpp new file mode 100755 index 0000000000..373dbe9327 --- /dev/null +++ b/ets2panda/test/unit/lsp/get_node_interface_test.cpp @@ -0,0 +1,114 @@ +/** + * Copyright (c) 2025 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 "ir/astNode.h" +#include "lsp/include/api.h" +#include "lsp_api_test.h" +#include "public/es2panda_lib.h" +#include "public/public.h" +#include + +namespace { +using ark::es2panda::lsp::Initializer; + +class LspGetNodeInterfaceTests : public LSPAPITests { +protected: + static void SetUpTestSuite() + { + initializer_ = new Initializer(); + GenerateContexts(*initializer_); + } + + static void TearDownTestSuite() + { + initializer_->DestroyContext(contexts_); + delete initializer_; + initializer_ = nullptr; + } + static void GenerateContexts(Initializer &initializer) + { + contexts_ = initializer.CreateContext("GetNodeInterfaceTest.ets", ES2PANDA_STATE_CHECKED, R"(namespace a { + interface User { + bar(): void; + } + namespace b { + interface Client extends a.User {} + } +} +interface Worker extends a.User {})"); + } + // NOLINTBEGIN(fuchsia-statically-constructed-objects, cert-err58-cpp) + static inline es2panda_Context *contexts_ = nullptr; + static inline Initializer *initializer_ = nullptr; + // NOLINTEND(fuchsia-statically-constructed-objects, cert-err58-cpp) +}; + +TEST_F(LspGetNodeInterfaceTests, GetTsInterfaceDeclarationNonExistentTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string interfaceName = "NonExistentInterface"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsInterfaceDeclaration(node, interfaceName); + ASSERT_TRUE(res == nullptr); +} + +TEST_F(LspGetNodeInterfaceTests, GetTsInterfaceDeclarationTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string interfaceName = "User"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsInterfaceDeclaration(node, interfaceName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSInterfaceDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSInterfaceDeclaration()->Id()->Name(), + interfaceName.data()); +} + +TEST_F(LspGetNodeInterfaceTests, GetTsInterfaceDeclarationExtendsTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string interfaceName = "Client"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsInterfaceDeclaration(node, interfaceName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSInterfaceDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSInterfaceDeclaration()->Id()->Name(), + interfaceName.data()); +} + +TEST_F(LspGetNodeInterfaceTests, GetTsInterfaceDeclarationExtendsTest1) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string interfaceName = "Worker"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsInterfaceDeclaration(node, interfaceName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSInterfaceDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSInterfaceDeclaration()->Id()->Name(), + interfaceName.data()); +} +} // namespace \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/get_node_member_expression_test.cpp b/ets2panda/test/unit/lsp/get_node_member_expression_test.cpp new file mode 100755 index 0000000000..43ece39de3 --- /dev/null +++ b/ets2panda/test/unit/lsp/get_node_member_expression_test.cpp @@ -0,0 +1,92 @@ +/** + * Copyright (c) 2025 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 "ir/astNode.h" +#include "lsp/include/api.h" +#include "lsp_api_test.h" +#include "public/es2panda_lib.h" +#include "public/public.h" +#include + +namespace { +using ark::es2panda::lsp::Initializer; + +class LspGetNodeMemberExpressionTests : public LSPAPITests {}; + +TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_PROPERTY_ACCESS) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +class Foo { + bar() {} +} +let foo = new Foo(); +foo.bar(); +)"; + es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + auto ctx = reinterpret_cast(contexts); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "bar"; + auto res = lspApi->getMemberExpression(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsMemberExpression()); + ASSERT_EQ(reinterpret_cast(res)->AsMemberExpression()->Property()->ToString(), + nodeName.data()); + initializer.DestroyContext(contexts); +} + +TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_ELEMENT_ACCESS) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +let obj: Record = { + prop: "value" +}; +let propName = "prop"; +obj[propName]; +)"; + es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + auto ctx = reinterpret_cast(contexts); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "propName"; + auto res = lspApi->getMemberExpression(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsMemberExpression()); + ASSERT_EQ(reinterpret_cast(res)->AsMemberExpression()->Property()->ToString(), + nodeName.data()); + initializer.DestroyContext(contexts); +} + +TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_NotFound) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +class Foo { + bar() {} +} +let foo = new Foo(); +foo.bar(); +)"; + es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + auto ctx = reinterpret_cast(contexts); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "nonexistent"; + auto res = lspApi->getMemberExpression(reinterpret_cast(ast), nodeName); + ASSERT_EQ(res, nullptr); + initializer.DestroyContext(contexts); +} + +} // namespace \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/get_node_test.cpp b/ets2panda/test/unit/lsp/get_node_test.cpp index 140f44ff22..f0111501fb 100644 --- a/ets2panda/test/unit/lsp/get_node_test.cpp +++ b/ets2panda/test/unit/lsp/get_node_test.cpp @@ -41,7 +41,17 @@ protected: { contexts_ = initializer.CreateContext("GetNodeTest.ets", ES2PANDA_STATE_CHECKED, R"(class Foo { Foo = 1; -})"); + bar() {} + enum Color { + Red, + Green, + Blue + }; +} + +const obj = { + prop: "value" +};)"); } // NOLINTBEGIN(fuchsia-statically-constructed-objects, cert-err58-cpp) static inline es2panda_Context *contexts_ = nullptr; @@ -70,6 +80,29 @@ TEST_F(LspGetNodeTests, GetClassDefinition1) nodeName.data()); } +TEST_F(LspGetNodeTests, GetClassProperty1) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "Foo"; + auto res = lspApi->getClassProperty(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsClassProperty()); + ASSERT_EQ(reinterpret_cast(res)->AsClassProperty()->Id()->Name(), nodeName.data()); +} + +TEST_F(LspGetNodeTests, GetProperty) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "prop"; + auto res = lspApi->getProperty(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsProperty()); + ASSERT_EQ(reinterpret_cast(res)->AsProperty()->Key()->AsIdentifier()->Name(), + nodeName.data()); +} + TEST_F(LspGetNodeTests, GetIdentifier1) { auto ctx = reinterpret_cast(contexts_); @@ -81,4 +114,39 @@ TEST_F(LspGetNodeTests, GetIdentifier1) ASSERT_EQ(reinterpret_cast(res)->AsIdentifier()->Name(), nodeName.data()); } +TEST_F(LspGetNodeTests, GetMethodDefinition1) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "bar"; + auto res = lspApi->getMethodDefinition(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsMethodDefinition()); + ASSERT_EQ(reinterpret_cast(res)->AsMethodDefinition()->Function()->Id()->Name(), + nodeName.data()); +} + +TEST_F(LspGetNodeTests, GetTsEnumDeclaration) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string enumName = "Color"; + auto res = lspApi->getTsEnumDeclaration(reinterpret_cast(ast), enumName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSEnumDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSEnumDeclaration()->Key()->Name(), + enumName.data()); +} + +TEST_F(LspGetNodeTests, GetTsEnumMember) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string memberName = "Red"; + auto res = lspApi->getTsEnumMember(reinterpret_cast(ast), memberName); + ASSERT_TRUE(reinterpret_cast(res)->IsTSEnumMember()); + ASSERT_EQ(reinterpret_cast(res)->AsTSEnumMember()->Name(), memberName.data()); +} } // namespace \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/get_node_type_namespace_test.cpp b/ets2panda/test/unit/lsp/get_node_type_namespace_test.cpp new file mode 100755 index 0000000000..2851cbf693 --- /dev/null +++ b/ets2panda/test/unit/lsp/get_node_type_namespace_test.cpp @@ -0,0 +1,129 @@ +/** + * Copyright (c) 2025 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 "ir/astNode.h" +#include "lsp/include/api.h" +#include "lsp_api_test.h" +#include "public/es2panda_lib.h" +#include "public/public.h" +#include + +namespace { +using ark::es2panda::lsp::Initializer; + +class LspGetNodeTypNamespaceTests : public LSPAPITests { +protected: + static void SetUpTestSuite() + { + initializer_ = new Initializer(); + GenerateContexts(*initializer_); + } + + static void TearDownTestSuite() + { + initializer_->DestroyContext(contexts_); + delete initializer_; + initializer_ = nullptr; + } + static void GenerateContexts(Initializer &initializer) + { + contexts_ = initializer.CreateContext("GetNodeInterfaceTest.ets", ES2PANDA_STATE_CHECKED, R"(type ID = string | number; +type Status = "active" | "inactive" | "pending"; +type List = T[]; +namespace Models { + namespace Utils { + type Formatter = (input: T) => string; + } +})"); + } + // NOLINTBEGIN(fuchsia-statically-constructed-objects, cert-err58-cpp) + static inline es2panda_Context *contexts_ = nullptr; + static inline Initializer *initializer_ = nullptr; + // NOLINTEND(fuchsia-statically-constructed-objects, cert-err58-cpp) +}; + +TEST_F(LspGetNodeTypNamespaceTests, GetTsTypeDeclarationNonExistentTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "NonExistentTypeDeclaration"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsTypeAliasDeclaration(node, nodeName); + ASSERT_TRUE(res == nullptr); +} + +TEST_F(LspGetNodeTypNamespaceTests, GetTsTypeDeclarationIDTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "ID"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsTypeAliasDeclaration(node, nodeName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSTypeAliasDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSTypeAliasDeclaration()->Id()->Name(), + nodeName.data()); +} + +TEST_F(LspGetNodeTypNamespaceTests, GetTsTypeDeclarationStatusTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "Status"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsTypeAliasDeclaration(node, nodeName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSTypeAliasDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSTypeAliasDeclaration()->Id()->Name(), + nodeName.data()); +} + +TEST_F(LspGetNodeTypNamespaceTests, GetTsTypeDeclarationGenericTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "List"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsTypeAliasDeclaration(node, nodeName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSTypeAliasDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSTypeAliasDeclaration()->Id()->Name(), + nodeName.data()); +} + +TEST_F(LspGetNodeTypNamespaceTests, GetTsTypeDeclarationChildTest) +{ + auto ctx = reinterpret_cast(contexts_); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "Formatter"; + auto node = reinterpret_cast(ast); + ASSERT_TRUE(node != nullptr); + auto res = lspApi->getTsTypeAliasDeclaration(node, nodeName); + ASSERT_TRUE(res != nullptr); + ASSERT_TRUE(reinterpret_cast(res)->IsTSTypeAliasDeclaration()); + ASSERT_EQ(reinterpret_cast(res)->AsTSTypeAliasDeclaration()->Id()->Name(), + nodeName.data()); +} + +} // namespace \ No newline at end of file -- Gitee From c3f10bfc8096d8ecb4ed0e025ee02c0348f773cd Mon Sep 17 00:00:00 2001 From: yp9522 Date: Mon, 11 Aug 2025 16:39:41 +0800 Subject: [PATCH 2/2] Lsp supports arkts mixed scene jumping Issue: https://gitee.com/openharmony/arkcompiler_ets_frontend/issues/ICSDWQ Signed-off-by: yp9522 --- ets2panda/bindings/native/src/lsp.cpp | 16 ++++ ets2panda/lsp/include/api.h | 2 + ets2panda/lsp/include/get_node.h | 1 + ets2panda/lsp/src/api.cpp | 12 +++ ets2panda/lsp/src/get_node.cpp | 40 ++++----- ets2panda/test/unit/lsp/CMakeLists.txt | 4 +- ..._test.cpp => get_node_expression_test.cpp} | 81 +++++++++++++++++-- 7 files changed, 128 insertions(+), 28 deletions(-) rename ets2panda/test/unit/lsp/{get_node_member_expression_test.cpp => get_node_expression_test.cpp} (50%) diff --git a/ets2panda/bindings/native/src/lsp.cpp b/ets2panda/bindings/native/src/lsp.cpp index c8d3e54300..88264d2da8 100644 --- a/ets2panda/bindings/native/src/lsp.cpp +++ b/ets2panda/bindings/native/src/lsp.cpp @@ -1907,6 +1907,22 @@ KNativePointer impl_getMemberExpression(KNativePointer astNodePtr, KStringPtr &n } TS_INTEROP_2(getMemberExpression, KNativePointer, KNativePointer, KStringPtr) +KNativePointer impl_getCallExpression(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getCallExpression(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getCallExpression, KNativePointer, KNativePointer, KStringPtr) + +KNativePointer impl_getSuperExpression(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) +{ + auto ast = reinterpret_cast(astNodePtr); + LSPAPI const *impl = GetImpl(); + return impl->getSuperExpression(ast, nodeNamePtr.data()); +} +TS_INTEROP_2(getSuperExpression, KNativePointer, KNativePointer, KStringPtr) + KNativePointer impl_getDefinitionDataFromNode(KNativePointer astNodePtr, KStringPtr &nodeNamePtr) { auto ast = reinterpret_cast(astNodePtr); diff --git a/ets2panda/lsp/include/api.h b/ets2panda/lsp/include/api.h index abe5e46356..1aa2c4c3a5 100644 --- a/ets2panda/lsp/include/api.h +++ b/ets2panda/lsp/include/api.h @@ -573,6 +573,8 @@ typedef struct LSPAPI { es2panda_AstNode *(*getTsTypeAliasDeclaration)(es2panda_AstNode *astNode, const std::string &nodeType); es2panda_AstNode *(*getTsModuleDeclaration)(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *(*getMemberExpression)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getCallExpression)(es2panda_AstNode *astNode, const std::string &nodeName); + es2panda_AstNode *(*getSuperExpression)(es2panda_AstNode *astNode, const std::string &nodeName); DefinitionInfo (*getDefinitionDataFromNode)(es2panda_AstNode *astNode, const std::string &nodeName); } LSPAPI; CAPI_EXPORT LSPAPI const *GetImpl(); diff --git a/ets2panda/lsp/include/get_node.h b/ets2panda/lsp/include/get_node.h index e3d6a1a237..61dd611d9d 100644 --- a/ets2panda/lsp/include/get_node.h +++ b/ets2panda/lsp/include/get_node.h @@ -29,6 +29,7 @@ es2panda_AstNode *GetTsInterfaceDeclarationImpl(es2panda_AstNode *astNode, const es2panda_AstNode *GetTsTypeAliasDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeType); es2panda_AstNode *GetTsModuleDeclarationImpl(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *GetMemberExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName); +es2panda_AstNode *GetInvocationExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *GetClassPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName); es2panda_AstNode *GetPropertyImpl(es2panda_AstNode *astNode, const std::string &nodeName); } // namespace ark::es2panda::lsp diff --git a/ets2panda/lsp/src/api.cpp b/ets2panda/lsp/src/api.cpp index d2b6d4627f..07496e1a9c 100644 --- a/ets2panda/lsp/src/api.cpp +++ b/ets2panda/lsp/src/api.cpp @@ -558,6 +558,16 @@ es2panda_AstNode *GetMemberExpression(es2panda_AstNode *astNode, const std::stri return GetMemberExpressionImpl(astNode, nodeName); } +es2panda_AstNode *GetCallExpression(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetInvocationExpressionImpl(astNode, nodeName); +} + +es2panda_AstNode *GetSpuerExpression(es2panda_AstNode *astNode, const std::string &nodeName) +{ + return GetInvocationExpressionImpl(astNode, nodeName); +} + DefinitionInfo GetDefinitionDataFromNode(es2panda_AstNode *astNode, const std::string &nodeName) { DefinitionInfo result; @@ -641,6 +651,8 @@ LSPAPI g_lspImpl = {GetDefinitionAtPosition, GetTsTypeAliasDeclaration, GetTsModuleDeclaration, GetMemberExpression, + GetCallExpression, + GetSpuerExpression, GetDefinitionDataFromNode}; } // namespace ark::es2panda::lsp diff --git a/ets2panda/lsp/src/get_node.cpp b/ets2panda/lsp/src/get_node.cpp index d00c70fc5d..ced718eb31 100644 --- a/ets2panda/lsp/src/get_node.cpp +++ b/ets2panda/lsp/src/get_node.cpp @@ -158,34 +158,36 @@ es2panda_AstNode *GetTsModuleDeclarationImpl(es2panda_AstNode *astNode, const st return reinterpret_cast(targetNode); } -bool findMenberExpression(ir::AstNode *childNode, const std::string &nodeName) +es2panda_AstNode *GetMemberExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName) { - if (childNode->IsMemberExpression()) { - auto memberExpr = childNode->AsMemberExpression(); - - std::string propertyName = memberExpr->Property()->ToString(); - if (propertyName != nodeName) { - return false; - } - if (memberExpr->HasMemberKind(ir::MemberExpressionKind::PROPERTY_ACCESS)) { - return true; - } - if (memberExpr->HasMemberKind(ir::MemberExpressionKind::ELEMENT_ACCESS)) { - return true; - } - return false; + if (astNode == nullptr) { + return nullptr; } - return false; + auto ast = reinterpret_cast(astNode); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + return childNode->IsMemberExpression() && childNode->AsMemberExpression()->Property()->ToString() == nodeName; + }); + return reinterpret_cast(targetNode); } -es2panda_AstNode *GetMemberExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName) +es2panda_AstNode *GetInvocationExpressionImpl(es2panda_AstNode *astNode, const std::string &nodeName) { if (astNode == nullptr) { return nullptr; } auto ast = reinterpret_cast(astNode); - auto targetNode = - ast->FindChild([&nodeName](ir::AstNode *childNode) { return findMenberExpression(childNode, nodeName); }); + auto targetNode = ast->FindChild([&nodeName](ir::AstNode *childNode) { + if (childNode->IsCallExpression()) { + auto callExpr = childNode->AsCallExpression(); + auto callee = callExpr->Callee(); + if (callee->IsSuperExpression() && nodeName == "super") { + std::cout << "Found super() call" << std::endl; + return true; + } + } + return false; + }); + return reinterpret_cast(targetNode); } } // namespace ark::es2panda::lsp \ No newline at end of file diff --git a/ets2panda/test/unit/lsp/CMakeLists.txt b/ets2panda/test/unit/lsp/CMakeLists.txt index 5ead62e468..95130374dc 100644 --- a/ets2panda/test/unit/lsp/CMakeLists.txt +++ b/ets2panda/test/unit/lsp/CMakeLists.txt @@ -317,8 +317,8 @@ ets2panda_add_gtest(lsp_api_get_definition_from_node_test CPP_SOURCES get_definition_from_node_test.cpp ) -ets2panda_add_gtest(lsp_api_get_node_member_expression_test CPP_SOURCES - get_node_member_expression_test.cpp +ets2panda_add_gtest(lsp_api_get_node_expression_test CPP_SOURCES + get_node_expression_test.cpp ) ets2panda_add_gtest(lsp_api_test_constructor_for_derived_need_super_call CPP_SOURCES diff --git a/ets2panda/test/unit/lsp/get_node_member_expression_test.cpp b/ets2panda/test/unit/lsp/get_node_expression_test.cpp similarity index 50% rename from ets2panda/test/unit/lsp/get_node_member_expression_test.cpp rename to ets2panda/test/unit/lsp/get_node_expression_test.cpp index 43ece39de3..9b62ed31ba 100755 --- a/ets2panda/test/unit/lsp/get_node_member_expression_test.cpp +++ b/ets2panda/test/unit/lsp/get_node_expression_test.cpp @@ -23,9 +23,9 @@ namespace { using ark::es2panda::lsp::Initializer; -class LspGetNodeMemberExpressionTests : public LSPAPITests {}; +class LspGetNodeExpressionTests : public LSPAPITests {}; -TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_PROPERTY_ACCESS) +TEST_F(LspGetNodeExpressionTests, GetMemberExpression_PROPERTY_ACCESS) { ark::es2panda::lsp::Initializer initializer; const std::string sourceCode = R"( @@ -35,7 +35,8 @@ class Foo { let foo = new Foo(); foo.bar(); )"; - es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + es2panda_Context *contexts = + initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); auto ctx = reinterpret_cast(contexts); auto ast = ctx->parserProgram->Ast(); LSPAPI const *lspApi = GetImpl(); @@ -47,7 +48,7 @@ foo.bar(); initializer.DestroyContext(contexts); } -TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_ELEMENT_ACCESS) +TEST_F(LspGetNodeExpressionTests, GetMemberExpression_ELEMENT_ACCESS) { ark::es2panda::lsp::Initializer initializer; const std::string sourceCode = R"( @@ -57,7 +58,8 @@ let obj: Record = { let propName = "prop"; obj[propName]; )"; - es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + es2panda_Context *contexts = + initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); auto ctx = reinterpret_cast(contexts); auto ast = ctx->parserProgram->Ast(); LSPAPI const *lspApi = GetImpl(); @@ -69,7 +71,7 @@ obj[propName]; initializer.DestroyContext(contexts); } -TEST_F(LspGetNodeMemberExpressionTests, GetMemberExpression_NotFound) +TEST_F(LspGetNodeExpressionTests, GetMemberExpression_NotFound) { ark::es2panda::lsp::Initializer initializer; const std::string sourceCode = R"( @@ -79,7 +81,8 @@ class Foo { let foo = new Foo(); foo.bar(); )"; - es2panda_Context *contexts = initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + es2panda_Context *contexts = + initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); auto ctx = reinterpret_cast(contexts); auto ast = ctx->parserProgram->Ast(); LSPAPI const *lspApi = GetImpl(); @@ -89,4 +92,68 @@ foo.bar(); initializer.DestroyContext(contexts); } +TEST_F(LspGetNodeExpressionTests, GetCallExpression_SpuerExpression) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +class Parent { + name: string; + + constructor(name: string) { + this.name = name; + } +} + +class Child extends Parent { + age: number; + + constructor(name: string, age: number) { + super(name); + this.age = age; + } +} +)"; + es2panda_Context *contexts = + initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + auto ctx = reinterpret_cast(contexts); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "super"; + auto res = lspApi->getSuperExpression(reinterpret_cast(ast), nodeName); + ASSERT_TRUE(reinterpret_cast(res)->IsCallExpression()); + ASSERT_TRUE(reinterpret_cast(res)->AsCallExpression()->Callee()->IsSuperExpression()); + initializer.DestroyContext(contexts); +} + +TEST_F(LspGetNodeExpressionTests, GetSuperExpression_NotFound) +{ + ark::es2panda::lsp::Initializer initializer; + const std::string sourceCode = R"( +class Parent { + name: string; + + constructor(name: string) { + this.name = name; + } +} + +class Child extends Parent { + age: number; + + constructor(name: string, age: number) { + super(name); + this.age = age; + } +} +)"; + es2panda_Context *contexts = + initializer.CreateContext("GetExpression.ets", ES2PANDA_STATE_CHECKED, sourceCode.c_str()); + auto ctx = reinterpret_cast(contexts); + auto ast = ctx->parserProgram->Ast(); + LSPAPI const *lspApi = GetImpl(); + const std::string nodeName = "nonexistent"; + auto res = lspApi->getSuperExpression(reinterpret_cast(ast), nodeName); + ASSERT_EQ(res, nullptr); + initializer.DestroyContext(contexts); +} } // namespace \ No newline at end of file -- Gitee