Disallow duplicated AST nodes (#11807)

This commit is contained in:
Huáng Jùnliàng 2020-07-14 09:32:16 -04:00 committed by GitHub
parent ffb42488ba
commit 5dd64ecc4a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 85 additions and 62 deletions

1
.gitignore vendored
View File

@ -72,3 +72,4 @@ packages/babel-standalone/babel.min.js
/eslint/*/node_modules
/eslint/*/LICENSE
!/packages/babel-eslint-plugin/LICENSE
/.vscode

View File

@ -457,7 +457,7 @@ You can set \`throwIfNamespace: false\` to bypass this warning.`,
}
return makeTrace(
state.fileNameIdentifier,
t.cloneNode(state.fileNameIdentifier),
location.start.line,
location.start.column,
);

View File

@ -137,7 +137,7 @@ export function buildDecoratedClass(ref, path, elements, file) {
let replacement = template.expression.ast`
${addDecorateHelper(file)}(
${classDecorators || t.nullLiteral()},
function (${initializeId}, ${superClass ? superId : null}) {
function (${initializeId}, ${superClass ? t.cloneNode(superId) : null}) {
${node}
return { F: ${t.cloneNode(node.id)}, d: ${definitions} };
},
@ -158,7 +158,7 @@ export function buildDecoratedClass(ref, path, elements, file) {
}
return {
instanceNodes: [template.statement.ast`${initializeId}(this)`],
instanceNodes: [template.statement.ast`${t.cloneNode(initializeId)}(this)`],
wrapClass(path) {
path.replaceWith(replacement);
return path.get(classPathDesc);

View File

@ -45,8 +45,9 @@ export function buildPrivateNamesNodes(privateNamesMap, loose, state) {
// In spec mode, only instance fields need a "private name" initializer
// because static fields are directly assigned to a variable in the
// buildPrivateStaticFieldInitSpec function.
const { id, static: isStatic, method: isMethod, getId, setId } = value;
const { static: isStatic, method: isMethod, getId, setId } = value;
const isAccessor = getId || setId;
const id = t.cloneNode(value.id);
if (loose) {
initNodes.push(
template.statement.ast`
@ -157,7 +158,7 @@ const privateInVisitor = privateNameVisitorFactory({
if (loose) {
const { id } = privateNamesMap.get(name);
path.replaceWith(template.expression.ast`
Object.prototype.hasOwnProperty.call(${right}, ${id})
Object.prototype.hasOwnProperty.call(${right}, ${t.cloneNode(id)})
`);
return;
}
@ -169,7 +170,7 @@ const privateInVisitor = privateNameVisitorFactory({
return;
}
path.replaceWith(template.expression.ast`${id}.has(${right})`);
path.replaceWith(template.expression.ast`${t.cloneNode(id)}.has(${right})`);
},
});
@ -327,8 +328,8 @@ const privateNameHandlerLoose = {
return template.expression`BASE(REF, PROP)[PROP]`({
BASE: file.addHelper("classPrivateFieldLooseBase"),
REF: object,
PROP: privateNamesMap.get(name).id,
REF: t.cloneNode(object),
PROP: t.cloneNode(privateNamesMap.get(name).id),
});
},
@ -387,7 +388,7 @@ function buildPrivateFieldInitLoose(ref, prop, privateNamesMap) {
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`
Object.defineProperty(${ref}, ${id}, {
Object.defineProperty(${ref}, ${t.cloneNode(id)}, {
// configurable is false by default
// enumerable is false by default
writable: true,
@ -400,7 +401,7 @@ function buildPrivateInstanceFieldInitSpec(ref, prop, privateNamesMap) {
const { id } = privateNamesMap.get(prop.node.key.id.name);
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`${id}.set(${ref}, {
return template.statement.ast`${t.cloneNode(id)}.set(${ref}, {
// configurable is always false for private elements
// enumerable is always false for private elements
writable: true,
@ -422,7 +423,7 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
});
return template.statement.ast`
var ${id.name} = {
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
// writable is false by default
@ -434,7 +435,7 @@ function buildPrivateStaticFieldInitSpec(prop, privateNamesMap) {
const value = prop.node.value || prop.scope.buildUndefinedNode();
return template.statement.ast`
var ${id} = {
var ${t.cloneNode(id)} = {
// configurable is false by default
// enumerable is false by default
writable: true,
@ -603,14 +604,14 @@ function buildPrivateMethodDeclaration(prop, privateNamesMap, loose = false) {
if (isStatic && !loose) {
return t.variableDeclaration("var", [
t.variableDeclarator(
id,
t.cloneNode(id),
t.functionExpression(id, params, body, generator, async),
),
]);
}
return t.variableDeclaration("var", [
t.variableDeclarator(methodId, methodValue),
t.variableDeclarator(t.cloneNode(methodId), methodValue),
]);
}

View File

@ -1,3 +1,4 @@
import { types as t } from "@babel/core";
import nameFunction from "@babel/helper-function-name";
import splitExportDeclaration from "@babel/helper-split-export-declaration";
import {
@ -129,7 +130,7 @@ export function createClassFeaturePlugin({
nameFunction(path);
ref = path.scope.generateUidIdentifier("class");
} else {
ref = path.node.id;
ref = t.cloneNode(path.node.id);
}
// NODE: These three functions don't support decorators yet,

View File

@ -72,8 +72,14 @@ export function injectInitialization(path, constructor, nodes, renamer) {
if (isDerived) {
const bareSupers = [];
constructor.traverse(findBareSupers, bareSupers);
let isFirst = true;
for (const bareSuper of bareSupers) {
bareSuper.insertAfter(nodes);
if (isFirst) {
bareSuper.insertAfter(nodes);
isFirst = false;
} else {
bareSuper.insertAfter(nodes.map(n => t.cloneNode(n)));
}
}
} else {
constructor.get("body").unshiftContainer("body", nodes);

View File

@ -235,8 +235,12 @@ const handle = {
t.binaryExpression(
"===",
baseNeedsMemoised
? t.assignmentExpression("=", baseRef, startingNode)
: baseRef,
? t.assignmentExpression(
"=",
t.cloneNode(baseRef),
t.cloneNode(startingNode),
)
: t.cloneNode(baseRef),
t.nullLiteral(),
),
t.binaryExpression(
@ -263,7 +267,7 @@ const handle = {
false,
true,
),
[context, ...endParent.arguments],
[t.cloneNode(context), ...endParent.arguments],
false,
),
);

View File

@ -337,7 +337,9 @@ const rewriteReferencesVisitor = {
path
.get("left")
.replaceWith(
t.variableDeclaration("let", [t.variableDeclarator(newLoopId)]),
t.variableDeclaration("let", [
t.variableDeclarator(t.cloneNode(newLoopId)),
]),
);
scope.registerDeclaration(path.get("left"));
}

View File

@ -146,6 +146,7 @@ function run(task) {
function getOpts(self) {
const newOpts = merge(
{
ast: true,
cwd: path.dirname(self.loc),
filename: self.loc,
filenameRelative: self.filename,

View File

@ -61,7 +61,7 @@ export default function (path, { getAsyncIterator }) {
ITERATOR_KEY: scope.generateUidIdentifier("iterator"),
GET_ITERATOR: getAsyncIterator,
OBJECT: node.right,
STEP_VALUE: stepValue,
STEP_VALUE: t.cloneNode(stepValue),
STEP_KEY: stepKey,
});

View File

@ -160,7 +160,7 @@ function applyTargetDecorators(path, state, decoratedProps) {
acc = acc.concat([
t.assignmentExpression(
"=",
descriptor,
t.cloneNode(descriptor),
t.callExpression(state.addHelper("applyDecoratedDescriptor"), [
t.cloneNode(target),
t.cloneNode(property),

View File

@ -7,7 +7,7 @@ export default declare(api => {
function getTempId(scope) {
let id = scope.path.getData("functionBind");
if (id) return id;
if (id) return t.cloneNode(id);
id = scope.generateDeclaredUidIdentifier("context");
return scope.path.setData("functionBind", id);
@ -35,7 +35,7 @@ export default declare(api => {
bind.callee.object,
);
}
return tempId;
return t.cloneNode(tempId);
}
return {

View File

@ -97,7 +97,7 @@ export default declare(api => {
"=",
t.cloneNode(functionLVal),
t.memberExpression(
receiverLVal,
t.cloneNode(receiverLVal),
node.callee.property,
false,
false,
@ -105,19 +105,19 @@ export default declare(api => {
),
...argsInitializers,
t.functionExpression(
node.callee.property,
t.cloneNode(node.callee.property),
placeholdersParams,
t.blockStatement(
[
t.returnStatement(
t.callExpression(
t.memberExpression(
functionLVal,
t.cloneNode(functionLVal),
t.identifier("call"),
false,
false,
),
[receiverLVal, ...args],
[t.cloneNode(receiverLVal), ...args],
),
),
],
@ -132,10 +132,14 @@ export default declare(api => {
t.assignmentExpression("=", t.cloneNode(functionLVal), node.callee),
...argsInitializers,
t.functionExpression(
node.callee,
t.cloneNode(node.callee),
placeholdersParams,
t.blockStatement(
[t.returnStatement(t.callExpression(functionLVal, args))],
[
t.returnStatement(
t.callExpression(t.cloneNode(functionLVal), args),
),
],
[],
),
false,

View File

@ -30,7 +30,7 @@ const buildOptimizedSequenceExpression = ({ assign, call, path }) => {
call.callee = evalSequence;
path.scope.push({ id: placeholderNode });
path.scope.push({ id: t.cloneNode(placeholderNode) });
return t.sequenceExpression([assign, call]);
}
@ -40,7 +40,7 @@ const buildOptimizedSequenceExpression = ({ assign, call, path }) => {
return t.sequenceExpression([pipelineLeft, calledExpression.body]);
}
path.scope.push({ id: placeholderNode });
path.scope.push({ id: t.cloneNode(placeholderNode) });
if (param) {
path.get("right").scope.rename(param.name, placeholderNode.name);

View File

@ -2,7 +2,7 @@ import { types as t } from "@babel/core";
const updateTopicReferenceVisitor = {
PipelinePrimaryTopicReference(path) {
path.replaceWith(this.topicId);
path.replaceWith(t.cloneNode(this.topicId));
},
PipelineTopicExpression(path) {
path.skip();

View File

@ -33,7 +33,7 @@ export default declare((api, opts) => {
const decl = node.declarations[i];
const assign = t.assignmentExpression(
"=",
decl.id,
t.cloneNode(decl.id),
decl.init || scope.buildUndefinedNode(),
);
assign._ignoreBlockScopingTDZ = true;

View File

@ -71,8 +71,8 @@ export default declare((api, options) => {
new Promise((${resolveId}, ${rejectId}) =>
${requireId}(
[${getImportSource(t, path.node)}],
imported => ${resolveId}(${result}),
${rejectId}
imported => ${t.cloneNode(resolveId)}(${result}),
${t.cloneNode(rejectId)}
)
)`,
);
@ -84,7 +84,7 @@ export default declare((api, options) => {
if (requireId) {
injectWrapper(
path,
buildAnonymousWrapper({ REQUIRE: requireId }),
buildAnonymousWrapper({ REQUIRE: t.cloneNode(requireId) }),
);
}
return;
@ -94,7 +94,7 @@ export default declare((api, options) => {
const importNames = [];
if (requireId) {
amdArgs.push(t.stringLiteral("require"));
importNames.push(requireId);
importNames.push(t.cloneNode(requireId));
}
let moduleName = getModuleName(this.file.opts, options);

View File

@ -233,8 +233,8 @@ export default declare((api, options) => {
}
},
exit(path, state) {
const undefinedIdent = path.scope.buildUndefinedNode();
const exportIdent = path.scope.generateUid("export");
const scope = path.scope;
const exportIdent = scope.generateUid("export");
const contextIdent = state.contextIdent;
const exportMap = Object.create(null);
@ -285,7 +285,7 @@ export default declare((api, options) => {
beforeBody.push(path.node);
removedPaths.push(path);
} else if (path.isClassDeclaration()) {
variableIds.push(path.node.id);
variableIds.push(t.cloneNode(path.node.id));
path.replaceWith(
t.expressionStatement(
t.assignmentExpression(
@ -299,7 +299,7 @@ export default declare((api, options) => {
const source = path.node.source.value;
pushModule(source, "imports", path.node.specifiers);
for (const name of Object.keys(path.getBindingIdentifiers())) {
path.scope.removeBinding(name);
scope.removeBinding(name);
variableIds.push(t.identifier(name));
}
path.remove();
@ -312,8 +312,8 @@ export default declare((api, options) => {
if (declar.isClassDeclaration()) {
if (id) {
exportNames.push("default");
exportValues.push(undefinedIdent);
variableIds.push(id);
exportValues.push(scope.buildUndefinedNode());
variableIds.push(t.cloneNode(id));
addExportName(id.name, "default");
path.replaceWith(
t.expressionStatement(
@ -360,8 +360,8 @@ export default declare((api, options) => {
} else if (path.isClass()) {
const name = declar.node.id.name;
exportNames.push(name);
exportValues.push(undefinedIdent);
variableIds.push(declar.node.id);
exportValues.push(scope.buildUndefinedNode());
variableIds.push(t.cloneNode(declar.node.id));
path.replaceWith(
t.expressionStatement(
t.assignmentExpression(
@ -389,9 +389,7 @@ export default declare((api, options) => {
const nodes = [];
for (const specifier of specifiers) {
const binding = path.scope.getBinding(
specifier.local.name,
);
const binding = scope.getBinding(specifier.local.name);
// hoisted function export
if (
binding &&
@ -426,7 +424,7 @@ export default declare((api, options) => {
modules.forEach(function (specifiers) {
let setterBody = [];
const target = path.scope.generateUid(specifiers.key);
const target = scope.generateUid(specifiers.key);
for (let specifier of specifiers.imports) {
if (t.isImportNamespaceSpecifier(specifier)) {
@ -510,7 +508,7 @@ export default declare((api, options) => {
variableIds.push(id);
if (!hasInit) {
exportNames.push(name);
exportValues.push(undefinedIdent);
exportValues.push(scope.buildUndefinedNode());
}
},
null,
@ -540,7 +538,7 @@ export default declare((api, options) => {
path.traverse(reassignmentVisitor, {
exports: exportMap,
buildCall: buildExportCall,
scope: path.scope,
scope,
});
for (const path of removedPaths) {

View File

@ -229,6 +229,6 @@ function buildScopeIIFE(shadowedParams, body) {
}
return t.returnStatement(
t.callExpression(t.arrowFunctionExpression(params, body), params),
t.callExpression(t.arrowFunctionExpression(params, body), args),
);
}

View File

@ -82,7 +82,7 @@ export default declare(api => {
}
const trace = makeTrace(
state.fileNameIdentifier,
t.cloneNode(state.fileNameIdentifier),
location.start.line,
location.start.column,
);

View File

@ -301,7 +301,11 @@ export default declare((api, options, dirname) => {
context2 = t.cloneNode(object);
} else {
context1 = path.scope.generateDeclaredUidIdentifier("context");
context2 = t.assignmentExpression("=", context1, object);
context2 = t.assignmentExpression(
"=",
t.cloneNode(context1),
object,
);
}
node.callee = t.memberExpression(
t.callExpression(

View File

@ -87,7 +87,7 @@ export default declare((api, options) => {
const lazyLoad = template.ast`
function ${templateObject}() {
const data = ${t.callExpression(helperId, callExpressionInput)};
${templateObject} = function() { return data };
${t.cloneNode(templateObject)} = function() { return data };
return data;
}
`;

View File

@ -134,7 +134,8 @@ export default declare(
);
}
return template.statement.ast`this.${id} = ${id}`;
return template.statement.ast`
this.${t.cloneNode(id)} = ${t.cloneNode(id)}`;
});
injectInitialization(classPath, path, assigns);

View File

@ -156,16 +156,16 @@ function handleNested(path, t, node, parentExport) {
let fallthroughValue = t.objectExpression([]);
if (parentExport) {
const memberExpr = t.memberExpression(parentExport, realName);
fallthroughValue = template.expression.ast`
${parentExport}.${realName} || (
${parentExport}.${realName} = ${fallthroughValue}
)
${t.cloneNode(memberExpr)} ||
(${t.cloneNode(memberExpr)} = ${fallthroughValue})
`;
}
return template.statement.ast`
(function (${t.identifier(name)}) {
${namespaceTopLevel}
})(${realName} || (${realName} = ${fallthroughValue}));
})(${realName} || (${t.cloneNode(realName)} = ${fallthroughValue}));
`;
}