[Java Resolution] use a smart psi pointer to store PSI in JavaElement for IDE

`JavaElement`s are reused between read actions, so underlying PSI elements might be invalidated when using hard PSI references

^KT-58194 fixed
This commit is contained in:
Ilya Kirillov
2023-05-08 17:51:39 +02:00
committed by Space Team
parent c114cb67cb
commit 2d08d29dac
6 changed files with 124 additions and 6 deletions
@@ -8,6 +8,7 @@ dependencies {
api(project(":analysis:analysis-api"))
api(project(":analysis:analysis-api-impl-barebone"))
api(project(":analysis:kt-references"))
api(project(":compiler:resolution.common.jvm"))
api(intellijCore())
implementation(project(":analysis:analysis-internal-utils"))
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.impl.base.java.source
import com.intellij.psi.PsiElement
import com.intellij.psi.SmartPsiElementPointer
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementPsiSource
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementSourceFactory
internal class JavaElementPsiSourceWithSmartPointer<PSI : PsiElement>(
private val pointer: SmartPsiElementPointer<PSI>,
override val factory: JavaElementSourceFactory,
) : JavaElementPsiSource<PSI>() {
override val psi: PSI
get() {
return pointer.element
?: error("Cannot restore a PsiElement from $pointer")
}
override fun toString(): String {
return pointer.element?.toString() ?: "Cannot restore a PsiElement from $pointer"
}
}
@@ -0,0 +1,28 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.impl.base.java.source
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiType
import com.intellij.psi.SmartPointerManager
import com.intellij.psi.SmartTypePointerManager
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementPsiSource
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementSourceFactory
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementTypeSource
class JavaElementSourceWithSmartPointerFactory(project: Project) : JavaElementSourceFactory() {
private val smartTypePointerManager = SmartTypePointerManager.getInstance(project)
private val smartPsiPointerManager = SmartPointerManager.getInstance(project)
override fun <PSI : PsiElement> createPsiSource(psi: PSI): JavaElementPsiSource<PSI> {
return JavaElementPsiSourceWithSmartPointer(smartPsiPointerManager.createSmartPsiElementPointer(psi), this)
}
override fun <TYPE : PsiType> createTypeSource(type: TYPE): JavaElementTypeSource<TYPE> {
return JavaElementTypeSourceWithSmartPointer(smartTypePointerManager.createSmartTypePointer(type), this)
}
}
@@ -0,0 +1,29 @@
/*
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.api.impl.base.java.source
import com.intellij.psi.PsiType
import com.intellij.psi.SmartTypePointer
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementSourceFactory
import org.jetbrains.kotlin.load.java.structure.impl.source.JavaElementTypeSource
internal class JavaElementTypeSourceWithSmartPointer<TYPE : PsiType>(
private val pointer: SmartTypePointer,
override val factory: JavaElementSourceFactory,
) : JavaElementTypeSource<TYPE>() {
override val type: TYPE
get() {
val type = pointer.type
?: error("Cannot restore a PsiType from $pointer")
@Suppress("UNCHECKED_CAST")
return type as TYPE
}
override fun toString(): String {
return pointer.type?.toString() ?: "Cannot restore a PsiType from $pointer"
}
}