JS inline refactor: refactored clean utils after code review
This commit is contained in:
committed by
Zalim Bashorov
parent
1ad090e3a7
commit
80eca3e49e
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.inline
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
|
||||
import java.util.IdentityHashMap
|
||||
import java.util.Collections
|
||||
|
||||
/**
|
||||
* Removes initializers for default parameters with non-void0 arguments given
|
||||
* Expands initializers for default parameters with void0 arguments given
|
||||
*
|
||||
* @see isInitializer
|
||||
*/
|
||||
fun removeRedundantDefaultInitializers(arguments: List<JsExpression>, parameters: List<JsParameter>, body: JsBlock) {
|
||||
val toRemove = getInitializedParametersNames(arguments, parameters)
|
||||
val toExpand = getUnInitializedParametersNames(arguments, parameters)
|
||||
|
||||
val statements = body.getStatements()
|
||||
|
||||
val newStatements = statements.flatMap {
|
||||
when {
|
||||
!isInitializer(it) -> listOf(it)
|
||||
else -> {
|
||||
val name = getNameFromInitializer(it)
|
||||
when {
|
||||
name in toRemove.keySet() -> listOf<JsStatement>()
|
||||
name in toExpand.keySet() -> expand(it)
|
||||
else -> listOf(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.filterNotNull()
|
||||
|
||||
statements.clear()
|
||||
statements.addAll(newStatements)
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if statement is an initializer for parameter with default value.
|
||||
*
|
||||
* This check assumes that default parameter initializer is generated like:
|
||||
* if (defaultParam === void 0) {
|
||||
* ...
|
||||
* }
|
||||
*/
|
||||
private fun isInitializer(statement: JsStatement): Boolean {
|
||||
return getNameFromInitializer(statement) != null
|
||||
}
|
||||
|
||||
private fun getNameFromInitializer(statement: JsStatement): JsName? {
|
||||
val jsIf = (statement as? JsIf)
|
||||
val ifExpr = jsIf?.getIfExpression() as? JsBinaryOperation
|
||||
|
||||
return when {
|
||||
jsIf?.getElseStatement() != null -> null
|
||||
else -> getNameFromInitializer(ifExpr)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getNameFromInitializer(initializerTestExpression: JsExpression?): JsName? {
|
||||
val binOp = initializerTestExpression as? JsBinaryOperation
|
||||
val arg1 = binOp?.getArg1()
|
||||
val arg2 = binOp?.getArg2()
|
||||
val operator = binOp?.getOperator()
|
||||
|
||||
return when {
|
||||
operator != JsBinaryOperator.REF_EQ -> null
|
||||
!isVoid0(arg2) -> null
|
||||
else -> (arg1 as? JsNameRef)?.getName()
|
||||
}
|
||||
}
|
||||
|
||||
private fun isVoid0(expr: JsExpression?): Boolean {
|
||||
val op = (expr as? JsUnaryOperation)?.getOperator()
|
||||
return op == JsUnaryOperator.VOID
|
||||
}
|
||||
|
||||
private fun getInitializedParametersNames(args: List<JsExpression>,
|
||||
params: List<JsParameter>): Map<JsName, Boolean> {
|
||||
|
||||
val names = IdentityHashMap<JsName, Boolean>()
|
||||
val argParams = (args zip params).stream()
|
||||
|
||||
val initialized = argParams.filter { it.second.hasDefaultValue() }
|
||||
.filter { !isVoid0(it.first) }
|
||||
.map { it.second }
|
||||
|
||||
initialized.map { it.getName() }
|
||||
.forEach { names.put(it, true) }
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
private fun getUnInitializedParametersNames(args: List<JsExpression>,
|
||||
params: List<JsParameter>): Map<JsName, Boolean> {
|
||||
|
||||
val names = IdentityHashMap<JsName, Boolean>()
|
||||
val argParams = (args zip params).stream()
|
||||
|
||||
val void0Params = argParams.filter { it.second.hasDefaultValue() }
|
||||
.filter { isVoid0(it.first) }
|
||||
.map { it.second }
|
||||
|
||||
val noArgsParams = params.drop(args.size).stream()
|
||||
val uninitialized = void0Params.plus(noArgsParams)
|
||||
|
||||
uninitialized.map { it.getName() }
|
||||
.forEach { names.put(it, true) }
|
||||
|
||||
return names
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes initializer check:
|
||||
* if (arg === void 0) { arg = ... }
|
||||
* To list of statement(s):
|
||||
* arg = ...
|
||||
*/
|
||||
private fun expand(initializer: JsStatement): Iterable<JsStatement> {
|
||||
val then = (initializer as? JsIf)?.getThenStatement()
|
||||
|
||||
return when {
|
||||
then is JsBlock -> then.getStatements()
|
||||
then != null -> listOf(then)
|
||||
else -> listOf()
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,7 @@ import org.jetbrains.k2js.inline.context.*;
|
||||
import static org.jetbrains.k2js.inline.util.UtilPackage.collectInstances;
|
||||
import static org.jetbrains.k2js.inline.util.UtilPackage.replaceReturns;
|
||||
import static org.jetbrains.k2js.inline.util.UtilPackage.replaceThisReference;
|
||||
import static org.jetbrains.k2js.inline.clean.CleanPackage.removeDefaultInitializers;
|
||||
|
||||
import static org.jetbrains.k2js.inline.InlinePackage.*;
|
||||
|
||||
@@ -78,7 +79,7 @@ class FunctionInlineMutator {
|
||||
List<JsParameter> parameters = getParameters();
|
||||
|
||||
replaceThis();
|
||||
removeRedundantDefaultInitializers(arguments, parameters, body);
|
||||
removeDefaultInitializers(arguments, parameters, body);
|
||||
aliasArgumentsIfNeeded(namingContext, arguments, parameters);
|
||||
renameLocalNames(namingContext, invokedFunction);
|
||||
|
||||
|
||||
@@ -27,8 +27,8 @@ import java.util.Set;
|
||||
import java.util.Stack;
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.k2js.inline.clean.CleanPackage.removeUnusedLocalFunctionInstances;
|
||||
import static org.jetbrains.k2js.inline.clean.CleanPackage.removeUnusedLocalFunctions;
|
||||
import static org.jetbrains.k2js.inline.clean.CleanPackage.removeUnusedLocalFunctionDeclarations;
|
||||
import static org.jetbrains.k2js.inline.clean.CleanPackage.removeUnusedFunctionDefinitions;
|
||||
import static org.jetbrains.k2js.inline.FunctionInlineMutator.getInlineableCallReplacement;
|
||||
import static org.jetbrains.k2js.inline.util.UtilPackage.IdentitySet;
|
||||
import static org.jetbrains.k2js.inline.util.UtilPackage.collectNamedFunctions;
|
||||
@@ -74,7 +74,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
IdentityHashMap<JsName, JsFunction> functions = collectNamedFunctions(program);
|
||||
JsInliner inliner = new JsInliner(functions);
|
||||
inliner.accept(program);
|
||||
removeUnusedLocalFunctions(program, functions);
|
||||
removeUnusedFunctionDefinitions(program, functions);
|
||||
return program;
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
||||
@Override
|
||||
public void endVisit(JsFunction function, JsContext context) {
|
||||
super.endVisit(function, context);
|
||||
removeUnusedLocalFunctionInstances(function);
|
||||
removeUnusedLocalFunctionDeclarations(function);
|
||||
processedFunctions.add(function);
|
||||
|
||||
assert inProcessFunctions.contains(function);
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.k2js.inline.util.IdentitySet
|
||||
|
||||
private class FunctionRemover(removable: Collection<JsFunction> = listOf()) : NodeRemovingVisitor<JsFunction>(removable) {
|
||||
|
||||
override fun endVisit(x: JsPropertyInitializer?, ctx: JsContext?) {
|
||||
if (x == null) return
|
||||
|
||||
val value = x.getValueExpr()
|
||||
if (value is JsFunction && shouldRemove(value)) {
|
||||
ctx?.removeMe()
|
||||
} else {
|
||||
super.endVisit(x, ctx)
|
||||
}
|
||||
}
|
||||
}
|
||||
+14
-7
@@ -16,17 +16,24 @@
|
||||
|
||||
package org.jetbrains.k2js.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import com.google.dart.compiler.backend.js.ast.JsVisitorWithContextImpl
|
||||
import com.google.dart.compiler.backend.js.ast.JsNode
|
||||
import com.google.dart.compiler.backend.js.ast.JsContext
|
||||
|
||||
private class GenericRemover<T : JsNode>(removable: Collection<T> = listOf()) : NodeRemovingVisitor<T>(removable) {
|
||||
private class NodeRemover<T>(val klass: Class<T>, val predicate: (T) -> Boolean): JsVisitorWithContextImpl() {
|
||||
|
||||
override fun <T : JsNode?> doTraverse(node: T?, ctx: JsContext?) {
|
||||
if (node == null) return
|
||||
if (node == null || ctx == null) return
|
||||
|
||||
if (shouldRemove(node)) {
|
||||
ctx?.removeMe()
|
||||
} else {
|
||||
super.doTraverse(node, ctx)
|
||||
if (klass.isInstance(node)) {
|
||||
val instance = klass.cast(node)!!
|
||||
|
||||
if (predicate(instance)) {
|
||||
ctx.removeMe()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
super.doTraverse(node, ctx)
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.k2js.inline.util.IdentitySet
|
||||
|
||||
import java.util.IdentityHashMap
|
||||
import org.jetbrains.k2js.inline.util.toIdentitySet
|
||||
|
||||
private abstract class NodeRemovingVisitor<T : JsNode>(removable: Collection<T>) : JsVisitorWithContextImpl() {
|
||||
private val removeSet: Set<T> = removable.toIdentitySet()
|
||||
|
||||
protected fun <R : JsNode?> shouldRemove(node: R): Boolean {
|
||||
return removeSet.contains(node)
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,7 @@ import java.util.ArrayList
|
||||
private class ReferenceTracker<Reference, RemoveCandidate : JsNode> {
|
||||
private val reachable = IdentityHashMap<Reference, Boolean>()
|
||||
private val removableCandidates = IdentityHashMap<Reference, RemoveCandidate>()
|
||||
private val refereceFromTo = IdentityHashMap<Reference, MutableList<Reference>>()
|
||||
private val refereceFromTo = IdentityHashMap<Reference, MutableSet<Reference>>()
|
||||
private val visited = IdentitySet<Reference>()
|
||||
|
||||
public val removable: List<RemoveCandidate>
|
||||
@@ -65,8 +65,8 @@ private class ReferenceTracker<Reference, RemoveCandidate : JsNode> {
|
||||
reachable[reference] = true
|
||||
}
|
||||
|
||||
private fun getReferencedBy(referer: Reference): MutableList<Reference> {
|
||||
return refereceFromTo.getOrPut(referer, { ArrayList<Reference>() })
|
||||
private fun getReferencedBy(referer: Reference): MutableSet<Reference> {
|
||||
return refereceFromTo.getOrPut(referer, { IdentitySet<Reference>() })
|
||||
}
|
||||
|
||||
private fun isKnown(ref: Reference): Boolean {
|
||||
|
||||
@@ -1,50 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
import org.jetbrains.k2js.inline.util.IdentitySet
|
||||
|
||||
import java.util.ArrayList
|
||||
|
||||
private fun collectFunctionReferencesInside(scope: JsNode): List<JsName> {
|
||||
return with(ReferenceNameCollector()) {
|
||||
accept(scope)
|
||||
references.filter { it.getStaticRef() is JsFunction }
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectReferencesInside(scope: JsNode): List<JsName> {
|
||||
return with(ReferenceNameCollector()) {
|
||||
accept(scope)
|
||||
references
|
||||
}
|
||||
}
|
||||
|
||||
private class ReferenceNameCollector : JsVisitorWithContextImpl() {
|
||||
private val referenceSet = IdentitySet<JsName>()
|
||||
|
||||
public val references: List<JsName>
|
||||
get() = referenceSet.toList()
|
||||
|
||||
override fun endVisit(x: JsNameRef?, ctx: JsContext?) {
|
||||
val name = x?.getName()
|
||||
if (name != null) {
|
||||
referenceSet.add(name)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
/*
|
||||
* Copyright 2010-2014 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.k2js.inline.clean
|
||||
|
||||
import com.google.dart.compiler.backend.js.ast.*
|
||||
|
||||
import org.jetbrains.k2js.inline.util.toIdentitySet
|
||||
import org.jetbrains.k2js.inline.util.zipWithDefault
|
||||
import org.jetbrains.k2js.translate.context.Namer
|
||||
import org.jetbrains.k2js.translate.context.Namer.isUndefined
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils.flattenStatement
|
||||
|
||||
import java.util.IdentityHashMap
|
||||
import java.util.Collections
|
||||
import org.jetbrains.k2js.translate.utils.JsAstUtils
|
||||
|
||||
/**
|
||||
* Removes initializers for default parameters with defined arguments given
|
||||
* Expands initializers for default parameters with undefined arguments given
|
||||
*
|
||||
* @see isInitializer
|
||||
*/
|
||||
public fun removeDefaultInitializers(arguments: List<JsExpression>, parameters: List<JsParameter>, body: JsBlock) {
|
||||
val toRemove = getDefaultParamsNames(arguments, parameters, initialized = true)
|
||||
val toExpand = getDefaultParamsNames(arguments, parameters, initialized = false)
|
||||
|
||||
val statements = body.getStatements()
|
||||
val newStatements = statements.flatMap {
|
||||
val name = getNameFromInitializer(it)
|
||||
if (name != null && !isNameInitialized(name, it)) {
|
||||
throw AssertionError("Unexpected initializer structure")
|
||||
}
|
||||
|
||||
when {
|
||||
name in toRemove ->
|
||||
listOf<JsStatement>()
|
||||
name in toExpand ->
|
||||
flattenStatement((it as JsIf).getThenStatement()!!)
|
||||
else ->
|
||||
listOf(it)
|
||||
}
|
||||
}
|
||||
|
||||
statements.clear()
|
||||
statements.addAll(newStatements)
|
||||
}
|
||||
|
||||
private fun getNameFromInitializer(statement: JsStatement): JsName? {
|
||||
val ifStmt = (statement as? JsIf)
|
||||
val testExpr = ifStmt?.getIfExpression()
|
||||
|
||||
val elseStmt = ifStmt?.getElseStatement()
|
||||
if (elseStmt == null && testExpr is JsBinaryOperation)
|
||||
return getNameFromInitializer(testExpr)
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getNameFromInitializer(isInitializedExpr: JsBinaryOperation): JsName? {
|
||||
val arg1 = isInitializedExpr.getArg1()
|
||||
val arg2 = isInitializedExpr.getArg2()
|
||||
val op = isInitializedExpr.getOperator()
|
||||
|
||||
if (arg1 == null || arg2 == null || op == null) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (op == JsBinaryOperator.REF_EQ && isUndefined(arg2)) {
|
||||
return (arg1 as? JsNameRef)?.getName()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Tests if the last statement of initializer
|
||||
* is name assignment.
|
||||
*/
|
||||
private fun isNameInitialized(
|
||||
name: JsName,
|
||||
initializer: JsStatement
|
||||
): Boolean {
|
||||
val thenStmt = (initializer as JsIf).getThenStatement()!!
|
||||
val lastThenStmt = flattenStatement(thenStmt).last
|
||||
|
||||
val expr = (lastThenStmt as? JsExpressionStatement)?.getExpression()
|
||||
if (expr !is JsBinaryOperation) return false
|
||||
|
||||
val op = expr.getOperator()!!
|
||||
if (!op.isAssignment()) return false
|
||||
|
||||
val arg1 = expr.getArg1()
|
||||
if (arg1 is HasName && arg1.getName() identityEquals name) return true
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun getDefaultParamsNames(
|
||||
args: List<JsExpression>,
|
||||
params: List<JsParameter>,
|
||||
initialized: Boolean
|
||||
): Set<JsName> {
|
||||
|
||||
val argsParams = args.zipWithDefault(params, Namer.UNDEFINED_EXPRESSION)
|
||||
val relevantParams = argsParams.stream()
|
||||
.filter { it.second.hasDefaultValue() }
|
||||
.filter { initialized == !isUndefined(it.first) }
|
||||
|
||||
val names = relevantParams.map { it.second.getName() }
|
||||
return names.toIdentitySet()
|
||||
}
|
||||
|
||||
+15
-4
@@ -21,17 +21,28 @@ import org.jetbrains.k2js.inline.util.IdentitySet
|
||||
|
||||
import com.intellij.util.containers.Stack
|
||||
import java.util.IdentityHashMap
|
||||
import org.jetbrains.k2js
|
||||
import org.jetbrains.k2js.inline.util.collectReferencesInside
|
||||
import org.jetbrains.k2js.inline.util.collectFunctionReferencesInside
|
||||
|
||||
public fun removeUnusedLocalFunctions(root: JsNode, functions: Map<JsName, JsFunction>) {
|
||||
/**
|
||||
* Removes unused function definitions:
|
||||
* f: function() { return 10 }
|
||||
*
|
||||
* At now, it only removes unused local functions and function literals,
|
||||
* because named functions can be referenced from another module.
|
||||
*/
|
||||
public fun removeUnusedFunctionDefinitions(root: JsNode, functions: Map<JsName, JsFunction>) {
|
||||
val removable = with(UnusedLocalFunctionsCollector(functions)) {
|
||||
process()
|
||||
accept(root)
|
||||
removableFunctions
|
||||
}
|
||||
|
||||
with(FunctionRemover(removable)) {
|
||||
accept(root)
|
||||
}
|
||||
NodeRemover(javaClass<JsPropertyInitializer>()) {
|
||||
val function = it.getValueExpr() as? JsFunction
|
||||
function in removable
|
||||
}.accept(root)
|
||||
}
|
||||
|
||||
private class UnusedLocalFunctionsCollector(functions: Map<JsName, JsFunction>) : JsVisitorWithContextImpl() {
|
||||
+16
-7
@@ -20,27 +20,36 @@ import com.google.dart.compiler.backend.js.ast.*
|
||||
|
||||
import java.util.ArrayList
|
||||
import java.util.IdentityHashMap
|
||||
import org.jetbrains.k2js
|
||||
|
||||
public fun removeUnusedLocalFunctionInstances(root: JsNode) {
|
||||
/**
|
||||
* Removes unused local function declarations like:
|
||||
* var inc = _.foo.f$inc(a)
|
||||
*
|
||||
* Declaration can become unused, if inlining happened.
|
||||
*/
|
||||
public fun removeUnusedLocalFunctionDeclarations(root: JsNode) {
|
||||
val removable =
|
||||
with(UnusedInstanceCollector()) {
|
||||
accept(root)
|
||||
removableInstances
|
||||
removableDeclarations
|
||||
}
|
||||
|
||||
GenericRemover(removable).accept(root)
|
||||
NodeRemover(javaClass<JsStatement>()) {
|
||||
it in removable
|
||||
}.accept(root)
|
||||
}
|
||||
|
||||
private class UnusedInstanceCollector : JsVisitorWithContextImpl() {
|
||||
private val tracker = ReferenceTracker<JsName, JsStatement>()
|
||||
|
||||
public val removableInstances: List<JsStatement>
|
||||
public val removableDeclarations: List<JsStatement>
|
||||
get() = tracker.removable
|
||||
|
||||
override fun visit(x: JsVars.JsVar?, ctx: JsContext?): Boolean {
|
||||
if (x == null) return false
|
||||
|
||||
if (!isLocalFunctionInstance(x)) return super.visit(x, ctx)
|
||||
if (!isLocalFunctionDeclaration(x)) return super.visit(x, ctx)
|
||||
|
||||
val name = x.getName()!!
|
||||
val statementContext = getLastStatementLevelContext()
|
||||
@@ -49,7 +58,7 @@ private class UnusedInstanceCollector : JsVisitorWithContextImpl() {
|
||||
val currentStatement = currentNode as JsStatement
|
||||
tracker.addCandidateForRemoval(name, currentStatement)
|
||||
|
||||
val references = collectReferencesInside(x)
|
||||
val references = k2js.inline.util.collectReferencesInside(x)
|
||||
references.filterNotNull()
|
||||
.forEach { tracker.addRemovableReference(name, it) }
|
||||
|
||||
@@ -66,7 +75,7 @@ private class UnusedInstanceCollector : JsVisitorWithContextImpl() {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun isLocalFunctionInstance(jsVar: JsVars.JsVar): Boolean {
|
||||
private fun isLocalFunctionDeclaration(jsVar: JsVars.JsVar): Boolean {
|
||||
val name = jsVar.getName()
|
||||
val expr = jsVar.getInitExpression()
|
||||
val staticRef = name?.getStaticRef()
|
||||
Reference in New Issue
Block a user