[Analysis API FIR] fix call resolution on error elements
This commit is contained in:
+5
@@ -124,6 +124,10 @@ internal class KtFe10CallResolver(
|
||||
Errors.UNRESOLVED_REFERENCE,
|
||||
)
|
||||
|
||||
private val syntaxErrors = setOf(
|
||||
Errors.ASSIGNMENT_IN_EXPRESSION_CONTEXT,
|
||||
)
|
||||
|
||||
val diagnosticWithResolvedCallsAtPosition1 = setOf(
|
||||
Errors.OVERLOAD_RESOLUTION_AMBIGUITY,
|
||||
Errors.NONE_APPLICABLE,
|
||||
@@ -640,6 +644,7 @@ internal class KtFe10CallResolver(
|
||||
diagnostics: Diagnostics = context.diagnostics
|
||||
) = diagnostics.firstOrNull { diagnostic ->
|
||||
if (diagnostic.severity != Severity.ERROR) return@firstOrNull false
|
||||
if (diagnostic.factory in syntaxErrors) return@firstOrNull true
|
||||
val isResolutionError = diagnostic.factory in resolutionFailureErrors
|
||||
val isCallArgError = diagnostic.factory in callArgErrors
|
||||
val reportedPsi = diagnostic.psiElement
|
||||
|
||||
+16
@@ -854,6 +854,22 @@ public class Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated extends A
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class InvalidCode {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvalidCode() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("getterAssignment.kt")
|
||||
public void testGetterAssignment() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/nonCalls")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+37
-17
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.analysis.api.fir.components
|
||||
|
||||
import org.jetbrains.kotlin.analysis.api.calls.*
|
||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnostic
|
||||
import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession
|
||||
import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols
|
||||
@@ -71,6 +72,7 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.buildErrorWithAttachment
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.shouldIjPlatformExceptionBeRethrown
|
||||
import org.jetbrains.kotlin.analysis.utils.errors.withPsiEntry
|
||||
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
|
||||
|
||||
internal class KtFirCallResolver(
|
||||
override val analysisSession: KtFirAnalysisSession,
|
||||
@@ -88,15 +90,21 @@ internal class KtFirCallResolver(
|
||||
|
||||
override fun resolveCall(psi: KtElement): KtCallInfo? {
|
||||
return wrapError(psi) {
|
||||
val ktCallInfos = getCallInfo(psi) { psiToResolve, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall ->
|
||||
listOfNotNull(
|
||||
toKtCallInfo(
|
||||
psiToResolve,
|
||||
resolveCalleeExpressionOfFunctionCall,
|
||||
resolveFragmentOfCall
|
||||
val ktCallInfos = getCallInfo(
|
||||
psi,
|
||||
getErrorCallInfo = { psiToResolve ->
|
||||
listOf(KtErrorCallInfo(emptyList(), createKtDiagnostic(psiToResolve), token))
|
||||
},
|
||||
getCallInfo = { psiToResolve, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall ->
|
||||
listOfNotNull(
|
||||
toKtCallInfo(
|
||||
psiToResolve,
|
||||
resolveCalleeExpressionOfFunctionCall,
|
||||
resolveFragmentOfCall
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
)
|
||||
check(ktCallInfos.size <= 1) { "Should only return 1 KtCallInfo" }
|
||||
ktCallInfos.singleOrNull()
|
||||
}
|
||||
@@ -104,6 +112,7 @@ internal class KtFirCallResolver(
|
||||
|
||||
private inline fun <T> getCallInfo(
|
||||
psi: KtElement,
|
||||
getErrorCallInfo: FirDiagnosticHolder.(psiToResolve: KtElement) -> List<T>,
|
||||
getCallInfo: FirElement.(
|
||||
psiToResolve: KtElement,
|
||||
resolveCalleeExpressionOfFunctionCall: Boolean,
|
||||
@@ -121,6 +130,9 @@ internal class KtFirCallResolver(
|
||||
?: containingUnaryExpressionForIncOrDec
|
||||
?: psi
|
||||
val fir = psiToResolve.getOrBuildFir(analysisSession.firResolveSession) ?: return emptyList()
|
||||
if (fir is FirDiagnosticHolder) {
|
||||
return fir.getErrorCallInfo(psiToResolve)
|
||||
}
|
||||
return fir.getCallInfo(
|
||||
psiToResolve,
|
||||
psiToResolve == containingCallExpressionForCalleeExpression,
|
||||
@@ -163,8 +175,7 @@ internal class KtFirCallResolver(
|
||||
}
|
||||
is FirErrorNamedReference -> {
|
||||
val diagnostic = calleeReference.diagnostic
|
||||
val ktDiagnostic = (source?.let { diagnostic.asKtDiagnostic(it, psi.toKtPsiSourceElement()) }
|
||||
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token))
|
||||
val ktDiagnostic = calleeReference.createKtDiagnostic(psi)
|
||||
|
||||
if (diagnostic is ConeHiddenCandidateError)
|
||||
return KtErrorCallInfo(emptyList(), ktDiagnostic, token)
|
||||
@@ -793,13 +804,17 @@ internal class KtFirCallResolver(
|
||||
}
|
||||
|
||||
override fun collectCallCandidates(psi: KtElement): List<KtCallCandidateInfo> = wrapError(psi) {
|
||||
getCallInfo(psi) { psiToResolve, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall ->
|
||||
collectCallCandidates(
|
||||
psiToResolve,
|
||||
resolveCalleeExpressionOfFunctionCall,
|
||||
resolveFragmentOfCall
|
||||
)
|
||||
}
|
||||
getCallInfo(
|
||||
psi,
|
||||
getErrorCallInfo = { emptyList() },
|
||||
getCallInfo = { psiToResolve, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall ->
|
||||
collectCallCandidates(
|
||||
psiToResolve,
|
||||
resolveCalleeExpressionOfFunctionCall,
|
||||
resolveFragmentOfCall
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
// TODO: Refactor common code with FirElement.toKtCallInfo() when other FirResolvables are handled
|
||||
@@ -1185,4 +1200,9 @@ internal class KtFirCallResolver(
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun FirDiagnosticHolder.createKtDiagnostic(psi: KtElement?): KtDiagnostic {
|
||||
return (source?.let { diagnostic.asKtDiagnostic(it, psi?.toKtPsiSourceElement()) }
|
||||
?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token))
|
||||
}
|
||||
}
|
||||
|
||||
+16
@@ -854,6 +854,22 @@ public class FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated extends Ab
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class InvalidCode {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvalidCode() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode"), Pattern.compile("^(.+)\\.kt$"), null, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("getterAssignment.kt")
|
||||
public void testGetterAssignment() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/nonCalls")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
+16
@@ -854,6 +854,22 @@ public class FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated ext
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
public class InvalidCode {
|
||||
@Test
|
||||
public void testAllFilesPresentInInvalidCode() throws Exception {
|
||||
KtTestUtil.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode"), Pattern.compile("^(.+)\\.kt$"), null, true, "withTestCompilerPluginEnabled");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("getterAssignment.kt")
|
||||
public void testGetterAssignment() throws Exception {
|
||||
runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@TestMetadata("analysis/analysis-api/testData/components/callResolver/resolveCall/nonCalls")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
|
||||
Vendored
+2
@@ -0,0 +1,2 @@
|
||||
val commonSettings: Int =
|
||||
<expr>get()</expr> = 1
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
KtErrorCallInfo:
|
||||
candidateCalls = []
|
||||
diagnostic = ERROR<ASSIGNMENT_IN_EXPRESSION_CONTEXT: Assignments are not expressions, and only expressions are allowed in this context>
|
||||
Reference in New Issue
Block a user