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 edf52ac2e5b..ae35f990a15 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 @@ -244,6 +244,12 @@ public class Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated extends A runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/checkNotNullCallAsCallee.kt"); } + @Test + @TestMetadata("companionObjectReference.kt") + public void testCompanionObjectReference() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt"); + } + @Test @TestMetadata("comparisonCall.kt") public void testComparisonCall() throws Exception { @@ -899,6 +905,24 @@ public class Fe10IdeNormalAnalysisSourceModuleResolveCallTestGenerated extends A runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt"); } + @Test + @TestMetadata("incompleteCodeNoParenthesis.kt") + public void testIncompleteCodeNoParenthesis() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt"); + } + + @Test + @TestMetadata("incompleteCodeWithAmbiguity.kt") + public void testIncompleteCodeWithAmbiguity() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt"); + } + + @Test + @TestMetadata("incorrectCodeJavaDeclaration.kt") + public void testIncorrectCodeJavaDeclaration() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt"); + } + @Test @TestMetadata("typeParameterAsValue.kt") public void testTypeParameterAsValue() throws Exception { 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 d2e52d37266..be03736c576 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 @@ -150,6 +150,15 @@ internal class KtFirCallResolver( createGenericTypeQualifierCallIfApplicable(this, psi)?.let { return it } + if (this is FirResolvedQualifier && psi is KtCallExpression) { + val constructors = findQualifierConstructors() + val calls = toKtCalls(constructors) + return when (calls.size) { + 0 -> KtErrorCallInfo(listOf(KtQualifierCall(token, psi)), inapplicableCandidateDiagnostic(), token) + else -> KtErrorCallInfo(calls, inapplicableCandidateDiagnostic(), token) + } + } + if (resolveCalleeExpressionOfFunctionCall && this is FirImplicitInvokeCall) { // For implicit invoke, we resolve the calleeExpression of the CallExpression to the call that creates the receiver of this // implicit invoke call. For example, @@ -231,6 +240,8 @@ internal class KtFirCallResolver( } } + private fun inapplicableCandidateDiagnostic() = KtNonBoundToPsiErrorDiagnostic(null, "Inapplicable candidate", token) + /** * Resolves call expressions like `Foo` or `test.Foo` in calls like `Foo::foo`, `test.Foo::foo` and class literals like `Foo`::class.java. * @@ -877,22 +888,31 @@ internal class KtFirCallResolver( } private fun FirResolvedQualifier.toKtCallCandidateInfos(): List { + return toKtCalls(findQualifierConstructors()).map { + KtInapplicableCallCandidateInfo( + it, + isInBestCandidates = false, + _diagnostic = inapplicableCandidateDiagnostic() + ) + } + } + + private fun FirResolvedQualifier.findQualifierConstructors(): List { val classSymbol = this.symbol?.fullyExpandedClass(analysisSession.useSiteSession) ?: return emptyList() - val constructors = classSymbol.unsubstitutedScope( + return classSymbol.unsubstitutedScope( analysisSession.useSiteSession, analysisSession.getScopeSessionFor(analysisSession.useSiteSession), withForcedTypeCalculator = true ) .getConstructors(analysisSession.firSymbolBuilder) .toList() + } + + private fun FirResolvedQualifier.toKtCalls(constructors: List): List { analysisSession.apply { return constructors.map { constructor -> val partiallyAppliedSymbol = KtPartiallyAppliedFunctionSymbol(constructor.asSignature(), null, null) - KtInapplicableCallCandidateInfo( - KtSimpleFunctionCall(partiallyAppliedSymbol, LinkedHashMap(), toTypeArgumentsMapping(partiallyAppliedSymbol), false), - isInBestCandidates = false, - _diagnostic = KtNonBoundToPsiErrorDiagnostic(null, "Inapplicable candidate", token) - ) + KtSimpleFunctionCall(partiallyAppliedSymbol, LinkedHashMap(), toTypeArgumentsMapping(partiallyAppliedSymbol), false) } } } 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 d5016885a05..d12432ecc28 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 @@ -244,6 +244,12 @@ public class FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated extends Ab runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/checkNotNullCallAsCallee.kt"); } + @Test + @TestMetadata("companionObjectReference.kt") + public void testCompanionObjectReference() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt"); + } + @Test @TestMetadata("comparisonCall.kt") public void testComparisonCall() throws Exception { @@ -899,6 +905,24 @@ public class FirIdeNormalAnalysisSourceModuleResolveCallTestGenerated extends Ab runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt"); } + @Test + @TestMetadata("incompleteCodeNoParenthesis.kt") + public void testIncompleteCodeNoParenthesis() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt"); + } + + @Test + @TestMetadata("incompleteCodeWithAmbiguity.kt") + public void testIncompleteCodeWithAmbiguity() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt"); + } + + @Test + @TestMetadata("incorrectCodeJavaDeclaration.kt") + public void testIncorrectCodeJavaDeclaration() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt"); + } + @Test @TestMetadata("typeParameterAsValue.kt") public void testTypeParameterAsValue() throws Exception { 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 dbf05a90f05..0f0f301fe9e 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 @@ -244,6 +244,12 @@ public class FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated ext runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/checkNotNullCallAsCallee.kt"); } + @Test + @TestMetadata("companionObjectReference.kt") + public void testCompanionObjectReference() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt"); + } + @Test @TestMetadata("comparisonCall.kt") public void testComparisonCall() throws Exception { @@ -899,6 +905,24 @@ public class FirStandaloneNormalAnalysisSourceModuleResolveCallTestGenerated ext runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/getterAssignment.kt"); } + @Test + @TestMetadata("incompleteCodeNoParenthesis.kt") + public void testIncompleteCodeNoParenthesis() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt"); + } + + @Test + @TestMetadata("incompleteCodeWithAmbiguity.kt") + public void testIncompleteCodeWithAmbiguity() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt"); + } + + @Test + @TestMetadata("incorrectCodeJavaDeclaration.kt") + public void testIncorrectCodeJavaDeclaration() throws Exception { + runTest("analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt"); + } + @Test @TestMetadata("typeParameterAsValue.kt") public void testTypeParameterAsValue() throws Exception { diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt index 134d884864e..baf05df373e 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/calls/KtCall.kt @@ -145,6 +145,25 @@ public class KtGenericTypeQualifier( public val qualifier: KtExpression get() = withValidityAssertion { _qualifier } } +/** + * A special call for type qualifiers with generic parameters which represent [KtCallExpression] in incomplete code. + * + * Example: + * + * ``` + * fun test() { + * List + * } + * ``` + */ +public class KtQualifierCall( + override val token: KtLifetimeToken, + private val _qualifier: KtCallExpression, +) : KtCall() { + + public val qualifier: KtCallExpression get() = withValidityAssertion { _qualifier } +} + /** * A callable symbol partially applied with receivers and type arguments. Essentially, this is a call that misses some information. For * properties, the missing information is the type of access (read, write, or compound access) to this property. For functions, the missing diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt new file mode 100644 index 00000000000..21219f75dc1 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.kt @@ -0,0 +1,9 @@ +open class Server() { + companion object { + val NAME = "Server" + } +} + +class Client: Server() { + val name = Server.NAME +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.txt new file mode 100644 index 00000000000..ec747fa47dd --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/companionObjectReference.txt @@ -0,0 +1 @@ +null \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.descriptors.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.descriptors.txt new file mode 100644 index 00000000000..ead004ce0a3 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.descriptors.txt @@ -0,0 +1,14 @@ +KtSuccessCallInfo: + call = KtSimpleFunctionCall: + isImplicitInvoke = false + partiallyAppliedSymbol = KtPartiallyAppliedSymbol: + dispatchReceiver = null + extensionReceiver = null + signature = KtFunctionLikeSignature: + receiverType = null + returnType = ALE + symbol = (): ALE + valueParameters = [] + callableIdIfNonLocal = null + typeArgumentsMapping = {} + argumentMapping = {} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt new file mode 100644 index 00000000000..2471f19d8b6 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.kt @@ -0,0 +1,5 @@ +class ALE {} + +fun main(args: Array) { + val ale = ALE +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.txt new file mode 100644 index 00000000000..1986982c958 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeNoParenthesis.txt @@ -0,0 +1,19 @@ +KtErrorCallInfo: + candidateCalls = [ + KtSimpleFunctionCall: + isImplicitInvoke = false + partiallyAppliedSymbol = KtPartiallyAppliedSymbol: + dispatchReceiver = null + extensionReceiver = null + signature = KtFunctionLikeSignature: + receiverType = null + returnType = ALE + symbol = (): ALE + valueParameters = [] + callableIdIfNonLocal = null + typeArgumentsMapping = { + T -> (kotlin.String) + } + argumentMapping = {} + ] + diagnostic = ERROR \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.descriptors.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.descriptors.txt new file mode 100644 index 00000000000..2edbde8d56e --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.descriptors.txt @@ -0,0 +1,3 @@ +KtSuccessCallInfo: + call = KtGenericTypeQualifier: + qualifier = Foo diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt new file mode 100644 index 00000000000..b7bab9a294f --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.kt @@ -0,0 +1,7 @@ +class Foo(len : Int) { + constructor(s : String) : this(s.length) {} +} + +fun f() { + Foo +} diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.txt new file mode 100644 index 00000000000..290c3baaa5f --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incompleteCodeWithAmbiguity.txt @@ -0,0 +1,48 @@ +KtErrorCallInfo: + candidateCalls = [ + KtSimpleFunctionCall: + isImplicitInvoke = false + partiallyAppliedSymbol = KtPartiallyAppliedSymbol: + dispatchReceiver = null + extensionReceiver = null + signature = KtFunctionLikeSignature: + receiverType = null + returnType = Foo + symbol = (len: kotlin.Int): Foo + valueParameters = [ + KtVariableLikeSignature: + name = len + receiverType = null + returnType = kotlin.Int + symbol = len: kotlin.Int + callableIdIfNonLocal = null + ] + callableIdIfNonLocal = null + typeArgumentsMapping = { + T -> (kotlin.String) + } + argumentMapping = {}, + KtSimpleFunctionCall: + isImplicitInvoke = false + partiallyAppliedSymbol = KtPartiallyAppliedSymbol: + dispatchReceiver = null + extensionReceiver = null + signature = KtFunctionLikeSignature: + receiverType = null + returnType = Foo + symbol = (s: kotlin.String): Foo + valueParameters = [ + KtVariableLikeSignature: + name = s + receiverType = null + returnType = kotlin.String + symbol = s: kotlin.String + callableIdIfNonLocal = null + ] + callableIdIfNonLocal = null + typeArgumentsMapping = { + T -> (kotlin.String) + } + argumentMapping = {} + ] + diagnostic = ERROR diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.descriptors.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.descriptors.txt new file mode 100644 index 00000000000..7484e827753 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.descriptors.txt @@ -0,0 +1,3 @@ +KtSuccessCallInfo: + call = KtGenericTypeQualifier: + qualifier = List \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt new file mode 100644 index 00000000000..6f23dacc7a8 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.kt @@ -0,0 +1,3 @@ +fun main(args: Array) { + List s = new ArrayList() +} \ No newline at end of file diff --git a/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.txt b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.txt new file mode 100644 index 00000000000..8a5226a29f8 --- /dev/null +++ b/analysis/analysis-api/testData/components/callResolver/resolveCall/invalidCode/incorrectCodeJavaDeclaration.txt @@ -0,0 +1,6 @@ +KtErrorCallInfo: + candidateCalls = [ + KtQualifierCall: + qualifier = List + ] + diagnostic = ERROR \ No newline at end of file