From bafe206558dbc1eb719bdcd5cb80d25c204f5991 Mon Sep 17 00:00:00 2001 From: littleGnAl Date: Mon, 8 Jan 2024 14:55:55 +0800 Subject: [PATCH] feat: [cxx-parser] Add resolveNodeByName --- .../unit_test/cxx_parser_ext.test.ts | 136 ++++++++++++++++++ cxx-parser/src/cxx_parser_ext.ts | 44 +++--- 2 files changed, 162 insertions(+), 18 deletions(-) diff --git a/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts b/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts index f888f66..7d413b6 100644 --- a/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts +++ b/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts @@ -32,6 +32,43 @@ describe('ParseResult', () => { expect(node).toBe(clazz); }); + it('can find Clazz with duplicated name, but different namespace', () => { + let parseResult = new ParseResult(); + + const clazz1 = new Clazz(); + clazz1.name = 'MyClass'; + clazz1.namespaces = ['A', 'B']; + + const clazz2 = new Clazz(); + clazz2.name = 'MyClass'; + clazz2.namespaces = ['A', 'B', 'C']; + + parseResult.nodes = [ + { + nodes: [clazz1, clazz2], + }, + ]; + + { + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.pointer_t; + simpleType.name = 'A::B::MyClass'; + simpleType.source = 'MyClass*'; + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(clazz1); + } + + // Can find the second A::B::C::MyClass + { + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.pointer_t; + simpleType.name = 'A::B::C::MyClass'; + simpleType.source = 'MyClass*'; + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(clazz2); + } + }); + it('can find Struct when the SimpleType ref to a struct', () => { let parseResult = new ParseResult(); const simpleType = new SimpleType(); @@ -163,4 +200,103 @@ describe('ParseResult', () => { expect(returnType).toBe(simpleType); }); }); + + describe('resolveNodeByName', () => { + it('can find Clazz with name', () => { + let parseResult = new ParseResult(); + + const clazz = new Clazz(); + clazz.name = 'MyClass'; + clazz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [clazz], + }, + ]; + + const node = parseResult.resolveNodeByName('A::B::MyClass'); + expect(node).toBe(clazz); + }); + + it('can find Clazz with duplicated name, but different namespace', () => { + let parseResult = new ParseResult(); + + const clazz1 = new Clazz(); + clazz1.name = 'MyClass'; + clazz1.namespaces = ['A', 'B']; + + const clazz2 = new Clazz(); + clazz2.name = 'MyClass'; + clazz2.namespaces = ['A', 'B', 'C']; + + parseResult.nodes = [ + { + nodes: [clazz1, clazz2], + }, + ]; + + { + const node = parseResult.resolveNodeByName('A::B::MyClass'); + expect(node).toBe(clazz1); + } + + // Can find the second A::B::C::MyClass + { + const node = parseResult.resolveNodeByName('A::B::C::MyClass'); + expect(node).toBe(clazz2); + } + }); + + it('can find Struct with name', () => { + let parseResult = new ParseResult(); + + const struct = new Struct(); + struct.name = 'MyStruct'; + struct.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [struct], + }, + ]; + + const node = parseResult.resolveNodeByName('A::B::MyStruct'); + expect(node).toBe(struct); + }); + + it('can find Enum with name', () => { + let parseResult = new ParseResult(); + + const enumz = new Enumz(); + enumz.name = 'MyEnum'; + enumz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [enumz], + }, + ]; + + const node = parseResult.resolveNodeByName('A::B::MyEnum'); + expect(node).toBe(enumz); + }); + + it('can not find a node by name', () => { + let parseResult = new ParseResult(); + + const clazz = new Clazz(); + clazz.name = 'MyClass'; + clazz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [clazz], + }, + ]; + + const returnType = parseResult.resolveNodeByName('unknow'); + expect(returnType).toBeUndefined(); + }); + }); }); diff --git a/cxx-parser/src/cxx_parser_ext.ts b/cxx-parser/src/cxx_parser_ext.ts index 543cead..0d6d99f 100644 --- a/cxx-parser/src/cxx_parser_ext.ts +++ b/cxx-parser/src/cxx_parser_ext.ts @@ -35,6 +35,14 @@ declare module '@agoraio-extensions/terra-core' { * @returns The resolved `CXXTerraNode`. */ resolveNodeByType(type: SimpleType): CXXTerraNode; + + /** + * Resolves a `CXXTerraNode` based on the given node's name. If none is found, the undefined is returned. + * + * @param name - The node's name to resolve. + * @returns The resolved `CXXTerraNode`. + */ + resolveNodeByName(name: string): CXXTerraNode | undefined; } } @@ -118,13 +126,6 @@ ParseResult.prototype.findEnumz = function ( ParseResult.prototype.resolveNodeByType = function ( type: SimpleType ): CXXTerraNode { - function _match(ns: string, namespace_string: string): boolean { - return ( - ns == namespace_string || - namespace_string == '' || - ns.includes(namespace_string) - ); - } let name = type.name; if (name.length === 0) { return type; @@ -142,26 +143,33 @@ ParseResult.prototype.resolveNodeByType = function ( name = type.template_arguments[0]; } - const namespaceInString = name.getNamespace(); - const nameWithoutNS = name.trimNamespace(); + return this.resolveNodeByName(name) ?? type; +}; +ParseResult.prototype.resolveNodeByName = function ( + name: string +): CXXTerraNode | undefined { for (const f of this.nodes) { let cxxFile = f as CXXFile; for (const node of cxxFile.nodes) { - if (node.name === nameWithoutNS) { - let ns = node.namespaces.join('::'); - let found = _match(ns, namespaceInString); - if (!found && node.parent_name) { - ns = [...node.namespaces, node.parent_name].join('::'); - found = _match(ns, namespaceInString); - } + if ( + name == node.fullName || + (node.fullName.includes(name) && name.trimNamespace() == node.name) + ) { + return node; + } - if (found) { + if (node.parent_name) { + let tmp = [...node.namespaces, node.parent_name, node.name].join('::'); + if ( + name == tmp || + (tmp.includes(name) && name.trimNamespace() == node.name) + ) { return node; } } } } - return type; + return undefined; };