diff --git a/plugins/devkit/devkit-core/intellij.devkit.core.iml b/plugins/devkit/devkit-core/intellij.devkit.core.iml index 59a96aedeea9..770fb03b50bb 100644 --- a/plugins/devkit/devkit-core/intellij.devkit.core.iml +++ b/plugins/devkit/devkit-core/intellij.devkit.core.iml @@ -4,7 +4,7 @@ - @@ -14,7 +14,10 @@ - $KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar + + $MAVEN_REPOSITORY$/org/jetbrains/kotlin/kotlin-compose-compiler-plugin/2.2.0/kotlin-compose-compiler-plugin-2.2.0.jar + $KOTLIN_BUNDLED$/lib/kotlinx-serialization-compiler-plugin.jar + @@ -107,5 +110,6 @@ + \ No newline at end of file diff --git a/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsCompose.kt b/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsCompose.kt index c74447b953f0..e7c9407739f7 100644 --- a/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsCompose.kt +++ b/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsCompose.kt @@ -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() } + val results = service.currentResults Column() { - Text("Working now?") + Text("Found ${results.size} execution paths") } } \ No newline at end of file diff --git a/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindow.kt b/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindow.kt deleted file mode 100644 index 353911f3b921..000000000000 --- a/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindow.kt +++ /dev/null @@ -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) } - } - } -} \ No newline at end of file diff --git a/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindowFactoryJewel.kt b/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindowFactoryJewel.kt new file mode 100644 index 000000000000..a14cc58283a8 --- /dev/null +++ b/plugins/devkit/devkit-core/src/threadingModelHelper/LockReqsToolWindowFactoryJewel.kt @@ -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) } + } +} + diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/threadingModelHelper/LockReqsUnitTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/threadingModelHelper/LockReqsUnitTest.kt index 8dbbbb242566..f0050b185b81 100644 --- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/threadingModelHelper/LockReqsUnitTest.kt +++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/threadingModelHelper/LockReqsUnitTest.kt @@ -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() }