Problem: workaround thread leaking problem
This commit is contained in:
+1
-1
@@ -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();
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ abstract class KotlinLightCodeInsightFixtureTestCase : KotlinLightCodeInsightFix
|
||||
KotlinInternalMode.enabled = kotlinInternalModeOriginalValue
|
||||
VfsRootAccess.disallowRootAccess(KotlinTestUtils.getHomeDirectory())
|
||||
|
||||
unInvalidateBuiltinsAndStdLib(project) {
|
||||
doKotlinTearDown(project) {
|
||||
super.tearDown()
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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());
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user