From e5f563a71069461ef92a6ef98f732a9859ef1ecb Mon Sep 17 00:00:00 2001 From: littleGnAl Date: Mon, 20 Nov 2023 20:02:30 +0800 Subject: [PATCH] feat: [cxx-parser] ParseResult.resolveNodeByType extension --- .../unit_test/cxx_parser_ext.test.ts | 166 ++++++++++++++++++ cxx-parser/src/cxx_parser_ext.ts | 79 ++++++++- cxx-parser/src/cxx_terra_node_ext.ts | 17 -- tsconfig.json | 2 +- 4 files changed, 245 insertions(+), 19 deletions(-) create mode 100644 cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts diff --git a/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts b/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts new file mode 100644 index 0000000..f888f66 --- /dev/null +++ b/cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts @@ -0,0 +1,166 @@ +import '../../src/cxx_parser_ext'; +import { ParseResult } from '@agoraio-extensions/terra-core'; + +import { + Clazz, + Enumz, + SimpleType, + SimpleTypeKind, + Struct, +} from '../../src/cxx_terra_node'; + +describe('ParseResult', () => { + describe('resolveNodeByType', () => { + it('can find Clazz when the SimpleType ref to a class', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.pointer_t; + simpleType.name = 'A::B::MyClass'; + simpleType.source = 'MyClass*'; + + const clazz = new Clazz(); + clazz.name = 'MyClass'; + clazz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [clazz], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(clazz); + }); + + it('can find Struct when the SimpleType ref to a struct', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.pointer_t; + simpleType.name = 'A::B::MyStruct'; + simpleType.source = 'MyStruct*'; + + const struct = new Struct(); + struct.name = 'MyStruct'; + struct.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [struct], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(struct); + }); + + it('can find Enum, when the SimpleType ref to a enum', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.pointer_t; + simpleType.name = 'A::B::MyEnum'; + simpleType.source = 'MyEnum*'; + + const enumz = new Enumz(); + enumz.name = 'MyEnum'; + enumz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [enumz], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(enumz); + }); + + it('return type if it is built-in type', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.value_t; + simpleType.name = 'int'; + simpleType.source = 'int'; + + const returnType = parseResult.resolveNodeByType(simpleType); + expect(returnType).toBe(simpleType); + }); + + it('can find Clazz when the SimpleType is template_t and template_arguments ref to a class', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.template_t; + simpleType.name = 'TemplateType'; + simpleType.source = 'TemplateType'; + simpleType.template_arguments = ['A::B::MyClass']; + + const clazz = new Clazz(); + clazz.name = 'MyClass'; + clazz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [clazz], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(clazz); + }); + + it('can find Struct when the SimpleType is template_t and template_arguments ref to a struct', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.template_t; + simpleType.name = 'TemplateType'; + simpleType.source = 'TemplateType'; + simpleType.template_arguments = ['A::B::MyStruct']; + + const struct = new Struct(); + struct.name = 'MyStruct'; + struct.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [struct], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(struct); + }); + + it('can find Enum, when the SimpleType is template_t and template_arguments ref to a enum', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.template_t; + simpleType.name = 'TemplateType'; + simpleType.source = 'TemplateType'; + simpleType.template_arguments = ['A::B::MyEnum']; + + const enumz = new Enumz(); + enumz.name = 'MyEnum'; + enumz.namespaces = ['A', 'B']; + + parseResult.nodes = [ + { + nodes: [enumz], + }, + ]; + + const node = parseResult.resolveNodeByType(simpleType); + expect(node).toBe(enumz); + }); + + it('return type if the SimpleType is template_t and template_arguments not ref to any nodes', () => { + let parseResult = new ParseResult(); + const simpleType = new SimpleType(); + simpleType.kind = SimpleTypeKind.template_t; + simpleType.name = 'TemplateType'; + simpleType.source = 'TemplateType'; + simpleType.template_arguments = ['int']; + + const returnType = parseResult.resolveNodeByType(simpleType); + expect(returnType).toBe(simpleType); + }); + }); +}); diff --git a/cxx-parser/src/cxx_parser_ext.ts b/cxx-parser/src/cxx_parser_ext.ts index dd1b876..543cead 100644 --- a/cxx-parser/src/cxx_parser_ext.ts +++ b/cxx-parser/src/cxx_parser_ext.ts @@ -1,6 +1,16 @@ +import './cxx_terra_node_string_ext'; + import { ParseResult } from '@agoraio-extensions/terra-core'; -import { CXXFile, CXXTYPE, Clazz, Enumz } from './cxx_terra_node'; +import { + CXXFile, + CXXTYPE, + CXXTerraNode, + Clazz, + Enumz, + SimpleType, + SimpleTypeKind, +} from './cxx_terra_node'; export {}; @@ -8,13 +18,23 @@ declare module '@agoraio-extensions/terra-core' { export interface ParseResult { /** * Find a `Clazz` by its name. + * @deprecated Use `resolveNodeByType` instead. */ findClazz(clazzName: string): Clazz | undefined; /** * Find a `Enumz` by its name. + * @deprecated Use `resolveNodeByType` instead. */ findEnumz(enumzName: string): Enumz | undefined; + + /** + * Resolves a `CXXTerraNode` based on the given `SimpleType`. If none is found, the `SimpleType` is returned. + * + * @param type - The `SimpleType` to resolve. + * @returns The resolved `CXXTerraNode`. + */ + resolveNodeByType(type: SimpleType): CXXTerraNode; } } @@ -88,3 +108,60 @@ ParseResult.prototype.findEnumz = function ( return undefined; }; + +/** + * Resolves a `CXXTerraNode` based on the given `SimpleType`. If none is found, the `SimpleType` is returned. + * + * @param type - The `SimpleType` to resolve. + * @returns The resolved `CXXTerraNode`. + */ +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; + } + + if (type.is_builtin_type) { + return type; + } + + if ( + type.kind == SimpleTypeKind.template_t && + type.template_arguments.length + ) { + // Only support the first template argument at this time + name = type.template_arguments[0]; + } + + const namespaceInString = name.getNamespace(); + const nameWithoutNS = name.trimNamespace(); + + 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 (found) { + return node; + } + } + } + } + + return type; +}; diff --git a/cxx-parser/src/cxx_terra_node_ext.ts b/cxx-parser/src/cxx_terra_node_ext.ts index 98161c3..a80cf44 100644 --- a/cxx-parser/src/cxx_terra_node_ext.ts +++ b/cxx-parser/src/cxx_terra_node_ext.ts @@ -4,23 +4,6 @@ import { SimpleType, SimpleTypeKind } from './cxx_terra_node'; export {}; -declare global { - export interface String { - /** - * This function removes the namespace from a fully qualified name. - * For example, "foo::bar" becomes "bar". - */ - trimNamespace(): string; - - /** - * Returns the namespace of the class name. - * - * Example: "std::vector::size_type" returns "std::vector" - */ - getNamespace(): string; - } -} - declare module '@agoraio-extensions/cxx-parser' { export interface SimpleType { /** diff --git a/tsconfig.json b/tsconfig.json index b7b7b78..9f2b01d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "es6", + "target": "es2021", "module": "commonjs", "strict": true, "sourceMap": true,