FunctionControlFlowTransformer.ts 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  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 { IVisitor } from '../../interfaces/IVisitor';
  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 { ControlFlowReplacers } from '../../enums/container/ControlFlowReplacers';
  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, ControlFlowReplacers>}
  25. */
  26. private static readonly controlFlowReplacersMap: Map <string, ControlFlowReplacers> = new Map([
  27. [NodeType.BinaryExpression, ControlFlowReplacers.BinaryExpressionControlFlowReplacer],
  28. [NodeType.CallExpression, ControlFlowReplacers.CallExpressionControlFlowReplacer],
  29. [NodeType.LogicalExpression, ControlFlowReplacers.LogicalExpressionControlFlowReplacer],
  30. [NodeType.Literal, ControlFlowReplacers.StringLiteralControlFlowReplacer]
  31. ]);
  32. /**
  33. * @type {number}
  34. */
  35. private static readonly hostNodeSearchMinDepth: number = 0;
  36. /**
  37. * @type {number}
  38. */
  39. private static readonly hostNodeSearchMaxDepth: number = 2;
  40. /**
  41. * @type {Map<ESTree.Node, IStorage<ICustomNode>>}
  42. */
  43. private readonly controlFlowData: Map <ESTree.Node, IStorage<ICustomNode>> = new Map();
  44. /**
  45. * @type {Set<ESTree.Function>}
  46. */
  47. private readonly visitedFunctionNodes: Set<ESTree.Function> = new Set();
  48. /**
  49. * @type {Set<TNodeWithBlockStatement>}
  50. */
  51. private readonly hostNodesWithControlFlowNode: Set<TNodeWithBlockStatement> = new Set();
  52. /**
  53. * @type {TControlFlowReplacerFactory}
  54. */
  55. private readonly controlFlowReplacerFactory: TControlFlowReplacerFactory;
  56. /**
  57. * @type {TControlFlowStorageFactory}
  58. */
  59. private readonly controlFlowStorageFactory: TControlFlowStorageFactory;
  60. /**
  61. * @type {TCustomNodeFactory}
  62. */
  63. private readonly customNodeFactory: TCustomNodeFactory;
  64. /**
  65. * @param controlFlowStorageFactory
  66. * @param controlFlowReplacerFactory
  67. * @param customNodeFactory
  68. * @param options
  69. */
  70. constructor (
  71. @inject(ServiceIdentifiers.Factory__TControlFlowStorage) controlFlowStorageFactory: TControlFlowStorageFactory,
  72. @inject(ServiceIdentifiers.Factory__IControlFlowReplacer) controlFlowReplacerFactory: TControlFlowReplacerFactory,
  73. @inject(ServiceIdentifiers.Factory__ICustomNode) customNodeFactory: TCustomNodeFactory,
  74. @inject(ServiceIdentifiers.IOptions) options: IOptions
  75. ) {
  76. super(options);
  77. this.controlFlowStorageFactory = controlFlowStorageFactory;
  78. this.controlFlowReplacerFactory = controlFlowReplacerFactory;
  79. this.customNodeFactory = customNodeFactory;
  80. }
  81. /**
  82. * @param functionNodeBody
  83. * @returns {TNodeWithBlockStatement}
  84. */
  85. private static getHostNode (functionNodeBody: ESTree.BlockStatement): TNodeWithBlockStatement {
  86. const blockScopesOfNode: TNodeWithBlockStatement[] = NodeUtils.getBlockScopesOfNode(functionNodeBody);
  87. if (blockScopesOfNode.length === 1) {
  88. return functionNodeBody;
  89. } else {
  90. blockScopesOfNode.pop();
  91. }
  92. if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMinDepth) {
  93. blockScopesOfNode.splice(0, FunctionControlFlowTransformer.hostNodeSearchMinDepth);
  94. }
  95. if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMaxDepth) {
  96. blockScopesOfNode.length = FunctionControlFlowTransformer.hostNodeSearchMaxDepth;
  97. }
  98. return RandomGeneratorUtils.getRandomGenerator().pickone(blockScopesOfNode);
  99. }
  100. /**
  101. * @return {IVisitor}
  102. */
  103. public getVisitor (): IVisitor {
  104. return {
  105. leave: (node: ESTree.Node, parentNode: ESTree.Node) => {
  106. if (
  107. Node.isFunctionDeclarationNode(node) ||
  108. Node.isFunctionExpressionNode(node) ||
  109. Node.isArrowFunctionExpressionNode(node)
  110. ) {
  111. return this.transformNode(node, parentNode);
  112. }
  113. }
  114. };
  115. }
  116. /**
  117. * @param functionNode
  118. * @param parentNode
  119. * @returns {ESTree.Function}
  120. */
  121. public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Function {
  122. this.visitedFunctionNodes.add(functionNode);
  123. if (!Node.isBlockStatementNode(functionNode.body)) {
  124. return functionNode;
  125. }
  126. const hostNode: TNodeWithBlockStatement = FunctionControlFlowTransformer.getHostNode(functionNode.body);
  127. const controlFlowStorage: IStorage<ICustomNode> = this.getControlFlowStorage(hostNode);
  128. this.controlFlowData.set(hostNode, controlFlowStorage);
  129. this.transformFunctionBody(functionNode.body, controlFlowStorage);
  130. if (!controlFlowStorage.getLength()) {
  131. return functionNode;
  132. }
  133. const controlFlowStorageCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageNode);
  134. controlFlowStorageCustomNode.initialize(controlFlowStorage);
  135. NodeAppender.prependNode(hostNode, controlFlowStorageCustomNode.getNode());
  136. this.hostNodesWithControlFlowNode.add(hostNode);
  137. return functionNode;
  138. }
  139. /**
  140. * @param hostNode
  141. * @return {IStorage<ICustomNode>}
  142. */
  143. private getControlFlowStorage (hostNode: TNodeWithBlockStatement): IStorage<ICustomNode> {
  144. const controlFlowStorage: IStorage <ICustomNode> = this.controlFlowStorageFactory();
  145. if (this.controlFlowData.has(hostNode)) {
  146. if (this.hostNodesWithControlFlowNode.has(hostNode)) {
  147. hostNode.body.shift();
  148. }
  149. const hostControlFlowStorage: IStorage<ICustomNode> = <IStorage<ICustomNode>>this.controlFlowData.get(hostNode);
  150. controlFlowStorage.mergeWith(hostControlFlowStorage, true);
  151. }
  152. return controlFlowStorage;
  153. }
  154. /**
  155. * @param node
  156. * @return {boolean}
  157. */
  158. private isVisitedFunctionNode (node: ESTree.Node): boolean {
  159. return (
  160. Node.isFunctionDeclarationNode(node) ||
  161. Node.isFunctionExpressionNode(node) ||
  162. Node.isArrowFunctionExpressionNode(node)
  163. ) && this.visitedFunctionNodes.has(node);
  164. }
  165. /**
  166. * @param functionNodeBody
  167. * @param controlFlowStorage
  168. */
  169. private transformFunctionBody (functionNodeBody: ESTree.BlockStatement, controlFlowStorage: IStorage<ICustomNode>): void {
  170. estraverse.replace(functionNodeBody, {
  171. enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
  172. if (this.isVisitedFunctionNode(node)) {
  173. return estraverse.VisitorOption.Skip;
  174. }
  175. if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
  176. return node;
  177. }
  178. if (RandomGeneratorUtils.getMathRandom() > this.options.controlFlowFlatteningThreshold) {
  179. return node;
  180. }
  181. const controlFlowReplacerName: ControlFlowReplacers = <ControlFlowReplacers>FunctionControlFlowTransformer
  182. .controlFlowReplacersMap.get(node.type);
  183. if (controlFlowReplacerName === undefined) {
  184. return node;
  185. }
  186. return {
  187. ...this.controlFlowReplacerFactory(controlFlowReplacerName).replace(node, parentNode, controlFlowStorage),
  188. parentNode
  189. };
  190. }
  191. });
  192. }
  193. }