diff --git a/compiler/fir/analysis-tests/testData/resolve/arrays/arraySetWithOperation.kt b/compiler/fir/analysis-tests/testData/resolve/arrays/arraySetWithOperation.kt index 468f9bcaf2a..2413f4bde3a 100644 --- a/compiler/fir/analysis-tests/testData/resolve/arrays/arraySetWithOperation.kt +++ b/compiler/fir/analysis-tests/testData/resolve/arrays/arraySetWithOperation.kt @@ -28,9 +28,9 @@ fun test_2(a: A) { } fun test_3(a: A) { - a[0] += D() // ambiguity + a[0] += D() // ambiguity } fun test_4(b: B) { - b[0] += B() // unresolved + b[0] += B() // unresolved } diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/access.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/access.kt index ead6b21eda9..43487deca83 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/access.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/access.kt @@ -21,7 +21,7 @@ class Bar { } // NB! abc() here is resolved to member Foo.abc(), and not to extension member of Bar - fun Foo.check() = abc() + bar() + fun Foo.check() = abc() + bar() // NB! + here is resolved to member String.plus (not to extension member above) fun Foo.check2() = "" + bar() diff --git a/compiler/fir/analysis-tests/testData/resolve/expresssions/operators/plusAssign.kt b/compiler/fir/analysis-tests/testData/resolve/expresssions/operators/plusAssign.kt index 235e861ef18..0c734abf427 100644 --- a/compiler/fir/analysis-tests/testData/resolve/expresssions/operators/plusAssign.kt +++ b/compiler/fir/analysis-tests/testData/resolve/expresssions/operators/plusAssign.kt @@ -7,7 +7,7 @@ class Foo { fun test_1() { val f = Foo() - f + f + f + f } fun test_2() { diff --git a/compiler/fir/analysis-tests/testData/resolve/visibility/visibilityWithOverrides.kt b/compiler/fir/analysis-tests/testData/resolve/visibility/visibilityWithOverrides.kt index 768d1052b24..9e5875af43c 100644 --- a/compiler/fir/analysis-tests/testData/resolve/visibility/visibilityWithOverrides.kt +++ b/compiler/fir/analysis-tests/testData/resolve/visibility/visibilityWithOverrides.kt @@ -19,5 +19,5 @@ abstract class A { // FILE: main.kt fun test(b: B): String { - return b foo "hello" // should be an error + return b foo "hello" // should be an error } diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt index c216f004c28..104e5d8cda9 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt @@ -46,6 +46,7 @@ enum class PositioningStrategy(private val strategy: String? = null) { INNER_MODIFIER, SELECTOR_BY_QUALIFIED, REFERENCE_BY_QUALIFIED, + REFERENCED_NAME_BY_QUALIFIED, PRIVATE_MODIFIER, COMPANION_OBJECT, CONST_MODIFIER, diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index ba946656f57..effe6b3aba8 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -67,7 +67,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val HIDDEN by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter>("hidden") } - val UNRESOLVED_REFERENCE by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { + val UNRESOLVED_REFERENCE by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) { parameter("reference") } val UNRESOLVED_LABEL by error() @@ -79,9 +79,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() { } val SUPER by object : DiagnosticGroup("Super") { - val SUPER_IS_NOT_AN_EXPRESSION by error() - val SUPER_NOT_AVAILABLE by error() - val ABSTRACT_SUPER_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) + val SUPER_IS_NOT_AN_EXPRESSION by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) + val SUPER_NOT_AVAILABLE by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) + val ABSTRACT_SUPER_CALL by error(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error { parameter("target") } @@ -497,12 +497,12 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val UNSAFE_IMPLICIT_INVOKE_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("receiverType") } - val UNSAFE_INFIX_CALL by error { + val UNSAFE_INFIX_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("lhs") parameter("operator") parameter("rhs") } - val UNSAFE_OPERATOR_CALL by error { + val UNSAFE_OPERATOR_CALL by error(PositioningStrategy.REFERENCE_BY_QUALIFIED) { parameter("lhs") parameter("operator") parameter("rhs") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 5a00e77e094..98bb25ede92 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -77,7 +77,7 @@ object FirErrors { // Unresolved val HIDDEN by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) - val UNRESOLVED_REFERENCE by error1(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val UNRESOLVED_REFERENCE by error1(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val UNRESOLVED_LABEL by error0() val DESERIALIZATION_ERROR by error0() val ERROR_FROM_JAVA_RESOLUTION by error0() @@ -86,9 +86,9 @@ object FirErrors { val NO_THIS by error0() // Super - val SUPER_IS_NOT_AN_EXPRESSION by error0() - val SUPER_NOT_AVAILABLE by error0() - val ABSTRACT_SUPER_CALL by error0(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val SUPER_IS_NOT_AN_EXPRESSION by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val SUPER_NOT_AVAILABLE by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) + val ABSTRACT_SUPER_CALL by error0(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error1() // Supertypes @@ -303,8 +303,8 @@ object FirErrors { // Nullability val UNSAFE_CALL by error1(SourceElementPositioningStrategies.DOT_BY_QUALIFIED) val UNSAFE_IMPLICIT_INVOKE_CALL by error1(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) - val UNSAFE_INFIX_CALL by error3() - val UNSAFE_OPERATOR_CALL by error3() + val UNSAFE_INFIX_CALL by error3(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) + val UNSAFE_OPERATOR_CALL by error3(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) // When expressions val NO_ELSE_IN_WHEN by error1>(SourceElementPositioningStrategies.WHEN_EXPRESSION) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt index 24305e7e4f1..42eaf831712 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/ErrorNodeDiagnosticCollectorComponent.kt @@ -14,9 +14,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.fir.analysis.diagnostics.toFirDiagnostics import org.jetbrains.kotlin.fir.declarations.FirErrorFunction import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic -import org.jetbrains.kotlin.fir.expressions.FirErrorExpression -import org.jetbrains.kotlin.fir.expressions.FirErrorLoop -import org.jetbrains.kotlin.fir.expressions.FirErrorResolvedQualifier +import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.references.FirErrorNamedReference import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeAmbiguityError import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeInapplicableCandidateError @@ -35,15 +33,18 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect } override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference, data: CheckerContext) { - val source = data.qualifiedAccesses.lastOrNull()?.source?.takeIf { it.elementType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION } - ?: errorNamedReference.source ?: return + val source = errorNamedReference.source ?: return + val qualifiedAccessSource = data.qualifiedAccesses.lastOrNull()?.takeIf { + // Use the source of the enclosing FirQualifiedAccessExpression if it is exactly the call to the erroneous callee. + it is FirQualifiedAccessExpression && it.calleeReference == errorNamedReference + }?.source // Don't report duplicated unresolved reference on annotation entry (already reported on its type) if (source.elementType == KtNodeTypes.ANNOTATION_ENTRY && errorNamedReference.diagnostic is ConeUnresolvedNameError) return // Already reported in FirConventionFunctionCallChecker - if (errorNamedReference.source?.kind == FirFakeSourceElementKind.ArrayAccessNameReference && + if (source.kind == FirFakeSourceElementKind.ArrayAccessNameReference && errorNamedReference.diagnostic is ConeUnresolvedNameError ) return - reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data) + reportFirDiagnostic(errorNamedReference.diagnostic, source, reporter, data, qualifiedAccessSource) } override fun visitErrorExpression(errorExpression: FirErrorExpression, data: CheckerContext) { @@ -65,7 +66,8 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect diagnostic: ConeDiagnostic, source: FirSourceElement, reporter: DiagnosticReporter, - context: CheckerContext + context: CheckerContext, + qualifiedAccessSource: FirSourceElement? = null ) { // Will be handled by [FirDestructuringDeclarationChecker] if (source.elementType == KtNodeTypes.DESTRUCTURING_DECLARATION_ENTRY) { @@ -81,7 +83,7 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect if (source.kind == FirFakeSourceElementKind.ImplicitConstructor) { return } - for (coneDiagnostic in diagnostic.toFirDiagnostics(source)) { + for (coneDiagnostic in diagnostic.toFirDiagnostics(source, qualifiedAccessSource)) { reporter.report(coneDiagnostic, context) } } diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt index 9c2bb1bcd9e..05021fbd55e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/LightTreePositioningStrategies.kt @@ -343,10 +343,11 @@ object LightTreePositioningStrategies { endOffset: Int, tree: FlyweightCapableTreeStructure ): List { - if (node.tokenType != KtNodeTypes.DOT_QUALIFIED_EXPRESSION) { - return super.mark(node, startOffset, endOffset, tree) + if (node.tokenType == KtNodeTypes.DOT_QUALIFIED_EXPRESSION) { + return markElement(tree.dotOperator(node) ?: node, startOffset, endOffset, tree, node) } - return markElement(tree.dotOperator(node) ?: node, startOffset, endOffset, tree, node) + // Fallback to mark the callee reference. + return REFERENCE_BY_QUALIFIED.mark(node, startOffset, endOffset, tree) } } @@ -368,7 +369,13 @@ object LightTreePositioningStrategies { } } - val REFERENCE_BY_QUALIFIED: LightTreePositioningStrategy = object : LightTreePositioningStrategy() { + val REFERENCE_BY_QUALIFIED: LightTreePositioningStrategy = FindReferencePositioningStrategy(false) + val REFERENCED_NAME_BY_QUALIFIED: LightTreePositioningStrategy = FindReferencePositioningStrategy(true) + + /** + * @param locateReferencedName see doc on [referenceExpression] + */ + class FindReferencePositioningStrategy(val locateReferencedName: Boolean) : LightTreePositioningStrategy() { override fun mark( node: LighterASTNode, startOffset: Int, @@ -376,7 +383,10 @@ object LightTreePositioningStrategies { tree: FlyweightCapableTreeStructure ): List { if (node.tokenType == KtNodeTypes.CALL_EXPRESSION || node.tokenType == KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL) { - return markElement(tree.referenceExpression(node) ?: node, startOffset, endOffset, tree, node) + return markElement(tree.referenceExpression(node, locateReferencedName) ?: node, startOffset, endOffset, tree, node) + } + if (node.tokenType in nodeTypesWithOperation) { + return markElement(tree.operationReference(node) ?: node, startOffset, endOffset, tree, node) } if (node.tokenType != KtNodeTypes.DOT_QUALIFIED_EXPRESSION && node.tokenType != KtNodeTypes.SAFE_ACCESS_EXPRESSION && @@ -389,14 +399,30 @@ object LightTreePositioningStrategies { when (selector.tokenType) { KtNodeTypes.REFERENCE_EXPRESSION -> return markElement(selector, startOffset, endOffset, tree, node) - KtNodeTypes.CALL_EXPRESSION, KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL, KtNodeTypes.SUPER_TYPE_CALL_ENTRY -> - return markElement(tree.referenceExpression(selector) ?: selector, startOffset, endOffset, tree, node) + KtNodeTypes.CALL_EXPRESSION, KtNodeTypes.CONSTRUCTOR_DELEGATION_CALL,KtNodeTypes.SUPER_TYPE_CALL_ENTRY -> + return markElement( + tree.referenceExpression(selector, locateReferencedName) ?: selector, + startOffset, + endOffset, + tree, + node + ) } } return super.mark(node, startOffset, endOffset, tree) } } + private val nodeTypesWithOperation = setOf( + KtNodeTypes.IS_EXPRESSION, + KtNodeTypes.BINARY_WITH_TYPE, + KtNodeTypes.BINARY_EXPRESSION, + KtNodeTypes.POSTFIX_EXPRESSION, + KtNodeTypes.PREFIX_EXPRESSION, + KtNodeTypes.BINARY_EXPRESSION, + KtNodeTypes.WHEN_CONDITION_IN_RANGE + ) + val WHEN_EXPRESSION = object : LightTreePositioningStrategy() { override fun mark( node: LighterASTNode, @@ -464,12 +490,33 @@ private fun FlyweightCapableTreeStructure.nameIdentifier(node: L private fun FlyweightCapableTreeStructure.operationReference(node: LighterASTNode): LighterASTNode? = findChildByType(node, KtNodeTypes.OPERATION_REFERENCE) -private fun FlyweightCapableTreeStructure.referenceExpression(node: LighterASTNode): LighterASTNode? { +/** + * @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for diagnostics + * on super and unresolved references. For example, with the following, only the part inside the parentheses should be highlighted. + * + * ``` + * fun foo() { + * (super)() + * ^^^^^ + * (random123)() + * ^^^^^^^^^ + * } + * ``` + */ +private fun FlyweightCapableTreeStructure.referenceExpression( + node: LighterASTNode, + locateReferencedName: Boolean +): LighterASTNode? { val childrenRef = Ref>() getChildren(node, childrenRef) - return childrenRef.get()?.firstOrNull { - it?.tokenType == KtNodeTypes.REFERENCE_EXPRESSION || it?.tokenType == KtNodeTypes.CONSTRUCTOR_DELEGATION_REFERENCE + var result = childrenRef.get()?.firstOrNull { + it?.tokenType == KtNodeTypes.REFERENCE_EXPRESSION || it?.tokenType == KtNodeTypes.CONSTRUCTOR_DELEGATION_REFERENCE || + it?.tokenType == KtNodeTypes.SUPER_EXPRESSION || it?.tokenType == KtNodeTypes.PARENTHESIZED } + while (locateReferencedName && result != null && result.tokenType == KtNodeTypes.PARENTHESIZED) { + result = referenceExpression(result, locateReferencedName = true) + } + return result } private fun FlyweightCapableTreeStructure.rightParenthesis(node: LighterASTNode): LighterASTNode? = diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt index 41e8cfe9de7..1232989c737 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/SourceElementPositioningStrategies.kt @@ -133,6 +133,11 @@ object SourceElementPositioningStrategies { PositioningStrategies.REFERENCE_BY_QUALIFIED ) + val REFERENCED_NAME_BY_QUALIFIED = SourceElementPositioningStrategy( + LightTreePositioningStrategies.REFERENCED_NAME_BY_QUALIFIED, + PositioningStrategies.REFERENCED_NAME_BY_QUALIFIED + ) + val WHEN_EXPRESSION = SourceElementPositioningStrategy( LightTreePositioningStrategies.WHEN_EXPRESSION, PositioningStrategies.WHEN_EXPRESSION diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt index 1396d217bd5..2db4cb0a8a3 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/coneDiagnosticToFirDiagnostic.kt @@ -23,7 +23,10 @@ import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.resolve.calls.tower.isSuccess import org.jetbrains.kotlin.utils.addToStdlib.safeAs -private fun ConeDiagnostic.toFirDiagnostic(source: FirSourceElement): FirDiagnostic? = when (this) { +private fun ConeDiagnostic.toFirDiagnostic( + source: FirSourceElement, + qualifiedAccessSource: FirSourceElement? +): FirDiagnostic? = when (this) { is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.name?.asString() ?: "") is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.classId.asString()) is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.name.asString()) @@ -36,14 +39,14 @@ private fun ConeDiagnostic.toFirDiagnostic(source: FirSourceElement): FirDiagnos } is ConeOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.on(source, this.candidates) is ConeVariableExpectedError -> FirErrors.VARIABLE_EXPECTED.on(source) - is ConeTypeMismatchError -> FirErrors.TYPE_MISMATCH.on(source, this.expectedType, this.actualType) + is ConeTypeMismatchError -> FirErrors.TYPE_MISMATCH.on(qualifiedAccessSource ?: source, this.expectedType, this.actualType) is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.on(this.source.safeAs() ?: source) is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.on(source, this.name.asString()) is ConeWrongNumberOfTypeArgumentsError -> - FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(source, this.desiredCount, this.type) + FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type) is ConeSimpleDiagnostic -> when { source.kind is FirFakeSourceElementKind -> null - else -> this.getFactory().on(source) + else -> this.getFactory().on(qualifiedAccessSource ?: source) } is ConeInstanceAccessBeforeSuperCall -> FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(source, this.target) is ConeStubDiagnostic -> null @@ -54,11 +57,14 @@ private fun ConeDiagnostic.toFirDiagnostic(source: FirSourceElement): FirDiagnos else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}") } -fun ConeDiagnostic.toFirDiagnostics(source: FirSourceElement): List> { +fun ConeDiagnostic.toFirDiagnostics( + source: FirSourceElement, + qualifiedAccessSource: FirSourceElement? +): List> { if (this is ConeInapplicableCandidateError) { - return mapInapplicableCandidateError(this, source) + return mapInapplicableCandidateError(this, source, qualifiedAccessSource) } - return listOfNotNull(toFirDiagnostic(source)) + return listOfNotNull(toFirDiagnostic(source, qualifiedAccessSource)) } private fun ConeKotlinType.isEffectivelyNotNull(): Boolean { @@ -75,13 +81,14 @@ private fun mapUnsafeCallError( diagnostic: ConeInapplicableCandidateError, source: FirSourceElement, rootCause: ResolutionDiagnostic?, + qualifiedAccessSource: FirSourceElement?, ): FirDiagnostic<*>? { - if (rootCause is InapplicableWrongReceiver && - rootCause.actualType?.isNullable == true && - (rootCause.expectedType == null || rootCause.expectedType!!.isEffectivelyNotNull()) - ) { + if (rootCause !is InapplicableWrongReceiver) return null + val actualType = rootCause.actualType ?: return null + val expectedType = rootCause.expectedType + if (actualType.isNullable && (expectedType == null || expectedType.isEffectivelyNotNull())) { if (diagnostic.candidate.callInfo.isImplicitInvoke) { - return FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL.on(source, rootCause.actualType!!) + return FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL.on(source, actualType) } val candidateFunction = diagnostic.candidate.symbol.fir as? FirSimpleFunction @@ -100,8 +107,11 @@ private fun mapUnsafeCallError( return FirErrors.UNSAFE_OPERATOR_CALL.on(source, left, candidateFunctionName!!.asString(), right) } } - - return FirErrors.UNSAFE_CALL.on(source, rootCause.actualType!!) + return if (source.kind == FirFakeSourceElementKind.ArrayAccessNameReference) { + FirErrors.UNSAFE_CALL.on(source, actualType) + } else { + FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, actualType) + } } return null } @@ -109,15 +119,18 @@ private fun mapUnsafeCallError( private fun mapInapplicableCandidateError( diagnostic: ConeInapplicableCandidateError, source: FirSourceElement, + qualifiedAccessSource: FirSourceElement?, ): List> { // TODO: Need to distinguish SMARTCAST_IMPOSSIBLE return diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause -> - mapUnsafeCallError(diagnostic, source, rootCause)?.let { return@mapNotNull it } + mapUnsafeCallError(diagnostic, source, rootCause, qualifiedAccessSource)?.let { return@mapNotNull it } when (rootCause) { - is VarargArgumentOutsideParentheses -> FirErrors.VARARG_OUTSIDE_PARENTHESES.on(rootCause.argument.source ?: source) + is VarargArgumentOutsideParentheses -> FirErrors.VARARG_OUTSIDE_PARENTHESES.on( + rootCause.argument.source ?: qualifiedAccessSource + ) is NamedArgumentNotAllowed -> FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED.on( - rootCause.argument.source ?: source, + rootCause.argument.source ?: qualifiedAccessSource, rootCause.forbiddenNamedArgumentsTarget ) else -> null diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt index 289c9af8859..c10e211ea07 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/PsiConversionUtils.kt @@ -45,7 +45,7 @@ internal fun KtWhenCondition.toFirWhenCondition( firRange.generateContainsOperation( firSubjectExpression, isNegated, - rangeExpression?.toFirPsiSourceElement(FirFakeSourceElementKind.WhenCondition), + this@toFirWhenCondition.toFirPsiSourceElement(FirFakeSourceElementKind.WhenCondition), operationReference.toFirPsiSourceElement() ) } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt index 6fecd098e27..e8e6f55f69d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/PositioningStrategies.kt @@ -729,7 +729,8 @@ object PositioningStrategies { return mark(element.operationTokenNode.psi) } } - return super.mark(element) + // Fallback to mark the callee reference. + return REFERENCE_BY_QUALIFIED.mark(element) } } @@ -744,21 +745,45 @@ object PositioningStrategies { } } - val REFERENCE_BY_QUALIFIED: PositioningStrategy = object : PositioningStrategy() { + val REFERENCE_BY_QUALIFIED: PositioningStrategy = FindReferencePositioningStrategy(false) + val REFERENCED_NAME_BY_QUALIFIED: PositioningStrategy = FindReferencePositioningStrategy(true) + + /** + * @param locateReferencedName whether to remove any nested parentheses while locating the reference element. This is useful for + * diagnostics on super and unresolved references. For example, with the following, only the part inside the parentheses should be + * highlighted. + * + * ``` + * fun foo() { + * (super)() + * ^^^^^ + * (random123)() + * ^^^^^^^^^ + * } + * ``` + */ + class FindReferencePositioningStrategy(val locateReferencedName: Boolean) : PositioningStrategy() { override fun mark(element: PsiElement): List { - when (element) { + var result: PsiElement = when (element) { is KtQualifiedExpression -> { when (val selectorExpression = element.selectorExpression) { - is KtCallExpression -> return mark(selectorExpression.calleeExpression ?: selectorExpression) - is KtReferenceExpression -> return mark(selectorExpression) + is KtCallExpression -> selectorExpression.calleeExpression ?: selectorExpression + is KtReferenceExpression -> selectorExpression + else -> element } } - is KtCallableReferenceExpression -> return mark(element.callableReference) - is KtCallExpression -> return mark(element.calleeExpression ?: element) - is KtConstructorDelegationCall -> return mark(element.calleeExpression ?: element) - is KtSuperTypeCallEntry -> return mark(element.calleeExpression) + is KtCallableReferenceExpression -> element.callableReference + is KtCallExpression -> element.calleeExpression ?: element + is KtConstructorDelegationCall -> element.calleeExpression ?: element + is KtSuperTypeCallEntry -> element.calleeExpression + is KtOperationExpression -> element.operationReference + is KtWhenConditionInRange -> element.operationReference + else -> element } - return super.mark(element) + while (locateReferencedName && result is KtParenthesizedExpression) { + result = result.expression ?: break + } + return super.mark(result) } } } diff --git a/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt b/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt index 520fffe2f90..34f681b3add 100644 --- a/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt +++ b/compiler/testData/diagnostics/tests/BinaryCallsOnNullableValues.fir.kt @@ -9,7 +9,7 @@ fun f(): Unit { x + 1 x plus 1 x < 1 - x += 1 + x += 1 x == 1 x != 1 diff --git a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt index 278ab1000ca..38f66e13e72 100644 --- a/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt +++ b/compiler/testData/diagnostics/tests/FunctionCalleeExpressions.fir.kt @@ -28,20 +28,20 @@ fun fooT2() : (t : T) -> T { fun main(args : Array) { args.foo()() - args.foo1()() - a.foo1()() + args.foo1()() + a.foo1()() a.foo1()(a) args.foo1()(1) - args.foo1()("1") - a.foo1()("1") + args.foo1()("1") + a.foo1()("1") a.foo1()(a) foo2()({}) foo2(){} (foo2()){} (foo2()){x -> } - foo2()({x -> }) + foo2()({x -> }) val a = fooT1(1)() checkSubtype(a) @@ -58,13 +58,13 @@ fun main(args : Array) { fun f() : Int.() -> Unit = {} fun main1() { - 1.(fun Int.() = 1)(); + 1.(fun Int.() = 1)(); {1}(); (fun (x : Int) = x)(1) - 1.(fun Int.(x : Int) = x)(1); + 1.(fun Int.(x : Int) = x)(1); l@{1}() - 1.((fun Int.() = 1))() - 1.(f())() + 1.((fun Int.() = 1))() + 1.(f())() 1.if(true){f()}else{f()}() 1.if(true)(fun Int.() {})else{f()}() @@ -78,10 +78,10 @@ fun main1() { fun test() { {x : Int -> 1}(); (fun Int.() = 1)() - "sd".(fun Int.() = 1)() + "sd".(fun Int.() = 1)() val i : Int? = null - i.(fun Int.() = 1)(); + i.(fun Int.() = 1)(); {}() - 1?.(fun Int.() = 1)() + 1?.(fun Int.() = 1)() 1.{}() } diff --git a/compiler/testData/diagnostics/tests/callableReference/compatibilityResolveWithVarargAndOperatorCall.fir.kt b/compiler/testData/diagnostics/tests/callableReference/compatibilityResolveWithVarargAndOperatorCall.fir.kt index f9b72970cea..8f47952580e 100644 --- a/compiler/testData/diagnostics/tests/callableReference/compatibilityResolveWithVarargAndOperatorCall.fir.kt +++ b/compiler/testData/diagnostics/tests/callableReference/compatibilityResolveWithVarargAndOperatorCall.fir.kt @@ -14,5 +14,5 @@ operator fun A.set(i: IFoo, newValue: Int) {} fun withVararg(vararg xs: Int) = 42 fun test1() { - A[::withVararg] += 1 -} \ No newline at end of file + A[::withVararg] += 1 +} diff --git a/compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.fir.kt index 7ad3ec07b8b..501a6e79e7c 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/namedFunAsLastExpressionInBlock.fir.kt @@ -45,7 +45,7 @@ fun test() { x4 checkType { _>() } { y: Int -> fun named14(): Int {return 1} } - val b = (fun named15(): Boolean { return true })() + val b = (fun named15(): Boolean { return true })() baz(fun named16(){}) } diff --git a/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.fir.kt b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.fir.kt index 0923425dd69..863bd73eb40 100644 --- a/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.fir.kt +++ b/compiler/testData/diagnostics/tests/enum/constructorWithDefaultParametersOnly.fir.kt @@ -18,4 +18,4 @@ enum class TestMultipleConstructors(val x: String = "", val y: Int = 0) { enum class TestVarargs(val x: Int) { TEST; constructor(vararg xs: Any) : this(xs.size) -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt index 5e36f04c40f..cf9e93659a0 100644 --- a/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt +++ b/compiler/testData/diagnostics/tests/extensions/throwOutCandidatesByReceiver.fir.kt @@ -35,7 +35,7 @@ fun test4() { // should be an error on receiver, shouldn't be thrown away fun test5() { - 1.(fun String.()=1)() + 1.(fun String.()=1)() } fun R?.sure() : R = this!! diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.fir.kt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.fir.kt index 85ce9597a68..8111b18415b 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.fir.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.fir.kt @@ -1,9 +1,9 @@ // !WITH_NEW_INFERENCE val receiver = { Int.() -> } -val receiverWithParameter = { Int.(a) -> } +val receiverWithParameter = { Int.(a) -> } val receiverAndReturnType = { Int.(): Int -> 5 } -val receiverAndReturnTypeWithParameter = { Int.(a: Int): Int -> 5 } +val receiverAndReturnTypeWithParameter = { Int.(a: Int): Int -> 5 } val returnType = { (): Int -> 5 } val returnTypeWithParameter = { (b: Int): Int -> 5 } diff --git a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.fir.kt b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.fir.kt index 859e1d1b28f..7dcf7de4b6f 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.fir.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/diagnosticWithSyntaxError/noTypeParamsInReturnType.fir.kt @@ -8,4 +8,3 @@ fun getMap() : Map = throw Exception() fun bar123() { foo(getMap( } - diff --git a/compiler/testData/diagnostics/tests/incompleteCode/inExpr.fir.kt b/compiler/testData/diagnostics/tests/incompleteCode/inExpr.fir.kt index e53e01564df..0e31891284e 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/inExpr.fir.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/inExpr.fir.kt @@ -2,4 +2,4 @@ package l fun test(a: Int) { if (a in ) {} //a is not unresolved -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/incompleteCode/inExpr.kt b/compiler/testData/diagnostics/tests/incompleteCode/inExpr.kt index c40646cbb25..2645d815631 100644 --- a/compiler/testData/diagnostics/tests/incompleteCode/inExpr.kt +++ b/compiler/testData/diagnostics/tests/incompleteCode/inExpr.kt @@ -2,4 +2,4 @@ package l fun test(a: Int) { if (a in ) {} //a is not unresolved -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.fir.kt b/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.fir.kt index 1076a1809f3..2e168387680 100644 --- a/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/classesInClassObjectHeader.fir.kt @@ -8,4 +8,4 @@ class Test { open class StaticClass open inner class InnerClass -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/inner/modality.fir.kt b/compiler/testData/diagnostics/tests/inner/modality.fir.kt index 720c5f95c83..e5f9277c709 100644 --- a/compiler/testData/diagnostics/tests/inner/modality.fir.kt +++ b/compiler/testData/diagnostics/tests/inner/modality.fir.kt @@ -14,4 +14,4 @@ class Outer { inner class Inner2 : FinalNested() inner class Inner3 : OpenInner() inner class Inner4 : FinalInner() -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/kt435.fir.kt b/compiler/testData/diagnostics/tests/kt435.fir.kt index c24f1f89f78..5ec15398cd4 100644 --- a/compiler/testData/diagnostics/tests/kt435.fir.kt +++ b/compiler/testData/diagnostics/tests/kt435.fir.kt @@ -3,5 +3,5 @@ fun Any.foo1() : (i : Int) -> Unit { } fun test(a : Any) { - a.foo1()() -} \ No newline at end of file + a.foo1()() +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/DeprecatedModAssignOperatorConventions.fir.kt b/compiler/testData/diagnostics/tests/operatorRem/DeprecatedModAssignOperatorConventions.fir.kt index 8dbd3ff4ab0..f64bd1bdf0d 100644 --- a/compiler/testData/diagnostics/tests/operatorRem/DeprecatedModAssignOperatorConventions.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorRem/DeprecatedModAssignOperatorConventions.fir.kt @@ -30,7 +30,7 @@ fun test() { oldAndNew %= 1 val onlyOld = OnlyOld() - onlyOld %= 1 + onlyOld %= 1 val onlyNew = OnlyNew() onlyNew %= 1 @@ -40,4 +40,4 @@ fun test() { var modAndRemAssign = ModAndRemAssign() modAndRemAssign %= 1 -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.fir.kt b/compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.fir.kt index 1b7ad2ad8af..842be5c2e1c 100644 --- a/compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorRem/forbiddenModOperatorConvention.fir.kt @@ -27,6 +27,6 @@ fun foo() { r.remAssign(1) val m = JustMod - m %= 1 + m %= 1 m.modAssign(1) -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/operatorRem/resolveToModWhenNoOperatorRemFeature.fir.kt b/compiler/testData/diagnostics/tests/operatorRem/resolveToModWhenNoOperatorRemFeature.fir.kt index 1877165b621..1d608206b05 100644 --- a/compiler/testData/diagnostics/tests/operatorRem/resolveToModWhenNoOperatorRemFeature.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorRem/resolveToModWhenNoOperatorRemFeature.fir.kt @@ -25,7 +25,7 @@ fun test() { takeInt(ModAndRem % 1) val c = ModAssignAndRemAssign - c %= "" + c %= "" var c1 = RemAndModAssign c1 %= 1 @@ -36,4 +36,4 @@ fun test() { c2 %= 1 } -fun takeInt(x: Int) {} \ No newline at end of file +fun takeInt(x: Int) {} diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/InconsistentGetSet.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/InconsistentGetSet.fir.kt index dcd7b5368ec..5933e9a4041 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/InconsistentGetSet.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/InconsistentGetSet.fir.kt @@ -20,7 +20,7 @@ object MismatchingTypes { fun testMismatchingTypes() { ++MismatchingTypes[0] MismatchingTypes[0]++ - MismatchingTypes[0] += 1 + MismatchingTypes[0] += 1 } object MismatchingArities1 { @@ -36,10 +36,9 @@ object MismatchingArities2 { fun testMismatchingArities() { ++MismatchingArities1[0] MismatchingArities1[0]++ - MismatchingArities1[0] += 1 + MismatchingArities1[0] += 1 ++MismatchingArities2[0] MismatchingArities2[0]++ - MismatchingArities2[0] += 1 + MismatchingArities2[0] += 1 } - diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt index 9884f34c1a1..6f622c7bf2c 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/assignmentOperationsCheckReturnType.fir.kt @@ -1,12 +1,12 @@ fun intBinEq() { var x = 0 - x += 'a' + x += 'a' x += 1.toByte() x += 1.toShort() x += 1L x += 1f x += 1.0 - x *= 'a' + x *= 'a' x *= 1.toByte() x *= 1.toShort() x *= 1L @@ -16,14 +16,14 @@ fun intBinEq() { fun shortBinEq() { var x = 0.toShort() - x += 'a' + x += 'a' x += 1.toByte() x += 1.toShort() x += 1L x += 1f x += 1.0 - x *= 'a' + x *= 'a' x *= 1.toByte() x *= 1.toShort() x *= 1L diff --git a/compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnArray.fir.kt b/compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnArray.fir.kt index bf4edbd5427..288139fe2c2 100644 --- a/compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnArray.fir.kt +++ b/compiler/testData/diagnostics/tests/operatorsOverloading/plusAssignOnArray.fir.kt @@ -16,5 +16,5 @@ fun test() { val c = C() c[0] += "" var c1 = C1() - c1[0] += "" -} \ No newline at end of file + c1[0] += "" +} diff --git a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/delegatedProperties.fir.kt b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/delegatedProperties.fir.kt index c7009ad980b..14ab7e5b685 100644 --- a/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/delegatedProperties.fir.kt +++ b/compiler/testData/diagnostics/tests/platformTypes/nullabilityWarnings/delegatedProperties.fir.kt @@ -19,5 +19,5 @@ public class J { // FILE: k.kt var A by J.staticNN -var B by J.staticN -var C by J.staticJ \ No newline at end of file +var B by J.staticN +var C by J.staticJ diff --git a/compiler/testData/diagnostics/tests/qualifiedExpression/calleeExpressionAsCallExpression.fir.kt b/compiler/testData/diagnostics/tests/qualifiedExpression/calleeExpressionAsCallExpression.fir.kt index 5bc68c265e7..77afc514e0c 100644 --- a/compiler/testData/diagnostics/tests/qualifiedExpression/calleeExpressionAsCallExpression.fir.kt +++ b/compiler/testData/diagnostics/tests/qualifiedExpression/calleeExpressionAsCallExpression.fir.kt @@ -1,2 +1,2 @@ // !WITH_NEW_INFERENCE -val unwrapped = some<sdf()()::unwrap +val unwrapped = some<sdf()()::unwrap diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt index e02acf7781b..68c4faece55 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/receiverPresenceErrorForInvoke.fir.kt @@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) { fun test2(f: (Int) -> Int) { 1.f(2) - 2.(f)(2) -} \ No newline at end of file + 2.(f)(2) +} diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt index 5a3559b9135..b92866a8c13 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/errors/wrongReceiverForInvokeOnExpression.fir.kt @@ -1,17 +1,17 @@ // !WITH_NEW_INFERENCE fun test1() { - 1. (fun String.(i: Int) = i )(1) - 1.(label@ fun String.(i: Int) = i )(1) + 1. (fun String.(i: Int) = i )(1) + 1.(label@ fun String.(i: Int) = i )(1) } fun test2(f: String.(Int) -> Unit) { - 11.(f)(1) - 11.(f)() + 11.(f)(1) + 11.(f)() } fun test3() { fun foo(): String.(Int) -> Unit = {} - 1.(foo())(1) + 1.(foo())(1) } diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt index 8af8d45ccec..a95ec3b4fd2 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/invokeAndSmartCast.fir.kt @@ -2,11 +2,11 @@ class A(val x: (String.() -> Unit)?) fun test(a: A) { if (a.x != null) { - "".(a.x)() + "".(a.x)() a.x("") // todo (a.x)("") } - "".(a.x)() + "".(a.x)() a.x("") (a.x)("") diff --git a/compiler/testData/diagnostics/tests/resolve/invoke/invokeOnVariableWithExtensionFunctionType.fir.kt b/compiler/testData/diagnostics/tests/resolve/invoke/invokeOnVariableWithExtensionFunctionType.fir.kt index 2ee6ca48bc2..cd0235c4b5e 100644 --- a/compiler/testData/diagnostics/tests/resolve/invoke/invokeOnVariableWithExtensionFunctionType.fir.kt +++ b/compiler/testData/diagnostics/tests/resolve/invoke/invokeOnVariableWithExtensionFunctionType.fir.kt @@ -8,7 +8,7 @@ class B val A.foo: B.() -> Unit get() = {} fun test(a: A, b: B) { - b.(a.foo)() + b.(a.foo)() (a.foo)(b) a.foo(b) @@ -25,7 +25,7 @@ fun test(a: A, b: B) { with(b) { a.foo() - a.(foo)() + a.(foo)() (a.foo)() @@ -50,7 +50,7 @@ class A { class B fun test(a: A, b: B) { - b.(a.foo)() + b.(a.foo)() (a.foo)(b) a.foo(b) @@ -59,7 +59,7 @@ fun test(a: A, b: B) { b.(foo)() - (b.foo)() + (b.foo)() foo(b) (foo)(b) @@ -67,7 +67,7 @@ fun test(a: A, b: B) { with(b) { a.foo() - a.(foo)() + a.(foo)() (a.foo)() diff --git a/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt b/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt index 7addcc32b87..d900c519e42 100644 --- a/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt +++ b/compiler/testData/diagnostics/tests/smartCasts/alwaysNull.fir.kt @@ -8,7 +8,7 @@ fun foo(): String { var t: String? = "y" if (t == null) t = "x" var x: Int? = null - if (x == null) x += null + if (x == null) x += null return t + s } diff --git a/compiler/testData/diagnostics/tests/traitWithRequired/traitSupertypeList.fir.kt b/compiler/testData/diagnostics/tests/traitWithRequired/traitSupertypeList.fir.kt index abca9fd22b6..c38b13da824 100644 --- a/compiler/testData/diagnostics/tests/traitWithRequired/traitSupertypeList.fir.kt +++ b/compiler/testData/diagnostics/tests/traitWithRequired/traitSupertypeList.fir.kt @@ -7,4 +7,4 @@ interface Foo2 : bar, Foo { } open class Foo1() : bar(), bar, Foo, Foo() {} -open class Foo12 : bar(), bar {} \ No newline at end of file +open class Foo12 : bar(), bar {} diff --git a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/plusAssignWithLambda.fir.kt b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/plusAssignWithLambda.fir.kt index 89e50eaa83a..6a393ec0908 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/plusAssignWithLambda.fir.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/coroutines/inference/plusAssignWithLambda.fir.kt @@ -26,7 +26,7 @@ fun id(x: T) = x fun foo2() = { var x = A() - x += { "" } + x += { "" } var y = A() y += 1 } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-named-parameters/p-1/pos/2.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-named-parameters/p-1/pos/2.1.fir.kt index 476e7e2e0c2..9638d5570bf 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-named-parameters/p-1/pos/2.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-named-parameters/p-1/pos/2.1.fir.kt @@ -63,7 +63,7 @@ fun case3() { */ fun case4(marker : Marker?) { marker?.foo(y=1) - marker?.foo(x=1)> + marker?.foo(x=1)> } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-trailing-lambda-expressions/p-1/pos/2.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-trailing-lambda-expressions/p-1/pos/2.1.fir.kt index 5f9b80e065f..ccf3ed12d65 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-trailing-lambda-expressions/p-1/pos/2.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/call-with-trailing-lambda-expressions/p-1/pos/2.1.fir.kt @@ -63,7 +63,7 @@ fun case3() { */ fun case4(marker: Marker?) { marker?.foo(y = { 1 }) - marker?.foo(x = { 1 })> + marker?.foo(x = { 1 })> } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.4.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.4.fir.kt index b23bb9fedf4..f2a664e306e 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.4.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.4.fir.kt @@ -26,9 +26,9 @@ import LibPackCase1.b.* fun case1 (){ var b: B? = B() - b += { C() } + b += { C() } - b += {1} + b += {1} } class B { @@ -63,9 +63,9 @@ import LibPackCase2.b.* fun case2 (){ var b: B = B() - b += { C() } + b += { C() } - b += {1} + b += {1} } class B { diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.5.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.5.fir.kt index 5dcc3461f9d..7dd153b55a1 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.5.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.5.fir.kt @@ -10,9 +10,9 @@ import LibPackCase1.a.* import LibPackCase1.b.* fun case1 (){ var b: B? = null - b += { C() } + b += { C() } - b += {1} + b += {1} } class B { diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.6.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.6.fir.kt index 4434928a706..d2ba79f7ee0 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.6.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.6.fir.kt @@ -15,9 +15,9 @@ import LibPackCase1.b.* fun case1 (){ var b: B? = B() - b += { C() } + b += { C() } - b += {1} + b += {1} } class B { diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.7.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.7.fir.kt index 650626deefb..84b91dc6529 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.7.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.7.fir.kt @@ -15,9 +15,9 @@ import LibPackCase1.b.plusAssign fun case1 (){ var b: B? = B() - b += { C() } + b += { C() } - b += {1} + b += {1} } class B { diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.8.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.8.fir.kt index b57c07ce3ad..5df10ae0ab8 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.8.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/building-the-overload-candidate-set-ocs/operator-call/p-1/neg/2.8.fir.kt @@ -15,8 +15,8 @@ import LibPackCase1.b.plusAssign fun case1 (){ var b: B = B() - b +={ C() } - b +={ 1 } + b +={ C() } + b +={ 1 } } class B @@ -48,8 +48,8 @@ import LibPackCase2.b.plusAssign fun case2 (){ var b: B = B() - b +={ C() } - b +={ 1 } + b +={ C() } + b +={ 1 } b.plusAssign{ C() } } diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.1.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.1.fir.kt index 7df09612c75..66968f0590a 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.1.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.1.fir.kt @@ -17,7 +17,7 @@ operator fun I2.invoke(): String = TODO() fun case1(a: A) { a.invoke() a() - A()() + A()() } // FILE: TestCase2.kt diff --git a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.2.fir.kt b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.2.fir.kt index 9b65fd3866a..1e3365503c0 100644 --- a/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.2.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/linked/overload-resolution/choosing-the-most-specific-candidate-from-the-overload-candidate-set/algorithm-of-msc-selection/p-17/neg/2.2.fir.kt @@ -17,7 +17,7 @@ operator fun I2.invoke(): String = TODO() fun case1(a: A) { a.invoke() a() - A()() + A()() } // FILE: TestCase2.kt diff --git a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt index 6855de1205a..69eed526113 100644 --- a/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt +++ b/compiler/tests-spec/testData/diagnostics/notLinked/dfa/neg/12.fir.kt @@ -6,7 +6,7 @@ fun case_1() { var x: Int? = 11 x!! - try {x = null;} finally { x += 10; } + try {x = null;} finally { x += 10; } } // TESTCASE NUMBER: 2 diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt index c484ad3538f..95d4bc6933c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirAnalysisSessionComponent.kt @@ -30,8 +30,8 @@ internal interface KtFirAnalysisSessionComponent { fun FirPsiDiagnostic<*>.asKtDiagnostic(): KtDiagnosticWithPsi<*> = KT_DIAGNOSTIC_CONVERTER.convert(analysisSession, this as FirDiagnostic<*>) - fun ConeDiagnostic.asKtDiagnostic(source: FirSourceElement): KtDiagnosticWithPsi<*>? { - val firDiagnostic = toFirDiagnostics(source).firstOrNull() ?: return null + fun ConeDiagnostic.asKtDiagnostic(source: FirSourceElement, qualifiedAccessSource: FirSourceElement?): KtDiagnosticWithPsi<*>? { + val firDiagnostic = toFirDiagnostics(source, qualifiedAccessSource).firstOrNull() ?: return null check(firDiagnostic is FirPsiDiagnostic<*>) return firDiagnostic.asKtDiagnostic() } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt index 8a8f1a2d2df..506b75df3b0 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import org.jetbrains.kotlin.builtins.StandardNames +import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.expressions.FirFunctionCall import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression import org.jetbrains.kotlin.fir.expressions.FirSafeCallExpression @@ -85,7 +86,7 @@ internal class KtFirCallResolver( } is FirErrorNamedReference -> KtVariableWithInvokeFunctionCall( variableLikeSymbol, - callReference.createErrorCallTarget() + callReference.createErrorCallTarget(source) ) else -> error("Unexpected call reference ${callReference::class.simpleName}") } @@ -93,8 +94,8 @@ internal class KtFirCallResolver( private fun FirFunctionCall.asSimpleFunctionCall(): KtFunctionCall? { val target = when (val calleeReference = calleeReference) { is FirResolvedNamedReference -> calleeReference.getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) } - is FirErrorNamedReference -> calleeReference.createErrorCallTarget() - is FirErrorReferenceWithCandidate -> calleeReference.createErrorCallTarget() + is FirErrorNamedReference -> calleeReference.createErrorCallTarget(source) + is FirErrorReferenceWithCandidate -> calleeReference.createErrorCallTarget(source) is FirSimpleNamedReference -> error( """ @@ -109,16 +110,16 @@ internal class KtFirCallResolver( return KtFunctionCall(target) } - private fun FirErrorNamedReference.createErrorCallTarget(): KtErrorCallTarget = + private fun FirErrorNamedReference.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget = KtErrorCallTarget( getCandidateSymbols().mapNotNull { it.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol }, - source?.let { diagnostic.asKtDiagnostic(it) } ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token) + source?.let { diagnostic.asKtDiagnostic(it, qualifiedAccessSource) } ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token) ) - private fun FirErrorReferenceWithCandidate.createErrorCallTarget(): KtErrorCallTarget = + private fun FirErrorReferenceWithCandidate.createErrorCallTarget(qualifiedAccessSource: FirSourceElement?): KtErrorCallTarget = KtErrorCallTarget( getCandidateSymbols().mapNotNull { it.fir.buildSymbol(firSymbolBuilder) as? KtFunctionLikeSymbol }, - source?.let { diagnostic.asKtDiagnostic(it) } ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token) + source?.let { diagnostic.asKtDiagnostic(it,qualifiedAccessSource) } ?: KtNonBoundToPsiErrorDiagnostic(factoryName = null, diagnostic.reason, token) ) private fun FirResolvedNamedReference.getKtFunctionOrConstructorSymbol(): KtFunctionLikeSymbol? =