diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.kt index c4cad84bfe3..89f770dc299 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/navigation/SourceNavigationHelper.kt @@ -276,7 +276,7 @@ object SourceNavigationHelper { SourceNavigationHelper.NavigationKind.SOURCES_TO_CLASS_FILES -> { val file = from.containingFile if (file is KtFile && file.isCompiled) return from - if (!ProjectRootsUtil.isInContent(from, false, true, false, true)) return from + if (!ProjectRootsUtil.isInContent(from, false, true, false, true, false)) return from if (KtPsiUtil.isLocal(from)) return from } } 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 be3a0cd3782..111ca7c43c8 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 @@ -24,12 +24,13 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.idea.util.ProjectRootsUtil class KotlinSourceFilterScope private constructor( - delegate: GlobalSearchScope, - private val includeProjectSourceFiles: Boolean, - private val includeLibrarySourceFiles: Boolean, - private val includeClassFiles: Boolean, - private val includeScriptDependencies: Boolean, - private val project: Project + delegate: GlobalSearchScope, + private val includeProjectSourceFiles: Boolean, + private val includeLibrarySourceFiles: Boolean, + private val includeClassFiles: Boolean, + private val includeScriptDependencies: Boolean, + private val includeScriptsOutsideSourceRoots: Boolean, + private val project: Project ) : DelegatingGlobalSearchScope(delegate) { private val index = ProjectRootManager.getInstance(project).fileIndex @@ -40,7 +41,14 @@ class KotlinSourceFilterScope private constructor( if (!super.contains(file)) return false return ProjectRootsUtil.isInContent( - project, file, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, includeScriptDependencies, index + project, + file, + includeProjectSourceFiles, + includeLibrarySourceFiles, + includeClassFiles, + includeScriptDependencies, + includeScriptsOutsideSourceRoots, + index ) } @@ -77,25 +85,25 @@ class KotlinSourceFilterScope private constructor( companion object { @JvmStatic - fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, true, true, project) + fun sourcesAndLibraries(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, true, true, true, project) @JvmStatic - fun sourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, true, project) + fun sourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, true, true, project) @JvmStatic - fun projectSourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, false, project) + fun projectSourceAndClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, true, false, true, project) @JvmStatic - fun projectSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, false, false, project) + fun projectSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, false, false, false, true, project) @JvmStatic - fun librarySources(delegate: GlobalSearchScope, project: Project) = create(delegate, false, true, false, true, project) + fun librarySources(delegate: GlobalSearchScope, project: Project) = create(delegate, false, true, false, true, false, project) @JvmStatic - fun libraryClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, false, false, true, true, project) + fun libraryClassFiles(delegate: GlobalSearchScope, project: Project) = create(delegate, false, false, true, true, false, project) @JvmStatic - fun projectAndLibrariesSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, false, false, project) + fun projectAndLibrariesSources(delegate: GlobalSearchScope, project: Project) = create(delegate, true, true, false, false, true, project) private fun create( delegate: GlobalSearchScope, @@ -103,6 +111,7 @@ class KotlinSourceFilterScope private constructor( includeLibrarySourceFiles: Boolean, includeClassFiles: Boolean, includeScriptDependencies: Boolean, + includeScriptsOutsideSourceRoots: Boolean, project: Project ): GlobalSearchScope { if (delegate === GlobalSearchScope.EMPTY_SCOPE) return delegate @@ -114,11 +123,12 @@ class KotlinSourceFilterScope private constructor( includeLibrarySourceFiles = delegate.includeLibrarySourceFiles && includeLibrarySourceFiles, includeClassFiles = delegate.includeClassFiles && includeClassFiles, includeScriptDependencies = delegate.includeScriptDependencies && includeScriptDependencies, + includeScriptsOutsideSourceRoots = delegate.includeScriptsOutsideSourceRoots && includeScriptsOutsideSourceRoots, project = project ) } - return KotlinSourceFilterScope(delegate, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, includeScriptDependencies, project) + return KotlinSourceFilterScope(delegate, includeProjectSourceFiles, includeLibrarySourceFiles, includeClassFiles, includeScriptDependencies, includeScriptsOutsideSourceRoots, 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 94d5728b918..1459391e15b 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 @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.util import com.intellij.ide.highlighter.ArchiveFileType import com.intellij.ide.highlighter.JavaClassFileType +import com.intellij.ide.scratch.ScratchUtil import com.intellij.injected.editor.VirtualFileWindow import com.intellij.openapi.extensions.ExtensionPointName import com.intellij.openapi.fileTypes.FileType @@ -28,6 +29,8 @@ import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesManager import org.jetbrains.kotlin.idea.decompiler.builtIns.KotlinBuiltInFileType import org.jetbrains.kotlin.idea.decompiler.js.KotlinJavaScriptMetaFileType import org.jetbrains.kotlin.idea.util.application.runReadAction +import org.jetbrains.kotlin.script.findScriptDefinition +import kotlin.script.experimental.location.ScriptExpectedLocation abstract class KotlinBinaryExtension(val fileType: FileType) { companion object { @@ -57,13 +60,64 @@ val PsiFileSystemItem.sourceRoot: VirtualFile? get() = virtualFile?.getSourceRoot(project) object ProjectRootsUtil { - @JvmStatic fun isInContent(project: Project, file: VirtualFile, includeProjectSource: Boolean, - includeLibrarySource: Boolean, includeLibraryClasses: Boolean, - includeScriptDependencies: Boolean, - fileIndex: ProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(project)): Boolean { + + @Suppress("DEPRECATION") + @JvmStatic + fun isInContent( + project: Project, file: VirtualFile, includeProjectSource: Boolean, + includeLibrarySource: Boolean, includeLibraryClasses: Boolean, + includeScriptDependencies: Boolean, includeScriptsOutsideSourceRoots: Boolean, + fileIndex: ProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + ): Boolean { + val scriptDefinition = findScriptDefinition(file, project) + if (scriptDefinition != null) { + val scriptScope = scriptDefinition.scriptExpectedLocations + val includeAll = scriptScope.contains(ScriptExpectedLocation.Everywhere) + || scriptScope.contains(ScriptExpectedLocation.Project) + || ScratchUtil.isScratch(file) + return isInContentWithoutScriptDefinitionCheck( + project, + file, + includeProjectSource && ( + includeAll + || scriptScope.contains(ScriptExpectedLocation.SourcesOnly) + || scriptScope.contains(ScriptExpectedLocation.TestsOnly) + ), + includeLibrarySource && (includeAll || scriptScope.contains(ScriptExpectedLocation.Libraries)), + includeLibraryClasses && (includeAll || scriptScope.contains(ScriptExpectedLocation.Libraries)), + includeScriptDependencies && (includeAll || scriptScope.contains(ScriptExpectedLocation.Libraries)), + includeScriptsOutsideSourceRoots && includeAll, + fileIndex + ) + } + return isInContentWithoutScriptDefinitionCheck( + project, + file, + includeProjectSource, + includeLibrarySource, + includeLibraryClasses, + includeScriptDependencies, + false, + fileIndex + ) + } + + private fun isInContentWithoutScriptDefinitionCheck( + project: Project, file: VirtualFile, includeProjectSource: Boolean, + includeLibrarySource: Boolean, includeLibraryClasses: Boolean, + includeScriptDependencies: Boolean, includeScriptsOutsideSourceRoots: Boolean, + fileIndex: ProjectFileIndex = ProjectFileIndex.SERVICE.getInstance(project) + ): Boolean { if (includeProjectSource && fileIndex.isInSourceContentWithoutInjected(file)) return true + if (includeScriptsOutsideSourceRoots) { + if (ProjectRootManager.getInstance(project).fileIndex.isInContent(file) || ScratchUtil.isScratch(file)) { + return true + } + return findScriptDefinition(file, project)?.scriptExpectedLocations?.contains(ScriptExpectedLocation.Everywhere) == 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 @@ -90,7 +144,8 @@ object ProjectRootsUtil { includeProjectSource: Boolean, includeLibrarySource: Boolean, includeLibraryClasses: Boolean, - includeScriptDependencies: Boolean + includeScriptDependencies: Boolean, + includeScriptsOutsideSourceRoots: Boolean ): Boolean { return runReadAction { val virtualFile = when (element) { @@ -99,40 +154,116 @@ object ProjectRootsUtil { } ?: return@runReadAction false val project = element.project - return@runReadAction isInContent(project, virtualFile, includeProjectSource, includeLibrarySource, includeLibraryClasses, includeScriptDependencies) + return@runReadAction isInContent( + project, + virtualFile, + includeProjectSource, + includeLibrarySource, + includeLibraryClasses, + includeScriptDependencies, + includeScriptsOutsideSourceRoots + ) } } - @JvmStatic fun isInProjectSource(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false, includeScriptDependencies = false) + @JvmStatic + fun isInProjectSource(element: PsiElement, includeScriptsOutsideSourceRoots: Boolean = false): Boolean { + return isInContent( + element, + includeProjectSource = true, + includeLibrarySource = false, + includeLibraryClasses = false, + includeScriptDependencies = false, + includeScriptsOutsideSourceRoots = includeScriptsOutsideSourceRoots + ) } - @JvmStatic fun isProjectSourceFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = false, includeScriptDependencies = false) + @JvmStatic + fun isProjectSourceFile(project: Project, file: VirtualFile, includeScriptsOutsideSourceRoots: Boolean = false): Boolean { + return isInContent( + project, + file, + includeProjectSource = true, + includeLibrarySource = false, + includeLibraryClasses = false, + includeScriptDependencies = false, + includeScriptsOutsideSourceRoots = includeScriptsOutsideSourceRoots + ) } - @JvmStatic fun isInProjectOrLibSource(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = false, includeScriptDependencies = false) + @JvmStatic + fun isInProjectOrLibSource(element: PsiElement, includeScriptsOutsideSourceRoots: Boolean = false): Boolean { + return isInContent( + element, + includeProjectSource = true, + includeLibrarySource = true, + includeLibraryClasses = false, + includeScriptDependencies = false, + includeScriptsOutsideSourceRoots = includeScriptsOutsideSourceRoots + ) } - @JvmStatic fun isInProjectOrLibraryContent(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = true, includeLibraryClasses = true, includeScriptDependencies = true) + @JvmStatic + fun isInProjectOrLibraryContent(element: PsiElement): Boolean { + return isInContent( + element, + includeProjectSource = true, + includeLibrarySource = true, + includeLibraryClasses = true, + includeScriptDependencies = true, + includeScriptsOutsideSourceRoots = false + ) } - @JvmStatic fun isInProjectOrLibraryClassFile(element: PsiElement): Boolean { - return isInContent(element, includeProjectSource = true, includeLibrarySource = false, includeLibraryClasses = true, includeScriptDependencies = false) + @JvmStatic + fun isInProjectOrLibraryClassFile(element: PsiElement): Boolean { + return isInContent( + element, + includeProjectSource = true, + includeLibrarySource = false, + includeLibraryClasses = true, + includeScriptDependencies = false, + includeScriptsOutsideSourceRoots = false + ) } - @JvmStatic fun isLibraryClassFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = false, includeLibraryClasses = true, includeScriptDependencies = true) + @JvmStatic + fun isLibraryClassFile(project: Project, file: VirtualFile): Boolean { + return isInContent( + project, + file, + includeProjectSource = false, + includeLibrarySource = false, + includeLibraryClasses = true, + includeScriptDependencies = true, + includeScriptsOutsideSourceRoots = false + ) } - @JvmStatic fun isLibrarySourceFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = false, includeScriptDependencies = true) + @JvmStatic + fun isLibrarySourceFile(project: Project, file: VirtualFile): Boolean { + return isInContent( + project, + file, + includeProjectSource = false, + includeLibrarySource = true, + includeLibraryClasses = false, + includeScriptDependencies = true, + includeScriptsOutsideSourceRoots = false + ) } - @JvmStatic fun isLibraryFile(project: Project, file: VirtualFile): Boolean { - return isInContent(project, file, includeProjectSource = false, includeLibrarySource = true, includeLibraryClasses = true, includeScriptDependencies = true) + @JvmStatic + fun isLibraryFile(project: Project, file: VirtualFile): Boolean { + return isInContent( + project, + file, + includeProjectSource = false, + includeLibrarySource = true, + includeLibraryClasses = true, + includeScriptDependencies = true, + includeScriptsOutsideSourceRoots = false + ) } } diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinTestNgConfigurationProducer.java b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinTestNgConfigurationProducer.java index 073e9533344..4a5e4f0c676 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinTestNgConfigurationProducer.java +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/KotlinTestNgConfigurationProducer.java @@ -112,7 +112,7 @@ public class KotlinTestNgConfigurationProducer extends TestNGConfigurationProduc Project project = context.getProject(); PsiElement leaf = location.getPsiElement(); - if (!ProjectRootsUtil.isInProjectOrLibSource(leaf)) { + if (!ProjectRootsUtil.isInProjectOrLibSource(leaf, false)) { return false; } diff --git a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectJavaInspectionTest.kt b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectJavaInspectionTest.kt index 395c5fe3cac..bd48f559ac1 100644 --- a/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectJavaInspectionTest.kt +++ b/idea/performanceTests/org/jetbrains/kotlin/idea/perf/WholeProjectJavaInspectionTest.kt @@ -30,6 +30,7 @@ class WholeProjectJavaInspectionTest : WholeProjectInspectionTest() { includeLibrarySource = false, includeLibraryClasses = false, includeScriptDependencies = false, + includeScriptsOutsideSourceRoots = false, fileIndex = index ) }