1/*
2 * Copyright (c) 2024 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 {
17  factory,
18  isStructDeclaration,
19  setParentRecursive,
20  visitEachChild,
21  isConstructorDeclaration,
22  isSourceFile,
23  getOriginalNode
24} from 'typescript';
25
26import type {
27  ClassElement,
28  Node,
29  SourceFile,
30  TransformationContext,
31  Transformer,
32  TransformerFactory
33} from 'typescript';
34
35import type {TransformPlugin} from '../TransformPlugin';
36import {TransformerOrder} from '../TransformPlugin';
37import type {IOptions} from '../../configs/IOptions';
38import {NodeUtils} from '../../utils/NodeUtils';
39import {performancePrinter} from '../../ArkObfuscator';
40import {EventList} from '../../utils/PrinterUtils';
41
42namespace secharmony {
43  export let transformerPlugin: TransformPlugin = {
44    'name': 'VirtualConstructorTransformerFactory',
45    'order': TransformerOrder.VIRTUAL_CONSTRUCTOR_TRANSFORMER,
46    'createTransformerFactory': (option: IOptions) => virtualConstructorTransformerFactory,
47  };
48}
49
50function virtualConstructorTransformerFactory(context: TransformationContext): Transformer<Node> {
51  return (node: SourceFile) => virtualConstructorTransformer(node, context);
52}
53
54function virtualConstructorTransformer(node: SourceFile, context: TransformationContext): Node {
55  if (!NodeUtils.isDETSFile(node)) {
56    return node;
57  }
58  performancePrinter?.singleFilePrinter?.startEvent(EventList.VIRTUAL_CONSTRUCTOR_OBFUSCATION,
59      performancePrinter.timeSumPrinter);
60  let astWithoutVirtualConstructor = removeVirtualConstructor(node, context);
61  let parentNodes = setParentRecursive(astWithoutVirtualConstructor, true);
62  performancePrinter?.singleFilePrinter?.endEvent(EventList.VIRTUAL_CONSTRUCTOR_OBFUSCATION,
63      performancePrinter.timeSumPrinter);
64  return parentNodes;
65}
66
67function removeVirtualConstructor(node: Node, context: TransformationContext): Node {
68  if (isStructDeclaration(node)) {
69    const tempStructMembers: ClassElement[] = node.members.filter((member) => !isVirtualConstructor(member));
70    const structMembersWithoutVirtualConstructor = factory.createNodeArray(tempStructMembers);
71
72    return factory.updateStructDeclaration(node, node.modifiers, node.name, node.typeParameters, node.heritageClauses,
73      structMembersWithoutVirtualConstructor);
74  }
75  return visitEachChild(node, (childNode) => removeVirtualConstructor(childNode, context), context);
76}
77
78function isVirtualConstructor(node: Node): boolean {
79  const originalNode = getOriginalNode(node);
80  //@ts-ignore
81  return isConstructorDeclaration(originalNode) && originalNode.virtual;
82}
83
84export = secharmony;
85