[Analysis API] Add IGNORE_SELF dangling file resolution mode

In the 'IGNORE_SELF' mode, dangling files don't have their own
declarations in providers. As a result, all references there resolve to
declarations of the original file. It is conceptually similar to that we
had in on-air resolve, however, now it's possible to work with the whole
content of the in-memory 'FirFile'.

As it can be seen in 'ProjectStructureProvider.kt'
(KtFile.danglingFileResolutionMode), the 'IGNORE_SELF' mode is
automatically applied for non-physical files with an original file being
set. For other scenarios, now there is a new 'analyzeCopy()' function
that allows to pass the analysis mode explicitly.
This commit is contained in:
Yan Zhulanow
2023-11-22 18:21:18 +09:00
committed by Space Team
parent ae6b690d4f
commit 452d22e14f
84 changed files with 1394 additions and 50 deletions
@@ -106,6 +106,7 @@ public abstract class KtAnalysisSession(final override val token: KtLifetimeToke
*
* @see analyzeInDependedAnalysisSession
*/
@Deprecated("On-air analysis is obsolete. Use 'analyzeCopy()' instead")
public abstract fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession
internal val smartCastProvider: KtSmartCastProvider get() = smartCastProviderImpl
@@ -7,9 +7,12 @@
package org.jetbrains.kotlin.analysis.api
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenFactory
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtModuleStructureInternals
import org.jetbrains.kotlin.analysis.project.structure.withDanglingFileResolutionMode
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -51,10 +54,41 @@ public inline fun <R> analyze(
*
* @see KtAnalysisSession.createContextDependentCopy
*/
@Deprecated(
"On-air analysis is obsolete. Use 'analyzeCopy()' instead",
ReplaceWith(
"analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE.SELF)",
imports = [
"org.jetbrains.kotlin.analysis.api.analyzeCopy",
"org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode"
]
)
)
public inline fun <R> analyzeInDependedAnalysisSession(
originalFile: KtFile,
@Suppress("unused", "UNUSED_PARAMETER") originalFile: KtFile,
elementToReanalyze: KtElement,
action: KtAnalysisSession.() -> R
): R =
KtAnalysisSessionProvider.getInstance(originalFile.project)
.analyseInDependedAnalysisSession(originalFile, elementToReanalyze, action)
crossinline action: KtAnalysisSession.() -> R
): R {
return analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE_SELF, action)
}
/**
* Executes the given [action] in a [KtAnalysisSession] context.
* Depending on the passed [resolutionMode], declarations inside a file copy will be treated in a specific way.
*
* Note that the [useSiteKtElement] must be inside a dangling file copy.
* Specifically, [PsiFile.getOriginalFile] must point to the copy source.
*
* The project will be analyzed from the perspective of [useSiteKtElement]'s module, also called the use-site module.
*/
@OptIn(KtModuleStructureInternals::class)
public inline fun <R> analyzeCopy(
useSiteKtElement: KtElement,
resolutionMode: DanglingFileResolutionMode,
crossinline action: KtAnalysisSession.() -> R,
): R {
val containingFile = useSiteKtElement.containingKtFile
return withDanglingFileResolutionMode(containingFile, resolutionMode) {
analyze(containingFile, action)
}
}
@@ -10,9 +10,11 @@ import com.intellij.openapi.project.Project
import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.analyzeCopy
import org.jetbrains.kotlin.analysis.api.lifetime.impl.NoWriteActionInAnalyseCallChecker
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenFactory
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
@@ -20,8 +22,8 @@ import org.jetbrains.kotlin.psi.KtFile
/**
* Provides [KtAnalysisSession]s by use-site [KtElement]s or [KtModule]s.
*
* This provider should not be used directly. Please use [analyze][org.jetbrains.kotlin.analysis.api.analyze] or
* [analyzeInDependedAnalysisSession][org.jetbrains.kotlin.analysis.api.analyzeInDependedAnalysisSession] instead.
* This provider should not be used directly.
* Please use [analyze][org.jetbrains.kotlin.analysis.api.analyze] or [analyzeCopy][org.jetbrains.kotlin.analysis.api.analyzeCopy] instead.
*/
@OptIn(KtAnalysisApiInternals::class)
public abstract class KtAnalysisSessionProvider(public val project: Project) : Disposable {
@@ -37,15 +39,22 @@ public abstract class KtAnalysisSessionProvider(public val project: Project) : D
public abstract fun getAnalysisSessionByUseSiteKtModule(useSiteKtModule: KtModule): KtAnalysisSession
@Deprecated(
"On-air analysis is obsolete. Use 'analyzeCopy()' instead",
replaceWith = ReplaceWith(
"analyzeCopy(elementToReanalyze, DanglingFileAnalysisMode.IGNORE_SELF, action)",
imports = [
"org.jetbrains.kotlin.analysis.api.analyzeCopy",
"org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode"
]
)
)
public inline fun <R> analyseInDependedAnalysisSession(
originalFile: KtFile,
@Suppress("unused", "UNUSED_PARAMETER") originalFile: KtFile,
elementToReanalyze: KtElement,
action: KtAnalysisSession.() -> R,
crossinline action: KtAnalysisSession.() -> R,
): R {
val originalAnalysisSession = getAnalysisSession(originalFile)
val dependedAnalysisSession = originalAnalysisSession
.createContextDependentCopy(originalFile, elementToReanalyze)
return analyse(dependedAnalysisSession, action)
return analyzeCopy(elementToReanalyze, DanglingFileResolutionMode.IGNORE_SELF, action)
}
public inline fun <R> analyse(
@@ -0,0 +1,9 @@
class Foo<Value> {
fun foo() {
call<V<caret>alue>()
}
}
fun <T> call(): T? {
return null
}
@@ -0,0 +1,2 @@
Resolved to:
0: Value [classTypeParameter.kt]
@@ -0,0 +1,9 @@
class Foo {
companion object
}
fun test() {
consume(F<caret>oo)
}
private fun consume(obj: Any) {}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) companion object [companionObject.kt]
@@ -0,0 +1,7 @@
fun <Value> foo() {
call<V<caret>alue>()
}
fun <T> call(): T? {
return null
}
@@ -0,0 +1,2 @@
Resolved to:
0: Value [fake.kt]
@@ -0,0 +1,9 @@
class Foo {
private fun foo() {
class Local {
fun call() {}
}
Lo<caret>cal().call()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: Foo.foo.Local) constructor() [fake.kt]
@@ -0,0 +1,6 @@
class Foo {
private fun foo() {
val name = "Foo"
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: Foo.foo) val name: kotlin.String [fake.kt]
@@ -0,0 +1,9 @@
class Outer {
val foo: String = "foo"
inner class Inner {
fun test() {
f<caret>oo
}
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Outer) val foo: kotlin.String [outerClassProperty.kt]
@@ -0,0 +1,7 @@
class Foo(name: String) {
private val userName: String
init {
userName = n<caret>ame
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: name: kotlin.String [primaryConstructorParameter.kt]
@@ -0,0 +1,9 @@
class Foo {
private class Bar {
fun call() {}
}
private fun foo() {
B<caret>ar().call()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo.Bar) constructor() [privateClass.kt]
@@ -0,0 +1,7 @@
class Foo() {
private fun call() {}
private fun foo() {
c<caret>all()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) private fun call() [privateFunction.kt]
@@ -0,0 +1,5 @@
class Foo(private val name: String) {
private fun foo() {
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) private val name: kotlin.String [privateProperty.kt]
@@ -0,0 +1,7 @@
class Foo() {
fun call() {}
private fun foo() {
c<caret>all()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) fun call() [publicFunction.kt]
@@ -0,0 +1,5 @@
class Foo(val name: String) {
private fun foo() {
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) val name: kotlin.String [publicProperty.kt]
@@ -0,0 +1,3 @@
var x: Int = 0
get() = f<caret>ield + 1
set(value) { field = value - 1 }
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: x) field
@@ -0,0 +1,5 @@
fun foo() {
c<caret>all()
}
fun call() {}
@@ -0,0 +1,2 @@
Resolved to:
0: (in ROOT) fun call() [topLevelFunction.kt]
@@ -0,0 +1,3 @@
fun foo(abc: Int) {
a<caret>bc
}
@@ -0,0 +1,2 @@
Resolved to:
0: abc: kotlin.Int [fake.kt]
@@ -0,0 +1,9 @@
class Foo<Value> {
fun foo() {
call<V<caret>alue>()
}
}
fun <T> call(): T? {
return null
}
@@ -0,0 +1,2 @@
Resolved to:
0: Value [fake.kt]
@@ -0,0 +1,9 @@
class Foo {
companion object
}
fun test() {
consume(F<caret>oo)
}
private fun consume(obj: Any) {}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) companion object [fake.kt]
@@ -0,0 +1,7 @@
fun <Value> foo() {
call<V<caret>alue>()
}
fun <T> call(): T? {
return null
}
@@ -0,0 +1,2 @@
Resolved to:
0: Value [fake.kt]
@@ -0,0 +1,9 @@
class Foo {
private fun foo() {
class Local {
fun call() {}
}
Lo<caret>cal().call()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: Foo.foo.Local) constructor() [fake.kt]
@@ -0,0 +1,6 @@
class Foo {
private fun foo() {
val name = "Foo"
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: Foo.foo) val name: kotlin.String [fake.kt]
@@ -0,0 +1,9 @@
class Outer {
val foo: String = "foo"
inner class Inner {
fun test() {
f<caret>oo
}
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Outer) val foo: kotlin.String [fake.kt]
@@ -0,0 +1,7 @@
class Foo(name: String) {
private val userName: String
init {
userName = n<caret>ame
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: name: kotlin.String [fake.kt]
@@ -0,0 +1,9 @@
class Foo {
private class Bar {
fun call() {}
}
private fun foo() {
B<caret>ar().call()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo.Bar) constructor() [fake.kt]
@@ -0,0 +1,7 @@
class Foo() {
private fun call() {}
private fun foo() {
c<caret>all()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) private fun call() [fake.kt]
@@ -0,0 +1,5 @@
class Foo(private val name: String) {
private fun foo() {
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) private val name: kotlin.String [fake.kt]
@@ -0,0 +1,7 @@
class Foo() {
fun call() {}
private fun foo() {
c<caret>all()
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) fun call() [fake.kt]
@@ -0,0 +1,5 @@
class Foo(val name: String) {
private fun foo() {
nam<caret>e.length
}
}
@@ -0,0 +1,2 @@
Resolved to:
0: (in Foo) val name: kotlin.String [fake.kt]
@@ -0,0 +1,3 @@
var x: Int = 0
get() = f<caret>ield + 1
set(value) { field = value - 1 }
@@ -0,0 +1,2 @@
Resolved to:
0: (in <local>: x) field
@@ -0,0 +1,5 @@
fun foo() {
c<caret>all()
}
fun call() {}
@@ -0,0 +1,2 @@
Resolved to:
0: (in ROOT) fun call() [fake.kt]
@@ -0,0 +1,3 @@
fun foo(abc: Int) {
a<caret>bc
}
@@ -0,0 +1,2 @@
Resolved to:
0: abc: kotlin.Int [fake.kt]