All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jetbrains.kotlin.js.inline.clean.removeUnusedImports.kt Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * Copyright 2010-2016 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.kotlin.js.inline.clean

import org.jetbrains.kotlin.js.backend.ast.*
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
import org.jetbrains.kotlin.js.backend.ast.metadata.imported


fun removeUnusedImports(fragment: JsProgramFragment, code: JsBlock) {
    val usedImports = mutableSetOf()

    collectUsedImports(code, usedImports)

    fragment.nameBindings.retainAll { !it.name.imported || it.name in usedImports }

    val existingTags = fragment.nameBindings.map { it.key }.toSet()

    fragment.imports.entries.retainAll { (k, _) -> k in existingTags }
}

private fun collectUsedImports(root: JsNode, to: MutableSet): Set {
    val collector = UsedImportsCollector(to)
    root.accept(collector)

    // See StaticContext.getVariableForPropertyMetadata
    // TODO Find a better way
    val removedPseudoImports = mutableSetOf()
    NodeRemover(JsVars::class.java) { statement ->
        if (statement.vars.size == 1) {
            val name = statement.vars[0].name
            (name.imported && name !in collector.usedImports).also {
                if (it) removedPseudoImports += name
            }
        } else {
            false
        }
    }.accept(root)
    collector.pseudoImports.forEach {
        if (it.name !in removedPseudoImports) {
            it.initExpression.accept(collector)
        }
    }

    return collector.usedImports
}

private class UsedImportsCollector(val usedImports: MutableSet) : RecursiveJsVisitor() {

    val pseudoImports = mutableListOf()

    override fun visit(x: JsVars.JsVar) {
        if (x.name.imported) {
            pseudoImports += x
        } else {
            super.visit(x)
        }
    }

    override fun visitNameRef(nameRef: JsNameRef) {
        val name = nameRef.name
        if (name != null && name.imported) {
            usedImports += name
        }
        super.visitNameRef(nameRef)
    }

    override fun visitFunction(x: JsFunction) {
        x.coroutineMetadata?.apply {
            accept(suspendObjectRef)
            accept(baseClassRef)
        }
        super.visitFunction(x)
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy