JS: fix removal of unused functions in handwritten JS

This commit is contained in:
Alexey Andreev 2023-11-13 10:37:30 +01:00
parent f6741b49d6
commit 1955973c3b
2 changed files with 38 additions and 17 deletions

View File

@ -268,7 +268,7 @@ public class AstVisitor {
public void visit(Scope node) {
var scope = enterScope(node);
visitChildren(node);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(LabeledStatement node) {
@ -294,7 +294,7 @@ public class AstVisitor {
var scope = enterScope(node);
visitProperty(node, DoLoop::getBody, DoLoop::setBody, EMPTY_DEFAULT);
visitProperty(node, DoLoop::getCondition, DoLoop::setCondition, NULL_DEFAULT);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(ForInLoop node) {
@ -302,7 +302,7 @@ public class AstVisitor {
visitProperty(node, ForInLoop::getIterator, ForInLoop::setIterator, NULL_DEFAULT);
visitProperty(node, ForInLoop::getIteratedObject, ForInLoop::setIteratedObject, NULL_DEFAULT);
visitProperty(node, ForInLoop::getBody, ForInLoop::setBody, EMPTY_DEFAULT);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(ForLoop node) {
@ -311,14 +311,14 @@ public class AstVisitor {
visitProperty(node, ForLoop::getCondition, ForLoop::setCondition, EMPTY_EXPR_DEFAULT);
visitProperty(node, ForLoop::getIncrement, ForLoop::setIncrement, EMPTY_EXPR_DEFAULT);
visitProperty(node, ForLoop::getBody, ForLoop::setBody, EMPTY_DEFAULT);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(WhileLoop node) {
var scope = enterScope(node);
visitProperty(node, WhileLoop::getCondition, WhileLoop::setCondition, NULL_DEFAULT);
visitProperty(node, WhileLoop::getBody, WhileLoop::setBody, EMPTY_DEFAULT);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(IfStatement node) {
@ -397,7 +397,7 @@ public class AstVisitor {
}
visitProperty(node, ArrayComprehension::getFilter, ArrayComprehension::setFilter);
visitProperty(node, ArrayComprehension::getResult, ArrayComprehension::setResult);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(GeneratorExpression node) {
@ -409,7 +409,7 @@ public class AstVisitor {
}
visitProperty(node, GeneratorExpression::getFilter, GeneratorExpression::setFilter);
visitProperty(node, GeneratorExpression::getResult, GeneratorExpression::setResult);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(NumberLiteral node) {
@ -452,14 +452,14 @@ public class AstVisitor {
visitProperty(node, FunctionNode::getFunctionName, FunctionNode::setFunctionName);
visitMany(node.getParams());
visitChildren(node.getBody());
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(LetNode node) {
var scope = enterScope(node);
visitProperty(node, LetNode::getVariables, LetNode::setVariables);
visitProperty(node, LetNode::getBody, LetNode::setBody);
leaveScope(scope);
leaveScope(node, scope);
}
public void visit(ParenthesizedExpression node) {
@ -492,6 +492,7 @@ public class AstVisitor {
private Map<String, Scope> enterScope(Scope scope) {
onEnterScope(scope);
if (scope.getSymbolTable() == null) {
return Collections.emptyMap();
}
@ -503,7 +504,11 @@ public class AstVisitor {
return map;
}
private void leaveScope(Map<String, Scope> backup) {
protected void onEnterScope(Scope scope) {
}
private void leaveScope(Scope scope, Map<String, Scope> backup) {
onLeaveScope(scope);
for (var entry : backup.entrySet()) {
if (entry.getValue() == null) {
currentScopes.remove(entry.getKey());
@ -513,6 +518,9 @@ public class AstVisitor {
}
}
protected void onLeaveScope(Scope scope) {
}
protected Scope scopeOfId(String id) {
return currentScopes.get(id);
}

View File

@ -34,7 +34,7 @@ import org.teavm.backend.javascript.ast.AstVisitor;
public class RemovablePartsFinder extends AstVisitor {
private Map<String, List<AstNode>> removableDeclarations = new HashMap<>();
private Map<String, Scope> removableDeclarationScopes = new HashMap<>();
private Set<Scope> removableDeclarationScopes = new HashSet<>();
private Map<String, Set<String>> dependencies = new HashMap<>();
private String insideDeclaration;
private boolean topLevel = true;
@ -44,7 +44,6 @@ public class RemovablePartsFinder extends AstVisitor {
if (topLevel) {
if (node.getName() != null && !node.getName().isEmpty()) {
removableDeclarations.computeIfAbsent(node.getName(), k -> new ArrayList<>()).add(node);
removableDeclarationScopes.put(node.getName(), scopeOfId(node.getName()));
}
topLevel = false;
insideDeclaration = node.getName();
@ -64,7 +63,6 @@ public class RemovablePartsFinder extends AstVisitor {
if (name != null) {
removableDeclarations.computeIfAbsent(name.getIdentifier(), k -> new ArrayList<>())
.add(initializer);
removableDeclarationScopes.put(name.getIdentifier(), scopeOfId(name.getIdentifier()));
if (initializer.getInitializer() != null) {
topLevel = false;
insideDeclaration = name.getIdentifier();
@ -86,7 +84,6 @@ public class RemovablePartsFinder extends AstVisitor {
var name = extractName(assign.getLeft());
removableDeclarations.computeIfAbsent(name.getIdentifier(), k -> new ArrayList<>())
.add(node.getExpression());
removableDeclarationScopes.put(name.getIdentifier(), scopeOfId(name.getIdentifier()));
if (name != null) {
topLevel = false;
insideDeclaration = name.getIdentifier();
@ -106,9 +103,11 @@ public class RemovablePartsFinder extends AstVisitor {
@Override
public void visit(Name node) {
if (scopeOfId(node.getIdentifier()) == removableDeclarationScopes.get(node.getIdentifier())
&& insideDeclaration != null) {
dependencies.computeIfAbsent(insideDeclaration, k -> new HashSet<>()).add(node.getIdentifier());
if (insideDeclaration != null) {
var actualScope = scopeOfId(node.getIdentifier());
if (actualScope == null || removableDeclarationScopes.contains(actualScope)) {
dependencies.computeIfAbsent(insideDeclaration, k -> new HashSet<>()).add(node.getIdentifier());
}
}
}
@ -141,4 +140,18 @@ public class RemovablePartsFinder extends AstVisitor {
}
return nodes;
}
@Override
protected void onEnterScope(Scope scope) {
if (topLevel) {
removableDeclarationScopes.add(scope);
}
}
@Override
protected void onLeaveScope(Scope scope) {
if (topLevel) {
removableDeclarationScopes.remove(scope);
}
}
}