123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- import { injectable, inject } from 'inversify';
- import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
- import * as estraverse from 'estraverse';
- import * as ESTree from 'estree';
- import { TControlFlowReplacerFactory } from '../../types/container/TControlFlowReplacerFactory';
- import { TControlFlowStorageFactory } from '../../types/container/TControlFlowStorageFactory';
- import { TCustomNodeFactory } from '../../types/container/TCustomNodeFactory';
- import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
- import { TStatement } from '../../types/node/TStatement';
- import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
- import { IOptions } from '../../interfaces/options/IOptions';
- import { IStorage } from '../../interfaces/storages/IStorage';
- import { CustomNodes } from '../../enums/container/CustomNodes';
- import { NodeType } from '../../enums/NodeType';
- import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
- import { Node } from '../../node/Node';
- import { NodeAppender } from '../../node/NodeAppender';
- import { NodeControlFlowReplacers } from '../../enums/container/NodeControlFlowReplacers';
- import { NodeUtils } from '../../node/NodeUtils';
- import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
- @injectable()
- export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
- /**
- * @type {Map <string, NodeControlFlowReplacers>}
- */
- private static readonly controlFlowReplacersMap: Map <string, NodeControlFlowReplacers> = new Map([
- [NodeType.BinaryExpression, NodeControlFlowReplacers.BinaryExpressionControlFlowReplacer]
- ]);
- /**
- * @type {number}
- */
- private static readonly hostNodeSearchMinDepth: number = 2;
- /**
- * @type {number}
- */
- private static readonly hostNodeSearchMaxDepth: number = 10;
- /**
- * @type {Map<ESTree.Node, IStorage<ICustomNode>>}
- */
- private controlFlowData: Map <ESTree.Node, IStorage<ICustomNode>> = new Map();
- /**
- * @type {TNodeWithBlockStatement[]}
- */
- private readonly hostNodesWithControlFlowNode: TNodeWithBlockStatement[] = [];
- /**
- * @type {TControlFlowReplacerFactory}
- */
- private readonly controlFlowReplacerFactory: TControlFlowReplacerFactory;
- /**
- * @type {TControlFlowStorageFactory}
- */
- private readonly controlFlowStorageFactory: TControlFlowStorageFactory;
- /**
- * @type {TCustomNodeFactory}
- */
- private readonly customNodeFactory: TCustomNodeFactory;
- /**
- * @param controlFlowStorageFactory
- * @param controlFlowReplacerFactory
- * @param customNodeFactory
- * @param options
- */
- constructor (
- @inject(ServiceIdentifiers['Factory<IStorage<ICustomNode>>']) controlFlowStorageFactory: TControlFlowStorageFactory,
- @inject(ServiceIdentifiers['Factory<IControlFlowReplacer>']) controlFlowReplacerFactory: TControlFlowReplacerFactory,
- @inject(ServiceIdentifiers['Factory<ICustomNode>']) customNodeFactory: TCustomNodeFactory,
- @inject(ServiceIdentifiers.IOptions) options: IOptions
- ) {
- super(options);
- this.controlFlowStorageFactory = controlFlowStorageFactory;
- this.controlFlowReplacerFactory = controlFlowReplacerFactory;
- this.customNodeFactory = customNodeFactory;
- }
- /**
- * @param functionNode
- * @returns {TNodeWithBlockStatement}
- */
- private static getHostNode (functionNode: ESTree.FunctionDeclaration | ESTree.FunctionExpression): TNodeWithBlockStatement {
- const blockScopesOfNode: TNodeWithBlockStatement[] = NodeUtils.getBlockScopesOfNode(functionNode);
- if (blockScopesOfNode.length === 1) {
- return functionNode.body;
- } else {
- blockScopesOfNode.pop();
- }
- if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMinDepth) {
- blockScopesOfNode.splice(0, FunctionControlFlowTransformer.hostNodeSearchMinDepth);
- }
- if (blockScopesOfNode.length > FunctionControlFlowTransformer.hostNodeSearchMaxDepth) {
- blockScopesOfNode.length = FunctionControlFlowTransformer.hostNodeSearchMaxDepth;
- }
- return RandomGeneratorUtils.getRandomGenerator().pickone(blockScopesOfNode);
- }
- /**
- * @param functionNode
- */
- public transformNode (functionNode: ESTree.Function): void {
- this.changeFunctionBodyControlFlow(functionNode);
- }
- /**
- * @param functionNode
- */
- private changeFunctionBodyControlFlow (functionNode: ESTree.Function): void {
- if (Node.isArrowFunctionExpressionNode(functionNode)) {
- return;
- }
- const controlFlowStorage: IStorage <ICustomNode> = this.controlFlowStorageFactory();
- const hostNode: TNodeWithBlockStatement = FunctionControlFlowTransformer.getHostNode(functionNode);
- if (this.controlFlowData.has(hostNode)) {
- if (this.hostNodesWithControlFlowNode.indexOf(hostNode) !== -1) {
- hostNode.body.shift();
- }
- const hostControlFlowStorage: IStorage<ICustomNode> = <IStorage<ICustomNode>>this.controlFlowData.get(hostNode);
- controlFlowStorage.mergeWith(hostControlFlowStorage, true);
- }
- this.controlFlowData.set(hostNode, controlFlowStorage);
- estraverse.replace(functionNode.body, {
- enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
- if (!FunctionControlFlowTransformer.controlFlowReplacersMap.has(node.type)) {
- return;
- }
- if (RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold) {
- return;
- }
- const controlFlowReplacerName: NodeControlFlowReplacers = <NodeControlFlowReplacers>FunctionControlFlowTransformer
- .controlFlowReplacersMap.get(node.type);
- return {
- ...this.controlFlowReplacerFactory(controlFlowReplacerName)
- .replace(node, parentNode, controlFlowStorage),
- parentNode
- };
- }
- });
- if (!controlFlowStorage.getLength()) {
- return;
- }
- const controlFlowStorageCustomNode: ICustomNode = this.customNodeFactory(CustomNodes.ControlFlowStorageNode);
- controlFlowStorageCustomNode.initialize(controlFlowStorage);
- const controlFlowStorageNode: TStatement[] = controlFlowStorageCustomNode.getNode();
- NodeAppender.prependNode(hostNode, controlFlowStorageNode);
- this.hostNodesWithControlFlowNode.push(hostNode);
- }
- }
|