mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-04-21 22:11:40 +07:00
[devkit] IDEA-298703 improve naming, add a check for backing fields in kotlin
GitOrigin-RevId: 5e74319e790c4246b64e6d5f57c51c6930dbf19f
This commit is contained in:
committed by
intellij-monorepo-bot
parent
da2793fc89
commit
4701e0fd21
@@ -1,15 +1,17 @@
|
||||
<html>
|
||||
<body>
|
||||
Reports assignments of application services to static final fields/properties.
|
||||
Reports assignments of application services to static final fields / immutable properties.
|
||||
<p><b>Static final fields (Java) or immutable properties with backing fields (Kotlin)</b></p>
|
||||
<p>
|
||||
Such assignments contribute to global state and make it impossible to tear down an application and set up another one in tests,
|
||||
Such services' assignments contribute to global state and make it impossible to tear down an application and set up another one in tests,
|
||||
therefore, repeated tests in the same process may fail.
|
||||
The only exception is an explicit constructor call to store dummy/default instances.
|
||||
</p>
|
||||
The only exception is an explicit constructor call to store dummy/default instances.</p>
|
||||
<p>
|
||||
The recommended way to avoid storing services is to retrieve a service locally or to wrap it in <code>java.util.function.Supplier</code>.
|
||||
The recommended way to avoid storing services is to retrieve a service locally.
|
||||
Alternatively, one can wrap it in <code>java.util.function.Supplier</code> (Java, Kotlin)
|
||||
or convert the property to a function (Kotlin).
|
||||
</p>
|
||||
<p><b>Example:</b></p>
|
||||
<p><b>Example (Java):</b></p>
|
||||
<pre><code lang="java">
|
||||
// Incorrect way
|
||||
private static final ManagingFS ourInstance = ApplicationManager.getApplication().getService(ManagingFS.class);
|
||||
@@ -24,6 +26,6 @@ Reports assignments of application services to static final fields/properties.
|
||||
// Exception
|
||||
private static final UniqueVFilePathBuilder DUMMY_BUILDER = new UniqueVFilePathBuilder()
|
||||
</code></pre>
|
||||
<p><small>New in 2023.2</small>
|
||||
<p><small>New in 2023.3</small>
|
||||
</body>
|
||||
</html>
|
||||
@@ -367,11 +367,11 @@
|
||||
enabledByDefault="false" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.CancellationCheckInLoopsInspection"/>
|
||||
|
||||
<localInspection language="UAST" shortName="ApplicationServiceAsStaticFinalField" groupPathKey="inspections.group.path"
|
||||
<localInspection language="UAST" shortName="ApplicationServiceAsStaticFinalFieldOrProperty" groupPathKey="inspections.group.path"
|
||||
projectType="INTELLIJ_PLUGIN"
|
||||
key="inspections.application.service.as.static.final.field.display.name" groupKey="inspections.group.code"
|
||||
key="inspections.application.service.as.static.final.field.or.property.display.name" groupKey="inspections.group.code"
|
||||
enabledByDefault="false" level="WARNING"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldInspection"/>
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldOrPropertyInspection"/>
|
||||
|
||||
<localInspection language="UAST" enabledByDefault="false" level="ERROR"
|
||||
projectType="INTELLIJ_PLUGIN"
|
||||
@@ -538,9 +538,9 @@
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.ServiceLevelExtractorForJVM"/>
|
||||
<lightServiceMustBeFinalErrorMessageProvider language="JVM"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.LightServiceMustBeFinalErrorMessageProvider"/>
|
||||
<appServiceAsStaticFinalFieldQuickFixProvider
|
||||
<appServiceAsStaticFinalFieldOrPropertyProvider
|
||||
language="JAVA"
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.quickfix.JavaAppServiceAsStaticFinalFieldFixProvider"/>
|
||||
implementationClass="org.jetbrains.idea.devkit.inspections.quickfix.JavaAppServiceAsStaticFinalFieldOrPropertyProvider"/>
|
||||
</extensions>
|
||||
|
||||
<extensionPoints>
|
||||
@@ -584,10 +584,10 @@
|
||||
dynamic="true">
|
||||
<with attribute="implementationClass" implements="org.jetbrains.idea.devkit.inspections.ErrorMessageProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="DevKit.lang.appServiceAsStaticFinalFieldQuickFixProvider"
|
||||
<extensionPoint qualifiedName="DevKit.lang.appServiceAsStaticFinalFieldOrPropertyProvider"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint"
|
||||
dynamic="true">
|
||||
<with attribute="implementationClass" implements="org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldFixProvider"/>
|
||||
<with attribute="implementationClass" implements="org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldOrPropertyProvider"/>
|
||||
</extensionPoint>
|
||||
<extensionPoint qualifiedName="DevKit.lang.uElementAsPsiCheckProvider"
|
||||
beanClass="com.intellij.lang.LanguageExtensionPoint"
|
||||
|
||||
@@ -657,7 +657,7 @@ inspection.cancellation.check.in.loops.display.name=Cancellation check in loops
|
||||
inspection.cancellation.check.in.loops.message=Cancellation check ''{0}'' should be the first statement in a loop body
|
||||
inspection.insert.cancellation.check.fix.message=Insert cancellation check
|
||||
|
||||
inspections.application.service.as.static.final.field.display.name=Application service assigned to a static final field/property
|
||||
inspections.application.service.as.static.final.field.or.property.display.name=Application service assigned to a static final field / immutable property
|
||||
inspections.application.service.as.static.final.field.message=Application service must not be assigned to a static final field
|
||||
inspections.wrap.application.service.in.supplier.quick.fix.message=Wrap application service in 'java.util.function.Supplier'
|
||||
|
||||
|
||||
@@ -2,17 +2,15 @@
|
||||
package org.jetbrains.idea.devkit.inspections
|
||||
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.codeInspection.registerUProblem
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.util.PsiTypesUtil
|
||||
import com.intellij.uast.UastHintedVisitorAdapter
|
||||
import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldQuickFixProviders
|
||||
import org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldOrPropertyProviders
|
||||
import org.jetbrains.uast.*
|
||||
import org.jetbrains.uast.visitor.AbstractUastNonRecursiveVisitor
|
||||
|
||||
|
||||
class ApplicationServiceAsStaticFinalFieldInspection : DevKitUastInspectionBase() {
|
||||
class ApplicationServiceAsStaticFinalFieldOrPropertyInspection : DevKitUastInspectionBase() {
|
||||
|
||||
override fun buildInternalVisitor(holder: ProblemsHolder, isOnTheFly: Boolean): PsiElementVisitor {
|
||||
|
||||
@@ -30,12 +28,10 @@ class ApplicationServiceAsStaticFinalFieldInspection : DevKitUastInspectionBase(
|
||||
if (serviceLevel == null || !serviceLevel.isApp()) return true
|
||||
|
||||
val sourcePsi = node.sourcePsi ?: return true
|
||||
val fixes = AppServiceAsStaticFinalFieldQuickFixProviders.forLanguage(holder.file.language)?.getFixes(sourcePsi) ?: emptyList()
|
||||
holder.registerUProblem(
|
||||
node,
|
||||
DevKitBundle.message("inspections.application.service.as.static.final.field.message"),
|
||||
*fixes.toTypedArray()
|
||||
)
|
||||
val anchor = node.uastAnchor?.sourcePsi ?: return true
|
||||
val provider = AppServiceAsStaticFinalFieldOrPropertyProviders.forLanguage(holder.file.language) ?: return true
|
||||
|
||||
provider.registerProblem(holder, sourcePsi, anchor)
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,9 +3,9 @@ package org.jetbrains.idea.devkit.inspections.quickfix
|
||||
|
||||
import com.intellij.codeInsight.FileModificationService
|
||||
import com.intellij.codeInsight.intention.preview.IntentionPreviewInfo
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.LocalQuickFixOnPsiElement
|
||||
import com.intellij.codeInspection.ProblemDescriptor
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.lang.LanguageExtension
|
||||
import com.intellij.openapi.application.ApplicationManager
|
||||
import com.intellij.openapi.application.CachedSingletonsRegistry
|
||||
@@ -26,23 +26,29 @@ import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import java.util.function.Supplier
|
||||
|
||||
|
||||
private val EP_NAME = ExtensionPointName.create<AppServiceAsStaticFinalFieldFixProvider>(
|
||||
"DevKit.lang.appServiceAsStaticFinalFieldQuickFixProvider"
|
||||
private val EP_NAME = ExtensionPointName.create<AppServiceAsStaticFinalFieldOrPropertyProvider>(
|
||||
"DevKit.lang.appServiceAsStaticFinalFieldOrPropertyProvider"
|
||||
)
|
||||
|
||||
internal object AppServiceAsStaticFinalFieldQuickFixProviders : LanguageExtension<AppServiceAsStaticFinalFieldFixProvider>(EP_NAME.name)
|
||||
internal object AppServiceAsStaticFinalFieldOrPropertyProviders : LanguageExtension<AppServiceAsStaticFinalFieldOrPropertyProvider>(EP_NAME.name)
|
||||
|
||||
@IntellijInternalApi
|
||||
@ApiStatus.Internal
|
||||
interface AppServiceAsStaticFinalFieldFixProvider {
|
||||
fun getFixes(psiElement: PsiElement): List<LocalQuickFix>
|
||||
interface AppServiceAsStaticFinalFieldOrPropertyProvider {
|
||||
fun registerProblem(holder: ProblemsHolder, sourcePsi: PsiElement, anchor: PsiElement)
|
||||
|
||||
}
|
||||
|
||||
|
||||
private class JavaAppServiceAsStaticFinalFieldFixProvider : AppServiceAsStaticFinalFieldFixProvider {
|
||||
private class JavaAppServiceAsStaticFinalFieldOrPropertyProvider : AppServiceAsStaticFinalFieldOrPropertyProvider {
|
||||
override fun registerProblem(holder: ProblemsHolder, sourcePsi: PsiElement, anchor: PsiElement) {
|
||||
if (sourcePsi !is PsiField) return
|
||||
|
||||
override fun getFixes(psiElement: PsiElement): List<LocalQuickFix> {
|
||||
return if (psiElement is PsiField) listOf(JavaWrapInSupplierQuickFix(psiElement)) else emptyList()
|
||||
return holder.registerProblem(
|
||||
anchor,
|
||||
DevKitBundle.message("inspections.application.service.as.static.final.field.message"),
|
||||
JavaWrapInSupplierQuickFix(sourcePsi),
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,12 +3,11 @@ package org.jetbrains.idea.devkit.inspections
|
||||
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
|
||||
import kotlin.io.path.*
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/applicationServiceAsStaticFinalField")
|
||||
class ApplicationServiceAsStaticFinalFieldInspectionTest : ApplicationServiceAsStaticFinalFieldInspectionTestBase() {
|
||||
@TestDataPath("/inspections/applicationServiceAsStaticFinalFieldOrProperty")
|
||||
class ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTest : ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase() {
|
||||
|
||||
override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/applicationServiceAsStaticFinalField"
|
||||
override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/applicationServiceAsStaticFinalFieldOrProperty"
|
||||
|
||||
override fun getFileExtension(): String = "java"
|
||||
|
||||
@@ -22,7 +22,7 @@ public class DevkitInspectionsRegistrationCheckTest extends BasePlatformTestCase
|
||||
List.of("ExtensionClassShouldBeFinalAndNonPublic",
|
||||
"ActionPresentationInstantiatedInCtor",
|
||||
"CancellationCheckInLoops",
|
||||
"ApplicationServiceAsStaticFinalField",
|
||||
"ApplicationServiceAsStaticFinalFieldOrProperty",
|
||||
"ThreadingConcurrency",
|
||||
"TokenSetInParserDefinition",
|
||||
"CallingMethodShouldBeRequiresBlockingContext",
|
||||
|
||||
@@ -4,10 +4,10 @@ package org.jetbrains.idea.devkit.inspections.quickfix
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import org.jetbrains.idea.devkit.DevkitJavaTestsUtil
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/wrapInSupplierFix")
|
||||
class WrapInSupplierFixTest : ApplicationServiceAsStaticFinalFieldInspectionTestBase() {
|
||||
class WrapInSupplierFixTest : ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase() {
|
||||
|
||||
override fun getBasePath() = DevkitJavaTestsUtil.TESTDATA_PATH + "inspections/wrapInSupplierFix"
|
||||
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
import serviceDeclarations.RegisteredApplicationService
|
||||
|
||||
|
||||
// -------- top-level declarations ---------
|
||||
// no backing fields
|
||||
val myAppService1: RegisteredApplicationService
|
||||
get() = RegisteredApplicationService.getInstance()
|
||||
|
||||
// with a backing field
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning>: RegisteredApplicationService = RegisteredApplicationService.getInstance()
|
||||
|
||||
// -------- companion object declarations ---------
|
||||
class MyClass {
|
||||
|
||||
companion object {
|
||||
// no backing fields
|
||||
val myAppService1: RegisteredApplicationService
|
||||
get() = RegisteredApplicationService.getInstance()
|
||||
|
||||
// with a backing field
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning>: RegisteredApplicationService = RegisteredApplicationService.getInstance()
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// -------- object declarations ---------
|
||||
|
||||
object MyObject {
|
||||
// no backing fields
|
||||
val myAppService1: RegisteredApplicationService
|
||||
get() = RegisteredApplicationService.getInstance()
|
||||
|
||||
// with a backing field
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning>: RegisteredApplicationService = RegisteredApplicationService.getInstance()
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import serviceDeclarations.RegisteredApplicationService
|
||||
// explicit constructor call
|
||||
val myAppService1 = RegisteredApplicationService()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
|
||||
// -------- companion object declarations ---------
|
||||
@@ -14,7 +14,7 @@ class MyClass {
|
||||
// explicit constructor call
|
||||
val myAppService1 = RegisteredApplicationService()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,6 +25,6 @@ object MyObject {
|
||||
// explicit constructor call
|
||||
val myAppService1 = RegisteredApplicationService()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
}
|
||||
@@ -2,11 +2,11 @@ import serviceDeclarations.*
|
||||
|
||||
// -------- top-level declarations ---------
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
|
||||
// non final
|
||||
var myAppService5 = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
@@ -23,11 +23,11 @@ class MyClass(val appService: LightServiceAppLevelAnnotation) {
|
||||
val myAppService5 = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
|
||||
companion object {
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
|
||||
// non final
|
||||
var myAppService5 = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
@@ -41,11 +41,11 @@ class MyClass(val appService: LightServiceAppLevelAnnotation) {
|
||||
// -------- object declarations ---------
|
||||
|
||||
object MyObject {
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = LightServiceAppLevelAnnotation.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService4</warning> = LightServiceEmptyAnnotation.getInstance()
|
||||
|
||||
// non final
|
||||
var myAppService5 = LightServiceAppAndProjectLevelAnnotation.getInstance()
|
||||
@@ -2,9 +2,9 @@ import serviceDeclarations.RegisteredApplicationService
|
||||
import serviceDeclarations.RegisteredProjectService
|
||||
|
||||
// -------- top-level declarations ---------
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
// non-final
|
||||
var myAppService3 = RegisteredApplicationService.getInstance()
|
||||
@@ -20,9 +20,9 @@ class MyClass(val appService: RegisteredApplicationService) {
|
||||
val myAppService = RegisteredApplicationService.getInstance()
|
||||
|
||||
companion object {
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
// non-final
|
||||
var myAppService3 = RegisteredApplicationService.getInstance()
|
||||
@@ -36,9 +36,9 @@ class MyClass(val appService: RegisteredApplicationService) {
|
||||
// -------- object declarations ---------
|
||||
|
||||
object MyObject {
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService1</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
val <warning descr="Application service must not be assigned to a static final field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">myAppService2</warning> = RegisteredApplicationService.getInstance()
|
||||
|
||||
// non-final
|
||||
var myAppService3 = RegisteredApplicationService.getInstance()
|
||||
@@ -13,7 +13,7 @@ class MyService {
|
||||
companion object {
|
||||
|
||||
@MyAnnotation
|
||||
val <warning descr="Application service must not be assigned to a static final field">companionObjectAppService<caret></warning> = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">companionObjectAppService<caret></warning> = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
|
||||
|
||||
// to test naming conflicts
|
||||
|
||||
@@ -12,7 +12,7 @@ class MyService {
|
||||
|
||||
object MyObject {
|
||||
@MyAnnotation
|
||||
val <warning descr="Application service must not be assigned to a static final field">objectAppService<caret></warning> = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">objectAppService<caret></warning> = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
|
||||
// to test naming conflicts
|
||||
val objectAppServiceSupplier = 0
|
||||
|
||||
@@ -6,7 +6,7 @@ import com.intellij.openapi.components.Service
|
||||
import inspections.wrapInSupplierFix.MyAnnotation
|
||||
|
||||
@MyAnnotation
|
||||
val <warning descr="Application service must not be assigned to a static final field">topLevelAppService<caret></warning>: MyService = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
val <warning descr="Application service must not be assigned to a static immutable property with a backing field">topLevelAppService<caret></warning>: MyService = ApplicationManager.getApplication().getService(MyService::class.java)
|
||||
|
||||
|
||||
// to test naming conflicts
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
package org.jetbrains.idea.devkit.kotlin.inspections
|
||||
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/applicationServiceAsStaticFinalField")
|
||||
class KtApplicationServiceAsStaticFinalFieldInspectionTest : ApplicationServiceAsStaticFinalFieldInspectionTestBase() {
|
||||
@TestDataPath("/inspections/applicationServiceAsStaticFinalFieldOrProperty")
|
||||
class KtApplicationServiceAsStaticFinalFieldOrPropertyInspectionTest : ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase() {
|
||||
|
||||
override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/applicationServiceAsStaticFinalField"
|
||||
override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/applicationServiceAsStaticFinalFieldOrProperty"
|
||||
|
||||
override fun getFileExtension(): String = "kt"
|
||||
|
||||
@@ -27,4 +27,8 @@ class KtApplicationServiceAsStaticFinalFieldInspectionTest : ApplicationServiceA
|
||||
fun testLightServices() {
|
||||
doHighlightTest()
|
||||
}
|
||||
|
||||
fun testBackingFields() {
|
||||
doHighlightTest()
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@ package org.jetbrains.idea.devkit.kotlin.inspections.quickfix
|
||||
|
||||
import com.intellij.testFramework.TestDataPath
|
||||
import org.jetbrains.idea.devkit.DevKitBundle
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.inspections.ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase
|
||||
import org.jetbrains.idea.devkit.kotlin.DevkitKtTestsUtil
|
||||
|
||||
@TestDataPath("\$CONTENT_ROOT/testData/inspections/wrapInSupplierFix")
|
||||
class KtWrapInSupplierFixTest : ApplicationServiceAsStaticFinalFieldInspectionTestBase() {
|
||||
class KtWrapInSupplierFixTest : ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase() {
|
||||
|
||||
override fun getBasePath() = DevkitKtTestsUtil.TESTDATA_PATH + "inspections/wrapInSupplierFix"
|
||||
|
||||
@@ -16,17 +16,6 @@ class KtWrapInSupplierFixTest : ApplicationServiceAsStaticFinalFieldInspectionTe
|
||||
|
||||
private val fixName = DevKitBundle.message("inspections.wrap.application.service.in.supplier.quick.fix.message")
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
myFixture.addClass(
|
||||
"""
|
||||
package kotlin.reflect;
|
||||
|
||||
public class KClass<T> {
|
||||
public Class<T> java;
|
||||
}
|
||||
""")
|
||||
}
|
||||
|
||||
fun testWrapTopLevelPropertyInSupplier() {
|
||||
doFixTest(fixName)
|
||||
|
||||
@@ -7,12 +7,12 @@ import kotlin.io.path.listDirectoryEntries
|
||||
import kotlin.io.path.name
|
||||
import kotlin.io.path.relativeTo
|
||||
|
||||
abstract class ApplicationServiceAsStaticFinalFieldInspectionTestBase : LightDevKitInspectionFixTestBase() {
|
||||
abstract class ApplicationServiceAsStaticFinalFieldOrPropertyInspectionTestBase : LightDevKitInspectionFixTestBase() {
|
||||
|
||||
override fun setUp() {
|
||||
super.setUp()
|
||||
addPlatformClasses()
|
||||
myFixture.enableInspections(ApplicationServiceAsStaticFinalFieldInspection())
|
||||
myFixture.enableInspections(ApplicationServiceAsStaticFinalFieldOrPropertyInspection())
|
||||
}
|
||||
|
||||
private fun addPlatformClasses() {
|
||||
@@ -115,6 +115,16 @@ abstract class ApplicationServiceAsStaticFinalFieldInspectionTestBase : LightDev
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
|
||||
myFixture.addClass(
|
||||
"""
|
||||
package kotlin.reflect;
|
||||
|
||||
public class KClass<T> {
|
||||
public Class<T> java;
|
||||
}
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
|
||||
private fun getServiceDeclarationPaths(namePrefix: String = ""): Array<String> {
|
||||
@@ -141,5 +151,4 @@ abstract class ApplicationServiceAsStaticFinalFieldInspectionTestBase : LightDev
|
||||
val resultName = testName + suffix?.let { "_$it" }.orEmpty()
|
||||
return "${resultName}.$fileExtension" to "${resultName}_after.$fileExtension"
|
||||
}
|
||||
|
||||
}
|
||||
@@ -55,8 +55,8 @@
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.ServiceLevelExtractorForKotlin"/>
|
||||
<lightServiceMustBeFinalErrorMessageProvider language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.LightServiceMustNotBeOpenErrorMessageProvider"/>
|
||||
<appServiceAsStaticFinalFieldQuickFixProvider language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.KtAppServiceAsStaticFinalFieldFixProvider"/>
|
||||
<appServiceAsStaticFinalFieldOrPropertyProvider language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.KtAppServiceAsStaticFinalFieldOrPropertyProvider"/>
|
||||
<uElementAsPsiCheckProvider language="kotlin"
|
||||
implementationClass="org.jetbrains.idea.devkit.kotlin.inspections.KtUElementAsPsiCheckProvider"/>
|
||||
</extensions>
|
||||
|
||||
@@ -22,4 +22,6 @@ inspections.move.prohibited.declarations.to.top.level.fix.text=Move prohibited d
|
||||
|
||||
inspection.light.service.must.not.be.open.message=Light service must not be open
|
||||
|
||||
inspection.extension.class.should.not.be.open.text=Extension class should not be open
|
||||
inspection.extension.class.should.not.be.open.text=Extension class should not be open
|
||||
|
||||
inspections.application.service.as.static.immutable.property.with.backing.field.message=Application service must not be assigned to a static immutable property with a backing field
|
||||
@@ -2,19 +2,22 @@
|
||||
package org.jetbrains.idea.devkit.kotlin.inspections
|
||||
|
||||
import com.intellij.codeInspection.IntentionWrapper
|
||||
import com.intellij.codeInspection.LocalQuickFix
|
||||
import com.intellij.codeInspection.ProblemHighlightType
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.openapi.application.CachedSingletonsRegistry
|
||||
import com.intellij.openapi.project.Project
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.PsiEditorUtil
|
||||
import com.intellij.psi.util.parentOfType
|
||||
import org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldFixProvider
|
||||
import org.jetbrains.idea.devkit.inspections.quickfix.AppServiceAsStaticFinalFieldOrPropertyProvider
|
||||
import org.jetbrains.idea.devkit.inspections.quickfix.WrapInSupplierQuickFix
|
||||
import org.jetbrains.idea.devkit.kotlin.DevKitKotlinBundle
|
||||
import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisFromWriteAction
|
||||
import org.jetbrains.kotlin.analysis.api.KtAllowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.analyze
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisFromWriteAction
|
||||
import org.jetbrains.kotlin.analysis.api.lifetime.allowAnalysisOnEdt
|
||||
import org.jetbrains.kotlin.analysis.api.symbols.KtPropertySymbol
|
||||
import org.jetbrains.kotlin.analysis.api.types.KtNonErrorClassType
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggester
|
||||
import org.jetbrains.kotlin.idea.base.codeInsight.KotlinNameSuggestionProvider
|
||||
@@ -29,13 +32,32 @@ import org.jetbrains.kotlin.psi.KtPsiFactory
|
||||
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
|
||||
import java.util.function.Supplier
|
||||
|
||||
private class KtAppServiceAsStaticFinalFieldOrPropertyProvider : AppServiceAsStaticFinalFieldOrPropertyProvider {
|
||||
|
||||
private class KtAppServiceAsStaticFinalFieldFixProvider : AppServiceAsStaticFinalFieldFixProvider {
|
||||
override fun registerProblem(holder: ProblemsHolder, sourcePsi: PsiElement, anchor: PsiElement) {
|
||||
if (sourcePsi !is KtProperty) return
|
||||
|
||||
override fun getFixes(psiElement: PsiElement): List<LocalQuickFix> {
|
||||
return if (psiElement is KtProperty) {
|
||||
listOf(KtWrapInSupplierQuickFix(psiElement), IntentionWrapper(ConvertPropertyToFunctionIntention()))
|
||||
} else emptyList()
|
||||
if (!sourcePsi.hasBackingField()) return
|
||||
|
||||
holder.registerProblem(
|
||||
anchor,
|
||||
DevKitKotlinBundle.message("inspections.application.service.as.static.immutable.property.with.backing.field.message"),
|
||||
ProblemHighlightType.WARNING,
|
||||
IntentionWrapper(ConvertPropertyToFunctionIntention()),
|
||||
KtWrapInSupplierQuickFix(sourcePsi),
|
||||
)
|
||||
}
|
||||
|
||||
@OptIn(KtAllowAnalysisOnEdt::class)
|
||||
private fun KtProperty.hasBackingField(): Boolean {
|
||||
allowAnalysisOnEdt {
|
||||
val property = this
|
||||
|
||||
analyze(property) {
|
||||
val propertySymbol = property.getVariableSymbol() as? KtPropertySymbol ?: return false
|
||||
return propertySymbol.hasBackingField
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -77,7 +99,7 @@ private class KtWrapInSupplierQuickFix(ktProperty: KtProperty) : WrapInSupplierQ
|
||||
}
|
||||
|
||||
override fun changeElementInitializerToSupplierCall(project: Project, element: KtProperty, supplierElement: KtProperty) {
|
||||
val receiverName = when(val container = supplierElement.containingClassOrObject) {
|
||||
val receiverName = when (val container = supplierElement.containingClassOrObject) {
|
||||
is KtClass -> container.name
|
||||
is KtObjectDeclaration -> if (container.isCompanion()) container.containingClassOrObject!!.name else container.name
|
||||
else -> null
|
||||
Reference in New Issue
Block a user