Problem: workaround thread leaking problem

This commit is contained in:
Nikolay Krasko
2016-09-09 16:44:47 +03:00
parent 835474e5a1
commit ea1aac07ec
8 changed files with 101 additions and 30 deletions
@@ -63,7 +63,7 @@ public class KotlinConfidenceTest extends LightCompletionTestCase {
@Override
protected void tearDown() throws Exception {
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinConfidenceTest.super.tearDown();
@@ -72,7 +72,7 @@ abstract class KotlinLightCodeInsightFixtureTestCase : KotlinLightCodeInsightFix
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
unInvalidateBuiltinsAndStdLib(project) {
doKotlinTearDown(project) {
super.tearDown()
}
@@ -40,7 +40,7 @@ abstract class KotlinLightPlatformCodeInsightFixtureTestCase: LightPlatformCodeI
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
unInvalidateBuiltinsAndStdLib(project) {
doKotlinTearDown(project) {
super.tearDown()
}
}
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.test
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.editor.Document
import com.intellij.openapi.module.Module
@@ -29,6 +30,7 @@ import com.intellij.psi.impl.PsiManagerEx
import com.intellij.psi.impl.file.impl.FileManagerImpl
import com.intellij.psi.impl.source.PsiFileImpl
import com.intellij.testFramework.LightPlatformTestCase
import com.intellij.testFramework.ThreadTracker
import com.intellij.util.Consumer
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
@@ -38,7 +40,10 @@ import org.jetbrains.kotlin.idea.decompiler.KotlinDecompiledFileViewProvider
import org.jetbrains.kotlin.idea.decompiler.KtDecompiledFile
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.psi.KtFile
import java.lang.IllegalArgumentException
import java.util.*
import java.util.concurrent.ForkJoinPool
import java.util.concurrent.atomic.AtomicBoolean
enum class ModuleKind {
KOTLIN_JVM_WITH_STDLIB_SOURCES,
@@ -47,18 +52,16 @@ enum class ModuleKind {
fun Module.configureAs(descriptor: KotlinLightProjectDescriptor) {
val module = this
updateModel(module, object : Consumer<ModifiableRootModel> {
override fun consume(model: ModifiableRootModel) {
if (descriptor.sdk != null) {
model.sdk = descriptor.sdk
}
val entries = model.contentEntries
if (entries.isEmpty()) {
descriptor.configureModule(module, model)
}
else {
descriptor.configureModule(module, model, entries[0])
}
updateModel(module, Consumer<ModifiableRootModel> { model ->
if (descriptor.sdk != null) {
model.sdk = descriptor.sdk
}
val entries = model.contentEntries
if (entries.isEmpty()) {
descriptor.configureModule(module, model)
}
else {
descriptor.configureModule(module, model, entries[0])
}
})
}
@@ -76,17 +79,29 @@ fun Module.configureAs(kind: ModuleKind) {
}
fun KtFile.dumpTextWithErrors(): String {
val diagnostics = analyzeFullyAndGetResult().bindingContext.getDiagnostics()
val errors = diagnostics.filter { it.getSeverity() == Severity.ERROR }
val diagnostics = analyzeFullyAndGetResult().bindingContext.diagnostics
val errors = diagnostics.filter { it.severity == Severity.ERROR }
if (errors.isEmpty()) return text
val header = errors.map { "// ERROR: " + DefaultErrorMessages.render(it).replace('\n', ' ') }.joinToString("\n", postfix = "\n")
return header + text
}
fun closeAndDeleteProject(): Unit =
ApplicationManager.getApplication().runWriteAction() { LightPlatformTestCase.closeAndDeleteProject() }
ApplicationManager.getApplication().runWriteAction { LightPlatformTestCase.closeAndDeleteProject() }
fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: RunnableWithException) {
fun doKotlinTearDown(project: Project, runnable: RunnableWithException) {
doKotlinTearDown(project) { runnable.run() }
}
fun doKotlinTearDown(project: Project, runnable: () -> Unit) {
unInvalidateBuiltinsAndStdLib(project) {
patchThreadTracker {
runnable()
}
}
}
fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: () -> Unit) {
val stdLibViewProviders = HashSet<KotlinDecompiledFileViewProvider>()
val vFileToViewProviderMap = ((PsiManager.getInstance(project) as PsiManagerEx).fileManager as FileManagerImpl).vFileToViewProviderMap
for ((file, viewProvider) in vFileToViewProviderMap) {
@@ -95,7 +110,7 @@ fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: RunnableWithExcept
}
}
runnable.run()
runnable()
// Base tearDown() invalidates builtins and std-lib files. Restore them with brute force.
fun unInvalidateFile(file: PsiFileImpl) {
@@ -106,23 +121,19 @@ fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: RunnableWithExcept
stdLibViewProviders.forEach {
it.allFiles.forEach { unInvalidateFile(it as KtDecompiledFile) }
vFileToViewProviderMap.set(it.virtualFile, it)
vFileToViewProviderMap[it.virtualFile] = it
}
}
private val VirtualFile.isStdLibFile: Boolean get() = presentableUrl.contains("kotlin-runtime.jar")
fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: () -> Unit) {
unInvalidateBuiltinsAndStdLib(project, RunnableWithException { runnable() })
}
fun invalidateLibraryCache(project: Project) {
LibraryModificationTracker.getInstance(project).incModificationCount()
}
fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret>"): Int {
val offset = runWriteAction {
val text = StringBuilder(getText())
val text = StringBuilder(text)
val offset = text.indexOf(caretMarker)
if (offset >= 0) {
@@ -137,4 +148,49 @@ fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(this)
return offset
}
private val patched = AtomicBoolean(false)
fun patchThreadTracker(runnable: RunnableWithException) {
patchThreadTracker {
runnable.run()
}
}
fun patchThreadTracker(runnable: () -> Unit) {
fun patch() {
if (patched.get()) return
patched.compareAndSet(false, true)
IdeaForkJoinWorkerThreadFactory.setupForkJoinCommonPool()
// Check setup was successful
val commonPoolFactoryName = ForkJoinPool.commonPool().factory.javaClass.name
if (commonPoolFactoryName == IdeaForkJoinWorkerThreadFactory::class.java.name) {
return
}
println("Patching!")
try {
val wellKnownOffendersField = ThreadTracker::class.java.getDeclaredField("wellKnownOffenders")
wellKnownOffendersField.isAccessible = true
@Suppress("UNCHECKED_CAST")
val wellKnownOffenders = wellKnownOffendersField.get(null) as MutableSet<String>
wellKnownOffenders.add("ForkJoinPool.commonPool-worker-")
}
catch (e: NoSuchFieldException) {
println("Patching failed: " + e)
}
catch (e: IllegalAccessException) {
println("Patching failed: " + e)
}
}
patch()
runnable()
}
@@ -18,6 +18,8 @@ package org.jetbrains.kotlin.idea;
import com.intellij.codeInsight.daemon.DaemonAnalyzerTestCase;
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
import org.jetbrains.kotlin.idea.test.RunnableWithException;
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
import org.jetbrains.kotlin.test.KotlinTestUtils;
abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase {
@@ -29,7 +31,12 @@ abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCas
@Override
protected void tearDown() throws Exception {
super.tearDown();
TestUtilsKt.patchThreadTracker(new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinDaemonAnalyzerTestCase.super.tearDown();
}
});
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
}
}
@@ -34,7 +34,7 @@ abstract public class KotlinLightQuickFixTestCase extends LightQuickFixTestCase
protected void tearDown() throws Exception {
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinLightQuickFixTestCase.super.tearDown();
@@ -45,6 +45,8 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade;
import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime;
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
import org.jetbrains.kotlin.idea.test.RunnableWithException;
import org.jetbrains.kotlin.idea.test.TestUtilsKt;
import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils;
import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.psi.KtFile;
@@ -99,6 +101,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase {
ConfigLibraryUtil.addLibrary(customLibEditor, model);
}
@SuppressWarnings("MethodDoesntCallSuperMethod")
@Override
protected void tearDown() throws Exception {
if (getTestName(true).startsWith("dex")) {
@@ -113,7 +116,12 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase {
}
});
super.tearDown();
TestUtilsKt.patchThreadTracker(new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinDebuggerTestCase.super.tearDown();
}
});
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
}
@@ -72,7 +72,7 @@ public abstract class KotlinAndroidTestCaseBase extends UsefulTestCase {
@Override
protected void tearDown() throws Exception {
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
@Override
public void run() throws Exception {
KotlinAndroidTestCaseBase.super.tearDown();