FIR IDE: fix reference resolve in import statement

This commit is contained in:
Ilya Kirillov
2021-05-25 19:27:57 +02:00
committed by TeamCityServer
parent 55621b7aad
commit b81ef157b2
12 changed files with 174 additions and 23 deletions
@@ -716,6 +716,64 @@ public class FirReferenceResolveTestGenerated extends AbstractFirReferenceResolv
}
}
@TestMetadata("idea/testData/resolve/references/inImport")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InImport extends AbstractFirReferenceResolveTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInImport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/resolve/references/inImport"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("javaClass.kt")
public void testJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaClass.kt");
}
@TestMetadata("javaPackageFirstQualifier.kt")
public void testJavaPackageFirstQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaPackageFirstQualifier.kt");
}
@TestMetadata("javaPackageSecondQualifier.kt")
public void testJavaPackageSecondQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaPackageSecondQualifier.kt");
}
@TestMetadata("kotlinClass.kt")
public void testKotlinClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinClass.kt");
}
@TestMetadata("kotlinPackageFirstQualifier.kt")
public void testKotlinPackageFirstQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinPackageFirstQualifier.kt");
}
@TestMetadata("kotlinPackageSecondQualifier.kt")
public void testKotlinPackageSecondQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinPackageSecondQualifier.kt");
}
@TestMetadata("kotlinTopLevelFunction.kt")
public void testKotlinTopLevelFunction() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinTopLevelFunction.kt");
}
@TestMetadata("staticMethodFromJavaClass.kt")
public void testStaticMethodFromJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/staticMethodFromJavaClass.kt");
}
@TestMetadata("staticMethodFromJavaClassJavaClass.kt")
public void testStaticMethodFromJavaClassJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/staticMethodFromJavaClassJavaClass.kt");
}
}
@TestMetadata("idea/testData/resolve/references/invoke")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -6,18 +6,25 @@
package org.jetbrains.kotlin.idea.references
import com.intellij.psi.tree.TokenSet
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.ROOT_PREFIX_FOR_IDE_RESOLUTION_MODE
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.buildImport
import org.jetbrains.kotlin.fir.declarations.synthetic.FirSyntheticProperty
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.calls.FirSyntheticPropertySymbol
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeOperatorAmbiguityError
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeUnmatchedTypeArgumentsError
import org.jetbrains.kotlin.fir.resolve.symbolProvider
import org.jetbrains.kotlin.fir.resolve.toSymbol
import org.jetbrains.kotlin.fir.resolve.transformers.FirImportResolveTransformer
import org.jetbrains.kotlin.fir.scopes.impl.FirExplicitSimpleImportingScope
import org.jetbrains.kotlin.fir.scopes.processClassifiersByName
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.ConeClassLikeLookupTagImpl
@@ -39,6 +46,7 @@ import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
import org.jetbrains.kotlin.psi.psiUtil.unwrapNullability
import org.jetbrains.kotlin.utils.addIfNotNull
internal object FirReferenceResolveHelper {
fun FirResolvedTypeRef.toTargetSymbol(session: FirSession, symbolBuilder: KtSymbolByFirBuilder): KtSymbol? {
@@ -116,11 +124,18 @@ internal object FirReferenceResolveHelper {
symbolBuilder: KtSymbolByFirBuilder,
forQualifiedType: Boolean
): KtFirPackageSymbol? {
return symbolBuilder.createPackageSymbolIfOneExists(getQualifierSelected(expression, forQualifiedType))
}
private fun getQualifierSelected(
expression: KtSimpleNameExpression,
forQualifiedType: Boolean
): FqName {
val qualified = when {
forQualifiedType -> expression.parent?.takeIf { it is KtUserType && it.referenceExpression === expression }
else -> expression.getQualifiedExpressionForSelector()
}
val fqName = when (qualified) {
return when (qualified) {
null -> FqName(expression.getReferencedName())
else -> {
qualified
@@ -130,7 +145,6 @@ internal object FirReferenceResolveHelper {
.let(::FqName)
}
}
return symbolBuilder.createPackageSymbolIfOneExists(fqName)
}
private fun KtSimpleNameExpression.isPartOfQualifiedExpression(): Boolean {
@@ -313,32 +327,30 @@ internal object FirReferenceResolveHelper {
return listOf(symbolBuilder.buildSymbol(fir))
}
@OptIn(ExperimentalStdlibApi::class)
private fun getSymbolsByResolvedImport(
expression: KtSimpleNameExpression,
symbolBuilder: KtSymbolByFirBuilder,
builder: KtSymbolByFirBuilder,
fir: FirResolvedImport,
session: FirSession
): List<KtSymbol> {
if (expression.isPartOfQualifiedExpression()) {
return listOfNotNull(getPackageSymbolFor(expression, symbolBuilder, forQualifiedType = false))
val fullFqName = fir.importedFqName
val selectedFqName = getQualifierSelected(expression, forQualifiedType = false)
val rawImportForSelectedFqName = buildImport {
importedFqName = selectedFqName
isAllUnder = false
}
val classId = fir.resolvedClassId
if (classId != null) {
return listOfNotNull(classId.toTargetPsi(session, symbolBuilder))
}
val name = fir.importedName ?: return emptyList()
val symbolProvider = session.symbolProvider
@OptIn(ExperimentalStdlibApi::class)
val resolvedImport = FirImportResolveTransformer(session).transformImport(rawImportForSelectedFqName, null) as FirResolvedImport
val scope = FirExplicitSimpleImportingScope(listOf(resolvedImport), session, ScopeSession())
val selectedName = resolvedImport.importedName ?: return emptyList()
return buildList {
symbolProvider.getTopLevelCallableSymbols(fir.packageFqName, name)
.mapTo(this) { it.fir.buildSymbol(symbolBuilder) }
symbolProvider
.getClassLikeSymbolByFqName(ClassId(fir.packageFqName, name))
?.fir
?.buildSymbol(symbolBuilder)
?.let(::add)
if (selectedFqName == fullFqName) {
// callables cannot be used as receiver expressions in imports
scope.processFunctionsByName(selectedName) { add(it.fir.buildSymbol(builder)) }
scope.processPropertiesByName(selectedName) { add(it.fir.buildSymbol(builder)) }
}
scope.processClassifiersByName(selectedName) { addIfNotNull(it.fir.buildSymbol(builder)) }
builder.createPackageSymbolIfOneExists(selectedFqName)?.let(::add)
}
}
@@ -0,0 +1,3 @@
import java.util.Ha<caret>shMap
// REF: (java.util).HashMap
@@ -0,0 +1,2 @@
import jav<caret>a.util.ArrayList
// REF: java
@@ -0,0 +1,2 @@
import java.uti<caret>l.ArrayList
// REF: util
@@ -0,0 +1,4 @@
import kotlin.collections.Mutab<caret>leList
// MULTIRESOLVE
// REF: (kotlin.collections).MutableList
// REF: (kotlin.collections).MutableList(kotlin.Int, (kotlin.Int) -> T)
@@ -0,0 +1,2 @@
import kotli<caret>n.text.toString
// REF: kotlin
@@ -0,0 +1,2 @@
import kotlin.tex<caret>t.toString
// REF: text
@@ -0,0 +1,4 @@
import kotlin.collections.mut<caret>ableListOf
// MULTIRESOLVE
// REF: (kotlin.collections).mutableListOf()
// REF: (kotlin.collections).mutableListOf(vararg T)
@@ -0,0 +1,2 @@
import java.lang.Math.si<caret>n
// REF: (in java.lang.Math).sin(double)
@@ -0,0 +1,2 @@
import java.lang.M<caret>ath.sin
// REF: (java.lang).Math
@@ -716,6 +716,64 @@ public class ReferenceResolveTestGenerated extends AbstractReferenceResolveTest
}
}
@TestMetadata("idea/testData/resolve/references/inImport")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class InImport extends AbstractReferenceResolveTest {
private void runTest(String testDataFilePath) throws Exception {
KotlinTestUtils.runTest(this::doTest, this, testDataFilePath);
}
public void testAllFilesPresentInInImport() throws Exception {
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("idea/testData/resolve/references/inImport"), Pattern.compile("^([^.]+)\\.kt$"), null, true);
}
@TestMetadata("javaClass.kt")
public void testJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaClass.kt");
}
@TestMetadata("javaPackageFirstQualifier.kt")
public void testJavaPackageFirstQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaPackageFirstQualifier.kt");
}
@TestMetadata("javaPackageSecondQualifier.kt")
public void testJavaPackageSecondQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/javaPackageSecondQualifier.kt");
}
@TestMetadata("kotlinClass.kt")
public void testKotlinClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinClass.kt");
}
@TestMetadata("kotlinPackageFirstQualifier.kt")
public void testKotlinPackageFirstQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinPackageFirstQualifier.kt");
}
@TestMetadata("kotlinPackageSecondQualifier.kt")
public void testKotlinPackageSecondQualifier() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinPackageSecondQualifier.kt");
}
@TestMetadata("kotlinTopLevelFunction.kt")
public void testKotlinTopLevelFunction() throws Exception {
runTest("idea/testData/resolve/references/inImport/kotlinTopLevelFunction.kt");
}
@TestMetadata("staticMethodFromJavaClass.kt")
public void testStaticMethodFromJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/staticMethodFromJavaClass.kt");
}
@TestMetadata("staticMethodFromJavaClassJavaClass.kt")
public void testStaticMethodFromJavaClassJavaClass() throws Exception {
runTest("idea/testData/resolve/references/inImport/staticMethodFromJavaClassJavaClass.kt");
}
}
@TestMetadata("idea/testData/resolve/references/invoke")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)