Problem: workaround thread leaking problem
This commit is contained in:
+1
-1
@@ -63,7 +63,7 @@ public class KotlinConfidenceTest extends LightCompletionTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
|
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
KotlinConfidenceTest.super.tearDown();
|
KotlinConfidenceTest.super.tearDown();
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ abstract class KotlinLightCodeInsightFixtureTestCase : KotlinLightCodeInsightFix
|
|||||||
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
|
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
|
||||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
||||||
|
|
||||||
unInvalidateBuiltinsAndStdLib(project) {
|
doKotlinTearDown(project) {
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -40,7 +40,7 @@ abstract class KotlinLightPlatformCodeInsightFixtureTestCase: LightPlatformCodeI
|
|||||||
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
|
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
|
||||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
||||||
|
|
||||||
unInvalidateBuiltinsAndStdLib(project) {
|
doKotlinTearDown(project) {
|
||||||
super.tearDown()
|
super.tearDown()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.test
|
package org.jetbrains.kotlin.idea.test
|
||||||
|
|
||||||
|
import com.intellij.concurrency.IdeaForkJoinWorkerThreadFactory
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.editor.Document
|
import com.intellij.openapi.editor.Document
|
||||||
import com.intellij.openapi.module.Module
|
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.file.impl.FileManagerImpl
|
||||||
import com.intellij.psi.impl.source.PsiFileImpl
|
import com.intellij.psi.impl.source.PsiFileImpl
|
||||||
import com.intellij.testFramework.LightPlatformTestCase
|
import com.intellij.testFramework.LightPlatformTestCase
|
||||||
|
import com.intellij.testFramework.ThreadTracker
|
||||||
import com.intellij.util.Consumer
|
import com.intellij.util.Consumer
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.diagnostics.rendering.DefaultErrorMessages
|
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.decompiler.KtDecompiledFile
|
||||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||||
import org.jetbrains.kotlin.psi.KtFile
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import java.lang.IllegalArgumentException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.concurrent.ForkJoinPool
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
enum class ModuleKind {
|
enum class ModuleKind {
|
||||||
KOTLIN_JVM_WITH_STDLIB_SOURCES,
|
KOTLIN_JVM_WITH_STDLIB_SOURCES,
|
||||||
@@ -47,18 +52,16 @@ enum class ModuleKind {
|
|||||||
|
|
||||||
fun Module.configureAs(descriptor: KotlinLightProjectDescriptor) {
|
fun Module.configureAs(descriptor: KotlinLightProjectDescriptor) {
|
||||||
val module = this
|
val module = this
|
||||||
updateModel(module, object : Consumer<ModifiableRootModel> {
|
updateModel(module, Consumer<ModifiableRootModel> { model ->
|
||||||
override fun consume(model: ModifiableRootModel) {
|
if (descriptor.sdk != null) {
|
||||||
if (descriptor.sdk != null) {
|
model.sdk = descriptor.sdk
|
||||||
model.sdk = descriptor.sdk
|
}
|
||||||
}
|
val entries = model.contentEntries
|
||||||
val entries = model.contentEntries
|
if (entries.isEmpty()) {
|
||||||
if (entries.isEmpty()) {
|
descriptor.configureModule(module, model)
|
||||||
descriptor.configureModule(module, model)
|
}
|
||||||
}
|
else {
|
||||||
else {
|
descriptor.configureModule(module, model, entries[0])
|
||||||
descriptor.configureModule(module, model, entries[0])
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -76,17 +79,29 @@ fun Module.configureAs(kind: ModuleKind) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun KtFile.dumpTextWithErrors(): String {
|
fun KtFile.dumpTextWithErrors(): String {
|
||||||
val diagnostics = analyzeFullyAndGetResult().bindingContext.getDiagnostics()
|
val diagnostics = analyzeFullyAndGetResult().bindingContext.diagnostics
|
||||||
val errors = diagnostics.filter { it.getSeverity() == Severity.ERROR }
|
val errors = diagnostics.filter { it.severity == Severity.ERROR }
|
||||||
if (errors.isEmpty()) return text
|
if (errors.isEmpty()) return text
|
||||||
val header = errors.map { "// ERROR: " + DefaultErrorMessages.render(it).replace('\n', ' ') }.joinToString("\n", postfix = "\n")
|
val header = errors.map { "// ERROR: " + DefaultErrorMessages.render(it).replace('\n', ' ') }.joinToString("\n", postfix = "\n")
|
||||||
return header + text
|
return header + text
|
||||||
}
|
}
|
||||||
|
|
||||||
fun closeAndDeleteProject(): Unit =
|
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 stdLibViewProviders = HashSet<KotlinDecompiledFileViewProvider>()
|
||||||
val vFileToViewProviderMap = ((PsiManager.getInstance(project) as PsiManagerEx).fileManager as FileManagerImpl).vFileToViewProviderMap
|
val vFileToViewProviderMap = ((PsiManager.getInstance(project) as PsiManagerEx).fileManager as FileManagerImpl).vFileToViewProviderMap
|
||||||
for ((file, viewProvider) in 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.
|
// Base tearDown() invalidates builtins and std-lib files. Restore them with brute force.
|
||||||
fun unInvalidateFile(file: PsiFileImpl) {
|
fun unInvalidateFile(file: PsiFileImpl) {
|
||||||
@@ -106,23 +121,19 @@ fun unInvalidateBuiltinsAndStdLib(project: Project, runnable: RunnableWithExcept
|
|||||||
|
|
||||||
stdLibViewProviders.forEach {
|
stdLibViewProviders.forEach {
|
||||||
it.allFiles.forEach { unInvalidateFile(it as KtDecompiledFile) }
|
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")
|
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) {
|
fun invalidateLibraryCache(project: Project) {
|
||||||
LibraryModificationTracker.getInstance(project).incModificationCount()
|
LibraryModificationTracker.getInstance(project).incModificationCount()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret>"): Int {
|
fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret>"): Int {
|
||||||
val offset = runWriteAction {
|
val offset = runWriteAction {
|
||||||
val text = StringBuilder(getText())
|
val text = StringBuilder(text)
|
||||||
val offset = text.indexOf(caretMarker)
|
val offset = text.indexOf(caretMarker)
|
||||||
|
|
||||||
if (offset >= 0) {
|
if (offset >= 0) {
|
||||||
@@ -137,4 +148,49 @@ fun Document.extractMarkerOffset(project: Project, caretMarker: String = "<caret
|
|||||||
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(this)
|
PsiDocumentManager.getInstance(project).doPostponedOperationsAndUnblockDocument(this)
|
||||||
|
|
||||||
return offset
|
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.codeInsight.daemon.DaemonAnalyzerTestCase;
|
||||||
import com.intellij.openapi.vfs.newvfs.impl.VfsRootAccess;
|
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;
|
import org.jetbrains.kotlin.test.KotlinTestUtils;
|
||||||
|
|
||||||
abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase {
|
abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCase {
|
||||||
@@ -29,7 +31,12 @@ abstract public class KotlinDaemonAnalyzerTestCase extends DaemonAnalyzerTestCas
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
super.tearDown();
|
TestUtilsKt.patchThreadTracker(new RunnableWithException() {
|
||||||
|
@Override
|
||||||
|
public void run() throws Exception {
|
||||||
|
KotlinDaemonAnalyzerTestCase.super.tearDown();
|
||||||
|
}
|
||||||
|
});
|
||||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ abstract public class KotlinLightQuickFixTestCase extends LightQuickFixTestCase
|
|||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||||
|
|
||||||
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
|
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
KotlinLightQuickFixTestCase.super.tearDown();
|
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.codegen.forTestCompile.ForTestCompileRuntime;
|
||||||
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
|
import org.jetbrains.kotlin.idea.test.ConfigLibraryUtil;
|
||||||
import org.jetbrains.kotlin.idea.test.PluginTestCaseBase;
|
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.load.kotlin.PackagePartClassUtils;
|
||||||
import org.jetbrains.kotlin.name.FqName;
|
import org.jetbrains.kotlin.name.FqName;
|
||||||
import org.jetbrains.kotlin.psi.KtFile;
|
import org.jetbrains.kotlin.psi.KtFile;
|
||||||
@@ -99,6 +101,7 @@ public abstract class KotlinDebuggerTestCase extends DescriptorTestCase {
|
|||||||
ConfigLibraryUtil.addLibrary(customLibEditor, model);
|
ConfigLibraryUtil.addLibrary(customLibEditor, model);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("MethodDoesntCallSuperMethod")
|
||||||
@Override
|
@Override
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
if (getTestName(true).startsWith("dex")) {
|
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());
|
VfsRootAccess.allowRootAccess(KotlinTestUtils.getHomeDirectory());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -72,7 +72,7 @@ public abstract class KotlinAndroidTestCaseBase extends UsefulTestCase {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void tearDown() throws Exception {
|
protected void tearDown() throws Exception {
|
||||||
TestUtilsKt.unInvalidateBuiltinsAndStdLib(getProject(), new RunnableWithException() {
|
TestUtilsKt.doKotlinTearDown(getProject(), new RunnableWithException() {
|
||||||
@Override
|
@Override
|
||||||
public void run() throws Exception {
|
public void run() throws Exception {
|
||||||
KotlinAndroidTestCaseBase.super.tearDown();
|
KotlinAndroidTestCaseBase.super.tearDown();
|
||||||
|
|||||||
Reference in New Issue
Block a user