Added ThroughIdentifierReplacer for code separate between ScopeIdentifierReplacer and ScopeThroughIdentifiersTransformer

This commit is contained in:
sanex
2021-05-30 12:12:59 +03:00
parent b62f49369c
commit 18f72a89c7
13 changed files with 362 additions and 37717 deletions
+1
View File
@@ -56,6 +56,7 @@ export enum ServiceIdentifiers {
IStringArrayScopeCallsWrapperNamesDataStorage = 'IStringArrayScopeCallsWrapperNamesDataStorage',
IStringArrayStorage = 'IStringArrayStorage',
IStringArrayStorageAnalyzer = 'IStringArrayStorageAnalyzer',
IThroughIdentifierReplacer = 'IThroughIdentifierReplacer',
IVisitedLexicalScopeNodesStackStorage = 'IVisitedLexicalScopeNodesStackStorage',
Newable__ICustomNode = 'Newable<ICustomNode>',
Newable__TControlFlowStorage = 'Newable<TControlFlowStorage>',
@@ -11,6 +11,8 @@ import { IdentifierReplacer } from '../../../node-transformers/rename-identifier
import { LabeledStatementTransformer } from '../../../node-transformers/rename-identifiers-transformers/LabeledStatementTransformer';
import { ScopeIdentifiersTransformer } from '../../../node-transformers/rename-identifiers-transformers/ScopeIdentifiersTransformer';
import { ScopeThroughIdentifiersTransformer } from '../../../node-transformers/rename-identifiers-transformers/ScopeThroughIdentifiersTransformer';
import { ThroughIdentifierReplacer } from '../../../node-transformers/rename-identifiers-transformers/through-replacer/ThroughIdentifierReplacer';
import { IThroughIdentifierReplacer } from '../../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IThroughIdentifierReplacer';
export const renameIdentifiersTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// rename identifiers transformers
@@ -34,4 +36,8 @@ export const renameIdentifiersTransformersModule: interfaces.ContainerModule = n
bind<IIdentifierReplacer>(ServiceIdentifiers.IIdentifierReplacer)
.to(IdentifierReplacer)
.inSingletonScope();
bind<IThroughIdentifierReplacer>(ServiceIdentifiers.IThroughIdentifierReplacer)
.to(ThroughIdentifierReplacer)
.inSingletonScope();
});
@@ -15,12 +15,6 @@ export interface IIdentifierReplacer {
*/
storeLocalName (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void;
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
storeThroughName (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void;
/**
* @param {Node} node
* @param {TNodeWithLexicalScope} lexicalScopeNode
@@ -0,0 +1,14 @@
import * as ESTree from 'estree';
export interface IThroughIdentifierReplacer {
/**
* @param {Identifier} identifierNode
*/
store (identifierNode: ESTree.Identifier): void;
/**
* @param {Identifier} identifierNode
* @returns {Identifier}
*/
replace (identifierNode: ESTree.Identifier): ESTree.Identifier;
}
@@ -1,58 +1,141 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as eslintScope from 'eslint-scope';
import * as ESTree from 'estree';
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
import { IIdentifierNamesCacheStorage } from '../../interfaces/storages/identifier-names-cache/IIdentifierNamesCacheStorage';
import { IIdentifierReplacer } from '../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IIdentifierReplacer';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifiersTraverser';
import { IScopeThroughIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeThroughIdentifiersTraverserCallbackData';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
import { ScopeThroughIdentifiersTransformer } from '../rename-identifiers-transformers/ScopeThroughIdentifiersTransformer';
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { NodeGuards } from '../../node/NodeGuards';
/**
* Renames all scope through identifiers for Dead Code Injection
*/
@injectable()
export class DeadCodeInjectionIdentifiersTransformer extends ScopeThroughIdentifiersTransformer {
export class DeadCodeInjectionIdentifiersTransformer extends AbstractNodeTransformer {
/**
* @type {IIdentifierReplacer}
*/
private readonly identifierReplacer: IIdentifierReplacer;
/**
* @type {IScopeIdentifiersTraverser}
*/
private readonly scopeIdentifiersTraverser: IScopeIdentifiersTraverser;
/**
* @param {IIdentifierReplacer} identifierReplacer
* @param {IRandomGenerator} randomGenerator
* @param {IScopeIdentifiersTraverser} scopeIdentifiersTraverser
* @param {IIdentifierNamesCacheStorage} identifierNamesCacheStorage
* @param {IOptions} options
* @param {IScopeIdentifiersTraverser} scopeIdentifiersTraverser
*/
public constructor (
@inject(ServiceIdentifiers.IIdentifierReplacer) identifierReplacer: IIdentifierReplacer,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IScopeIdentifiersTraverser)
scopeIdentifiersTraverser: IScopeIdentifiersTraverser,
@inject(ServiceIdentifiers.IIdentifierNamesCacheStorage)
identifierNamesCacheStorage: IIdentifierNamesCacheStorage,
@inject(ServiceIdentifiers.IOptions) options: IOptions
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.IScopeIdentifiersTraverser) scopeIdentifiersTraverser: IScopeIdentifiersTraverser
) {
super(
identifierReplacer,
randomGenerator,
scopeIdentifiersTraverser,
identifierNamesCacheStorage,
options
super(randomGenerator, options);
this.identifierReplacer = identifierReplacer;
this.scopeIdentifiersTraverser = scopeIdentifiersTraverser;
}
/**
* @param {NodeTransformationStage} nodeTransformationStage
* @returns {IVisitor | null}
*/
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
switch (nodeTransformationStage) {
case NodeTransformationStage.RenameIdentifiers:
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
if (parentNode && NodeGuards.isProgramNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
default:
return null;
}
}
/**
* @param {VariableDeclaration} programNode
* @param {NodeGuards} parentNode
* @returns {NodeGuards}
*/
public transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node {
this.scopeIdentifiersTraverser.traverseScopeThroughIdentifiers(
programNode,
parentNode,
(data: IScopeThroughIdentifiersTraverserCallbackData) => {
const {
reference,
variableLexicalScopeNode
} = data;
this.transformScopeThroughIdentifiers(reference, variableLexicalScopeNode);
}
);
return programNode;
}
/**
* @param {Reference} reference
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
private transformScopeThroughIdentifiers (
reference: eslintScope.Reference,
lexicalScopeNode: TNodeWithLexicalScope,
): void {
if (reference.resolved) {
return;
}
const identifier: ESTree.Identifier = reference.identifier;
this.storeIdentifierName(identifier, lexicalScopeNode);
this.replaceIdentifierName(identifier, lexicalScopeNode, reference);
}
/**
* Override parent method, because we have to store only local scope names
*
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
protected override storeIdentifierName (
private storeIdentifierName (
identifierNode: ESTree.Identifier,
lexicalScopeNode: TNodeWithLexicalScope
): void {
this.identifierReplacer.storeLocalName(identifierNode, lexicalScopeNode);
}
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {Variable} reference
*/
private replaceIdentifierName (
identifierNode: ESTree.Identifier,
lexicalScopeNode: TNodeWithLexicalScope,
reference: eslintScope.Reference
): void {
const newIdentifier: ESTree.Identifier = this.identifierReplacer
.replace(identifierNode, lexicalScopeNode);
// rename of identifier
reference.identifier.name = newIdentifier.name;
}
}
@@ -6,12 +6,11 @@ import * as ESTree from 'estree';
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
import { IIdentifierNamesCacheStorage } from '../../interfaces/storages/identifier-names-cache/IIdentifierNamesCacheStorage';
import { IIdentifierReplacer } from '../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IIdentifierReplacer';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IScopeIdentifiersTraverser } from '../../interfaces/node/IScopeIdentifiersTraverser';
import { IScopeThroughIdentifiersTraverserCallbackData } from '../../interfaces/node/IScopeThroughIdentifiersTraverserCallbackData';
import { IThroughIdentifierReplacer } from '../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IThroughIdentifierReplacer';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
@@ -24,42 +23,32 @@ import { NodeGuards } from '../../node/NodeGuards';
*/
@injectable()
export class ScopeThroughIdentifiersTransformer extends AbstractNodeTransformer {
/**
* @type {IIdentifierNamesCacheStorage}
*/
protected readonly identifierNamesCacheStorage: IIdentifierNamesCacheStorage;
/**
* @type {IIdentifierReplacer}
*/
protected readonly identifierReplacer: IIdentifierReplacer;
/**
* @type {IScopeIdentifiersTraverser}
*/
protected readonly scopeIdentifiersTraverser: IScopeIdentifiersTraverser;
/**
* @param {IIdentifierReplacer} identifierReplacer
* @param {IRandomGenerator} randomGenerator
* @type {IThroughIdentifierReplacer}
*/
protected readonly throughIdentifierReplacer: IThroughIdentifierReplacer;
/**
* @param {IThroughIdentifierReplacer} throughIdentifierReplacer
* @param {IScopeIdentifiersTraverser} scopeIdentifiersTraverser
* @param {IIdentifierNamesCacheStorage} identifierNamesCacheStorage
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IIdentifierReplacer) identifierReplacer: IIdentifierReplacer,
@inject(ServiceIdentifiers.IThroughIdentifierReplacer) throughIdentifierReplacer: IThroughIdentifierReplacer,
@inject(ServiceIdentifiers.IScopeIdentifiersTraverser) scopeIdentifiersTraverser: IScopeIdentifiersTraverser,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IScopeIdentifiersTraverser)
scopeIdentifiersTraverser: IScopeIdentifiersTraverser,
@inject(ServiceIdentifiers.IIdentifierNamesCacheStorage)
identifierNamesCacheStorage: IIdentifierNamesCacheStorage,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
this.identifierReplacer = identifierReplacer;
this.throughIdentifierReplacer = throughIdentifierReplacer;
this.scopeIdentifiersTraverser = scopeIdentifiersTraverser;
this.identifierNamesCacheStorage = identifierNamesCacheStorage;
}
/**
@@ -93,15 +82,13 @@ export class ScopeThroughIdentifiersTransformer extends AbstractNodeTransformer
parentNode,
(data: IScopeThroughIdentifiersTraverserCallbackData) => {
const {
isGlobalDeclaration,
reference,
variableLexicalScopeNode
} = data;
this.transformScopeThroughIdentifiers(
reference,
variableLexicalScopeNode,
isGlobalDeclaration
variableLexicalScopeNode
);
}
);
@@ -112,12 +99,10 @@ export class ScopeThroughIdentifiersTransformer extends AbstractNodeTransformer
/**
* @param {Reference} reference
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {boolean} isGlobalDeclaration
*/
protected transformScopeThroughIdentifiers (
reference: eslintScope.Reference,
lexicalScopeNode: TNodeWithLexicalScope,
isGlobalDeclaration: boolean
lexicalScopeNode: TNodeWithLexicalScope
): void {
if (reference.resolved) {
return;
@@ -125,35 +110,28 @@ export class ScopeThroughIdentifiersTransformer extends AbstractNodeTransformer
const identifier: ESTree.Identifier = reference.identifier;
this.storeIdentifierName(identifier, lexicalScopeNode, isGlobalDeclaration);
this.replaceIdentifierName(identifier, lexicalScopeNode, reference);
this.storeIdentifierName(identifier);
this.replaceIdentifierName(identifier, reference);
}
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {boolean} isGlobalDeclaration
*/
protected storeIdentifierName (
identifierNode: ESTree.Identifier,
lexicalScopeNode: TNodeWithLexicalScope,
isGlobalDeclaration: boolean
identifierNode: ESTree.Identifier
): void {
this.identifierReplacer.storeThroughName(identifierNode, lexicalScopeNode);
this.throughIdentifierReplacer.store(identifierNode);
}
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @param {Variable} reference
*/
protected replaceIdentifierName (
identifierNode: ESTree.Identifier,
lexicalScopeNode: TNodeWithLexicalScope,
reference: eslintScope.Reference
): void {
const newIdentifier: ESTree.Identifier = this.identifierReplacer
.replace(identifierNode, lexicalScopeNode);
const newIdentifier: ESTree.Identifier = this.throughIdentifierReplacer.replace(identifierNode);
// rename of identifier
reference.identifier.name = newIdentifier.name;
@@ -105,37 +105,6 @@ export class IdentifierReplacer implements IIdentifierReplacer {
namesMap.set(identifierName, newIdentifierName);
}
/**
* Store identifier node `name` of `through` identifiers as key in map with value from identifier names cache.
* Reserved name will be ignored.
*
* @param {Node} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
public storeThroughName (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
const identifierName: string = identifierNode.name;
if (this.isReservedName(identifierName)) {
return;
}
const newIdentifierName: string | null = this.identifierNamesCacheStorage.get(identifierName) ?? null;
if (!newIdentifierName) {
return;
}
if (!this.blockScopesMap.has(lexicalScopeNode)) {
this.blockScopesMap.set(lexicalScopeNode, new Map());
}
const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
namesMap.set(identifierName, newIdentifierName);
this.identifierNamesCacheStorage.set(identifierName, newIdentifierName);
}
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
@@ -0,0 +1,84 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { IIdentifierNamesCacheStorage } from '../../../interfaces/storages/identifier-names-cache/IIdentifierNamesCacheStorage';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IThroughIdentifierReplacer } from '../../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IThroughIdentifierReplacer';
import { NodeFactory } from '../../../node/NodeFactory';
@injectable()
export class ThroughIdentifierReplacer implements IThroughIdentifierReplacer {
/**
* @type {IIdentifierNamesCacheStorage}
*/
private readonly identifierNamesCacheStorage: IIdentifierNamesCacheStorage;
/**
* @type {IOptions}
*/
private readonly options: IOptions;
/**
* @param {IIdentifierNamesCacheStorage} identifierNamesCacheStorage
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IIdentifierNamesCacheStorage)
identifierNamesCacheStorage: IIdentifierNamesCacheStorage,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.identifierNamesCacheStorage = identifierNamesCacheStorage;
this.options = options;
}
/**
* Store identifier node `name` of `through` identifiers as key in map with value from identifier names cache.
* Reserved name will be ignored.
*
* @param {Node} identifierNode
*/
public store (identifierNode: ESTree.Identifier): void {
const identifierName: string = identifierNode.name;
if (this.isReservedName(identifierName)) {
return;
}
const newIdentifierName: string | null = this.identifierNamesCacheStorage.get(identifierName) ?? null;
if (!newIdentifierName) {
return;
}
this.identifierNamesCacheStorage.set(identifierName, newIdentifierName);
}
/**
* @param {Identifier} identifierNode
* @returns {Identifier}
*/
public replace (identifierNode: ESTree.Identifier): ESTree.Identifier {
const identifierName: string = this.identifierNamesCacheStorage.get(identifierNode.name)
?? identifierNode.name;
return NodeFactory.identifierNode(identifierName);
}
/**
* @param {string} name
* @returns {boolean}
*/
private isReservedName (name: string): boolean {
if (!this.options.reservedNames.length) {
return false;
}
return this.options.reservedNames
.some((reservedName: string) => {
return new RegExp(reservedName, 'g').exec(name) !== null;
});
}
}