Skip to content
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

feat: [cxx-parser] Add resolveNodeByName #48

Merged
merged 1 commit into from
Jan 8, 2024
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
136 changes: 136 additions & 0 deletions cxx-parser/__tests__/unit_test/cxx_parser_ext.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
});
});
});
44 changes: 26 additions & 18 deletions cxx-parser/src/cxx_parser_ext.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand Down Expand Up @@ -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;
Expand All @@ -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;
};
Loading