idlize
105 строк · 3.5 Кб
1/*
2* Copyright (c) 2022-2023 Huawei Device Co., Ltd.
3* Licensed under the Apache License, Version 2.0 (the "License");
4* you may not use this file except in compliance with the License.
5* You may obtain a copy of the License at
6*
7* http://www.apache.org/licenses/LICENSE-2.0
8*
9* Unless required by applicable law or agreed to in writing, software
10* distributed under the License is distributed on an "AS IS" BASIS,
11* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12* See the License for the specific language governing permissions and
13* limitations under the License.
14*/
15
16import * as ts from 'ohos-typescript'
17import { AbstractVisitor } from "./AbstractVisitor"
18import { asString, CallTable, isBuilder, isGlobalBuilder, prependMemoComment } from './utils'
19import { Void, getDeclarationsByNode, prependComment } from './ApiUtils'
20
21
22export class CustomBuilderTransformer extends AbstractVisitor {
23
24public globalFunctions: string[] = []
25
26constructor(
27sourceFile: ts.SourceFile,
28ctx: ts.TransformationContext,
29private typechecker: ts.TypeChecker,
30private callTable: CallTable
31) {
32super(sourceFile, ctx)
33}
34
35refersToGlobalBuilder(call: ts.CallExpression): boolean {
36const originalCall = ts.getOriginalNode(call) as ts.CallExpression
37return this.callTable.globalBuilderCalls.has(originalCall)
38}
39
40refersToBuilderMethod(callee: ts.Expression): boolean {
41if (ts.isPropertyAccessExpression(callee)) {
42const declarations = getDeclarationsByNode(this.typechecker, callee.name)
43if (declarations.length == 0) return false
44const firstDeclaration = declarations[0]
45if (ts.isMethodDeclaration(firstDeclaration) &&
46isBuilder(firstDeclaration)
47) return true
48}
49return false
50}
51
52isBuilderCall(node: ts.CallExpression): boolean {
53const callee = node.expression
54return this.refersToBuilderMethod(callee) ||
55this.refersToGlobalBuilder(node)
56}
57
58parentIsStatement(node: ts.CallExpression) {
59const original = ts.getOriginalNode(node)
60return (ts.isExpressionStatement(original.parent) || !original.parent)
61}
62
63private wrapInMemoLambda(node: ts.CallExpression): ts.Expression {
64const lambda = ts.factory.createArrowFunction(
65undefined,
66undefined,
67[],
68Void(),
69ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
70node
71)
72return prependMemoComment(
73// This is an expression so make sure memo is a separate line
74prependComment(lambda, " ")
75)
76}
77
78private wrapPropertyInMemoLambdaCall(node: ts.PropertyAccessExpression): ts.Expression {
79const lambda = ts.factory.createArrowFunction(
80undefined,
81undefined,
82[],
83undefined,
84ts.factory.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
85ts.factory.createCallExpression(node, undefined, undefined)
86)
87return prependMemoComment(
88// This is an expression so make sure memo is a separate line
89prependComment(lambda, " ")
90)
91}
92
93visitor(beforeChildren: ts.Node): ts.Node {
94const node = this.visitEachChild(beforeChildren)
95
96if (ts.isCallExpression(node) &&
97this.isBuilderCall(node) &&
98!this.parentIsStatement(node)
99) {
100return this.wrapInMemoLambda(node)
101}
102
103return node
104}
105}
106