[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
@@ -80,6 +80,7 @@ class KtFe10AnalysisSession(
override val substitutorProviderImpl: KtSubstitutorProvider
get() = throw NotSupportedForK1Exception()
@Suppress("OVERRIDE_DEPRECATION")
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession =
KtFe10AnalysisSession(originalKtFile.project, elementToReanalyze, token)
}
@@ -135,7 +135,7 @@ private constructor(
override val substitutorProviderImpl: KtSubstitutorProvider = KtFirSubstitutorProvider(this)
@Suppress("AnalysisApiMissingLifetimeCheck")
@Suppress("AnalysisApiMissingLifetimeCheck", "OVERRIDE_DEPRECATION")
override fun createContextDependentCopy(originalKtFile: KtFile, elementToReanalyze: KtElement): KtAnalysisSession {
check(mode == AnalysisSessionMode.REGULAR) {
"Cannot create context-dependent copy of KtAnalysis session from a context dependent one"
@@ -69,4 +69,204 @@ public class FirIdeDependentAnalysisSourceModuleDanglingFileReferenceResolveTest
public void testFunctionSameFile() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/functionSameFile.kt");
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf")
@TestDataPath("$PROJECT_ROOT")
public class IgnoreSelf {
@Test
public void testAllFilesPresentInIgnoreSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/valueParameter.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf")
@TestDataPath("$PROJECT_ROOT")
public class PreferSelf {
@Test
public void testAllFilesPresentInPreferSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/valueParameter.kt");
}
}
}
@@ -69,4 +69,204 @@ public class FirIdeNormalAnalysisLibrarySourceModuleDanglingFileReferenceResolve
public void testFunctionSameFile() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/functionSameFile.kt");
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf")
@TestDataPath("$PROJECT_ROOT")
public class IgnoreSelf {
@Test
public void testAllFilesPresentInIgnoreSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/valueParameter.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf")
@TestDataPath("$PROJECT_ROOT")
public class PreferSelf {
@Test
public void testAllFilesPresentInPreferSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/valueParameter.kt");
}
}
}
@@ -69,4 +69,204 @@ public class FirIdeNormalAnalysisSourceModuleDanglingFileReferenceResolveTestGen
public void testFunctionSameFile() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/functionSameFile.kt");
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf")
@TestDataPath("$PROJECT_ROOT")
public class IgnoreSelf {
@Test
public void testAllFilesPresentInIgnoreSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/valueParameter.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf")
@TestDataPath("$PROJECT_ROOT")
public class PreferSelf {
@Test
public void testAllFilesPresentInPreferSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/valueParameter.kt");
}
}
}
@@ -6,15 +6,44 @@
package org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.analyzeCopy
import org.jetbrains.kotlin.analysis.api.impl.base.test.cases.references.AbstractDanglingFileReferenceResolveTest.Directives.COPY_RESOLUTION_MODE
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtPsiFactory
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.model.SimpleDirectivesContainer
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestModuleStructure
import org.jetbrains.kotlin.test.services.TestServices
abstract class AbstractDanglingFileReferenceResolveTest : AbstractReferenceResolveTest() {
override fun configureTest(builder: TestConfigurationBuilder) {
super.configureTest(builder)
builder.apply {
useDirectives(Directives)
forTestsMatching("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/*") {
defaultDirectives {
COPY_RESOLUTION_MODE.with(DanglingFileResolutionMode.IGNORE_SELF)
}
}
forTestsMatching("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/*") {
defaultDirectives {
COPY_RESOLUTION_MODE.with(DanglingFileResolutionMode.PREFER_SELF)
}
}
}
}
override fun KtAnalysisSession.getAdditionalSymbolInfo(symbol: KtSymbol): String? {
val containingFile = symbol.psi?.containingFile ?: return null
return containingFile.name
@@ -29,6 +58,25 @@ abstract class AbstractDanglingFileReferenceResolveTest : AbstractReferenceResol
val ktPsiFactory = KtPsiFactory.contextual(mainKtFile, markGenerated = true, eventSystemEnabled = true)
val fakeKtFile = ktPsiFactory.createFile("fake.kt", mainKtFile.text)
if (mainModule.directives.contains(COPY_RESOLUTION_MODE)) {
fakeKtFile.originalFile = mainKtFile
}
doTestByFileStructure(fakeKtFile, caretPosition, mainModule, testServices)
}
override fun <R> analyzeReferenceElement(element: KtElement, mainModule: TestModule, action: KtAnalysisSession.() -> R): R {
val resolutionMode = mainModule.directives.singleOrZeroValue(COPY_RESOLUTION_MODE)
return if (resolutionMode != null) {
analyzeCopy(element, resolutionMode) { action() }
} else {
analyze(element) { action() }
}
}
private object Directives : SimpleDirectivesContainer() {
val COPY_RESOLUTION_MODE by enumDirective(description = "Dangling file resolution mode for a copy") {
DanglingFileResolutionMode.valueOf(it)
}
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModulePr
import org.jetbrains.kotlin.analysis.test.framework.services.expressionMarkerProvider
import org.jetbrains.kotlin.analysis.test.framework.utils.unwrapMultiReferences
import org.jetbrains.kotlin.idea.references.KtReference
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives
@@ -74,12 +75,11 @@ abstract class AbstractReferenceResolveTest : AbstractAnalysisApiBasedTest() {
testServices.assertions.fail { "No references at caret found" }
}
val resolvedTo =
analyseForTest(ktReferences.first().element) {
val symbols = ktReferences.flatMap { it.resolveToSymbols() }
checkReferenceResultForValidity(ktReferences, mainModule, testServices, symbols)
renderResolvedTo(symbols, renderingOptions) { getAdditionalSymbolInfo(it) }
}
val resolvedTo = analyzeReferenceElement(ktReferences.first().element, mainModule) {
val symbols = ktReferences.flatMap { it.resolveToSymbols() }
checkReferenceResultForValidity(ktReferences, mainModule, testServices, symbols)
renderResolvedTo(symbols, renderingOptions) { getAdditionalSymbolInfo(it) }
}
if (Directives.UNRESOLVED_REFERENCE in mainModule.directives) {
return
@@ -89,6 +89,10 @@ abstract class AbstractReferenceResolveTest : AbstractAnalysisApiBasedTest() {
testServices.assertions.assertEqualsToTestDataFileSibling(actual)
}
protected open fun <R> analyzeReferenceElement(element: KtElement, mainModule: TestModule, action: KtAnalysisSession.() -> R): R {
return analyseForTest(element) { action() }
}
open fun KtAnalysisSession.getAdditionalSymbolInfo(symbol: KtSymbol): String? = null
private fun findReferencesAtCaret(mainKtFile: KtFile, caretPosition: Int): List<KtReference> =
@@ -69,4 +69,204 @@ public class FirStandaloneNormalAnalysisSourceModuleDanglingFileReferenceResolve
public void testFunctionSameFile() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/functionSameFile.kt");
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf")
@TestDataPath("$PROJECT_ROOT")
public class IgnoreSelf {
@Test
public void testAllFilesPresentInIgnoreSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/ignoreSelf/valueParameter.kt");
}
}
@Nested
@TestMetadata("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf")
@TestDataPath("$PROJECT_ROOT")
public class PreferSelf {
@Test
public void testAllFilesPresentInPreferSelf() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@Test
@TestMetadata("classTypeParameter.kt")
public void testClassTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/classTypeParameter.kt");
}
@Test
@TestMetadata("companionObject.kt")
public void testCompanionObject() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/companionObject.kt");
}
@Test
@TestMetadata("functionTypeParameter.kt")
public void testFunctionTypeParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/functionTypeParameter.kt");
}
@Test
@TestMetadata("localClass.kt")
public void testLocalClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localClass.kt");
}
@Test
@TestMetadata("localVariable.kt")
public void testLocalVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/localVariable.kt");
}
@Test
@TestMetadata("outerClassProperty.kt")
public void testOuterClassProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/outerClassProperty.kt");
}
@Test
@TestMetadata("primaryConstructorParameter.kt")
public void testPrimaryConstructorParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/primaryConstructorParameter.kt");
}
@Test
@TestMetadata("privateClass.kt")
public void testPrivateClass() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateClass.kt");
}
@Test
@TestMetadata("privateFunction.kt")
public void testPrivateFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateFunction.kt");
}
@Test
@TestMetadata("privateProperty.kt")
public void testPrivateProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/privateProperty.kt");
}
@Test
@TestMetadata("publicFunction.kt")
public void testPublicFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicFunction.kt");
}
@Test
@TestMetadata("publicProperty.kt")
public void testPublicProperty() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/publicProperty.kt");
}
@Test
@TestMetadata("syntheticFieldVariable.kt")
public void testSyntheticFieldVariable() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/syntheticFieldVariable.kt");
}
@Test
@TestMetadata("topLevelFunction.kt")
public void testTopLevelFunction() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/topLevelFunction.kt");
}
@Test
@TestMetadata("valueParameter.kt")
public void testValueParameter() throws Exception {
runTest("analysis/analysis-api/testData/danglingFileReferenceResolve/preferSelf/valueParameter.kt");
}
}
}
@@ -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]
@@ -11,7 +11,8 @@ import com.intellij.testFramework.TestDataFile
import junit.framework.ComparisonFailure
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyze
import org.jetbrains.kotlin.analysis.api.analyzeInDependedAnalysisSession
import org.jetbrains.kotlin.analysis.api.analyzeCopy
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.test.framework.AnalysisApiTestDirectives
import org.jetbrains.kotlin.analysis.test.framework.TestWithDisposable
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
@@ -205,12 +206,10 @@ abstract class AbstractAnalysisApiBasedTest : TestWithDisposable() {
return if (configurator.analyseInDependentSession) {
val originalContainingFile = contextElement.containingKtFile
val fileCopy = originalContainingFile.copy() as KtFile
val sameElementInCopy = PsiTreeUtil.findSameElementInCopy(contextElement, fileCopy)
analyzeInDependedAnalysisSession(
originalContainingFile,
sameElementInCopy,
action = { action(sameElementInCopy) }
)
analyzeCopy(fileCopy, DanglingFileResolutionMode.IGNORE_SELF) {
action(PsiTreeUtil.findSameElementInCopy<KtElement>(contextElement, fileCopy))
}
} else {
analyze(contextElement, action = { action(contextElement) })
}
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtMod
import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtStaticProjectStructureProvider
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.psiUtil.contains
import org.jetbrains.kotlin.serialization.deserialization.builtins.BuiltInSerializerProtocol
import org.jetbrains.kotlin.utils.KotlinExceptionWithAttachments
@@ -29,9 +28,7 @@ class KtTestProjectStructureProvider(
@OptIn(KtModuleStructureInternals::class)
override fun getModule(element: PsiElement, contextualModule: KtModule?): KtModule {
// Unwrap context-dependent file copies coming from dependent sessions
val containingFile = element.containingFile.originalFile
val containingFile = element.containingFile
val virtualFile = containingFile.virtualFile
if (virtualFile != null) {
@@ -5,11 +5,15 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.api
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.llFirModuleData
import org.jetbrains.kotlin.analysis.low.level.api.fir.providers.nullableJavaSymbolProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirLibraryOrLibrarySourceResolvableModuleSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.FirElementFinder
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.isScriptDependentDeclaration
import org.jetbrains.kotlin.analysis.low.level.api.fir.util.unwrapCopy
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
import org.jetbrains.kotlin.analysis.utils.errors.requireIsInstance
import org.jetbrains.kotlin.analysis.utils.errors.unexpectedElementError
import org.jetbrains.kotlin.builtins.StandardNames
@@ -28,6 +32,7 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirScriptSymbol
import org.jetbrains.kotlin.fir.utils.exceptions.withFirEntry
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.utils.exceptions.checkWithAttachment
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
@@ -173,14 +178,16 @@ private fun collectDesignationPathWithContainingClass(target: FirDeclaration, co
if (chunks.any { it.shortClassName.isSpecial }) {
val fallbackResult = collectDesignationPathWithTreeTraversal(target)
if (fallbackResult != null) {
return fallbackResult
return patchDesignationPathIfNeeded(target, fallbackResult)
}
}
return chunks
val result = chunks
.dropWhile { it.shortClassName.isSpecial }
.map { resolveChunk(it) }
.asReversed()
return patchDesignationPathIfNeeded(target, result)
}
/*
@@ -300,3 +307,29 @@ private fun FirDeclaration.scriptDesignation(): FirDesignationWithFile? {
else -> null
}
}
internal fun patchDesignationPathIfNeeded(target: FirElementWithResolveState, targetPath: List<FirRegularClass>): List<FirRegularClass> {
return patchDesignationPathForCopy(target, targetPath) ?: targetPath
}
private fun patchDesignationPathForCopy(target: FirElementWithResolveState, targetPath: List<FirRegularClass>): List<FirRegularClass>? {
val targetModule = target.llFirModuleData.ktModule
if (targetModule is KtDanglingFileModule && targetModule.resolutionMode == DanglingFileResolutionMode.IGNORE_SELF) {
val targetPsiFile = targetModule.file
val contextModule = targetModule.contextModule
val contextResolveSession = contextModule.getFirResolveSession(contextModule.project)
return buildList {
for (targetPathClass in targetPath) {
val targetPathPsi = targetPathClass.psi as? KtDeclaration ?: return null
val originalPathPsi = targetPathPsi.unwrapCopy(targetPsiFile) ?: return null
val originalPathClass = originalPathPsi.getOrBuildFirSafe<FirRegularClass>(contextResolveSession) ?: return null
add(originalPathClass)
}
}
}
return targetPath
}
@@ -40,6 +40,7 @@ import org.jetbrains.kotlin.fir.utils.exceptions.withFirSymbolEntry
import org.jetbrains.kotlin.fir.visitors.FirTransformer
import org.jetbrains.kotlin.fir.visitors.transformSingle
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.types.Variance
import org.jetbrains.kotlin.utils.exceptions.errorWithAttachment
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
@@ -584,7 +585,10 @@ private fun calculateLazyBodiesForField(designation: FirDesignation) {
val field = designation.target as FirField
require(field.initializer is FirLazyExpression)
val newField = revive<FirField>(designation, designation.path.last().psi)
// 'designation.path.last()' cannot be used here, as for dangling files designation target may be in a different file
val psi = field.psi?.getStrictParentOfType<KtClassOrObject>()
val newField = revive<FirField>(designation, psi)
field.replaceInitializer(newField.initializer)
}
@@ -0,0 +1,44 @@
/*
* 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.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.resolve.providers.FirEmptySymbolNamesProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolNamesProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
internal class LLEmptySymbolProvider(session: FirSession) : FirSymbolProvider(session) {
override val symbolNamesProvider: FirSymbolNamesProvider
get() = FirEmptySymbolNamesProvider
override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
return null
}
@FirSymbolProviderInternals
override fun getTopLevelCallableSymbolsTo(destination: MutableList<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, packageFqName: FqName, name: Name) {
}
override fun getPackage(fqName: FqName): FqName? {
return null
}
}
@@ -33,9 +33,11 @@ internal class LLFirProvider(
val session: LLFirSession,
private val moduleComponents: LLFirModuleResolveComponents,
canContainKotlinPackage: Boolean,
disregardSelfDeclarations: Boolean = false,
declarationProviderFactory: (GlobalSearchScope) -> KotlinDeclarationProvider?,
) : FirProvider() {
override val symbolProvider: FirSymbolProvider = SymbolProvider()
override val symbolProvider: FirSymbolProvider =
if (disregardSelfDeclarations) LLEmptySymbolProvider(session) else SymbolProvider()
private val providerHelper = LLFirProviderHelper(
session,
@@ -494,6 +494,7 @@ internal abstract class LLFirAbstractSessionFactory(protected val project: Proje
this,
components,
canContainKotlinPackage = true,
disregardSelfDeclarations = module.resolutionMode == DanglingFileResolutionMode.IGNORE_SELF,
declarationProviderFactory = { scope -> scope.createScopedDeclarationProviderForFile(danglingFile) }
)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.analysis.low.level.api.fir.util
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.patchDesignationPathIfNeeded
import org.jetbrains.kotlin.utils.exceptions.requireWithAttachment
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.declarations.*
@@ -14,6 +15,7 @@ import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.psiUtil.containingClassOrObject
import org.jetbrains.kotlin.utils.ifEmpty
internal object FirElementFinder {
fun findClassifierWithClassId(
@@ -129,12 +131,17 @@ internal object FirElementFinder {
}
find(firFile.declarations, classIdPathIndex = 0)
return result?.let {
FirDeclarationDesignation(
path = if (path.isEmpty()) emptyList() else path,
target = it,
)
if (result == null) {
return null
}
// K1 doesn't perform smart-casts on 'result'
@Suppress("UNNECESSARY_NOT_NULL_ASSERTION")
return FirDeclarationDesignation(
path = patchDesignationPathIfNeeded(result!!, path).ifEmpty { emptyList() },
target = result!!,
)
}
inline fun <reified E : FirElement> findElementIn(
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.util
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiTreeUtil
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.low.level.api.fir.LLFirInternals
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
@@ -249,4 +250,17 @@ val PsiElement.parentsWithSelfCodeFragmentAware: Sequence<PsiElement>
}
val PsiElement.parentsCodeFragmentAware: Sequence<PsiElement>
get() = parentsWithSelfCodeFragmentAware.drop(1)
get() = parentsWithSelfCodeFragmentAware.drop(1)
internal fun <T : PsiElement> T.unwrapCopy(containingFile: PsiFile = this.containingFile): T? {
val originalFile = containingFile.originalFile.takeIf { it !== containingFile }
?: (containingFile as? KtFile)?.analysisContext?.containingFile
?: return null
return try {
PsiTreeUtil.findSameElementInCopy(this, originalFile)
} catch (_: IllegalStateException) {
// File copy has a different file structure
null
}
}
@@ -230,6 +230,11 @@ public interface KtDanglingFileModule : KtModule {
*/
public val contextModule: KtModule
/**
* A way of resolving references to non-local declarations in the dangling file.
*/
public val resolutionMode: DanglingFileResolutionMode
/**
* True if the [file] is a code fragment.
* Useful to recognize code fragments when their PSI was collected.
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.analysis.project.structure
import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.analysis.project.structure.impl.KtDanglingFileModuleImpl
@@ -13,6 +14,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.UserDataProperty
import org.jetbrains.kotlin.psi.analysisContext
import org.jetbrains.kotlin.psi.doNotAnalyze
@@ -54,12 +56,21 @@ public abstract class ProjectStructureProvider {
if (file is KtFile && file.isDangling) {
val contextModule = computeContextModule(file)
return KtDanglingFileModuleImpl(file, contextModule)
val resolutionMode = file.danglingFileResolutionMode ?: computeDefaultDanglingFileResolutionMode(file)
return KtDanglingFileModuleImpl(file, contextModule, resolutionMode)
}
return null
}
private fun computeDefaultDanglingFileResolutionMode(file: KtFile): DanglingFileResolutionMode {
if (!file.isPhysical && !file.viewProvider.isEventSystemEnabled && file.originalFile != file) {
return DanglingFileResolutionMode.IGNORE_SELF
}
return DanglingFileResolutionMode.PREFER_SELF
}
@OptIn(KtModuleStructureInternals::class)
private fun computeContextModule(file: KtFile): KtModule {
val contextElement = file.context
@@ -97,8 +108,63 @@ public abstract class ProjectStructureProvider {
}
@OptIn(KtModuleStructureInternals::class)
private val KtFile.isDangling: Boolean
get() = this is KtCodeFragment
|| !isPhysical
|| analysisContext != null
|| doNotAnalyze != null
public val KtFile.isDangling: Boolean
get() = when {
this is KtCodeFragment -> true
virtualFile?.analysisExtensionFileContextModule != null -> false
!isPhysical -> true
analysisContext != null -> true
doNotAnalyze != null -> true
else -> false
}
/**
* Returns the resolution mode that is explicitly set for this dangling file.
* Returns `null` for files that are not dangling, or if the mode was not set.
*
* Use the `analyzeCopy {}` method for specifying the analysis mode. Note that the effect is thread-local; this is made on purpose, as
* the file might potentially be resolved in parallel in different threads.
*
* Note that the resolution mode affects equality of [KtDanglingFileModule]. It means that for each resolution mode, a separate
* resolution session will be created.
*/
@OptIn(KtModuleStructureInternals::class)
public val KtFile.danglingFileResolutionMode: DanglingFileResolutionMode?
get() = danglingFileResolutionModeState?.get()
/**
* Runs the [action] with a resolution mode being explicitly set for the dangling [file].
*
* Avoid using this function in client-side code. Use `analyzeCopy {}` from Analysis API instead.
*/
@KtModuleStructureInternals
public fun <R> withDanglingFileResolutionMode(file: KtFile, mode: DanglingFileResolutionMode, action: () -> R): R {
require(file.isDangling) { "'withDanglingFileResolutionMode()' is only available to dangling files" }
require(file.originalFile != file) { "'withDanglingFileResolutionMode()' is only available to file copies" }
val modeState = getOrCreateDanglingFileResolutionModeState(file)
val oldValue = modeState.get()
try {
modeState.set(mode)
return action()
} finally {
modeState.set(oldValue)
}
}
private fun getOrCreateDanglingFileResolutionModeState(file: KtFile): ThreadLocal<DanglingFileResolutionMode?> {
synchronized(file) {
val existingState = file.danglingFileResolutionModeState
if (existingState != null) {
return existingState
}
val newState = ThreadLocal<DanglingFileResolutionMode?>()
file.danglingFileResolutionModeState = newState
return newState
}
}
private var KtFile.danglingFileResolutionModeState: ThreadLocal<DanglingFileResolutionMode?>?
by UserDataProperty(Key.create("DANGLING_FILE_RESOLUTION_MODE"))
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.analysis.project.structure.impl
import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analysis.project.structure.DanglingFileResolutionMode
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.KtDanglingFileModule
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -18,7 +19,8 @@ import java.util.Objects
public class KtDanglingFileModuleImpl(
file: KtFile,
override val contextModule: KtModule
override val contextModule: KtModule,
override val resolutionMode: DanglingFileResolutionMode
) : KtDanglingFileModule {
override val isCodeFragment: Boolean = file is KtCodeFragment
@@ -67,7 +69,9 @@ public class KtDanglingFileModuleImpl(
if (other is KtDanglingFileModuleImpl) {
val selfFile = this.fileRef.element
val otherFile = other.fileRef.element
return selfFile != null && selfFile == otherFile && contextModule == other.contextModule
return selfFile != null && selfFile == otherFile
&& contextModule == other.contextModule
&& resolutionMode == other.resolutionMode
}
return false
@@ -64,3 +64,14 @@ public inline fun <reified M : KtModule> KtModule.allDirectDependenciesOfType():
*/
public fun computeTransitiveDependsOnDependencies(directDependsOnDependencies: List<KtModule>): List<KtModule> =
topologicalSort(directDependsOnDependencies) { this.directDependsOnDependencies }
/**
* Specifies how references to non-local declarations in the dangling files should be resolved.
*/
public enum class DanglingFileResolutionMode {
/** Resolve first to declarations in the dangling file, and delegate to the original file or module only when needed. */
PREFER_SELF,
/** * Resolve only to declarations in the original file or module. Ignore all non-local declarations in the dangling file copy. */
IGNORE_SELF
}