FunctionControlFlowTransformer.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. import { injectable, inject } from 'inversify';
  2. import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
  3. import * as estraverse from 'estraverse';
  4. import * as ESTree from 'estree';
  5. import { TControlFlowReplacerFactory } from '../../types/container/TControlFlowReplacerFactory';
  6. import { TControlFlowStorageFactory } from '../../types/container/TControlFlowStorageFactory';
  7. import { TCustomNodeFactory } from '../../types/container/TCustomNodeFactory';
  8. import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
  9. import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
  10. import { IOptions } from '../../interfaces/options/IOptions';
  11. import { IStorage } from '../../interfaces/storages/IStorage';
  12. import { CustomNodes } from '../../enums/container/CustomNodes';
  13. import { NodeType } from '../../enums/NodeType';
  14. import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
  15. import { Node } from '../../node/Node';
  16. import { NodeAppender } from '../../node/NodeAppender';
  17. import { NodeControlFlowReplacers } from '../../enums/container/NodeControlFlowReplacers';
  18. import { NodeUtils } from '../../node/NodeUtils';
  19. import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
  20. @injectable()
  21. export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
  22. /**
  23. * @type {Map <string, NodeControlFlowReplacers>}
  24. */
  25. private static readonly controlFlowReplacersMap: Map <string, NodeControlFlowReplacers> = new Map([
  26. [NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer],
  27. [NodeType.BlockStatement, NodeControlFlowReplacers.BlockStatementControlFlowReplacer],
  28. [NodeType.CallExpression, NodeControlFlowReplacers.CallExpressionControlFlowReplacer],
  29. [NodeType.LogicalExpression, NodeControlFlowReplacers.LogicalExpressionControlFlowReplacer]
  30. ]);
  31. /**
  32. * @type {number}
  33. */
  34. private static readonly hostNodeSearchMinDepth: number = 0;
  35. /**
  36. * @type {number}
  37. */
  38. private static readonly hostNodeSearchMaxDepth: number = 2;
  39. /**
  40. * @type {Map<ESTree.Node, IStorage<ICustomNode>>}
  41. */
  42. private controlFlowData: Map <ESTree.Node, IStorage<ICustomNode>> = new Map();
  43. /**
  44. * @type {TNodeWithBlockStatement[]}
  45. */
  46. private readonly hostNodesWithControlFlowNode: TNodeWithBlockStatement[] = [];
  47. /**
  48. * @type {TControlFlowReplacerFactory}
  49. */
  50. private readonly controlFlowReplacerFactory: TControlFlowReplacerFactory;
  51. /**
  52. * @type {TControlFlowStorageFactory}
  53. */
  54. private readonly controlFlowStorageFactory: TControlFlowStorageFactory;
  55. /**
  56. * @type {TCustomNodeFactory}
  57. */
  58. private readonly customNodeFactory: TCustomNodeFactory;
  59. /**
  60. * @param controlFlowStorageFactory
  61. * @param controlFlowReplacerFactory
  62. * @param customNodeFactory
  63. * @param options
  64. */
  65. constructor (
  66. @inject(ServiceIdentifiers.Factory__TControlFlowStorage) controlFlowStorageFactory: TControlFlowStorageFactory,
  67. @inject(ServiceIdentifiers.Factory__IControlFlowReplacer) controlFlowReplacerFactory: TControlFlowReplacerFactory,
  68. @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
  69. @inject(ServiceIdentifiers.IOptions) options: IOptions
  70. ) {
  71. super(options);
  72. this.controlFlowStorageFactory = controlFlowStorageFactory;
  73. this.controlFlowReplacerFactory = controlFlowReplacerFactory;
  74. this.customNodeFactory = customNodeFactory;
  75. }
  76. /**
  77. * @param functionNode
  78. * @returns {TNodeWithBlockStatement}
  79. */
  80. private static getHostNode (functionNode: ESTree.FunctionDeclaration | ESTree.FunctionExpression): TNodeWithBlockStatement {
  81. const blockScopesOfNode: TNodeWithBlockStatement[] = NodeUtils.getBlockScopesOfNode(functionNode);
  82. if (blockScopesOfNode.length === 1) {
  83. return functionNode.body;
  84. } else {
  85. blockScopesOfNode.pop();
  86. }
  87. if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMinDepth) {
  88. blockScopesOfNode.splice(0, FunctionControlFlowTransformer.hostNodeSearchMinDepth);
  89. }
  90. if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMaxDepth) {
  91. blockScopesOfNode.length = FunctionControlFlowTransformer.hostNodeSearchMaxDepth;
  92. }
  93. return RandomGeneratorUtils.getRandomGenerator().pickone(blockScopesOfNode);
  94. }
  95. /**
  96. * @param functionNode
  97. * @returns {ESTree.Node}
  98. */
  99. public transformNode (functionNode: ESTree.Function): ESTree.Node {
  100. if (Node.isArrowFunctionExpressionNode(functionNode)) {
  101. return functionNode;
  102. }
  103. const hostNode: TNodeWithBlockStatement = FunctionControlFlowTransformer.getHostNode(functionNode);
  104. const controlFlowStorage: IStorage<ICustomNode> = this.getControlFlowStorage(hostNode);
  105. this.controlFlowData.set(hostNode, controlFlowStorage);
  106. this.transformFunctionBody(functionNode.body, controlFlowStorage);
  107. NodeUtils.parentize(functionNode);
  108. if (!controlFlowStorage.getLength()) {
  109. return functionNode;
  110. }
  111. const controlFlowStorageCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageNode);
  112. controlFlowStorageCustomNode.initialize(controlFlowStorage);
  113. NodeAppender.prependNode(hostNode, controlFlowStorageCustomNode.getNode());
  114. this.hostNodesWithControlFlowNode.push(hostNode);
  115. return functionNode;
  116. }
  117. /**
  118. * @param hostNode
  119. * @return {IStorage<ICustomNode>}
  120. */
  121. private getControlFlowStorage (hostNode: TNodeWithBlockStatement): IStorage<ICustomNode> {
  122. const controlFlowStorage: IStorage <ICustomNode> = this.controlFlowStorageFactory();
  123. if (this.controlFlowData.has(hostNode)) {
  124. if (this.hostNodesWithControlFlowNode.indexOf(hostNode) !== -1) {
  125. hostNode.body.shift();
  126. }
  127. const hostControlFlowStorage: IStorage<ICustomNode> = <IStorage<ICustomNode>>this.controlFlowData.get(hostNode);
  128. controlFlowStorage.mergeWith(hostControlFlowStorage, true);
  129. }
  130. return controlFlowStorage;
  131. }
  132. /**
  133. * @param functionNodeBody
  134. * @param controlFlowStorage
  135. * @return {ESTree.Node}
  136. */
  137. private transformFunctionBody (functionNodeBody: ESTree.BlockStatement, controlFlowStorage: IStorage<ICustomNode>): void {
  138. estraverse.replace(functionNodeBody, {
  139. enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
  140. if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
  141. return node;
  142. }
  143. if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
  144. return node;
  145. }
  146. const controlFlowReplacerName: NodeControlFlowReplacers = <NodeControlFlowReplacers>FunctionControlFlowTransformer
  147. .controlFlowReplacersMap.get(node.type);
  148. return {
  149. ...this.controlFlowReplacerFactory(controlFlowReplacerName).replace(node, parentNode, controlFlowStorage),
  150. parentNode
  151. };
  152. }
  153. });
  154. }
  155. }