From f74416a1514975389ad1fbb20c80bf635447dda5 Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Thu, 31 Aug 2017 18:53:34 +0200 Subject: [PATCH] Cache the result of hasTopLevelCallables() for a KtFile #KT-19885 Fixed --- .../load/kotlin/PackagePartClassUtils.kt | 13 ++---------- .../src/org/jetbrains/kotlin/psi/KtFile.kt | 20 +++++++++++++++++++ .../asJava/classes/KtLightClassForFacade.kt | 3 +-- .../resolve/IDELightClassGenerationSupport.kt | 10 ++++++---- .../idea/stubindex/IdeStubIndexService.java | 3 +-- 5 files changed, 30 insertions(+), 19 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt index 10b750a384a..8c8d85c127e 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/PackagePartClassUtils.kt @@ -20,11 +20,10 @@ import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.vfs.VirtualFile import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.idea.KotlinFileType -import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.NameUtils -import org.jetbrains.kotlin.psi.* +import org.jetbrains.kotlin.psi.KtFile import java.util.* object PackagePartClassUtils { @@ -52,15 +51,7 @@ object PackagePartClassUtils { } @JvmStatic fun getFilesWithCallables(files: Collection): List = - files.filter { fileHasTopLevelCallables(it) } - - @JvmStatic fun fileHasTopLevelCallables(file: KtFile): Boolean = - file.declarations.any { - (it is KtProperty || - it is KtNamedFunction || - it is KtScript || - it is KtTypeAlias) && !it.hasModifier(KtTokens.HEADER_KEYWORD) - } + files.filter { it.hasTopLevelCallables() } @JvmStatic fun getFilePartShortName(fileName: String): String = NameUtils.getPackagePartClassNamePrefix(FileUtil.getNameWithoutExtension(fileName)) + PART_CLASS_NAME_SUFFIX diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt index 4335f68cf80..6a3d39cc3ef 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/KtFile.kt @@ -27,6 +27,7 @@ import com.intellij.util.IncorrectOperationException import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.KotlinLanguage +import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.parsing.KotlinParserDefinition import org.jetbrains.kotlin.psi.psiUtil.getChildOfType @@ -43,8 +44,12 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : PsiNamedElement, PsiModifiableCodeBlock { + @Volatile private var isScript: Boolean? = null + @Volatile + private var hasTopLeveCallables: Boolean? = null + val importList: KtImportList? get() = findChildByTypeOrClass(KtStubElementTypes.IMPORT_LIST, KtImportList::class.java) @@ -153,10 +158,25 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : override fun clearCaches() { super.clearCaches() isScript = null + hasTopLeveCallables = null } fun isScript(): Boolean = stub?.isScript() ?: isScriptByTree + fun hasTopLevelCallables(): Boolean { + hasTopLeveCallables?.let { return it } + + val result = declarations.any { + (it is KtProperty || + it is KtNamedFunction || + it is KtScript || + it is KtTypeAlias) && !it.hasModifier(KtTokens.HEADER_KEYWORD) + } + + hasTopLeveCallables = result + return result + } + override fun accept(visitor: PsiElementVisitor) { if (visitor is KtVisitor<*, *>) { @Suppress("UNCHECKED_CAST") diff --git a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt index 22fff3279fb..69eb4ea77c3 100644 --- a/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt +++ b/compiler/light-classes/src/org/jetbrains/kotlin/asJava/classes/KtLightClassForFacade.kt @@ -37,7 +37,6 @@ import org.jetbrains.kotlin.fileClasses.javaFileFacadeFqName import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils -import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils.fileHasTopLevelCallables import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.KtClassOrObject import org.jetbrains.kotlin.psi.KtFile @@ -190,7 +189,7 @@ class KtLightClassForFacade private constructor( override fun getQualifiedName() = facadeClassFqName.asString() - override fun isValid() = files.all { it.isValid && fileHasTopLevelCallables(it) && facadeClassFqName == it.javaFileFacadeFqName } + override fun isValid() = files.all { it.isValid && it.hasTopLevelCallables() && facadeClassFqName == it.javaFileFacadeFqName } override fun copy() = KtLightClassForFacade(manager, facadeClassFqName, lightClassDataCache, files) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt index c659c7b967a..42fd7af1d12 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/IDELightClassGenerationSupport.kt @@ -27,7 +27,10 @@ import org.jetbrains.kotlin.asJava.LightClassBuilder import org.jetbrains.kotlin.asJava.LightClassGenerationSupport import org.jetbrains.kotlin.asJava.builder.ClsWrapperStubPsiFactory import org.jetbrains.kotlin.asJava.builder.LightClassDataHolder -import org.jetbrains.kotlin.asJava.classes.* +import org.jetbrains.kotlin.asJava.classes.FakeLightClassForFileOfPackage +import org.jetbrains.kotlin.asJava.classes.KtLightClass +import org.jetbrains.kotlin.asJava.classes.KtLightClassForFacade +import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil @@ -39,7 +42,6 @@ import org.jetbrains.kotlin.idea.stubindex.* import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.idea.util.application.runReadAction -import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -330,13 +332,13 @@ class KtFileClassProviderImpl(val lightClassGenerationSupport: LightClassGenerat val fileClassFqName = file.javaFileFacadeFqName val facadeClasses = when { - file.analysisContext != null && PackagePartClassUtils.fileHasTopLevelCallables(file) -> + file.analysisContext != null && file.hasTopLevelCallables() -> listOf(KtLightClassForFacade.createForSyntheticFile(PsiManager.getInstance(file.project), fileClassFqName, file)) jvmClassInfo.withJvmMultifileClass -> lightClassGenerationSupport.getFacadeClasses(fileClassFqName, moduleInfo.contentScope()) - PackagePartClassUtils.fileHasTopLevelCallables(file) -> + file.hasTopLevelCallables() -> (lightClassGenerationSupport as IDELightClassGenerationSupport).createLightClassForFileFacade( fileClassFqName, listOf(file), moduleInfo) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IdeStubIndexService.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IdeStubIndexService.java index a4e3f3c5009..9f8d8431ed0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IdeStubIndexService.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/IdeStubIndexService.java @@ -27,7 +27,6 @@ import org.jetbrains.kotlin.fileClasses.JvmFileClassInfo; import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil; import org.jetbrains.kotlin.lexer.KtTokens; import org.jetbrains.kotlin.load.java.JvmAbi; -import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.KtClassOrObject; @@ -256,7 +255,7 @@ public class IdeStubIndexService extends StubIndexService { public KotlinFileStub createFileStub(@NotNull KtFile file) { StringRef packageFqName = StringRef.fromString(file.getPackageFqNameByTree().asString()); boolean isScript = file.isScriptByTree(); - if (PackagePartClassUtils.fileHasTopLevelCallables(file)) { + if (file.hasTopLevelCallables()) { JvmFileClassInfo fileClassInfo = JvmFileClassUtil.getFileClassInfoNoResolve(file); StringRef facadeSimpleName = StringRef.fromString(fileClassInfo.getFacadeClassFqName().shortName().asString()); StringRef partSimpleName = StringRef.fromString(fileClassInfo.getFileClassFqName().shortName().asString());