1/* 2 * Copyright (c) 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 * as path from 'path'; 17import { PluginTestContext, PluginTester } from '../../../utils/plugin-tester'; 18import { BuildConfig, mockBuildConfig } from '../../../utils/artkts-config'; 19import { getRootPath, MOCK_ENTRY_DIR_PATH } from '../../../utils/path-config'; 20import { parseDumpSrc } from '../../../utils/parse-string'; 21import { memoNoRecheck } from '../../../utils/plugins'; 22 23const METHOD_DIR_PATH: string = 'memo/methods'; 24 25const buildConfig: BuildConfig = mockBuildConfig(); 26buildConfig.compileFiles = [path.resolve(getRootPath(), MOCK_ENTRY_DIR_PATH, METHOD_DIR_PATH, 'internal-calls.ets')]; 27 28const pluginTester = new PluginTester('test memo method', buildConfig); 29 30const expectedScript: string = ` 31import { memo as memo, __memo_context_type as __memo_context_type, __memo_id_type as __memo_id_type } from \"@ohos.arkui.stateManagement\"; 32function main() {} 33function __context(): __memo_context_type 34function __id(): __memo_id_type 35type MemoType = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type)=> void); 36class Test { 37 public void_method(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { 38 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 0); 39 if (__memo_scope.unchanged) { 40 __memo_scope.cached; 41 return; 42 } 43 { 44 __memo_scope.recache(); 45 return; 46 } 47 } 48 public internal_call(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { 49 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 0); 50 if (__memo_scope.unchanged) { 51 __memo_scope.cached; 52 return; 53 } 54 this.void_method(__memo_context, ((__memo_id) + (<some_random_number>))); 55 { 56 __memo_scope.recache(); 57 return; 58 } 59 } 60 public method_with_internals(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { 61 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 0); 62 if (__memo_scope.unchanged) { 63 __memo_scope.cached; 64 return; 65 } 66 __context(); 67 __id(); 68 { 69 __memo_scope.recache(); 70 return; 71 } 72 } 73 public memo_lambda() { 74 @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): void => { 75 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 0); 76 if (__memo_scope.unchanged) { 77 __memo_scope.cached; 78 return; 79 } 80 { 81 __memo_scope.recache(); 82 return; 83 } 84 }); 85 } 86 public memo_variables(__memo_context: __memo_context_type, __memo_id: __memo_id_type): void { 87 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 0); 88 if (__memo_scope.unchanged) { 89 __memo_scope.cached; 90 return; 91 } 92 @memo() const f = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { 93 const __memo_scope = __memo_context.scope<number>(((__memo_id) + (<some_random_number>)), 0); 94 if (__memo_scope.unchanged) { 95 return __memo_scope.cached; 96 } 97 return __memo_scope.recache(123); 98 }), g = ((__memo_context: __memo_context_type, __memo_id: __memo_id_type, x: number): number => { 99 const __memo_scope = __memo_context.scope<number>(((__memo_id) + (<some_random_number>)), 1); 100 const __memo_parameter_x = __memo_scope.param(0, x); 101 if (__memo_scope.unchanged) { 102 return __memo_scope.cached; 103 } 104 return __memo_scope.recache(((123) + (__memo_parameter_x.value))); 105 }); 106 const h = @memo() ((__memo_context: __memo_context_type, __memo_id: __memo_id_type): number => { 107 const __memo_scope = __memo_context.scope<number>(((__memo_id) + (<some_random_number>)), 0); 108 if (__memo_scope.unchanged) { 109 return __memo_scope.cached; 110 } 111 return __memo_scope.recache(1); 112 }); 113 f(__memo_context, ((__memo_id) + (<some_random_number>))); 114 g(__memo_context, ((__memo_id) + (<some_random_number>)), 1); 115 h(__memo_context, ((__memo_id) + (<some_random_number>))); 116 { 117 __memo_scope.recache(); 118 return; 119 } 120 } 121 @functions.OptionalParametersAnnotation({minArgCount:0}) public args_with_default_values(__memo_context: __memo_context_type, __memo_id: __memo_id_type, gensym%%_1?: int, gensym%%_2?: (()=> int), gensym%%_3?: int, arg4?: int): void { 122 let arg1: int = (((gensym%%_1) !== (undefined)) ? gensym%%_1 : (10 as int)); 123 let arg2: (()=> int) = (((gensym%%_2) !== (undefined)) ? gensym%%_2 : ((() => { 124 return 20; 125 }) as (()=> int))); 126 let arg3: int = (((gensym%%_3) !== (undefined)) ? gensym%%_3 : (arg1 as int)); 127 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 4); 128 const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2), __memo_parameter_arg3 = __memo_scope.param(2, arg3), __memo_parameter_arg4 = __memo_scope.param(3, arg4); 129 if (__memo_scope.unchanged) { 130 __memo_scope.cached; 131 return; 132 } 133 console.log(__memo_parameter_arg1.value, __memo_parameter_arg2.value, __memo_parameter_arg3.value, __memo_parameter_arg4.value); 134 console.log(__memo_parameter_arg2.value()); 135 { 136 __memo_scope.recache(); 137 return; 138 } 139 } 140 @functions.OptionalParametersAnnotation({minArgCount:0}) public optional_args(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg1?: int, arg2?: (()=> int)): void { 141 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 2); 142 const __memo_parameter_arg1 = __memo_scope.param(0, arg1), __memo_parameter_arg2 = __memo_scope.param(1, arg2); 143 if (__memo_scope.unchanged) { 144 __memo_scope.cached; 145 return; 146 } 147 console.log(__memo_parameter_arg1.value); 148 console.log(__memo_parameter_arg2.value); 149 console.log(({let gensym%%_166 = __memo_parameter_arg2.value; 150 (((gensym%%_166) == (null)) ? undefined : gensym%%_166())})); 151 { 152 __memo_scope.recache(); 153 return; 154 } 155 } 156 public type_alias(__memo_context: __memo_context_type, __memo_id: __memo_id_type, arg: MemoType): void { 157 const __memo_scope = __memo_context.scope<void>(((__memo_id) + (<some_random_number>)), 1); 158 const __memo_parameter_arg = __memo_scope.param(0, arg); 159 if (__memo_scope.unchanged) { 160 __memo_scope.cached; 161 return; 162 } 163 __memo_parameter_arg.value(__memo_context, ((__memo_id) + (<some_random_number>))); 164 { 165 __memo_scope.recache(); 166 return; 167 } 168 } 169 public constructor() {} 170} 171`; 172 173function testMemoTransformer(this: PluginTestContext): void { 174 expect(parseDumpSrc(this.scriptSnapshot ?? '')).toBe(parseDumpSrc(expectedScript)); 175} 176 177pluginTester.run( 178 'transform inner calls in methods', 179 [memoNoRecheck], 180 { 181 'checked:memo-no-recheck': [testMemoTransformer], 182 }, 183 { 184 stopAfter: 'checked', 185 } 186); 187