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 db5da496e11..ffe49f48878 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 @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.api.diagnostics.KtNonBoundToPsiErrorDiagnos import org.jetbrains.kotlin.analysis.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.analysis.api.fir.getCandidateSymbols import org.jetbrains.kotlin.analysis.api.fir.isInvokeFunction +import org.jetbrains.kotlin.analysis.api.fir.scopes.getConstructors import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOf import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayOfSymbol import org.jetbrains.kotlin.analysis.api.fir.symbols.KtFirArrayOfSymbolProvider.arrayTypeToArrayOfCall @@ -26,8 +27,10 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFir import org.jetbrains.kotlin.analysis.low.level.api.fir.resolver.AllCandidatesResolver import org.jetbrains.kotlin.analysis.utils.printer.parentOfType import org.jetbrains.kotlin.fir.FirElement +import org.jetbrains.kotlin.fir.analysis.checkers.declaration.expandedClass import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol import org.jetbrains.kotlin.fir.declarations.FirValueParameter +import org.jetbrains.kotlin.fir.declarations.fullyExpandedClass import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.builder.buildFunctionCall import org.jetbrains.kotlin.fir.expressions.impl.FirNoReceiverExpression @@ -210,6 +213,9 @@ internal class KtFirCallResolver( val call = psiElement.getPossiblyQualifiedCallExpression() ?: return null if (call.typeArgumentList == null || call.valueArgumentList != null) return null + val parentReferenceExpression = psiElement.parent as? KtCallableReferenceExpression ?: return null + if (parentReferenceExpression.lhs != psiElement) return null + return KtSuccessCallInfo(KtGenericTypeQualifier(token, psiElement)) } @@ -411,13 +417,26 @@ internal class KtFirCallResolver( ) } is FirPropertyAccessExpression -> { - if (unsubstitutedKtSignature.symbol !is KtVariableLikeSymbol) return null - @Suppress("UNCHECKED_CAST") // safe because of the above check on targetKtSymbol - KtSimpleVariableAccessCall( - partiallyAppliedSymbol as KtPartiallyAppliedVariableSymbol, - fir.toTypeArgumentsMapping(partiallyAppliedSymbol), - KtSimpleVariableAccess.Read - ) + when (unsubstitutedKtSignature.symbol) { + is KtVariableLikeSymbol -> { + @Suppress("UNCHECKED_CAST") // safe because of the above check on targetKtSymbol + KtSimpleVariableAccessCall( + partiallyAppliedSymbol as KtPartiallyAppliedVariableSymbol, + fir.toTypeArgumentsMapping(partiallyAppliedSymbol), + KtSimpleVariableAccess.Read + ) + } + // if errorsness call without () + is KtFunctionLikeSymbol -> { + @Suppress("UNCHECKED_CAST") // safe because of the above check on targetKtSymbol + KtSimpleFunctionCall( + partiallyAppliedSymbol as KtPartiallyAppliedFunctionSymbol, + LinkedHashMap(), + fir.toTypeArgumentsMapping(partiallyAppliedSymbol), + _isImplicitInvoke = false, + ) + } + } } is FirFunctionCall -> { if (unsubstitutedKtSignature.symbol !is KtFunctionLikeSymbol) return null @@ -732,6 +751,19 @@ internal class KtFirCallResolver( private fun FirQualifiedAccess.toTypeArgumentsMapping( partiallyAppliedSymbol: KtPartiallyAppliedSymbol<*, *> + ): Map { + return toTypeArgumentsMapping(typeArguments, partiallyAppliedSymbol) + } + + private fun FirResolvedQualifier.toTypeArgumentsMapping( + partiallyAppliedSymbol: KtPartiallyAppliedSymbol<*, *> + ): Map { + return toTypeArgumentsMapping(typeArguments, partiallyAppliedSymbol) + } + + private fun toTypeArgumentsMapping( + typeArguments: List, + partiallyAppliedSymbol: KtPartiallyAppliedSymbol<*, *> ): Map { val typeParameters = partiallyAppliedSymbol.symbol.typeParameters if (typeParameters.isEmpty()) return emptyMap() @@ -802,12 +834,36 @@ internal class KtFirCallResolver( resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall ) - is FirArrayOfCall, is FirComparisonExpression, is FirEqualityOperatorCall -> { + is FirArrayOfCall, is FirEqualityOperatorCall -> { toKtCallInfo(psi, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall).toKtCallCandidateInfos() } - else -> { - // TODO: FirDelegatedConstructorCall, FirAnnotationCall, FirPropertyAccessExpression, FirVariableAssignment - listOf() + is FirComparisonExpression -> compareToCall.toKtCallInfo( + psi, + resolveCalleeExpressionOfFunctionCall, + resolveFragmentOfCall + ).toKtCallCandidateInfos() + is FirResolvedQualifier -> toKtCallCandidateInfos() + else -> toKtCallInfo(psi, resolveCalleeExpressionOfFunctionCall, resolveFragmentOfCall).toKtCallCandidateInfos() + } + } + + private fun FirResolvedQualifier.toKtCallCandidateInfos(): List { + val classSymbol = this.symbol?.fullyExpandedClass(analysisSession.useSiteSession) ?: return emptyList() + val constructors = classSymbol.unsubstitutedScope( + analysisSession.useSiteSession, + analysisSession.getScopeSessionFor(analysisSession.useSiteSession), + withForcedTypeCalculator = true + ) + .getConstructors(analysisSession.firSymbolBuilder) + .toList() + 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) + ) } } }