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
This commit is contained in:
Pavel V. Talanov
2016-06-16 19:24:11 +03:00
parent 7ededbd5e2
commit 1a9c46f34b
9 changed files with 71 additions and 58 deletions
@@ -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
@@ -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)
@@ -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
}
@@ -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<Boolean?>(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)
}
}
}
@@ -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<Boolean?>? = 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)
}
}
@@ -47,7 +47,7 @@ class KotlinGotoClassContributor : GotoClassContributor {
override fun getItemsByName(name: String, pattern: String, project: Project, includeNonProjectItems: Boolean): Array<NavigationItem> {
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<NavigationItem> {
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<NavigationItem>()
result += KotlinFunctionShortNameIndex.getInstance().get(name, project, noLibrarySourceScope)
@@ -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<KtSimpleNameReference>()
.mapNotNull { ref -> ref.expression.getStrictParentOfType<KtImportDirective>() }
@@ -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<KtSimpleNameReference>()
.map { ref -> ref.expression }
@@ -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<PsiClass, Direct
if (scope == null) return
runReadAction {
val noLibrarySourceScope = KotlinSourceFilterScope.sourceAndClassFiles(scope, baseClass.project)
val noLibrarySourceScope = KotlinSourceFilterScope.projectSourceAndClassFiles(scope, baseClass.project)
KotlinSuperClassIndex.getInstance()
.get(name, baseClass.project, noLibrarySourceScope).asSequence()
.mapNotNull { candidate -> SourceNavigationHelper.getOriginalPsiClassOrCreateLightClass(candidate) }