FunctionControlFlowTransformer.ts 6.6 KB

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