From c9e4b71010da9b8f6463f67eba092f6d1e5d1f9b Mon Sep 17 00:00:00 2001 From: Roman Golyshev Date: Mon, 4 Sep 2023 16:00:17 +0200 Subject: [PATCH] KT-61689 [LL API] Handle scripts in `ContextCollector` Add `FirDesignationWithScript`, because regular designation does not account for scripts at all - that makes it cumbersome to add the script's top level and implicit receiver scopes when collecting contexts for the non-top-level declarations (class members, for example) ^KT-61689 Fixed --- .../low/level/api/fir/api/FirDesignation.kt | 6 + .../level/api/fir/util/ContextCollector.kt | 19 +++- .../scripts/insideClassMember.kts | 24 ++++ .../scripts/insideClassMember.txt | 105 ++++++++++++++++++ .../scripts/insideTopLevelFunction.kts | 20 ++++ .../scripts/insideTopLevelFunction.txt | 93 ++++++++++++++++ .../contextCollector/scripts/topLevel.kts | 18 +++ .../contextCollector/scripts/topLevel.txt | 87 +++++++++++++++ .../ContextCollectorScriptTestGenerated.java | 38 +++++++ .../ContextCollectorSourceTestGenerated.java | 12 +- 10 files changed, 420 insertions(+), 2 deletions(-) create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.kts create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.txt create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/insideTopLevelFunction.kts create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/insideTopLevelFunction.txt create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/topLevel.kts create mode 100644 analysis/low-level-api-fir/testdata/contextCollector/scripts/topLevel.txt diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt index 4741a29c227..1fad1cd65fb 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/api/FirDesignation.kt @@ -45,6 +45,12 @@ class FirDesignationWithFile( } } +class FirDesignationWithScript( + path: List, + target: FirElementWithResolveState, + val firScript: FirScript, +): FirDesignation(path, target) + open class FirDesignation( val path: List, val target: FirElementWithResolveState, diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt index d711d8f8626..ab8e63d8dbd 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/ContextCollector.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util import com.intellij.openapi.progress.ProgressManager import com.intellij.psi.PsiElement import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignation +import org.jetbrains.kotlin.analysis.low.level.api.fir.api.FirDesignationWithScript import org.jetbrains.kotlin.analysis.low.level.api.fir.element.builder.getNonLocalContainingOrThisDeclaration import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.ContextKind import org.jetbrains.kotlin.analysis.low.level.api.fir.util.ContextCollector.Context @@ -35,6 +36,7 @@ import org.jetbrains.kotlin.fir.types.typeContext import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.psi.psiUtil.parentsWithSelf +import org.jetbrains.kotlin.utils.yieldIfNotNull internal object ContextCollector { enum class ContextKind { @@ -106,7 +108,13 @@ internal object ContextCollector { if (contextKtDeclaration != null) { val designationPath = FirElementFinder.collectDesignationPath(file, contextKtDeclaration) if (designationPath != null) { - return FirDesignation(designationPath.path, designationPath.target) + val script = file.declarations.singleOrNull() as? FirScript + + return if (script == null || script === designationPath.target) { + FirDesignation(designationPath.path, designationPath.target) + } else { + FirDesignationWithScript(designationPath.path, designationPath.target, script) + } } } @@ -138,6 +146,7 @@ internal object ContextCollector { private class DesignationInterceptor(private val designation: FirDesignation) : () -> FirElement? { private val targetIterator = iterator { + yieldIfNotNull((designation as? FirDesignationWithScript)?.firScript) yieldAll(designation.path) yield(designation.target) } @@ -278,6 +287,14 @@ private class ContextCollectorVisitor( return node !is ClassExitNode } + override fun visitScript(script: FirScript) { + context.withScopesForScript(script, holder) { + withInterceptor { + super.visitScript(script) + } + } + } + override fun visitFile(file: FirFile) { context.withFile(file, holder) { withInterceptor { diff --git a/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.kts b/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.kts new file mode 100644 index 00000000000..78a2b46cf76 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.kts @@ -0,0 +1,24 @@ +/* + * Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +fun before_Fun() {} + +val before_Val = 10 + +class Before_OtherClass + +class MyClass { + val foo = 10 + + fun usage() { + foo + } +} + +fun after_Fun() {} + +val after_Val = 10 + +class After_OtherClass \ No newline at end of file diff --git a/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.txt b/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.txt new file mode 100644 index 00000000000..b81b7864ea6 --- /dev/null +++ b/analysis/low-level-api-fir/testdata/contextCollector/scripts/insideClassMember.txt @@ -0,0 +1,105 @@ +Tower Data Context: + Element 0 + Scope: FirDefaultStarImportingScope + Element 1 + Scope: FirDefaultSimpleImportingScope + Element 2 + Scope: FirExplicitStarImportingScope + Element 3 + Scope: FirDefaultSimpleImportingScope + Element 4 + Scope: FirDefaultSimpleImportingScope + Element 5 + Scope: FirPackageMemberScope + Element 6 + Scope: FirExplicitSimpleImportingScope + Element 7 + Scope: FirScriptDeclarationsScope + Classifiers: + FirRegularClassSymbol public? final? class After_OtherClass : R|kotlin/Any| + FirRegularClassSymbol public? final? class Before_OtherClass : R|kotlin/Any| + FirRegularClassSymbol public final class MyClass : R|kotlin/Any| + Functions + FirNamedFunctionSymbol public? final? fun after_Fun(): R|kotlin/Unit| + FirNamedFunctionSymbol public? final? fun before_Fun(): R|kotlin/Unit| + Properties: + FirPropertySymbol public? final? val after_Val: + public? get(): + FirPropertySymbol public? final? val before_Val: + public? get(): + Element 8 + Scope: FirLocalScope + Classifiers: + FirRegularClassSymbol public final class MyClass : R|kotlin/Any| + Properties: + FirPropertySymbol lval args: R|kotlin/Array| + Element 9 + Context receivers: + FirScriptSymbol context(