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