[threading] IJPL-179707: Include ToolWindowFactoryJewel class

GitOrigin-RevId: 54c2b022ae5fe47a5eafe6a9330b8df5bf96575c
This commit is contained in:
Moncef Slimani
2025-11-17 13:31:32 +00:00
committed by intellij-monorepo-bot
parent 3eabd0ac8a
commit e6eb7a8575
5 changed files with 92 additions and 53 deletions
@@ -4,7 +4,7 @@
<facet type="kotlin-language" name="Kotlin">
<configuration version="5" platform="JVM 21" allPlatforms="JVM [21]" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi -opt-in=org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -XXLanguage:+AllowEagerSupertypeAccessibilityChecks" />
<option name="additionalArguments" value="-opt-in=androidx.compose.ui.ExperimentalComposeUiApi -Xcontext-receivers -opt-in=androidx.compose.foundation.ExperimentalFoundationApi -opt-in=org.jetbrains.jewel.foundation.ExperimentalJewelApi -opt-in=org.jetbrains.jewel.foundation.InternalJewelApi -Xjvm-default=all -opt-in=com.intellij.openapi.util.IntellijInternalApi -opt-in=org.jetbrains.kotlin.utils.addToStdlib.UnsafeCastFunction -XXLanguage:+AllowEagerSupertypeAccessibilityChecks" />
</compilerSettings>
<compilerArguments>
<stringArguments>
@@ -14,7 +14,10 @@
</stringArguments>
<arrayArguments>
<arrayArg name="pluginClasspaths">
<args>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</args>
<args>
<arg>$MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-compose-compiler-plugin/2.2.0/kotlin-compose-compiler-plugin-2.2.0.jar</arg>
<arg>$KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar</arg>
</args>
</arrayArg>
<arrayArg name="pluginOptions" />
</arrayArguments>
@@ -107,5 +110,6 @@
<orderEntry type="library" name="studio-platform" level="project" />
<orderEntry type="module" module-name="intellij.platform.jewel.ideLafBridge" />
<orderEntry type="module" module-name="intellij.platform.jewel.ui" />
<orderEntry type="module" module-name="intellij.platform.compose" />
</component>
</module>
@@ -1,47 +1,18 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.threadingModelHelper
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.itemsIndexed
import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.foundation.text.input.rememberTextFieldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp
import java.util.Locale
import org.jetbrains.jewel.bridge.LocalComponent
import org.jetbrains.jewel.foundation.modifier.trackActivation
import org.jetbrains.jewel.foundation.modifier.trackComponentActivation
import org.jetbrains.jewel.foundation.theme.JewelTheme
import org.jetbrains.jewel.ui.Orientation
import org.jetbrains.jewel.ui.component.Divider
import com.intellij.openapi.components.service
import org.jetbrains.jewel.ui.component.Text
import org.jetbrains.jewel.ui.component.TextArea
import org.jetbrains.jewel.ui.component.VerticallyScrollableContainer
import org.jetbrains.jewel.ui.component.scrollbarContentSafePadding
import com.intellij.openapi.project.Project
@Composable
fun LockReqsCompose(project: Project) {
val service = remember(project) { project.service<LockReqsService>() }
val results = service.currentResults
Column() {
Text("Working now?")
Text("Found ${results.size} execution paths")
}
}
@@ -1,18 +0,0 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.threadingModelHelper
import androidx.compose.foundation.layout.*
import androidx.compose.runtime.*
import androidx.compose.ui.*
import org.jetbrains.jewel.ui.component.Text
@Composable
fun LockReqsToolWindow(service: LockReqsService) {
val results = service.getCurrentResults()
Column() {
Text("Found ${results.size} execution paths:")
Column() { items(results) { path -> Text(text = path) }
}
}
}
@@ -0,0 +1,17 @@
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.threadingModelHelper
import com.intellij.openapi.project.Project
import com.intellij.openapi.wm.ToolWindow
import com.intellij.openapi.wm.ToolWindowFactory
import org.jetbrains.idea.devkit.DevKitBundle
import org.jetbrains.jewel.bridge.addComposeTab
import org.jetbrains.idea.devkit.threadingModelHelper.LockReqsCompose
import org.jetbrains.jewel.foundation.JewelFlags
class LockReqsToolWindowFactoryJewel : ToolWindowFactory {
override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) {
toolWindow.addComposeTab(DevKitBundle.message("tab.title.locking.requirements")) { LockReqsCompose(project) }
}
}
@@ -38,6 +38,71 @@ class LockReqsUnitTest : BasePlatformTestCase() {
override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "threadingModelHelper/"
fun testMethodsInDifferentClassesInline() {
val testFileContent = """
package test;
import com.intellij.util.concurrency.annotations.RequiresReadLock;
public class MethodsInDifferentClasses {
public void testMethod() {
Helper helper = new Helper();
helper.helperMethod();
}
}
class Helper {
public void helperMethod() {
Service service = new Service();
service.serviceMethod();
}
}
class Service {
@RequiresReadLock
public void serviceMethod() {
System.out.println("Service method");
}
}
""".trimIndent()
// Write the content to a temporary file
val psiJavaFile = myFixture.configureByText("TestFile.java", testFileContent) as PsiJavaFile
// Create the analyzer
val analyzer = LockReqsAnalyzer()
// Get all classes from the file
println("Classes in file: ${psiJavaFile.classes.map { it.name }}")
// Find the main test class
val testClass = psiJavaFile.classes.find { it.name == "MethodsInDifferentClasses" }
assertNotNull("Could not find MethodsInDifferentClasses", testClass)
println("Found test class: ${testClass?.name}")
// Extract expected paths
val expectedPathAnnotations = testClass!!.annotations
println("Annotations on test class: ${expectedPathAnnotations.map { it.qualifiedName }}")
val expectedPaths = listOf("MethodsInDifferentClasses.testMethod -> Helper.helperMethod -> Service.serviceMethod -> @RequiresReadLock")
println("Expected paths: $expectedPaths")
// Find the test method
val sourceMethod = testClass.findMethodsByName("testMethod", false).firstOrNull()
assertNotNull("Could not find testMethod", sourceMethod)
println("Found method: ${sourceMethod?.name}")
// Analyze the method
val executionPaths = analyzer.analyzeMethod(sourceMethod!!)
println("Found ${executionPaths.size} execution paths")
val actualPaths = executionPaths.map { it.pathString }
assertEquals("Paths don't match!", expectedPaths, actualPaths)
}
fun testNoLockRequirements() {
doTest()
}