From 015d7f33007b306dab23216fa38970f1e148db9d Mon Sep 17 00:00:00 2001 From: Yan Zhulanow Date: Fri, 11 May 2018 00:07:21 +0300 Subject: [PATCH] Kapt: Do not retain references to Kotlin compiler classes in customized Javac components This should fix potential memory leakages. --- .../org/jetbrains/kotlin/kapt3/KaptContext.kt | 22 +++++++++++-------- .../kotlin/kapt3/javac/KaptJavaLog.kt | 7 +++--- .../kotlin/kapt3/javac/KaptTreeMaker.kt | 20 ++++++++++++++++- .../kapt3/test/AbstractKotlinKapt3Test.kt | 8 ++++++- 4 files changed, 42 insertions(+), 15 deletions(-) diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContext.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContext.kt index 64ecb86b868..146623b4ce2 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContext.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/KaptContext.kt @@ -20,6 +20,7 @@ import com.intellij.openapi.project.Project import com.sun.tools.javac.file.JavacFileManager import com.sun.tools.javac.jvm.ClassReader import com.sun.tools.javac.main.JavaCompiler +import com.sun.tools.javac.tree.TreeMaker import com.sun.tools.javac.util.Context import com.sun.tools.javac.util.Options import org.jetbrains.kotlin.codegen.state.GenerationState @@ -34,21 +35,22 @@ import org.jetbrains.org.objectweb.asm.tree.ClassNode import javax.tools.JavaFileManager class KaptContext( - val logger: KaptLogger, - val project: Project, - val bindingContext: BindingContext, - val compiledClasses: List, - val origins: Map, - val generationState: GState, - mapDiagnosticLocations: Boolean, - processorOptions: Map, - javacOptions: Map = emptyMap() + val logger: KaptLogger, + val project: Project, + val bindingContext: BindingContext, + val compiledClasses: List, + val origins: Map, + val generationState: GState, + mapDiagnosticLocations: Boolean, + processorOptions: Map, + javacOptions: Map = emptyMap() ) : AutoCloseable { val context = Context() val compiler: KaptJavaCompiler val fileManager: JavacFileManager val options: Options val javaLog: KaptJavaLog + val treeMaker: KaptTreeMaker init { KaptJavaLog.preRegister(this, logger.messageCollector, mapDiagnosticLocations) @@ -81,9 +83,11 @@ class KaptContext( ClassReader.instance(context).saveParameterNames = true javaLog = compiler.log as KaptJavaLog + treeMaker = TreeMaker.instance(context) as KaptTreeMaker } override fun close() { + treeMaker.dispose() compiler.close() fileManager.close() generationState?.destroy() diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaLog.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaLog.kt index 778563afcc0..1045f45dc5a 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaLog.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptJavaLog.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.kapt3.javac -import com.intellij.openapi.project.Project import com.sun.tools.javac.tree.JCTree import com.sun.tools.javac.util.* import com.sun.tools.javac.util.JCDiagnostic.DiagnosticType @@ -36,7 +35,7 @@ import javax.tools.SimpleJavaFileObject import com.sun.tools.javac.util.List as JavacList class KaptJavaLog( - private val project: Project, + private val projectBasePath: String?, context: Context, errWriter: PrintWriter, warnWriter: PrintWriter, @@ -184,7 +183,7 @@ class KaptJavaLog( private fun getKotlinSourceFile(pos: KotlinPosition): File? { return if (pos.isRelativePath) { - val basePath = project.basePath + val basePath = this.projectBasePath if (basePath != null) File(basePath, pos.path) else null } else { @@ -242,7 +241,7 @@ class KaptJavaLog( val noticeWriter = makeWriter(WARNING) KaptJavaLog( - kaptContext.project, newContext, errWriter, warnWriter, noticeWriter, + kaptContext.project.basePath, newContext, errWriter, warnWriter, noticeWriter, interceptorData, mapDiagnosticLocations) }) } diff --git a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt index 70e1eda92cc..c75c4f5c59f 100644 --- a/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt +++ b/plugins/kapt3/kapt3-compiler/src/org/jetbrains/kotlin/kapt3/javac/KaptTreeMaker.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.kapt3.javac +import com.intellij.openapi.Disposable import com.intellij.psi.JavaPsiFacade import com.intellij.psi.PsiClass import com.intellij.psi.search.GlobalSearchScope @@ -32,7 +33,9 @@ import org.jetbrains.org.objectweb.asm.Type import org.jetbrains.org.objectweb.asm.Type.* import org.jetbrains.org.objectweb.asm.tree.ClassNode -class KaptTreeMaker(context: Context, private val kaptContext: KaptContext<*>) : TreeMaker(context) { +class KaptTreeMaker(context: Context, kaptContext: KaptContext<*>) : TreeMaker(context), Disposable { + private var kaptContext = DisposableReference(kaptContext) + val nameTable: Name.Table = Names.instance(context).table fun Type(type: Type): JCTree.JCExpression { @@ -70,6 +73,8 @@ class KaptTreeMaker(context: Context, private val kaptContext: KaptContext<*>) : // This is a top-level class if ('$' !in nameWithDots) return nameWithDots + val kaptContext = this.kaptContext.get() + // Maybe it's in our sources? val classFromSources = kaptContext.compiledClasses.firstOrNull { it.name == internalName } if (classFromSources != null) { @@ -161,9 +166,22 @@ class KaptTreeMaker(context: Context, private val kaptContext: KaptContext<*>) : fun name(name: String): Name = nameTable.fromString(name) + override fun dispose() { + kaptContext.dispose() + } + companion object { internal fun preRegister(context: Context, kaptContext: KaptContext<*>) { context.put(treeMakerKey, Context.Factory { KaptTreeMaker(it, kaptContext) }) } } +} + +private class DisposableReference(obj: T) : Disposable { + private var obj: T? = obj + fun get() = obj!! + + override fun dispose() { + obj = null + } } \ No newline at end of file diff --git a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt index ba44069f5a1..94e110c0f55 100644 --- a/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt +++ b/plugins/kapt3/kapt3-compiler/test/org/jetbrains/kotlin/kapt3/test/AbstractKotlinKapt3Test.kt @@ -208,7 +208,13 @@ open class AbstractClassFileToSourceStubConverterTest : AbstractKotlinKapt3Test( @JvmStatic fun main(args: Array) { if (args.isEmpty()) error("1 argument expected, 0 passed") - AbstractClassFileToSourceStubConverterTest().doTest(args[0]) + val test = AbstractClassFileToSourceStubConverterTest() + try { + test.setUp() + test.doTest(args[0]) + } finally { + test.tearDown() + } } }