diff --git a/plugins/devkit/devkit-core/resources/inspectionDescriptions/ReadOrWriteActionInServiceInitialization.html b/plugins/devkit/devkit-core/resources/inspectionDescriptions/PotentialDeadlockInServiceInitialization.html
similarity index 91%
rename from plugins/devkit/devkit-core/resources/inspectionDescriptions/ReadOrWriteActionInServiceInitialization.html
rename to plugins/devkit/devkit-core/resources/inspectionDescriptions/PotentialDeadlockInServiceInitialization.html
index b05eae075069..872ae84ca2ae 100644
--- a/plugins/devkit/devkit-core/resources/inspectionDescriptions/ReadOrWriteActionInServiceInitialization.html
+++ b/plugins/devkit/devkit-core/resources/inspectionDescriptions/PotentialDeadlockInServiceInitialization.html
@@ -1,6 +1,6 @@
-Reports read and write actions run from the scope of service initialization:
+Reports read/write actions and invokeAndWait called from the scope of service initialization:
- service constructors and initialization blocks (including static)
- service companion object's initialization blocks (Kotlin)
@@ -13,7 +13,7 @@ Reports read and write actions run from the scope of service initialization:
-Running a read or write action during service initialization may cause deadlocks.
+Running a read/write action or calling invokeAndWait during service initialization may cause deadlocks.
Examples:
Kotlin:
diff --git a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
index 1a0d95bb3484..b218c8dd2041 100644
--- a/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
+++ b/plugins/devkit/devkit-core/resources/intellij.devkit.core.xml
@@ -459,14 +459,14 @@
implementationClass="org.jetbrains.idea.devkit.inspections.ListenerImplementationMustNotBeDisposableInspection"/>
+ implementationClass="org.jetbrains.idea.devkit.inspections.PotentialDeadlockInServiceInitializationInspection"/>
diff --git a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
index 1bf7dc2bb009..e4928a4ceb4b 100644
--- a/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
+++ b/plugins/devkit/devkit-core/resources/messages/DevKitBundle.properties
@@ -683,16 +683,16 @@ inspections.static.initialization.in.extensions.message=Extension point implemen
inspections.listener.implementation.must.not.be.disposable.name=Listener implementation implements 'Disposable'
inspections.listener.implementation.must.not.implement.disposable=Listener implementation must not implement 'Disposable'
-inspection.read.or.write.action.during.service.init.display.name=Read or Write Action run during service initialization
-inspection.read.or.write.action.during.service.init.message.read=Do not run read actions during service initialization{0}
-inspection.read.or.write.action.during.service.init.message.write=Do not run write actions during service initialization{0}
-inspection.read.or.write.action.during.service.init.message.invoke.and.wait=Do not run ''invokeAndWait'' during service initialization{0}
-inspection.read.or.write.action.during.service.init.message.context=\ ({0} is called in {1})
-inspection.read.or.write.action.during.service.init.message.context.field=''{0}'' field initializer
-inspection.read.or.write.action.during.service.init.message.context.method=''{0}'' method
-inspection.read.or.write.action.during.service.init.message.context.constructor=''{0}'' constructor or init block
-inspection.read.or.write.action.during.service.init.message.context.static.initializer=static initialization block
-inspection.read.or.write.action.during.service.init.message.context.instance.initializer=instance initialization block
+inspection.potential.deadlock.during.service.init.display.name=Read or Write Action run during service initialization
+inspection.potential.deadlock.during.service.init.message.read=Do not run read actions during service initialization{0}
+inspection.potential.deadlock.during.service.init.message.write=Do not run write actions during service initialization{0}
+inspection.potential.deadlock.during.service.init.message.invoke.and.wait=Do not run ''invokeAndWait'' during service initialization{0}
+inspection.potential.deadlock.during.service.init.message.context=\ ({0} is called in {1})
+inspection.potential.deadlock.during.service.init.message.context.field=''{0}'' field initializer
+inspection.potential.deadlock.during.service.init.message.context.method=''{0}'' method
+inspection.potential.deadlock.during.service.init.message.context.constructor=''{0}'' constructor or init block
+inspection.potential.deadlock.during.service.init.message.context.static.initializer=static initialization block
+inspection.potential.deadlock.during.service.init.message.context.instance.initializer=instance initialization block
inspection.plugin.xml.registration.check.display.name=Plugin.xml registration check
diff --git a/plugins/devkit/devkit-core/src/inspections/ReadOrWriteActionInServiceInitializationInspection.kt b/plugins/devkit/devkit-core/src/inspections/PotentialDeadlockInServiceInitializationInspection.kt
similarity index 65%
rename from plugins/devkit/devkit-core/src/inspections/ReadOrWriteActionInServiceInitializationInspection.kt
rename to plugins/devkit/devkit-core/src/inspections/PotentialDeadlockInServiceInitializationInspection.kt
index f18b7a033287..9dfb5d9d37c3 100644
--- a/plugins/devkit/devkit-core/src/inspections/ReadOrWriteActionInServiceInitializationInspection.kt
+++ b/plugins/devkit/devkit-core/src/inspections/PotentialDeadlockInServiceInitializationInspection.kt
@@ -43,7 +43,7 @@ private val PERSISTENT_STATE_COMPONENT_INIT_METHOD_NAMES = arrayOf(
private const val VISIT_CHILDREN = false
private const val SKIP_CHILDREN = true
-internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastInspectionBase() {
+internal class PotentialDeadlockInServiceInitializationInspection : DevKitUastInspectionBase() {
override fun buildInternalVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
return UastHintedVisitorAdapter.create(
@@ -71,12 +71,12 @@ internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastIn
}
}
- private fun isCalledDuringServiceInitialization(readOrWriteActionCall: UCallExpression, callContextHolder: CallContextHolder): Boolean {
- val uClass = readOrWriteActionCall.getContainingNonCompanionObjectClass() ?: return false
+ private fun isCalledDuringServiceInitialization(forbiddenCall: UCallExpression, callContextHolder: CallContextHolder): Boolean {
+ val uClass = forbiddenCall.getContainingNonCompanionObjectClass() ?: return false
return isService(uClass) &&
- (isCalledDuringInit(readOrWriteActionCall) ||
- isInMethodCalledDuringInit(uClass, readOrWriteActionCall, callContextHolder) ||
- isCalledDuringPersistentStateComponentInit(uClass, readOrWriteActionCall, callContextHolder))
+ (isCalledDuringInit(forbiddenCall) ||
+ isInMethodCalledDuringInit(uClass, forbiddenCall, callContextHolder) ||
+ isCalledDuringPersistentStateComponentInit(uClass, forbiddenCall, callContextHolder))
}
private fun UElement.getContainingNonCompanionObjectClass(): UClass? {
@@ -84,41 +84,37 @@ internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastIn
return if (uClass.javaPsi.name == "Companion") uClass.getParentOfType() else uClass
}
- private fun isCalledDuringInit(readOrWriteActionCall: UCallExpression): Boolean {
- return !isCalledInAnonymousClassOrLambda(readOrWriteActionCall) &&
- (isCalledInConstructor(readOrWriteActionCall) ||
- isCalledInInitBlock(readOrWriteActionCall) ||
- isCalledInFieldAssignment(readOrWriteActionCall))
+ private fun isCalledDuringInit(forbiddenCall: UCallExpression): Boolean {
+ return !isCalledInAnonymousClassOrLambda(forbiddenCall) &&
+ (isCalledInConstructor(forbiddenCall) ||
+ isCalledInInitBlock(forbiddenCall) ||
+ isCalledInFieldAssignment(forbiddenCall))
}
- private fun isCalledInAnonymousClassOrLambda(readOrWriteActionCall: UCallExpression): Boolean {
+ private fun isCalledInAnonymousClassOrLambda(forbiddenActionCall: UCallExpression): Boolean {
// do not report calls in listener, alarm, etc. registration
- return readOrWriteActionCall.getParentOfType() != null ||
- readOrWriteActionCall.getParentOfType() != null
+ return forbiddenActionCall.getParentOfType() != null ||
+ forbiddenActionCall.getParentOfType() != null
}
- private fun isCalledInConstructor(readOrWriteActionCall: UCallExpression): Boolean {
- return readOrWriteActionCall.getContainingUMethod()?.isConstructor == true
+ private fun isCalledInConstructor(forbiddenCall: UCallExpression): Boolean {
+ return forbiddenCall.getContainingUMethod()?.isConstructor == true
}
- private fun isCalledInInitBlock(readOrWriteActionCall: UCallExpression): Boolean {
- return readOrWriteActionCall.getParentOfType() != null
+ private fun isCalledInInitBlock(forbiddenCall: UCallExpression): Boolean {
+ return forbiddenCall.getParentOfType() != null
}
- private fun isCalledInFieldAssignment(readOrWriteActionCall: UCallExpression): Boolean {
- return readOrWriteActionCall.getParentOfType() != null
+ private fun isCalledInFieldAssignment(forbiddenCall: UCallExpression): Boolean {
+ return forbiddenCall.getParentOfType() != null
}
- private fun isInMethodCalledDuringInit(
- serviceClass: UClass,
- readOrWriteActionCall: UCallExpression,
- callContextHolder: CallContextHolder,
- ): Boolean {
- if (isCalledInAnonymousClassOrLambda(readOrWriteActionCall)) return false
+ private fun isInMethodCalledDuringInit(serviceClass: UClass, forbiddenCall: UCallExpression, callContextHolder: CallContextHolder): Boolean {
+ if (isCalledInAnonymousClassOrLambda(forbiddenCall)) return false
val companionObject = serviceClass.innerClasses.firstOrNull { it.javaPsi.name == "Companion" }
val initializationElements: List = serviceClass.getInitializationElements() +
(companionObject?.getInitializationElements() ?: emptyList())
- val containingMethod = readOrWriteActionCall.getContainingUMethod() ?: return false
+ val containingMethod = forbiddenCall.getContainingUMethod() ?: return false
return containingMethod.isCalledInAnyOf(initializationElements, callContextHolder)
}
@@ -154,30 +150,30 @@ internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastIn
private fun getContextText(calledMethod: UMethod, caller: UElement): @Nls String? {
val callerName = when (caller) {
is UMethod ->
- if (caller.isConstructor) message("inspection.read.or.write.action.during.service.init.message.context.constructor", caller.name)
- else message("inspection.read.or.write.action.during.service.init.message.context.method", caller.name)
+ if (caller.isConstructor) message("inspection.potential.deadlock.during.service.init.message.context.constructor", caller.name)
+ else message("inspection.potential.deadlock.during.service.init.message.context.method", caller.name)
is UField ->
- message("inspection.read.or.write.action.during.service.init.message.context.field", @Suppress("UElementAsPsi") caller.name)
+ message("inspection.potential.deadlock.during.service.init.message.context.field", @Suppress("UElementAsPsi") caller.name)
is UClassInitializer ->
// there is no API in UAST to distinguish companion object context, but we can live with it
- if (caller.isStatic) message("inspection.read.or.write.action.during.service.init.message.context.static.initializer")
- else message("inspection.read.or.write.action.during.service.init.message.context.instance.initializer")
+ if (caller.isStatic) message("inspection.potential.deadlock.during.service.init.message.context.static.initializer")
+ else message("inspection.potential.deadlock.during.service.init.message.context.instance.initializer")
else -> return null
}
- return message("inspection.read.or.write.action.during.service.init.message.context", "'${calledMethod.name}'", callerName)
+ return message("inspection.potential.deadlock.during.service.init.message.context", "'${calledMethod.name}'", callerName)
}
private fun isCalledDuringPersistentStateComponentInit(
serviceClass: UClass,
- readOrWriteActionCall: UCallExpression,
+ forbiddenCall: UCallExpression,
callContextHolder: CallContextHolder,
): Boolean {
return isPersistentStateComponent(serviceClass) &&
- (isCalledDuringPersistentStateComponentInitMethods(readOrWriteActionCall) ||
- isInMethodCalledDuringPersistentStateComponentInit(serviceClass, readOrWriteActionCall, callContextHolder))
+ (isCalledDuringPersistentStateComponentInitMethods(forbiddenCall) ||
+ isInMethodCalledDuringPersistentStateComponentInit(serviceClass, forbiddenCall, callContextHolder))
}
private fun isPersistentStateComponent(serviceClass: UClass): Boolean {
@@ -185,19 +181,19 @@ internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastIn
return JvmInheritanceUtil.isInheritor(servicePsiClass, PersistentStateComponent::class.java.canonicalName)
}
- private fun isCalledDuringPersistentStateComponentInitMethods(readOrWriteActionCall: UCallExpression): Boolean {
- if (isCalledInAnonymousClassOrLambda(readOrWriteActionCall)) return false
- val containingMethod = readOrWriteActionCall.getContainingUMethod() ?: return false
+ private fun isCalledDuringPersistentStateComponentInitMethods(forbiddenCall: UCallExpression): Boolean {
+ if (isCalledInAnonymousClassOrLambda(forbiddenCall)) return false
+ val containingMethod = forbiddenCall.getContainingUMethod() ?: return false
return PERSISTENT_STATE_COMPONENT_INIT_METHOD_NAMES.contains(containingMethod.name)
}
private fun isInMethodCalledDuringPersistentStateComponentInit(
- serviceClass: UClass, readOrWriteActionCall: UCallExpression,
+ serviceClass: UClass, forbiddenCall: UCallExpression,
callContextHolder: CallContextHolder,
): Boolean {
- if (isCalledInAnonymousClassOrLambda(readOrWriteActionCall)) return false
+ if (isCalledInAnonymousClassOrLambda(forbiddenCall)) return false
val lifecycleMethods: List = serviceClass.methods.filter { PERSISTENT_STATE_COMPONENT_INIT_METHOD_NAMES.contains(it.name) }
- val containingMethod = readOrWriteActionCall.getContainingUMethod() ?: return false
+ val containingMethod = forbiddenCall.getContainingUMethod() ?: return false
return containingMethod.isCalledInAnyOf(lifecycleMethods, callContextHolder)
}
@@ -210,9 +206,9 @@ internal class ReadOrWriteActionInServiceInitializationInspection : DevKitUastIn
val anchor = uCallExpression.methodIdentifier?.sourcePsi ?: return
val callContext = callContextHolder.value ?: ""
val message = when (actionType) {
- CallType.READ -> message("inspection.read.or.write.action.during.service.init.message.read", callContext)
- CallType.WRITE -> message("inspection.read.or.write.action.during.service.init.message.write", callContext)
- CallType.INVOKE_AND_WAIT -> message("inspection.read.or.write.action.during.service.init.message.invoke.and.wait", callContext)
+ CallType.READ -> message("inspection.potential.deadlock.during.service.init.message.read", callContext)
+ CallType.WRITE -> message("inspection.potential.deadlock.during.service.init.message.write", callContext)
+ CallType.INVOKE_AND_WAIT -> message("inspection.potential.deadlock.during.service.init.message.invoke.and.wait", callContext)
}
holder.registerProblem(anchor, message)
}
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/DevkitInspectionsRegistrationCheckTest.java b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/DevkitInspectionsRegistrationCheckTest.java
index 5e29387eab66..86c47941711e 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/DevkitInspectionsRegistrationCheckTest.java
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/DevkitInspectionsRegistrationCheckTest.java
@@ -31,7 +31,7 @@ public class DevkitInspectionsRegistrationCheckTest extends BasePlatformTestCase
"ThreadingConcurrency",
"CallingMethodShouldBeRequiresBlockingContext",
"IncorrectProcessCanceledExceptionHandling",
- "ReadOrWriteActionInServiceInitialization"
+ "PotentialDeadlockInServiceInitialization"
).sorted().toList();
/**
diff --git a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTest.kt b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTest.kt
similarity index 99%
rename from plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTest.kt
rename to plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTest.kt
index b350f2052ba2..c1503bcccace 100644
--- a/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTest.kt
+++ b/plugins/devkit/devkit-java-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTest.kt
@@ -1,7 +1,7 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.inspections
-class ReadOrWriteActionInServiceInitializationInspectionTest : ReadOrWriteActionInServiceInitializationInspectionTestBase() {
+class PotentialDeadlockInServiceInitializationInspectionTest : PotentialDeadlockInServiceInitializationInspectionTestBase() {
fun `test read and write actions are reported in a light service`() {
myFixture.configureByText("TestService.java", getServiceWithReadAndWriteActionsCalledDuringInit(true))
diff --git a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtReadOrWriteActionInServiceInitializationInspectionTest.kt b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtPotentialDeadlockInServiceInitializationInspectionTest.kt
similarity index 98%
rename from plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtReadOrWriteActionInServiceInitializationInspectionTest.kt
rename to plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtPotentialDeadlockInServiceInitializationInspectionTest.kt
index 79d163f409e3..ec34208c395e 100644
--- a/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtReadOrWriteActionInServiceInitializationInspectionTest.kt
+++ b/plugins/devkit/devkit-kotlin-tests/testSrc/org/jetbrains/idea/devkit/kotlin/inspections/KtPotentialDeadlockInServiceInitializationInspectionTest.kt
@@ -1,9 +1,9 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.idea.devkit.kotlin.inspections
-import org.jetbrains.idea.devkit.inspections.ReadOrWriteActionInServiceInitializationInspectionTestBase
+import org.jetbrains.idea.devkit.inspections.PotentialDeadlockInServiceInitializationInspectionTestBase
-class KtReadOrWriteActionInServiceInitializationInspectionTest : ReadOrWriteActionInServiceInitializationInspectionTestBase() {
+class KtPotentialDeadlockInServiceInitializationInspectionTest : PotentialDeadlockInServiceInitializationInspectionTestBase() {
fun `test read and write actions are reported in a light service`() {
myFixture.configureByText("TestService.kt", getServiceWithReadAndWriteActionsCalledDuringInit(true))
diff --git a/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTestBase.kt b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTestBase.kt
similarity index 94%
rename from plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTestBase.kt
rename to plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTestBase.kt
index d7e5ba330711..b8de3dbc815d 100644
--- a/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/ReadOrWriteActionInServiceInitializationInspectionTestBase.kt
+++ b/plugins/devkit/devkit-tests/testSrc/org/jetbrains/idea/devkit/inspections/PotentialDeadlockInServiceInitializationInspectionTestBase.kt
@@ -17,7 +17,7 @@ import com.intellij.util.Alarm
import com.intellij.util.PathUtil
import org.jetbrains.idea.devkit.inspections.quickfix.DevKitInspectionFixTestBase
-abstract class ReadOrWriteActionInServiceInitializationInspectionTestBase : DevKitInspectionFixTestBase() {
+abstract class PotentialDeadlockInServiceInitializationInspectionTestBase : DevKitInspectionFixTestBase() {
override fun tuneFixture(moduleBuilder: JavaModuleFixtureBuilder<*>) {
// too many classes to add manually via addClass, so using the slower libraries approach:
@@ -39,7 +39,7 @@ abstract class ReadOrWriteActionInServiceInitializationInspectionTestBase : DevK
KotlinTester.configureKotlinStdLib(it)
}
IndexingTestUtil.waitUntilIndexesAreReady(project)
- myFixture.enableInspections(ReadOrWriteActionInServiceInitializationInspection())
+ myFixture.enableInspections(PotentialDeadlockInServiceInitializationInspection())
}
}