IJPL-149042 fix INRE on building java classes

it's not safe to use PsiClass#getMethods during building indexes

GitOrigin-RevId: a7828cf93e8004b6cd55f743a7ff0958a53afcbb
This commit is contained in:
Max Medvedev
2024-09-30 22:44:50 +00:00
committed by intellij-monorepo-bot
parent e2f362956e
commit e34f3578be
11 changed files with 74 additions and 41 deletions
@@ -4,15 +4,15 @@ package com.intellij.platform.ml.embeddings.indexer
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeExtension
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableClass
import com.intellij.psi.PsiFile
import com.intellij.util.concurrency.ThreadingAssertions
import com.intellij.util.concurrency.annotations.RequiresReadLock
import com.intellij.util.containers.toArray
import com.intellij.util.indexing.FileContent
import org.jetbrains.annotations.ApiStatus.Internal
@Internal
interface ClassesProvider {
fun extract(file: PsiFile): List<IndexableClass>
fun extract(fileContent: FileContent): List<IndexableClass>
companion object {
private val EXTENSION = FileTypeExtension<ClassesProvider>("com.intellij.embeddings.indexer.classesProvider")
@@ -21,9 +21,9 @@ interface ClassesProvider {
get() = EXTENSION.getAllRegisteredExtensions().keys.toArray(FileType.EMPTY_ARRAY)
@RequiresReadLock
fun extractClasses(file: PsiFile): List<IndexableClass> {
fun extractClasses(fileContent: FileContent): List<IndexableClass> {
ThreadingAssertions.assertReadAccess() // annotation doesn't work in Kotlin
return EXTENSION.forFileType(file.fileType)?.extract(file) ?: emptyList()
return EXTENSION.forFileType(fileContent.fileType)?.extract(fileContent) ?: emptyList()
}
}
}
@@ -4,15 +4,15 @@ package com.intellij.platform.ml.embeddings.indexer
import com.intellij.openapi.fileTypes.FileType
import com.intellij.openapi.fileTypes.FileTypeExtension
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableSymbol
import com.intellij.psi.PsiFile
import com.intellij.util.concurrency.ThreadingAssertions
import com.intellij.util.concurrency.annotations.RequiresReadLock
import com.intellij.util.containers.toArray
import com.intellij.util.indexing.FileContent
import org.jetbrains.annotations.ApiStatus.Internal
@Internal
interface SymbolsProvider {
fun extract(file: PsiFile): List<IndexableSymbol>
fun extract(fileContent: FileContent): List<IndexableSymbol>
companion object {
private val EXTENSION = FileTypeExtension<SymbolsProvider>("com.intellij.embeddings.indexer.symbolsProvider")
@@ -21,9 +21,9 @@ interface SymbolsProvider {
get() = EXTENSION.getAllRegisteredExtensions().keys.toArray(FileType.EMPTY_ARRAY)
@RequiresReadLock
fun extractSymbols(file: PsiFile): List<IndexableSymbol> {
fun extractSymbols(fileContent: FileContent): List<IndexableSymbol> {
ThreadingAssertions.assertReadAccess() // annotation doesn't work in Kotlin
return EXTENSION.forFileType(file.fileType)?.extract(file) ?: emptyList()
return EXTENSION.forFileType(fileContent.fileType)?.extract(fileContent) ?: emptyList()
}
}
}
@@ -50,9 +50,9 @@ internal class ClassNameEmbeddingIndex : PsiBaseEmbeddingIndex() {
get() = ClassesProvider.supportedFileTypes
override fun getName(): ID<EmbeddingKey, String> = CLASS_NAME_EMBEDDING_INDEX_NAME
override fun getVersion(): Int = 1
override fun getVersion(): Int = 2
override fun index(inputData: FileContent): List<IndexingItem> {
return ClassesProvider.extractClasses(inputData.psiFile).map { IndexingItem(it.id.id) }
return ClassesProvider.extractClasses(inputData).map { IndexingItem(it.id.id) }
}
}
@@ -61,9 +61,9 @@ internal class SymbolNameEmbeddingIndex : PsiBaseEmbeddingIndex() {
get() = SymbolsProvider.supportedFileTypes
override fun getName(): ID<EmbeddingKey, String> = SYMBOL_NAME_EMBEDDING_INDEX_NAME
override fun getVersion(): Int = 1
override fun getVersion(): Int = 2
override fun index(inputData: FileContent): List<IndexingItem> {
return SymbolsProvider.extractSymbols(inputData.psiFile).map { IndexingItem(it.id.id) }
return SymbolsProvider.extractSymbols(inputData).map { IndexingItem(it.id.id) }
}
}
@@ -26,6 +26,8 @@ import com.intellij.platform.ml.embeddings.settings.EmbeddingIndexSettingsImpl
import com.intellij.platform.ml.embeddings.utils.SEMANTIC_SEARCH_TRACER
import com.intellij.platform.util.coroutines.childScope
import com.intellij.psi.PsiManager
import com.intellij.util.indexing.FileContentImpl
import com.intellij.util.indexing.IndexingDataKeys.PSI_FILE
import kotlinx.coroutines.*
import kotlinx.coroutines.channels.Channel
import java.util.concurrent.atomic.AtomicBoolean
@@ -149,16 +151,24 @@ internal class VFSBasedEmbeddingEntitiesIndexer(private val cs: CoroutineScope)
}
if (classesChannel != null || symbolsChannel != null) {
val psiFile = readActionUndispatched { psiManager.findFile(file) } ?: return@coroutineScope
val (psiFile, fileType) = readActionUndispatched {
val psiFile = psiManager.findFile(file) ?: return@readActionUndispatched null
val fileType = psiFile.fileType
psiFile to fileType
} ?: return@coroutineScope
val content: FileContentImpl = FileContentImpl.createByFile(file, psiManager.project) as FileContentImpl
content.putUserData(PSI_FILE, psiFile) // todo I think we can avoid explicit passing of file
content.setSubstituteFileType(fileType) // todo we don't want to infer the substituted file type, do we?
if (classesChannel != null) {
launch {
readActionUndispatched { ClassesProvider.extractClasses(psiFile) }.forEach { classesChannel.send(it) }
readActionUndispatched { ClassesProvider.extractClasses(content) }.forEach { classesChannel.send(it) }
}
}
if (symbolsChannel != null) {
launch {
readActionUndispatched { SymbolsProvider.extractSymbols(psiFile) }.forEach { symbolsChannel.send(it) }
readActionUndispatched { SymbolsProvider.extractSymbols(content) }.forEach { symbolsChannel.send(it) }
}
}
}
@@ -12,6 +12,6 @@
<orderEntry type="module" module-name="intellij.searchEverywhereMl.semantics" />
<orderEntry type="module" module-name="intellij.java.psi" />
<orderEntry type="module" module-name="intellij.platform.ml.embeddings" />
<orderEntry type="module" module-name="intellij.java.frontback.psi.impl" />
<orderEntry type="module" module-name="intellij.java.psi.impl" />
</component>
</module>
@@ -3,14 +3,25 @@ package com.intellij.searchEverywhereMl.semantics.java
import com.intellij.platform.ml.embeddings.indexer.ClassesProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableClass
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.impl.source.JavaLightTreeUtil
import com.intellij.psi.impl.source.tree.JavaElementType
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.PsiDependentFileContent
internal class JavaClassesProvider : ClassesProvider {
override fun extract(file: PsiFile): List<IndexableClass> {
return (file as PsiJavaFile).classes.asSequence()
.mapNotNull { c -> c.name }
override fun extract(fileContent: FileContent): List<IndexableClass> {
val ast = (fileContent as PsiDependentFileContent).lighterAST
val topLevelNodes = ast.getChildren(ast.root).asSequence()
val classes = topLevelNodes.filter { node -> node.tokenType == JavaElementType.CLASS }
val classNames = classes
.mapNotNull { clazz -> JavaLightTreeUtil.getNameIdentifierText(ast, clazz) }
.filter { name -> name != ANONYMOUS_ID }
return classNames
.map { name -> IndexableClass(EntityId(name)) }
.toList()
}
}
}
private const val ANONYMOUS_ID = "<anonymous>"
@@ -3,15 +3,27 @@ package com.intellij.searchEverywhereMl.semantics.java
import com.intellij.platform.ml.embeddings.indexer.SymbolsProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableSymbol
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiJavaFile
import com.intellij.psi.impl.source.JavaLightTreeUtil
import com.intellij.psi.impl.source.tree.JavaElementType
import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.PsiDependentFileContent
internal class JavaSymbolsProvider : SymbolsProvider {
override fun extract(file: PsiFile): List<IndexableSymbol> {
return (file as PsiJavaFile).classes.asSequence()
.flatMap { c -> c.methods.asSequence() }
.filter { m -> m.name != ANONYMOUS_ID }
.map { m -> IndexableSymbol(EntityId(m.name)) }
override fun extract(fileContent: FileContent): List<IndexableSymbol> {
val ast = (fileContent as PsiDependentFileContent).lighterAST
val topLevelNodes = ast.getChildren(ast.root).asSequence()
val classes = topLevelNodes.filter { node -> node.tokenType == JavaElementType.CLASS }
val methods = classes
.flatMap { classNode -> ast.getChildren(classNode) }
.filter { node -> node.tokenType == JavaElementType.METHOD }
val methodNames = methods
.mapNotNull { method -> JavaLightTreeUtil.getNameIdentifierText(ast, method) }
.filter { name -> name != ANONYMOUS_ID }
return methodNames
.map { name -> IndexableSymbol(EntityId(name)) }
.toList()
}
}
@@ -3,13 +3,13 @@ package com.intellij.searchEverywhereMl.semantics.kotlin
import com.intellij.platform.ml.embeddings.indexer.ClassesProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableClass
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.util.childrenOfType
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.psi.KtClass
internal class KotlinClassesProvider : ClassesProvider {
override fun extract(file: PsiFile): List<IndexableClass> {
return file.childrenOfType<KtClass>().asSequence()
override fun extract(fileContent: FileContent): List<IndexableClass> {
return fileContent.psiFile.childrenOfType<KtClass>().asSequence()
.mapNotNull { c -> c.name }
.filter { name -> name != ANONYMOUS_ID }
.map { name -> IndexableClass(EntityId(name)) }
@@ -3,13 +3,13 @@ package com.intellij.searchEverywhereMl.semantics.kotlin
import com.intellij.platform.ml.embeddings.indexer.SymbolsProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableSymbol
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.psi.KtFunction
internal class KotlinSymbolsProvider : SymbolsProvider {
override fun extract(file: PsiFile): List<IndexableSymbol> {
return PsiTreeUtil.findChildrenOfAnyType(file, false, KtFunction::class.java).asSequence()
override fun extract(fileContent: FileContent): List<IndexableSymbol> {
return PsiTreeUtil.findChildrenOfAnyType(fileContent.psiFile, false, KtFunction::class.java).asSequence()
.mapNotNull { f -> f.name }
.filter { name -> name != ANONYMOUS_ID }
.map { name -> IndexableSymbol(EntityId(name)) }
@@ -3,13 +3,13 @@ package com.intellij.searchEverywhereMl.semantics.python
import com.intellij.platform.ml.embeddings.indexer.ClassesProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableClass
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.util.childrenOfType
import com.intellij.util.indexing.FileContent
import com.jetbrains.python.psi.PyClass
internal class PythonClassesProvider : ClassesProvider {
override fun extract(file: PsiFile): List<IndexableClass> {
return file.childrenOfType<PyClass>().asSequence()
override fun extract(fileContent: FileContent): List<IndexableClass> {
return fileContent.psiFile.childrenOfType<PyClass>()
.mapNotNull { c -> c.name }
.filter { name -> name != ANONYMOUS_ID }
.map { name -> IndexableClass(EntityId(name)) }
@@ -3,13 +3,13 @@ package com.intellij.searchEverywhereMl.semantics.python
import com.intellij.platform.ml.embeddings.indexer.SymbolsProvider
import com.intellij.platform.ml.embeddings.indexer.entities.IndexableSymbol
import com.intellij.platform.ml.embeddings.jvm.indices.EntityId
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.indexing.FileContent
import com.jetbrains.python.psi.PyFunction
internal class PythonSymbolsProvider : SymbolsProvider {
override fun extract(file: PsiFile): List<IndexableSymbol> {
return PsiTreeUtil.findChildrenOfAnyType(file, false, PyFunction::class.java).asSequence()
override fun extract(fileContent: FileContent): List<IndexableSymbol> {
return PsiTreeUtil.findChildrenOfAnyType(fileContent.psiFile, false, PyFunction::class.java).asSequence()
.mapNotNull { f -> f.name }
.filter { name -> name != ANONYMOUS_ID }
.map { name -> IndexableSymbol(EntityId(name)) }