[Analysis API FIR] fix call resolution on error elements
diff --git a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CallResolver.kt b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CallResolver.kt
index 082f4e9..8a3ca76 100644
--- a/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CallResolver.kt
+++ b/analysis/analysis-api-fe10/src/org/jetbrains/kotlin/analysis/api/descriptors/components/KtFe10CallResolver.kt
@@ -124,6 +124,10 @@
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 @@
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
diff --git a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/callResolver/Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated.java b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/callResolver/Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
index 8b40293..e4699d4 100644
--- a/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/callResolver/Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
+++ b/analysis/analysis-api-fe10/tests-gen/org/jetbrains/kotlin/analysis/api/fe10/test/cases/generated/cases/components/callResolver/Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
@@ -855,6 +855,22 @@
}
@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")
public class NonCalls {
diff --git a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt
index fe30873..de4d95c 100644
--- a/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt
+++ b/analysis/analysis-api-fir/src/org/jetbrains/kotlin/analysis/api/fir/components/KtFirCallResolver.kt
@@ -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.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 @@
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 @@
private inline fun <T> getCallInfo(
psi: KtElement,
+ getErrorCallInfo: FirDiagnosticHolder.(psiToResolve: KtElement) -> List<T>,
getCallInfo: FirElement.(
psiToResolve: KtElement,
resolveCalleeExpressionOfFunctionCall: Boolean,
@@ -121,6 +130,9 @@
?: 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 @@
}
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 @@
}
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 @@
}
}
+
+ private fun FirDiagnosticHolder.createKtDiagnostic(psi: KtElement?): KtDiagnostic {
+ return (source?.let { diagnostic.asKtDiagnostic(it, psi?.toKtPsiSourceElement()) }
+ ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token))
+ }
}
diff --git a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/callResolver/FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated.java b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/callResolver/FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
index 7fb5362..2973fe5 100644
--- a/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/callResolver/FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
+++ b/analysis/analysis-api-fir/tests-gen/org/jetbrains/kotlin/analysis/api/fir/test/cases/generated/cases/components/callResolver/FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated.java
@@ -855,6 +855,22 @@
}
@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")
public class NonCalls {
diff --git a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/callResolver/FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated.java b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/callResolver/FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated.java
index ca5b21a..d444635 100644
--- a/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/callResolver/FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated.java
+++ b/analysis/analysis-api-standalone/tests-gen/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/generated/cases/components/callResolver/FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated.java
@@ -855,6 +855,22 @@
}
@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")
public class NonCalls {
diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt
new file mode 100644
index 0000000..4df71a3
--- /dev/null
+++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt
@@ -0,0 +1,2 @@
+val commonSettings: Int =
+ <expr>get()</expr> = 1
\ No newline at end of file
diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.txt
new file mode 100644
index 0000000..e58ddba
--- /dev/null
+++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.txt
@@ -0,0 +1,3 @@
+KtErrorCallInfo:
+ candidateCalls = []
+ diagnostic = ERROR<ASSIGNMENT_IN_EXPRESSION_CONTEXT: Assignments are not expressions, and only expressions are allowed in this context>