• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024-2025 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 ts from 'ohos-typescript';
17import { ArkField, FieldCategory } from '../ArkField';
18import Logger, { LOG_MODULE_TYPE } from '../../../utils/logger';
19import { ArkClass } from '../ArkClass';
20import { ArkMethod } from '../ArkMethod';
21import { buildDecorators, buildGenericType, buildModifiers, handlePropertyAccessExpression, tsNode2Type } from './builderUtils';
22import { FieldSignature } from '../ArkSignature';
23import { ClassType, Type, UnknownType } from '../../base/Type';
24import { LineColPosition } from '../../base/Position';
25import { ModifierType } from '../ArkBaseModel';
26import { IRUtils } from '../../common/IRUtils';
27
28const logger = Logger.getLogger(LOG_MODULE_TYPE.ARKANALYZER, 'ArkFieldBuilder');
29
30export type PropertyLike = ts.PropertyDeclaration | ts.PropertyAssignment;
31
32export function buildProperty2ArkField(
33    member: ts.PropertyDeclaration | ts.PropertyAssignment | ts.ShorthandPropertyAssignment | ts.SpreadAssignment | ts.PropertySignature | ts.EnumMember,
34    sourceFile: ts.SourceFile,
35    cls: ArkClass
36): ArkField {
37    let field = new ArkField();
38    field.setCategory(mapSyntaxKindToFieldOriginType(member.kind) as FieldCategory);
39    field.setCode(member.getText(sourceFile));
40    field.setDeclaringArkClass(cls);
41    field.setOriginPosition(LineColPosition.buildFromNode(member, sourceFile));
42
43    let fieldName = member.getText(sourceFile);
44    if (member.name && ts.isComputedPropertyName(member.name)) {
45        if (ts.isIdentifier(member.name.expression)) {
46            fieldName = member.name.expression.text;
47        } else if (ts.isPropertyAccessExpression(member.name.expression)) {
48            fieldName = handlePropertyAccessExpression(member.name.expression);
49        } else {
50            logger.warn(`Other property expression type found: ${member.name.expression.getText()}!`);
51        }
52    } else if (member.name && (ts.isIdentifier(member.name) || ts.isLiteralExpression(member.name))) {
53        fieldName = member.name.text;
54    } else if (member.name && ts.isPrivateIdentifier(member.name)) {
55        let propertyName = member.name.text;
56        fieldName = propertyName.substring(1);
57        field.addModifier(ModifierType.PRIVATE);
58    } else {
59        logger.warn(`Other type of property name found: ${member.getText()}!`);
60    }
61
62    let fieldType: Type = UnknownType.getInstance();
63    if (ts.isPropertyDeclaration(member) || ts.isPropertySignature(member)) {
64        if (member.modifiers) {
65            field.addModifier(buildModifiers(member));
66        }
67        field.addModifier(0);
68        field.setDecorators(buildDecorators(member, sourceFile));
69        field.setQuestionToken(member.questionToken !== undefined);
70
71        if (member.type) {
72            fieldType = buildGenericType(tsNode2Type(member.type, sourceFile, cls), field);
73        }
74    }
75
76    if (ts.isEnumMember(member)) {
77        field.addModifier(ModifierType.STATIC);
78        fieldType = new ClassType(cls.getSignature());
79    }
80    field.setSignature(new FieldSignature(fieldName, cls.getSignature(), fieldType, field.isStatic()));
81
82    if (ts.isPropertyDeclaration(member) && member.exclamationToken) {
83        field.setExclamationToken(true);
84    }
85    IRUtils.setComments(field, member, sourceFile, cls.getDeclaringArkFile().getScene().getOptions());
86    cls.addField(field);
87    return field;
88}
89
90export function buildIndexSignature2ArkField(member: ts.IndexSignatureDeclaration, sourceFile: ts.SourceFile, cls: ArkClass): void {
91    const field = new ArkField();
92    field.setCode(member.getText(sourceFile));
93    field.setCategory(mapSyntaxKindToFieldOriginType(member.kind) as FieldCategory);
94    field.setDeclaringArkClass(cls);
95
96    field.setOriginPosition(LineColPosition.buildFromNode(member, sourceFile));
97
98    if (member.modifiers) {
99        let modifier = buildModifiers(member);
100        field.addModifier(modifier);
101    }
102
103    const fieldName = '[' + member.parameters[0].getText(sourceFile) + ']';
104    const fieldType = buildGenericType(tsNode2Type(member.type, sourceFile, field), field);
105    const fieldSignature = new FieldSignature(fieldName, cls.getSignature(), fieldType, true);
106    field.setSignature(fieldSignature);
107    IRUtils.setComments(field, member, sourceFile, cls.getDeclaringArkFile().getScene().getOptions());
108    cls.addField(field);
109}
110
111export function buildGetAccessor2ArkField(member: ts.GetAccessorDeclaration, mthd: ArkMethod, sourceFile: ts.SourceFile): void {
112    let cls = mthd.getDeclaringArkClass();
113    let field = new ArkField();
114    field.setDeclaringArkClass(cls);
115
116    field.setCode(member.getText(sourceFile));
117    field.setCategory(mapSyntaxKindToFieldOriginType(member.kind) as FieldCategory);
118    field.setOriginPosition(LineColPosition.buildFromNode(member, sourceFile));
119
120    let fieldName = member.getText(sourceFile);
121    if (ts.isIdentifier(member.name) || ts.isLiteralExpression(member.name)) {
122        fieldName = member.name.text;
123    } else if (ts.isComputedPropertyName(member.name)) {
124        if (ts.isIdentifier(member.name.expression)) {
125            let propertyName = member.name.expression.text;
126            fieldName = propertyName;
127        } else if (ts.isPropertyAccessExpression(member.name.expression)) {
128            fieldName = handlePropertyAccessExpression(member.name.expression);
129        } else if (ts.isLiteralExpression(member.name.expression)) {
130            fieldName = member.name.expression.text;
131        } else {
132            logger.warn('Other type of computed property name found!');
133        }
134    } else {
135        logger.warn('Please contact developers to support new type of GetAccessor name!');
136    }
137
138    const fieldType = mthd.getReturnType();
139    const fieldSignature = new FieldSignature(fieldName, cls.getSignature(), fieldType, false);
140    field.setSignature(fieldSignature);
141    cls.addField(field);
142}
143
144function mapSyntaxKindToFieldOriginType(syntaxKind: ts.SyntaxKind): FieldCategory | null {
145    let fieldOriginType: FieldCategory | null = null;
146    switch (syntaxKind) {
147        case ts.SyntaxKind.PropertyDeclaration:
148            fieldOriginType = FieldCategory.PROPERTY_DECLARATION;
149            break;
150        case ts.SyntaxKind.PropertyAssignment:
151            fieldOriginType = FieldCategory.PROPERTY_ASSIGNMENT;
152            break;
153        case ts.SyntaxKind.ShorthandPropertyAssignment:
154            fieldOriginType = FieldCategory.SHORT_HAND_PROPERTY_ASSIGNMENT;
155            break;
156        case ts.SyntaxKind.SpreadAssignment:
157            fieldOriginType = FieldCategory.SPREAD_ASSIGNMENT;
158            break;
159        case ts.SyntaxKind.PropertySignature:
160            fieldOriginType = FieldCategory.PROPERTY_SIGNATURE;
161            break;
162        case ts.SyntaxKind.EnumMember:
163            fieldOriginType = FieldCategory.ENUM_MEMBER;
164            break;
165        case ts.SyntaxKind.IndexSignature:
166            fieldOriginType = FieldCategory.INDEX_SIGNATURE;
167            break;
168        case ts.SyntaxKind.GetAccessor:
169            fieldOriginType = FieldCategory.GET_ACCESSOR;
170            break;
171        default:
172    }
173    return fieldOriginType;
174}
175