From 1a9c46f34b695216095da017192bc9d635fe1fe0 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 16 Jun 2016 19:24:11 +0300 Subject: [PATCH] Ide Scopes: Allow including script dependencies into search scope This includes script dependencies into scopes for some of the IDE services Should be revisited later to decide if given service should work for scripts --- .../resolve/IDELightClassGenerationSupport.kt | 2 +- .../caches/resolve/JavaResolveExtension.kt | 1 + .../kotlin/idea/caches/resolve/scopeUtils.kt | 2 +- .../idea/stubindex/KotlinSourceFilterScope.kt | 66 ++++++++++--------- .../kotlin/idea/util/ProjectRootsUtil.kt | 44 ++++++++----- .../kotlin/idea/goto/gotoContributors.kt | 4 +- .../ConflictingExtensionPropertyInspection.kt | 4 +- .../DeprecatedSymbolUsageInWholeProjectFix.kt | 2 +- .../KotlinDirectInheritorsSearcher.kt | 4 +- 9 files changed, 71 insertions(+), 58 deletions(-) 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 fbc6e6aef2a..00d958f59a7 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 @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.idea.decompiler.classFile.KtClsFile import org.jetbrains.kotlin.idea.decompiler.navigation.SourceNavigationHelper import org.jetbrains.kotlin.idea.project.ResolveElementCache import org.jetbrains.kotlin.idea.stubindex.* -import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.sourceAndClassFiles +import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope.Companion.sourceAndClassFiles import org.jetbrains.kotlin.idea.util.ProjectRootsUtil import org.jetbrains.kotlin.incremental.components.NoLookupLocation import org.jetbrains.kotlin.load.kotlin.PackagePartClassUtils diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt index 7b79ab206e6..54d2dfd9d1d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/JavaResolveExtension.kt @@ -108,6 +108,7 @@ private fun PsiElement.getJavaDescriptorResolver(resolutionFacade: ResolutionFac return resolutionFacade.getFrontendService(this, JavaDescriptorResolver::class.java) } else { + //TODO_R: should this work in scripts? if (!ProjectRootsUtil.isInProjectOrLibraryClassFile(this)) return null val cacheService = KotlinCacheService.getInstance(project) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/scopeUtils.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/scopeUtils.kt index 944c4f0baa3..bbd7a3a0b46 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/scopeUtils.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/scopeUtils.kt @@ -31,7 +31,7 @@ fun getResolveScope(file: KtFile): GlobalSearchScope { } return when (file.getModuleInfo()) { - is ModuleSourceInfo -> KotlinSourceFilterScope.sourceAndClassFiles(file.resolveScope, file.project) + is ModuleSourceInfo -> KotlinSourceFilterScope.projectSourceAndClassFiles(file.resolveScope, file.project) is ScriptModuleInfo -> file.getModuleInfo().contentScope() else -> GlobalSearchScope.EMPTY_SCOPE } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt index 03d4dfe37cf..c648aec0284 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/stubindex/KotlinSourceFilterScope.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,67 +29,69 @@ class KotlinSourceFilterScope private constructor( private val includeProjectSourceFiles: Boolean, private val includeLibrarySourceFiles: Boolean, private val includeClassFiles: Boolean, - private val project: Project) : DelegatingGlobalSearchScope(delegate) { + private val includeScriptDependencies: Boolean, + private val project: Project +) : DelegatingGlobalSearchScope(delegate) { private val index = ProjectRootManager.getInstance(project).fileIndex //NOTE: avoid recomputing in potentially bottleneck 'contains' method private val isJsProjectRef = Ref(null) - override fun getProject(): Project? { - return project - } + override fun getProject() = project override fun contains(file: VirtualFile): Boolean { if (!super.contains(file)) return false + return ProjectRootsUtil.isInContent( - project, file, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, index, isJsProjectRef) + project, file, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, includeScriptDependencies, index, isJsProjectRef + ) } companion object { - fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project): GlobalSearchScope { - return create(delegate, true, true, true, project) - } + @JvmStatic + fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, true, true, project) - fun sourceAndClassFiles(delegate: GlobalSearchScope, project: Project): GlobalSearchScope { - return create(delegate, true, false, true, project) - } + @JvmStatic + fun sourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, true, project) - fun sources(delegate: GlobalSearchScope, project: Project): GlobalSearchScope { - return create(delegate, true, false, false, project) - } + @JvmStatic + fun projectSourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, false, project) - fun librarySources(delegate: GlobalSearchScope, project: Project): GlobalSearchScope { - return create(delegate, false, true, false, project) - } + @JvmStatic + fun sources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, false, true, project) - fun libraryClassFiles(delegate: GlobalSearchScope, project: Project): GlobalSearchScope { - return create(delegate, false, false, true, project) - } + @JvmStatic + fun projectSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, false, false, project) + + @JvmStatic + fun librarySources(delegate: GlobalSearchScope, project: Project) = create(delegate, false, true, false, true, project) + + @JvmStatic + fun libraryClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, false, false, true, true, project) private fun create( delegate: GlobalSearchScope, includeProjectSourceFiles: Boolean, includeLibrarySourceFiles: Boolean, includeClassFiles: Boolean, + includeScriptDependencies: Boolean, project: Project ): GlobalSearchScope { if (delegate === GlobalSearchScope.EMPTY_SCOPE) return delegate if (delegate is KotlinSourceFilterScope) { - - val doIncludeProjectSourceFiles = delegate.includeProjectSourceFiles && includeProjectSourceFiles - val doIncludeLibrarySourceFiles = delegate.includeLibrarySourceFiles && includeLibrarySourceFiles - val doIncludeClassFiles = delegate.includeClassFiles && includeClassFiles - - return KotlinSourceFilterScope(delegate.myBaseScope, - doIncludeProjectSourceFiles, - doIncludeLibrarySourceFiles, - doIncludeClassFiles, - project) + return KotlinSourceFilterScope( + delegate.myBaseScope, + includeProjectSourceFiles = delegate.includeProjectSourceFiles && includeProjectSourceFiles, + includeLibrarySourceFiles = delegate.includeLibrarySourceFiles && includeLibrarySourceFiles, + includeClassFiles = delegate.includeClassFiles && includeClassFiles, + includeScriptDependencies = delegate.includeScriptDependencies && includeScriptDependencies, + project = project + ) } - return KotlinSourceFilterScope(delegate, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, project) + return KotlinSourceFilterScope(delegate, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, includeScriptDependencies, project) } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt index 0e68bada053..06fdfa818e9 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/util/ProjectRootsUtil.kt @@ -24,29 +24,38 @@ import com.intellij.openapi.util.Ref import com.intellij.openapi.vfs.VirtualFile import com.intellij.psi.PsiDirectory import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.idea.KotlinModuleFileType import org.jetbrains.kotlin.idea.caches.resolve.JsProjectDetector +import org.jetbrains.kotlin.idea.core.script.KotlinScriptConfigurationManager import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType import org.jetbrains.kotlin.idea.util.application.runReadAction -private val classFileLike = listOf(JavaClassFileType.INSTANCE, KotlinBuiltInFileType) +private val classFileLike = listOf(JavaClassFileType.INSTANCE, KotlinBuiltInFileType, KotlinModuleFileType.INSTANCE) object ProjectRootsUtil { @JvmStatic fun isInContent(project: Project, file: VirtualFile, includeProjectSource: Boolean, includeLibrarySource: Boolean, includeLibraryClasses: Boolean, + includeScriptDependencies: Boolean, fileIndex: ProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(project), isJsProjectRef: Ref? = null): Boolean { - if (includeProjectSource && fileIndex.isInSourceContent(file)) { - return true - } + + if (includeProjectSource && fileIndex.isInSourceContent(file)) return true + + if (!includeLibraryClasses && !includeLibrarySource) return false // NOTE: the following is a workaround for cases when class files are under library source roots and source files are under class roots val canContainClassFiles = file.fileType == ArchiveFileType.INSTANCE || file.isDirectory val isClassFile = file.fileType in classFileLike - if ((includeLibraryClasses && (isClassFile || canContainClassFiles) && fileIndex.isInLibraryClasses(file)) || - (includeLibrarySource && !isClassFile && fileIndex.isInLibrarySource(file))) { + val scriptConfigurationManager = if (includeScriptDependencies) KotlinScriptConfigurationManager.getInstance(project) else null - return true + if (includeLibraryClasses && (isClassFile || canContainClassFiles)) { + if (fileIndex.isInLibraryClasses(file)) return true + if (scriptConfigurationManager?.getAllScriptsClasspathScope()?.contains(file) == true) return true + } + if (includeLibrarySource && !isClassFile) { + if (fileIndex.isInLibrarySource(file)) return true + if (scriptConfigurationManager?.getAllLibrarySourcesScope()?.contains(file) == true) return true } if ((includeLibraryClasses && fileIndex.isInLibraryClasses(file)) || @@ -65,7 +74,8 @@ object ProjectRootsUtil { element: PsiElement, includeProjectSource: Boolean, includeLibrarySource: Boolean, - includeLibraryClasses: Boolean + includeLibraryClasses: Boolean, + includeScriptDependencies: Boolean ): Boolean { return runReadAction { val virtualFile = when (element) { @@ -74,39 +84,39 @@ object ProjectRootsUtil { } ?: return@runReadAction false val project = element.project - return@runReadAction isInContent(project, virtualFile, includeProjectSource, includeLibrarySource, includeLibraryClasses) + return@runReadAction isInContent(project, virtualFile, includeProjectSource, includeLibrarySource, includeLibraryClasses, includeScriptDependencies) } } @JvmStatic fun isInProjectSource(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false) + return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false, includeScriptDependencies = false) } @JvmStatic fun isProjectSourceFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false) + return isInContent(project, file, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false, includeScriptDependencies = false) } @JvmStatic fun isInProjectOrLibSource(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = false) + return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = false, includeScriptDependencies = false) } @JvmStatic fun isInProjectOrLibraryContent(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = true) + return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = true, includeScriptDependencies = true) } @JvmStatic fun isInProjectOrLibraryClassFile(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = true) + return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = true, includeScriptDependencies = false) } @JvmStatic fun isLibraryClassFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = false, includeLibraryClasses = true) + return isInContent(project, file, includeProjectSource = false, includeLibrarySource = false, includeLibraryClasses = true, includeScriptDependencies = true) } @JvmStatic fun isLibrarySourceFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = false) + return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = false, includeScriptDependencies = true) } @JvmStatic fun isLibraryFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = true) + return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = true, includeScriptDependencies = true) } } diff --git a/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt b/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt index 7858e5587c8..c525dad2c0a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt +++ b/idea/src/org/jetbrains/kotlin/idea/goto/gotoContributors.kt @@ -47,7 +47,7 @@ class KotlinGotoClassContributor : GotoClassContributor { override fun getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array { val scope = if (includeNonProjectItems) GlobalSearchScope.allScope(project) else GlobalSearchScope.projectScope(project) - val classesOrObjects = KotlinClassShortNameIndex.getInstance().get(name, project, KotlinSourceFilterScope.sourceAndClassFiles(scope, project)) + val classesOrObjects = KotlinClassShortNameIndex.getInstance().get(name, project, KotlinSourceFilterScope.projectSourceAndClassFiles(scope, project)) if (classesOrObjects.isEmpty()) return NavigationItem.EMPTY_NAVIGATION_ITEM_ARRAY @@ -73,7 +73,7 @@ class KotlinGotoSymbolContributor : ChooseByNameContributor { override fun getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array { val baseScope = if (includeNonProjectItems) GlobalSearchScope.allScope(project) else GlobalSearchScope.projectScope(project) - val noLibrarySourceScope = KotlinSourceFilterScope.sourceAndClassFiles(baseScope, project) + val noLibrarySourceScope = KotlinSourceFilterScope.projectSourceAndClassFiles(baseScope, project) val result = ArrayList() result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope) diff --git a/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt b/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt index 94590a20376..3beb3a10871 100644 --- a/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt +++ b/idea/src/org/jetbrains/kotlin/idea/inspections/ConflictingExtensionPropertyInspection.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -193,7 +193,7 @@ class ConflictingExtensionPropertyInspection : AbstractKotlinInspection(), Clean object : Task.Modal(project, "Searching for imports to delete", true) { override fun run(indicator: ProgressIndicator) { val importsToDelete = runReadAction { - val searchScope = KotlinSourceFilterScope.sources(GlobalSearchScope.projectScope(project), project) + val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project) ReferencesSearch.search(declaration, searchScope) .filterIsInstance() .mapNotNull { ref -> ref.expression.getStrictParentOfType() } diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt index 592b18ad94d..f6043b20219 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/replaceWith/DeprecatedSymbolUsageInWholeProjectFix.kt @@ -67,7 +67,7 @@ class DeprecatedSymbolUsageInWholeProjectFix( object : Task.Modal(project, "Applying '$text'", true) { override fun run(indicator: ProgressIndicator) { val usages = runReadAction { - val searchScope = KotlinSourceFilterScope.sources(GlobalSearchScope.projectScope(project), project) + val searchScope = KotlinSourceFilterScope.projectSources(GlobalSearchScope.projectScope(project), project) ReferencesSearch.search(psiElement, searchScope) .filterIsInstance() .map { ref -> ref.expression } diff --git a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDirectInheritorsSearcher.kt b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDirectInheritorsSearcher.kt index c952ad38c5d..398fa055511 100644 --- a/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDirectInheritorsSearcher.kt +++ b/idea/src/org/jetbrains/kotlin/idea/search/ideaExtensions/KotlinDirectInheritorsSearcher.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2015 JetBrains s.r.o. + * Copyright 2010-2016 JetBrains s.r.o. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -44,7 +44,7 @@ open class KotlinDirectInheritorsSearcher() : QueryExecutorBase SourceNavigationHelper.getOriginalPsiClassOrCreateLightClass(candidate) }