123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- import { injectable, inject } from 'inversify';
- import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
- import * as estraverse from 'estraverse';
- import * as ESTree from 'estree';
- import { IOptions } from '../../interfaces/options/IOptions';
- import { IVisitor } from '../../interfaces/IVisitor';
- import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
- import { Node } from '../../node/Node';
- import { Nodes } from '../../node/Nodes';
- import { NodeUtils } from '../../node/NodeUtils';
- import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
- @injectable()
- export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
- /**
- * @type {ESTree.BlockStatement[]}
- */
- private collectedBlockStatements: ESTree.BlockStatement[] = [];
- /**
- * @param options
- */
- constructor (
- @inject(ServiceIdentifiers.IOptions) options: IOptions
- ) {
- super(options);
- }
- /**
- * @param targetNode
- * @param collectedBlockStatements
- */
- private static collectBlockStatementNodes (targetNode: ESTree.Node, collectedBlockStatements: ESTree.BlockStatement[]): void {
- if (!Node.isBlockStatementNode(targetNode) || !DeadCodeInjectionTransformer.isValidBlockStatementNode(targetNode)) {
- return;
- }
- const clonedBlockStatementNode: ESTree.BlockStatement = <ESTree.BlockStatement>NodeUtils.clone(targetNode);
- estraverse.replace(clonedBlockStatementNode, {
- enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
- if (Node.isIdentifierNode(node)) {
- node.name = RandomGeneratorUtils.getRandomVariableName(6);
- }
- return node;
- }
- });
- collectedBlockStatements.push(clonedBlockStatementNode);
- }
- /**
- * @param blockStatementNode
- * @param randomBlockStatementNode
- * @return {ESTree.BlockStatement}
- */
- private static replaceBlockStatementNodes (
- blockStatementNode: ESTree.BlockStatement,
- randomBlockStatementNode: ESTree.BlockStatement
- ): ESTree.BlockStatement {
- const leftString: string = RandomGeneratorUtils.getRandomString(3);
- let operator: ESTree.BinaryOperator,
- rightString: string,
- consequent: ESTree.BlockStatement,
- alternate: ESTree.BlockStatement;
- if (RandomGeneratorUtils.getMathRandom() > 0.5) {
- operator = '===';
- if (RandomGeneratorUtils.getMathRandom() > 0.5) {
- rightString = leftString;
- consequent = blockStatementNode;
- alternate = randomBlockStatementNode;
- } else {
- rightString = RandomGeneratorUtils.getRandomString(3);
- consequent = randomBlockStatementNode;
- alternate = blockStatementNode;
- }
- } else {
- operator = '!==';
- if (RandomGeneratorUtils.getMathRandom() > 0.5) {
- rightString = leftString;
- consequent = randomBlockStatementNode;
- alternate = blockStatementNode;
- } else {
- rightString = RandomGeneratorUtils.getRandomString(3);
- consequent = blockStatementNode;
- alternate = randomBlockStatementNode;
- }
- }
- let newBlockStatementNode: ESTree.BlockStatement = Nodes.getBlockStatementNode([
- Nodes.getIfStatementNode(
- Nodes.getBinaryExpressionNode(
- operator,
- Nodes.getLiteralNode(leftString),
- Nodes.getLiteralNode(rightString)
- ),
- consequent,
- alternate
- )
- ]);
- newBlockStatementNode = NodeUtils.parentize(newBlockStatementNode);
- return newBlockStatementNode;
- }
- /**
- * @param blockStatementNode
- * @return {boolean}
- */
- private static isValidBlockStatementNode (blockStatementNode: ESTree.BlockStatement): boolean {
- let isValidBlockStatementNode: boolean = true;
- estraverse.traverse(blockStatementNode, {
- enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
- if (
- (node !== blockStatementNode && Node.isBlockStatementNode(node)) ||
- Node.isBreakStatementNode(node) ||
- Node.isContinueStatementNode(node)
- ) {
- isValidBlockStatementNode = false;
- }
- }
- });
- return isValidBlockStatementNode;
- }
- /**
- * @return {IVisitor}
- */
- public getVisitor (): IVisitor {
- return {
- leave: (node: ESTree.Node, parentNode: ESTree.Node) => {
- if (Node.isProgramNode(node)) {
- return this.transformNode(node, parentNode);
- }
- }
- };
- }
- /**
- * @param programNode
- * @param parentNode
- * @returns {ESTree.Node}
- */
- public transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node {
- this.transformProgramNode(programNode);
- return programNode;
- }
- /**
- * @param programNode
- */
- private transformProgramNode (programNode: ESTree.Program): void {
- estraverse.traverse(programNode, {
- enter: (node: ESTree.Node, parentNode: ESTree.Node): any =>
- DeadCodeInjectionTransformer.collectBlockStatementNodes(node, this.collectedBlockStatements)
- });
- estraverse.replace(programNode, {
- leave: (node: ESTree.Node, parentNode: ESTree.Node): any => {
- if (!Node.isBlockStatementNode(node) || !this.collectedBlockStatements.length) {
- return node;
- }
- if (RandomGeneratorUtils.getMathRandom() > this.options.deadCodeInjectionThreshold) {
- return node;
- }
- const randomIndex: number = RandomGeneratorUtils.getRandomInteger(0, this.collectedBlockStatements.length - 1);
- const randomBlockStatementNode: ESTree.BlockStatement = this.collectedBlockStatements.splice(randomIndex, 1)[0];
- if (randomBlockStatementNode === node) {
- return node;
- }
- return DeadCodeInjectionTransformer.replaceBlockStatementNodes(node, randomBlockStatementNode);
- }
- });
- }
- }
|