Skip to content

Commit 40e365a

Browse files
committed
Refactor class accessor checks
1 parent 00d2d4e commit 40e365a

3 files changed

Lines changed: 49 additions & 60 deletions

File tree

src/transformation/transformers/class/creation.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ import {
1414
createSelfIdentifier,
1515
} from "../../utils/lua-ast";
1616
import { importLuaLibFeature, LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib";
17-
import { hasGetAccessorInClassOrAncestor, hasSetAccessorInClassOrAncestor } from "./members/accessors";
17+
import { hasMemberInClassOrAncestor } from "./members/accessors";
1818
import { getExtendedTypeNode, isStaticNode } from "./utils";
1919

2020
export function createClassCreationMethods(
@@ -136,7 +136,7 @@ export function createClassCreationMethods(
136136
createClassPrototype(),
137137
tstl.createStringLiteral("__index")
138138
);
139-
if (hasGetAccessorInClassOrAncestor(context, statement, false)) {
139+
if (hasMemberInClassOrAncestor(context, statement, m => ts.isGetAccessor(m) && !isStaticNode(m))) {
140140
// localClassName.prototype.__index = __TS__Index(localClassName.prototype)
141141
const assignClassPrototypeIndex = tstl.createAssignmentStatement(
142142
classPrototypeIndex,
@@ -168,7 +168,7 @@ export function createClassCreationMethods(
168168
result.push(assignClassPrototypeSetters);
169169
}
170170

171-
if (hasSetAccessorInClassOrAncestor(context, statement, false)) {
171+
if (hasMemberInClassOrAncestor(context, statement, m => ts.isSetAccessor(m) && !isStaticNode(m))) {
172172
// localClassName.prototype.__newindex = __TS__NewIndex(localClassName.prototype)
173173
const classPrototypeNewIndex = tstl.createTableIndexExpression(
174174
createClassPrototype(),
@@ -194,8 +194,16 @@ export function createClassCreationMethods(
194194
);
195195
result.push(assignClassPrototypeConstructor);
196196

197-
const hasStaticGetters = hasGetAccessorInClassOrAncestor(context, statement, true);
198-
const hasStaticSetters = hasSetAccessorInClassOrAncestor(context, statement, true);
197+
const hasStaticGetters = hasMemberInClassOrAncestor(
198+
context,
199+
statement,
200+
m => ts.isGetAccessor(m) && isStaticNode(m)
201+
);
202+
const hasStaticSetters = hasMemberInClassOrAncestor(
203+
context,
204+
statement,
205+
m => ts.isSetAccessor(m) && isStaticNode(m)
206+
);
199207

200208
if (extendsType) {
201209
const extendedTypeNode = getExtendedTypeNode(context, statement);

src/transformation/transformers/class/members/accessors.ts

Lines changed: 36 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,31 +4,43 @@ import { TransformationContext } from "../../../context";
44
import { createSelfIdentifier } from "../../../utils/lua-ast";
55
import { transformFunctionBody, transformParameters } from "../../function";
66
import { transformIdentifier } from "../../identifier";
7-
import { findInClassOrAncestor, isStaticNode } from "../utils";
7+
import { getExtendedType, isStaticNode } from "../utils";
88

9-
export function hasSetAccessorInClassOrAncestor(
9+
// TODO: Inline to `hasMemberInClassOrAncestor`?
10+
function* classWithAncestors(
1011
context: TransformationContext,
11-
classDeclaration: ts.ClassLikeDeclarationBase,
12-
isStatic: boolean
13-
): boolean {
14-
return (
15-
findInClassOrAncestor(context, classDeclaration, c =>
16-
c.members.some(m => ts.isSetAccessor(m) && isStaticNode(m) === isStatic)
17-
) !== undefined
18-
);
12+
classDeclaration: ts.ClassLikeDeclarationBase
13+
): Generator<ts.ClassLikeDeclarationBase> {
14+
yield classDeclaration;
15+
16+
const extendsType = getExtendedType(context, classDeclaration);
17+
if (!extendsType) {
18+
return false;
19+
}
20+
21+
const symbol = extendsType.getSymbol();
22+
if (symbol === undefined) {
23+
return false;
24+
}
25+
26+
const symbolDeclarations = symbol.getDeclarations();
27+
if (symbolDeclarations === undefined) {
28+
return false;
29+
}
30+
31+
const declaration = symbolDeclarations.find(ts.isClassLike);
32+
if (!declaration) {
33+
return false;
34+
}
35+
36+
yield* classWithAncestors(context, declaration);
1937
}
2038

21-
export function hasGetAccessorInClassOrAncestor(
39+
export const hasMemberInClassOrAncestor = (
2240
context: TransformationContext,
2341
classDeclaration: ts.ClassLikeDeclarationBase,
24-
isStatic: boolean
25-
): boolean {
26-
return (
27-
findInClassOrAncestor(context, classDeclaration, c =>
28-
c.members.some(m => ts.isGetAccessor(m) && isStaticNode(m) === isStatic)
29-
) !== undefined
30-
);
31-
}
42+
callback: (m: ts.ClassElement) => boolean
43+
) => [...classWithAncestors(context, classDeclaration)].some(c => c.members.some(callback));
3244

3345
function getPropertyName(propertyName: ts.PropertyName): string | number | undefined {
3446
if (ts.isIdentifier(propertyName) || ts.isStringLiteral(propertyName) || ts.isNumericLiteral(propertyName)) {
@@ -53,10 +65,11 @@ export function isGetAccessorOverride(
5365
return false;
5466
}
5567

56-
const hasInitializedField = (e: ts.ClassElement) =>
57-
ts.isPropertyDeclaration(e) && e.initializer !== undefined && isSamePropertyName(e.name, element.name);
58-
59-
return findInClassOrAncestor(context, classDeclaration, c => c.members.some(hasInitializedField)) !== undefined;
68+
return hasMemberInClassOrAncestor(
69+
context,
70+
classDeclaration,
71+
m => ts.isPropertyDeclaration(m) && m.initializer !== undefined && isSamePropertyName(m.name, element.name)
72+
);
6073
}
6174

6275
export function transformAccessorDeclaration(

src/transformation/transformers/class/utils.ts

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,3 @@ export function getExtendedType(
3030
const extendedTypeNode = getExtendedTypeNode(context, node);
3131
return extendedTypeNode && context.checker.getTypeAtLocation(extendedTypeNode);
3232
}
33-
34-
export function findInClassOrAncestor(
35-
context: TransformationContext,
36-
classDeclaration: ts.ClassLikeDeclarationBase,
37-
callback: (classDeclaration: ts.ClassLikeDeclarationBase) => boolean
38-
): ts.ClassLikeDeclarationBase | undefined {
39-
if (callback(classDeclaration)) {
40-
return classDeclaration;
41-
}
42-
43-
const extendsType = getExtendedType(context, classDeclaration);
44-
if (!extendsType) {
45-
return undefined;
46-
}
47-
48-
const symbol = extendsType.getSymbol();
49-
if (symbol === undefined) {
50-
return undefined;
51-
}
52-
53-
const symbolDeclarations = symbol.getDeclarations();
54-
if (symbolDeclarations === undefined) {
55-
return undefined;
56-
}
57-
58-
const declaration = symbolDeclarations.find(ts.isClassLike);
59-
if (!declaration) {
60-
return undefined;
61-
}
62-
63-
return findInClassOrAncestor(context, declaration, callback);
64-
}

0 commit comments

Comments
 (0)