AA: do not use full decompilation for built-ins

This is the major performance bottleneck for AA/UAST artifacts rollout
to Android Lint. KT stubs are good/fast enough.
This commit is contained in:
Jinseong Jeon
2023-01-17 00:43:22 -08:00
committed by Ilya Kirillov
parent 669afdd463
commit 2da4693cc0
4 changed files with 55 additions and 16 deletions
@@ -6,20 +6,22 @@
package org.jetbrains.kotlin.analysis.providers.impl package org.jetbrains.kotlin.analysis.providers.impl
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem
import com.intellij.psi.* import com.intellij.psi.*
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StubElement
import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.FileContent
import com.intellij.util.indexing.FileContentImpl import com.intellij.util.indexing.FileContentImpl
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinBuiltInDecompiler
import org.jetbrains.kotlin.analysis.decompiler.psi.KotlinDecompiledFileViewProvider
import org.jetbrains.kotlin.analysis.decompiler.psi.file.KtDecompiledFile
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory
import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName
import org.jetbrains.kotlin.idea.KotlinLanguage
import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
public class KotlinStaticDeclarationProvider internal constructor( public class KotlinStaticDeclarationProvider internal constructor(
@@ -107,7 +109,7 @@ public class KotlinStaticDeclarationProviderFactory(
private val psiManager = PsiManager.getInstance(project) private val psiManager = PsiManager.getInstance(project)
private val builtInDecompiler = KotlinBuiltInDecompiler() private val builtInDecompiler = KotlinBuiltInDecompiler()
private fun loadBuiltIns(): Collection<KtDecompiledFile> { private fun loadBuiltIns(): Collection<KotlinFileStubImpl> {
val classLoader = this::class.java.classLoader val classLoader = this::class.java.classLoader
return buildList { return buildList {
StandardClassIds.builtInsPackages.forEach { builtInPackageFqName -> StandardClassIds.builtInsPackages.forEach { builtInPackageFqName ->
@@ -121,7 +123,7 @@ public class KotlinStaticDeclarationProviderFactory(
val pathToQuery = jarPath + URLUtil.JAR_SEPARATOR + builtInFile val pathToQuery = jarPath + URLUtil.JAR_SEPARATOR + builtInFile
jarFileSystem.findFileByPath(pathToQuery)?.let { vf -> jarFileSystem.findFileByPath(pathToQuery)?.let { vf ->
val fileContent = FileContentImpl.createByFile(vf, project) val fileContent = FileContentImpl.createByFile(vf, project)
createKtFileStub(fileContent)?.let { file -> add(file) } createKtFileStub(psiManager, builtInDecompiler, fileContent)?.let { file -> add(file) }
} }
} }
} }
@@ -130,18 +132,25 @@ public class KotlinStaticDeclarationProviderFactory(
} }
private fun createKtFileStub( private fun createKtFileStub(
psiManager: PsiManager,
builtInDecompiler: KotlinBuiltInDecompiler,
fileContent: FileContent, fileContent: FileContent,
): KtDecompiledFile? { ): KotlinFileStubImpl? {
val fileViewProvider = val ktFileStub = builtInDecompiler.stubBuilder.buildFileStub(fileContent) as? KotlinFileStubImpl ?: return null
builtInDecompiler.createFileViewProvider(fileContent.file, psiManager, physical = true) as? KotlinDecompiledFileViewProvider val fakeFile = object : KtFile(KtClassFileViewProvider(psiManager, fileContent.file), isCompiled = true) {
?: return null override fun getStub() = ktFileStub
return builtInDecompiler.readFile(fileContent.content, fileContent.file)?.let { fileWithMetadata ->
KtDecompiledFile(fileViewProvider) { override fun isPhysical() = false
builtInDecompiler.buildDecompiledText(fileWithMetadata)
}
} }
ktFileStub.psi = fakeFile
return ktFileStub
} }
private class KtClassFileViewProvider(
psiManager: PsiManager,
virtualFile: VirtualFile,
) : SingleRootFileViewProvider(psiManager, virtualFile, true, KotlinLanguage.INSTANCE)
private inner class KtDeclarationRecorder : KtVisitorVoid() { private inner class KtDeclarationRecorder : KtVisitorVoid() {
override fun visitElement(element: PsiElement) { override fun visitElement(element: PsiElement) {
@@ -217,8 +226,23 @@ public class KotlinStaticDeclarationProviderFactory(
val recorder = KtDeclarationRecorder() val recorder = KtDeclarationRecorder()
// Indexing built-ins // Indexing built-ins
loadBuiltIns().forEach { fun indexStub(stub: StubElement<*>) {
it.accept(recorder) when (stub) {
is KotlinClassStubImpl -> {
addToClassMap(stub.psi)
// member functions and properties
stub.childrenStubs.forEach(::indexStub)
}
is KotlinTypeAliasStubImpl -> addToTypeAliasMap(stub.psi)
is KotlinFunctionStubImpl -> addToFunctionMap(stub.psi)
is KotlinPropertyStubImpl -> addToPropertyMap(stub.psi)
}
}
loadBuiltIns().forEach { ktFileStub ->
addToFacadeFileMap(ktFileStub.psi)
// top-level functions and properties, built-in classes
ktFileStub.childrenStubs.forEach(::indexStub)
} }
// Indexing user source files // Indexing user source files
@@ -9,9 +9,24 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.PsiMethod import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiParameter import com.intellij.psi.PsiParameter
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtParameter
object TestPsiElementRenderer { object TestPsiElementRenderer {
fun render(psiElement: PsiElement): String = when (psiElement) { fun render(psiElement: PsiElement): String = when (psiElement) {
is KtNamedFunction -> buildString {
append("KtNamedFunction:")
append(psiElement.name)
append("(")
psiElement.valueParameters.joinTo(this) { render(it) }
append(")")
}
is KtParameter -> buildString {
if (psiElement.isVarArg) {
append("vararg ")
}
append(psiElement.name)
}
is KtElement -> psiElement.text is KtElement -> psiElement.text
is PsiMethod -> buildString { is PsiMethod -> buildString {
append("PsiMethod:") append("PsiMethod:")
@@ -1,2 +1,2 @@
Resolved to: Resolved to:
public abstract fun add(element: T): kotlin.Unit KtNamedFunction:add(element)
@@ -1,2 +1,2 @@
Resolved to: Resolved to:
@kotlin.SinceKotlin @kotlin.internal.PlatformDependent public open fun getOrDefault(key: K, defaultValue: V): V { /* compiled code */ } KtNamedFunction:getOrDefault(key, defaultValue)