From 2da4693cc04fe5bec325aaa30bf0e08cdd54737e Mon Sep 17 00:00:00 2001 From: Jinseong Jeon Date: Tue, 17 Jan 2023 00:43:22 -0800 Subject: [PATCH] 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. --- .../impl/KotlinStaticDeclarationProvider.kt | 52 ++++++++++++++----- .../TestPsiElementRenderer.kt | 15 ++++++ .../standalone/singleModule/listIterator.txt | 2 +- .../singleModule/mapGetOrDefault.txt | 2 +- 4 files changed, 55 insertions(+), 16 deletions(-) diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt index 61bcdf1e8a7..6ce884aa80c 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt @@ -6,20 +6,22 @@ package org.jetbrains.kotlin.analysis.providers.impl import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.impl.jar.CoreJarFileSystem import com.intellij.psi.* import com.intellij.psi.search.GlobalSearchScope +import com.intellij.psi.stubs.StubElement import com.intellij.util.indexing.FileContent import com.intellij.util.indexing.FileContentImpl import com.intellij.util.io.URLUtil 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.KotlinDeclarationProviderFactory import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName +import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.stubs.impl.* import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol public class KotlinStaticDeclarationProvider internal constructor( @@ -107,7 +109,7 @@ public class KotlinStaticDeclarationProviderFactory( private val psiManager = PsiManager.getInstance(project) private val builtInDecompiler = KotlinBuiltInDecompiler() - private fun loadBuiltIns(): Collection { + private fun loadBuiltIns(): Collection { val classLoader = this::class.java.classLoader return buildList { StandardClassIds.builtInsPackages.forEach { builtInPackageFqName -> @@ -121,7 +123,7 @@ public class KotlinStaticDeclarationProviderFactory( val pathToQuery = jarPath + URLUtil.JAR_SEPARATOR + builtInFile jarFileSystem.findFileByPath(pathToQuery)?.let { vf -> 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( + psiManager: PsiManager, + builtInDecompiler: KotlinBuiltInDecompiler, fileContent: FileContent, - ): KtDecompiledFile? { - val fileViewProvider = - builtInDecompiler.createFileViewProvider(fileContent.file, psiManager, physical = true) as? KotlinDecompiledFileViewProvider - ?: return null - return builtInDecompiler.readFile(fileContent.content, fileContent.file)?.let { fileWithMetadata -> - KtDecompiledFile(fileViewProvider) { - builtInDecompiler.buildDecompiledText(fileWithMetadata) - } + ): KotlinFileStubImpl? { + val ktFileStub = builtInDecompiler.stubBuilder.buildFileStub(fileContent) as? KotlinFileStubImpl ?: return null + val fakeFile = object : KtFile(KtClassFileViewProvider(psiManager, fileContent.file), isCompiled = true) { + override fun getStub() = ktFileStub + + override fun isPhysical() = false } + ktFileStub.psi = fakeFile + return ktFileStub } + private class KtClassFileViewProvider( + psiManager: PsiManager, + virtualFile: VirtualFile, + ) : SingleRootFileViewProvider(psiManager, virtualFile, true, KotlinLanguage.INSTANCE) + private inner class KtDeclarationRecorder : KtVisitorVoid() { override fun visitElement(element: PsiElement) { @@ -217,8 +226,23 @@ public class KotlinStaticDeclarationProviderFactory( val recorder = KtDeclarationRecorder() // Indexing built-ins - loadBuiltIns().forEach { - it.accept(recorder) + fun indexStub(stub: StubElement<*>) { + 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 diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/components/psiDeclarationProvider/TestPsiElementRenderer.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/components/psiDeclarationProvider/TestPsiElementRenderer.kt index f037a0f40e3..800c4d62641 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/components/psiDeclarationProvider/TestPsiElementRenderer.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/components/psiDeclarationProvider/TestPsiElementRenderer.kt @@ -9,9 +9,24 @@ import com.intellij.psi.PsiElement import com.intellij.psi.PsiMethod import com.intellij.psi.PsiParameter import org.jetbrains.kotlin.psi.KtElement +import org.jetbrains.kotlin.psi.KtNamedFunction +import org.jetbrains.kotlin.psi.KtParameter object TestPsiElementRenderer { 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 PsiMethod -> buildString { append("PsiMethod:") diff --git a/analysis/analysis-api/testData/standalone/singleModule/listIterator.txt b/analysis/analysis-api/testData/standalone/singleModule/listIterator.txt index e2a46ee8150..3b9fd32bb25 100644 --- a/analysis/analysis-api/testData/standalone/singleModule/listIterator.txt +++ b/analysis/analysis-api/testData/standalone/singleModule/listIterator.txt @@ -1,2 +1,2 @@ Resolved to: -public abstract fun add(element: T): kotlin.Unit \ No newline at end of file +KtNamedFunction:add(element) \ No newline at end of file diff --git a/analysis/analysis-api/testData/standalone/singleModule/mapGetOrDefault.txt b/analysis/analysis-api/testData/standalone/singleModule/mapGetOrDefault.txt index 01533e93529..a7de3a5a09b 100644 --- a/analysis/analysis-api/testData/standalone/singleModule/mapGetOrDefault.txt +++ b/analysis/analysis-api/testData/standalone/singleModule/mapGetOrDefault.txt @@ -1,2 +1,2 @@ Resolved to: -@kotlin.SinceKotlin @kotlin.internal.PlatformDependent public open fun getOrDefault(key: K, defaultValue: V): V { /* compiled code */ } \ No newline at end of file +KtNamedFunction:getOrDefault(key, defaultValue) \ No newline at end of file