FIR: pass the qualified access source when reporting ErrorNamedReference

Currently if there is an error in a function call, FIR would report the
entire expression if this call is qualified, but *only* the name if it's
not qualified. For example, assume the following two calls are all
contains some errors.

```
a.foo(1,2,3)
^^^^^^^^^^^^
bar(1,2,3)
^^^
```

The entire call of `foo` is reported since it's qualified. But only the
reference `bar` is reported since it's not qualified. This limits the
usage of position strategies because the IDE does not allow position
strategies to go outside of the initially reported PSI element
(org.jetbrains.kotlin.idea.fir.highlighter.KotlinHighLevelDiagnosticHighlightingPass#addDiagnostic).

This change passes both the original error named reference and the
surrounding qualified access expression and defer the decision of which
to use to the reporting logic.

For unresolved reference and checks on `super` keyword, the position
strategy should not highlight the surrounding parentheses. Hence a new
position strategy `REFERENCED_NAME_BY_QUALIFIED` is added.

In addition, this change also has the following side effect

* some diagnostics are no longer reported when there is a syntax error
  since the higher level structure does not exist when there is a syntax
  error
This commit is contained in:
Tianyu Geng
2021-03-07 16:10:29 -08:00
committed by Dmitriy Novozhilov
parent 8805675539
commit d6907222cd
53 changed files with 247 additions and 155 deletions
@@ -28,9 +28,9 @@ fun test_2(a: A<C>) {
}
fun test_3(a: A<D>) {
<!AMBIGUITY!>a[0] += D()<!> // ambiguity
a[0] <!AMBIGUITY!>+=<!> D() // ambiguity
}
fun test_4(b: B) {
<!UNRESOLVED_REFERENCE!>b<!NO_GET_METHOD!>[0]<!> += B()<!> // unresolved
b<!NO_GET_METHOD!>[0]<!> <!UNRESOLVED_REFERENCE!>+=<!> B() // unresolved
}
@@ -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() = <!NONE_APPLICABLE{LT}!>abc() <!NONE_APPLICABLE{PSI}!>+<!> bar()<!>
fun Foo.check() = abc() <!NONE_APPLICABLE!>+<!> bar()
// NB! + here is resolved to member String.plus (not to extension member above)
fun Foo.check2() = "" + bar()
@@ -7,7 +7,7 @@ class Foo {
fun test_1() {
val f = Foo()
<!UNRESOLVED_REFERENCE{LT}!>f <!UNRESOLVED_REFERENCE{PSI}!>+<!> f<!>
f <!UNRESOLVED_REFERENCE!>+<!> f
}
fun test_2() {
@@ -19,5 +19,5 @@ abstract class A {
// FILE: main.kt
fun test(b: B): String {
return <!HIDDEN{LT}!>b <!HIDDEN{PSI}!>foo<!> "hello"<!> // should be an error
return b <!HIDDEN!>foo<!> "hello" // should be an error
}
@@ -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,
@@ -67,7 +67,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val HIDDEN by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<AbstractFirBasedSymbol<*>>("hidden")
}
val UNRESOLVED_REFERENCE by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
val UNRESOLVED_REFERENCE by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) {
parameter<String>("reference")
}
val UNRESOLVED_LABEL by error<FirSourceElement, PsiElement>()
@@ -79,9 +79,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
}
val SUPER by object : DiagnosticGroup("Super") {
val SUPER_IS_NOT_AN_EXPRESSION by error<FirSourceElement, PsiElement>()
val SUPER_NOT_AVAILABLE by error<FirSourceElement, PsiElement>()
val ABSTRACT_SUPER_CALL by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED)
val SUPER_IS_NOT_AN_EXPRESSION by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val SUPER_NOT_AVAILABLE by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val ABSTRACT_SUPER_CALL by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error<FirSourceElement, PsiElement> {
parameter<String>("target")
}
@@ -497,12 +497,12 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val UNSAFE_IMPLICIT_INVOKE_CALL by error<FirSourceElement, PsiElement>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<ConeKotlinType>("receiverType")
}
val UNSAFE_INFIX_CALL by error<FirSourceElement, KtExpression> {
val UNSAFE_INFIX_CALL by error<FirSourceElement, KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<FirExpression>("lhs")
parameter<String>("operator")
parameter<FirExpression>("rhs")
}
val UNSAFE_OPERATOR_CALL by error<FirSourceElement, KtExpression> {
val UNSAFE_OPERATOR_CALL by error<FirSourceElement, KtExpression>(PositioningStrategy.REFERENCE_BY_QUALIFIED) {
parameter<FirExpression>("lhs")
parameter<String>("operator")
parameter<FirExpression>("rhs")
@@ -77,7 +77,7 @@ object FirErrors {
// Unresolved
val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNRESOLVED_REFERENCE by error1<FirSourceElement, PsiElement, String>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNRESOLVED_REFERENCE by error1<FirSourceElement, PsiElement, String>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val UNRESOLVED_LABEL by error0<FirSourceElement, PsiElement>()
val DESERIALIZATION_ERROR by error0<FirSourceElement, PsiElement>()
val ERROR_FROM_JAVA_RESOLUTION by error0<FirSourceElement, PsiElement>()
@@ -86,9 +86,9 @@ object FirErrors {
val NO_THIS by error0<FirSourceElement, PsiElement>()
// Super
val SUPER_IS_NOT_AN_EXPRESSION by error0<FirSourceElement, PsiElement>()
val SUPER_NOT_AVAILABLE by error0<FirSourceElement, PsiElement>()
val ABSTRACT_SUPER_CALL by error0<FirSourceElement, PsiElement>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val SUPER_IS_NOT_AN_EXPRESSION by error0<FirSourceElement, PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val SUPER_NOT_AVAILABLE by error0<FirSourceElement, PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val ABSTRACT_SUPER_CALL by error0<FirSourceElement, PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val INSTANCE_ACCESS_BEFORE_SUPER_CALL by error1<FirSourceElement, PsiElement, String>()
// Supertypes
@@ -303,8 +303,8 @@ object FirErrors {
// Nullability
val UNSAFE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.DOT_BY_QUALIFIED)
val UNSAFE_IMPLICIT_INVOKE_CALL by error1<FirSourceElement, PsiElement, ConeKotlinType>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNSAFE_INFIX_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>()
val UNSAFE_OPERATOR_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>()
val UNSAFE_INFIX_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
val UNSAFE_OPERATOR_CALL by error3<FirSourceElement, KtExpression, FirExpression, String, FirExpression>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
// When expressions
val NO_ELSE_IN_WHEN by error1<FirSourceElement, KtWhenExpression, List<WhenMissingCase>>(SourceElementPositioningStrategies.WHEN_EXPRESSION)
@@ -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)
}
}
@@ -343,10 +343,11 @@ object LightTreePositioningStrategies {
endOffset: Int,
tree: FlyweightCapableTreeStructure<LighterASTNode>
): List<TextRange> {
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<LighterASTNode>
): List<TextRange> {
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<LighterASTNode>.nameIdentifier(node: L
private fun FlyweightCapableTreeStructure<LighterASTNode>.operationReference(node: LighterASTNode): LighterASTNode? =
findChildByType(node, KtNodeTypes.OPERATION_REFERENCE)
private fun FlyweightCapableTreeStructure<LighterASTNode>.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<LighterASTNode>.referenceExpression(
node: LighterASTNode,
locateReferencedName: Boolean
): LighterASTNode? {
val childrenRef = Ref<Array<LighterASTNode?>>()
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<LighterASTNode>.rightParenthesis(node: LighterASTNode): LighterASTNode? =
@@ -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
@@ -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<FirSourceElement>? = when (this) {
private fun ConeDiagnostic.toFirDiagnostic(
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?
): FirDiagnostic<FirSourceElement>? = when (this) {
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.name?.asString() ?: "<No name>")
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<FirDiagnostic<FirSourceElement>> {
fun ConeDiagnostic.toFirDiagnostics(
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?
): List<FirDiagnostic<FirSourceElement>> {
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<FirDiagnostic<FirSourceElement>> {
// 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
@@ -45,7 +45,7 @@ internal fun KtWhenCondition.toFirWhenCondition(
firRange.generateContainsOperation(
firSubjectExpression,
isNegated,
rangeExpression?.toFirPsiSourceElement(FirFakeSourceElementKind.WhenCondition),
this@toFirWhenCondition.toFirPsiSourceElement(FirFakeSourceElementKind.WhenCondition),
operationReference.toFirPsiSourceElement()
)
}
@@ -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<PsiElement> = object : PositioningStrategy<PsiElement>() {
val REFERENCE_BY_QUALIFIED: PositioningStrategy<PsiElement> = FindReferencePositioningStrategy(false)
val REFERENCED_NAME_BY_QUALIFIED: PositioningStrategy<PsiElement> = 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<PsiElement>() {
override fun mark(element: PsiElement): List<TextRange> {
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)
}
}
}
@@ -9,7 +9,7 @@ fun f(): Unit {
x <!NONE_APPLICABLE!>+<!> 1
x <!NONE_APPLICABLE!>plus<!> 1
x <!NONE_APPLICABLE!><<!> 1
<!UNRESOLVED_REFERENCE!>x += 1<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 1
x == 1
x != 1
@@ -28,20 +28,20 @@ fun <T> fooT2() : (t : T) -> T {
fun main(args : Array<String>) {
args.foo()()
args.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
<!UNRESOLVED_REFERENCE!>a<!>.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
<!INAPPLICABLE_CANDIDATE!>args.foo1()<!>()
<!INAPPLICABLE_CANDIDATE!><!UNRESOLVED_REFERENCE!>a<!>.foo1()<!>()
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
args.foo1()(1)
args.<!INAPPLICABLE_CANDIDATE!>foo1<!>()("1")
<!UNRESOLVED_REFERENCE!>a<!>.<!INAPPLICABLE_CANDIDATE!>foo1<!>()("1")
<!INAPPLICABLE_CANDIDATE!>args.foo1()<!>("1")
<!INAPPLICABLE_CANDIDATE!><!UNRESOLVED_REFERENCE!>a<!>.foo1()<!>("1")
<!UNRESOLVED_REFERENCE!>a<!>.foo1()(<!UNRESOLVED_REFERENCE!>a<!>)
foo2()({})
<!INAPPLICABLE_CANDIDATE!>foo2<!>(){}
(foo2()){}
<!INAPPLICABLE_CANDIDATE!>(foo2())<!>{x -> }
<!INAPPLICABLE_CANDIDATE!>foo2<!>()({x -> })
<!INAPPLICABLE_CANDIDATE!>foo2()<!>({x -> })
val a = fooT1(1)()
checkSubtype<Int>(a)
@@ -58,13 +58,13 @@ fun main(args : Array<String>) {
fun f() : Int.() -> Unit = {}
fun main1() {
1.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>();
1.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)();
{1}();
(fun (x : Int) = x)(1)
1.<!UNRESOLVED_REFERENCE!>(fun Int.(x : Int) = x)<!>(1);
1.(<!UNRESOLVED_REFERENCE!>fun Int.(x : Int) = x<!>)(1);
l@{1}()
1.<!UNRESOLVED_REFERENCE!>((fun Int.() = 1))<!>()
1.<!UNRESOLVED_REFERENCE!>(f())<!>()
1.((<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>))()
1.(<!UNRESOLVED_REFERENCE!>f()<!>)()
1.<!UNRESOLVED_REFERENCE!>if(true){f()}else{f()}<!>()
1.<!UNRESOLVED_REFERENCE!>if(true)(fun Int.() {})else{f()}<!>()
@@ -78,10 +78,10 @@ fun main1() {
fun test() {
<!INAPPLICABLE_CANDIDATE!>{x : Int -> 1}<!>();
<!INAPPLICABLE_CANDIDATE!>(fun Int.() = 1)<!>()
"sd".<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>()
"sd".(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)()
val i : Int? = null
i.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>();
i.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)();
<!INAPPLICABLE_CANDIDATE!>{}<!><Int>()
1?.<!UNRESOLVED_REFERENCE!>(fun Int.() = 1)<!>()
1?.(<!UNRESOLVED_REFERENCE!>fun Int.() = 1<!>)()
1.<!UNRESOLVED_REFERENCE!>{}<!>()
}
@@ -14,5 +14,5 @@ operator fun A.set(i: IFoo, newValue: Int) {}
fun withVararg(vararg xs: Int) = 42
fun test1() {
<!UNRESOLVED_REFERENCE!>A[::withVararg] += 1<!>
}
A[::withVararg] <!UNRESOLVED_REFERENCE!>+=<!> 1
}
@@ -45,7 +45,7 @@ fun test() {
x4 checkType { _<Function1<Int, Unit>>() }
{ y: Int -> fun named14(): Int {return 1} }
val b = <!UNRESOLVED_REFERENCE!>(<!EXPRESSION_REQUIRED!>fun named15(): Boolean { return true }<!>)<!>()
val b = (<!EXPRESSION_REQUIRED, UNRESOLVED_REFERENCE!>fun named15(): Boolean { return true }<!>)()
baz(<!EXPRESSION_REQUIRED!>fun named16(){}<!>)
}
@@ -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)
}
}
@@ -35,7 +35,7 @@ fun test4() {
// should be an error on receiver, shouldn't be thrown away
fun test5() {
1.<!UNRESOLVED_REFERENCE!>(fun String.()=1)<!>()
1.(<!UNRESOLVED_REFERENCE!>fun String.()=1<!>)()
}
fun <R: Any> R?.sure() : R = this!!
@@ -1,9 +1,9 @@
// !WITH_NEW_INFERENCE
val receiver = { Int.(<!SYNTAX!><!>) <!SYNTAX!>-><!> }
val receiverWithParameter = { <!UNRESOLVED_REFERENCE!>Int.(a)<!> <!SYNTAX!>-><!> }
val receiverWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!>) <!SYNTAX!>-><!> }
val receiverAndReturnType = { Int.(<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
val receiverAndReturnTypeWithParameter = { Int.(a<!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
val receiverAndReturnTypeWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
val returnType = { (<!SYNTAX!><!>): Int -> 5 }
val returnTypeWithParameter = { <!COMPONENT_FUNCTION_MISSING!>(b: Int): Int<!> -> 5 }
@@ -8,4 +8,3 @@ fun <F, G> getMap() : Map<F, G> = throw Exception()
fun bar123() {
foo(<!INAPPLICABLE_CANDIDATE!>getMap<!>(
<!SYNTAX!><!>}
@@ -2,4 +2,4 @@ package l
fun test(a: Int) {
if (a <!UNRESOLVED_REFERENCE!>in<!><!SYNTAX!><!> ) {} //a is not unresolved
}
}
@@ -2,4 +2,4 @@ package l
fun test(a: Int) {
if (a in<!SYNTAX!><!> ) {} //a is not unresolved
}
}
@@ -8,4 +8,4 @@ class Test {
open class StaticClass
open inner class InnerClass
}
}
+1 -1
View File
@@ -14,4 +14,4 @@ class Outer {
inner class Inner2 : FinalNested()
inner class Inner3 : OpenInner()
inner class Inner4 : FinalInner()
}
}
+2 -2
View File
@@ -3,5 +3,5 @@ fun Any.foo1() : (i : Int) -> Unit {
}
fun test(a : Any) {
a.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
}
<!INAPPLICABLE_CANDIDATE!>a.foo1()<!>()
}
@@ -30,7 +30,7 @@ fun test() {
oldAndNew %= 1
val onlyOld = OnlyOld()
<!INAPPLICABLE_CANDIDATE!>onlyOld %= 1<!>
onlyOld <!INAPPLICABLE_CANDIDATE!>%=<!> 1
val onlyNew = OnlyNew()
onlyNew %= 1
@@ -40,4 +40,4 @@ fun test() {
var modAndRemAssign = ModAndRemAssign()
modAndRemAssign %= 1
}
}
@@ -27,6 +27,6 @@ fun foo() {
r.remAssign(1)
val m = JustMod
<!UNRESOLVED_REFERENCE!>m %= 1<!>
m <!UNRESOLVED_REFERENCE!>%=<!> 1
m.modAssign(1)
}
}
@@ -25,7 +25,7 @@ fun test() {
<!INAPPLICABLE_CANDIDATE!>takeInt<!>(ModAndRem % 1)
val c = ModAssignAndRemAssign
<!INAPPLICABLE_CANDIDATE!>c %= ""<!>
c <!INAPPLICABLE_CANDIDATE!>%=<!> ""
var c1 = RemAndModAssign
c1 %= 1
@@ -36,4 +36,4 @@ fun test() {
c2 %= 1
}
fun takeInt(x: Int) {}
fun takeInt(x: Int) {}
@@ -20,7 +20,7 @@ object MismatchingTypes {
fun testMismatchingTypes() {
++<!INAPPLICABLE_CANDIDATE!>MismatchingTypes[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingTypes[0]<!>++
<!UNRESOLVED_REFERENCE!>MismatchingTypes[0] += 1<!>
MismatchingTypes[0] <!UNRESOLVED_REFERENCE!>+=<!> 1
}
object MismatchingArities1 {
@@ -36,10 +36,9 @@ object MismatchingArities2 {
fun testMismatchingArities() {
++<!INAPPLICABLE_CANDIDATE!>MismatchingArities1[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities1[0]<!>++
<!UNRESOLVED_REFERENCE!>MismatchingArities1[0] += 1<!>
MismatchingArities1[0] <!UNRESOLVED_REFERENCE!>+=<!> 1
++<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!>++
<!UNRESOLVED_REFERENCE!><!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!> += 1<!>
<!INAPPLICABLE_CANDIDATE!>MismatchingArities2[0]<!> <!UNRESOLVED_REFERENCE!>+=<!> 1
}
@@ -1,12 +1,12 @@
fun intBinEq() {
var x = 0
<!UNRESOLVED_REFERENCE!>x += 'a'<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte()
x += 1.toShort()
x += 1L
x += 1f
x += 1.0
<!UNRESOLVED_REFERENCE!>x *= 'a'<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte()
x *= 1.toShort()
x *= 1L
@@ -16,14 +16,14 @@ fun intBinEq() {
fun shortBinEq() {
var x = 0.toShort()
<!UNRESOLVED_REFERENCE!>x += 'a'<!>
x <!UNRESOLVED_REFERENCE!>+=<!> 'a'
x += 1.toByte()
x += 1.toShort()
x += 1L
x += 1f
x += 1.0
<!UNRESOLVED_REFERENCE!>x *= 'a'<!>
x <!UNRESOLVED_REFERENCE!>*=<!> 'a'
x *= 1.toByte()
x *= 1.toShort()
x *= 1L
@@ -16,5 +16,5 @@ fun test() {
val c = C()
c[0] += ""
var c1 = C1()
<!AMBIGUITY!>c1[0] += ""<!>
}
c1[0] <!AMBIGUITY!>+=<!> ""
}
@@ -19,5 +19,5 @@ public class J {
// FILE: k.kt
var A by J.staticNN
var B by J<!UNSAFE_CALL, UNSAFE_CALL!>.<!>staticN
var C by J.staticJ
var B by J<!UNSAFE_CALL!>.<!>staticN
var C by J.staticJ
@@ -1,2 +1,2 @@
// !WITH_NEW_INFERENCE
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><!UNRESOLVED_REFERENCE!><<!><!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>sdf<!>()()<out Any>::<!UNRESOLVED_REFERENCE!>unwrap<!>
val unwrapped = <!UNRESOLVED_REFERENCE!>some<!><!UNRESOLVED_REFERENCE!><<!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!><!UNRESOLVED_REFERENCE!>sdf<!>()<!>()<!><out Any>::<!UNRESOLVED_REFERENCE!>unwrap<!>
@@ -7,5 +7,5 @@ fun test1(f: String.() -> Unit) {
fun test2(f: (Int) -> Int) {
1.<!UNRESOLVED_REFERENCE!>f<!>(2)
2.<!UNRESOLVED_REFERENCE!>(f)<!>(2)
}
2.(<!UNRESOLVED_REFERENCE!>f<!>)(2)
}
@@ -1,17 +1,17 @@
// !WITH_NEW_INFERENCE
fun test1() {
1. <!UNRESOLVED_REFERENCE!>(fun String.(i: Int) = i )<!>(1)
1.<!UNRESOLVED_REFERENCE!>(label@ fun String.(i: Int) = i )<!>(1)
1. (<!UNRESOLVED_REFERENCE!>fun String.(i: Int) = i<!> )(1)
1.(<!UNRESOLVED_REFERENCE!>label@ fun String.(i: Int) = i<!> )(1)
}
fun test2(f: String.(Int) -> Unit) {
11.<!INAPPLICABLE_CANDIDATE!>(f)<!>(1)
11.<!INAPPLICABLE_CANDIDATE!>(f)<!>()
11.(<!INAPPLICABLE_CANDIDATE!>f<!>)(1)
11.(<!INAPPLICABLE_CANDIDATE!>f<!>)()
}
fun test3() {
fun foo(): String.(Int) -> Unit = {}
1.<!UNRESOLVED_REFERENCE!>(foo())<!>(1)
1.(<!UNRESOLVED_REFERENCE!>foo()<!>)(1)
}
@@ -2,11 +2,11 @@ class A(val x: (String.() -> Unit)?)
fun test(a: A) {
if (a.x != null) {
"".<!UNRESOLVED_REFERENCE!>(a.x)<!>()
"".(<!UNRESOLVED_REFERENCE!>a.x<!>)()
a.x("") // todo
(a.x)("")
}
"".<!UNRESOLVED_REFERENCE!>(a.x)<!>()
"".(<!UNRESOLVED_REFERENCE!>a.x<!>)()
a.<!UNSAFE_IMPLICIT_INVOKE_CALL!>x<!>("")
<!UNSAFE_IMPLICIT_INVOKE_CALL!>(a.x)<!>("")
@@ -8,7 +8,7 @@ class B
val A.foo: B.() -> Unit get() = {}
fun test(a: A, b: B) {
b.<!UNRESOLVED_REFERENCE!>(a.foo)<!>()
b.(<!UNRESOLVED_REFERENCE!>a.foo<!>)()
(a.foo)(b)
a.foo(b)
@@ -25,7 +25,7 @@ fun test(a: A, b: B) {
with(b) {
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
a.<!INAPPLICABLE_CANDIDATE!>(foo)<!>()
a.(<!INAPPLICABLE_CANDIDATE!>foo<!>)()
(a.foo)()
@@ -50,7 +50,7 @@ class A {
class B
fun test(a: A, b: B) {
b.<!UNRESOLVED_REFERENCE!>(a.foo)<!>()
b.(<!UNRESOLVED_REFERENCE!>a.foo<!>)()
(a.foo)(b)
a.foo(b)
@@ -59,7 +59,7 @@ fun test(a: A, b: B) {
b.(foo)()
<!UNRESOLVED_REFERENCE!>(b.<!UNRESOLVED_REFERENCE!>foo<!>)<!>()
(<!UNRESOLVED_REFERENCE!>b.<!UNRESOLVED_REFERENCE!>foo<!><!>)()
foo(b)
(foo)(b)
@@ -67,7 +67,7 @@ fun test(a: A, b: B) {
with(b) {
a.<!INAPPLICABLE_CANDIDATE!>foo<!>()
a.<!INAPPLICABLE_CANDIDATE!>(foo)<!>()
a.(<!INAPPLICABLE_CANDIDATE!>foo<!>)()
(a.foo)()
@@ -8,7 +8,7 @@ fun foo(): String {
var t: String? = "y"
if (t == null) t = "x"
var x: Int? = null
if (x == null) <!UNRESOLVED_REFERENCE!>x += null<!>
if (x == null) x <!UNRESOLVED_REFERENCE!>+=<!> null
return t + s
}
@@ -7,4 +7,4 @@ interface Foo2 : <!INTERFACE_WITH_SUPERCLASS!>bar<!>, Foo {
}
open class Foo1() : bar(), bar, Foo, <!UNRESOLVED_REFERENCE!>Foo<!>() {}
open class Foo12 : bar(), bar {}
open class Foo12 : bar(), bar {}
@@ -26,7 +26,7 @@ fun <T> id(x: T) = x
fun foo2() = {
var x = A()
<!INAPPLICABLE_CANDIDATE!>x += { "" }<!>
x <!INAPPLICABLE_CANDIDATE!>+=<!> { "" }
var y = A()
y += 1
}
@@ -63,7 +63,7 @@ fun case3() {
*/
fun case4(marker : Marker?) {
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.foo; typeCall: function")!>foo(y=1)<!>
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.invoke; typeCall: variable&invoke")!>foo(x=1)<!><!UNSAFE_CALL!>><!><!SYNTAX!><!>
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.invoke; typeCall: variable&invoke")!>foo(x=1)<!>><!SYNTAX!><!>
}
@@ -63,7 +63,7 @@ fun case3() {
*/
fun case4(marker: Marker?) {
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.foo; typeCall: function")!>foo(y = { 1 })<!>
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.invoke; typeCall: variable&invoke")!>foo(x = { 1 })<!><!UNSAFE_CALL!>><!><!SYNTAX!><!>
marker?.<!DEBUG_INFO_CALL("fqName: libPackage.Marker.invoke; typeCall: variable&invoke")!>foo(x = { 1 })<!>><!SYNTAX!><!>
}
@@ -26,9 +26,9 @@ import LibPackCase1.b.*
fun case1 (){
var b: B? = B()
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += { C() }<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> { C() }<!>
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += {1}<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> {1}<!>
}
class B {
@@ -63,9 +63,9 @@ import LibPackCase2.b.*
fun case2 (){
var b: B = B()
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += { C() }<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> { C() }<!>
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += {1}<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> {1}<!>
}
class B {
@@ -10,9 +10,9 @@ import LibPackCase1.a.*
import LibPackCase1.b.*
fun case1 (){
var b: B? = null
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += { C() }<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> { C() }<!>
<!AMBIGUITY, DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b += {1}<!>
<!DEBUG_INFO_CALL("fqName: fqName is unknown; typeCall: unresolved")!>b <!AMBIGUITY!>+=<!> {1}<!>
}
class B {
@@ -15,9 +15,9 @@ import LibPackCase1.b.*
fun case1 (){
var b: B? = B()
<!AMBIGUITY!>b += { C() }<!>
b <!AMBIGUITY!>+=<!> { C() }
<!AMBIGUITY!>b += {1}<!>
b <!AMBIGUITY!>+=<!> {1}
}
class B {
@@ -15,9 +15,9 @@ import LibPackCase1.b.plusAssign
fun case1 (){
var b: B? = B()
<!AMBIGUITY!>b += { C() }<!>
b <!AMBIGUITY!>+=<!> { C() }
<!AMBIGUITY!>b += {1}<!>
b <!AMBIGUITY!>+=<!> {1}
}
class B {
@@ -15,8 +15,8 @@ import LibPackCase1.b.plusAssign
fun case1 (){
var b: B = B()
<!AMBIGUITY!>b +={ C() }<!>
<!AMBIGUITY!>b +={ 1 }<!>
b <!AMBIGUITY!>+=<!>{ C() }
b <!AMBIGUITY!>+=<!>{ 1 }
}
class B
@@ -48,8 +48,8 @@ import LibPackCase2.b.plusAssign
fun case2 (){
var b: B = B()
<!AMBIGUITY!>b +={ C() }<!>
<!AMBIGUITY!>b +={ 1 }<!>
b <!AMBIGUITY!>+=<!>{ C() }
b <!AMBIGUITY!>+=<!>{ 1 }
b.<!AMBIGUITY!>plusAssign<!>{ C() }
}
@@ -17,7 +17,7 @@ operator fun I2.invoke(): String = TODO()
fun case1(a: A) {
a.<!AMBIGUITY!>invoke<!>()
<!AMBIGUITY!>a<!>()
<!AMBIGUITY!>A<!>()()
<!AMBIGUITY!>A()<!>()
}
// FILE: TestCase2.kt
@@ -17,7 +17,7 @@ operator fun <R>I2.invoke(): String = TODO()
fun case1(a: A) {
a.<!AMBIGUITY!>invoke<!>()
<!AMBIGUITY!>a<!>()
<!AMBIGUITY!>A<!>()()
<!AMBIGUITY!>A()<!>()
}
// FILE: TestCase2.kt
@@ -6,7 +6,7 @@
fun case_1() {
var x: Int? = 11
x!!
try {x = null;} finally { <!UNRESOLVED_REFERENCE!><!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>x<!> += 10<!>; }
try {x = null;} finally { <!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Int?")!>x<!> <!UNRESOLVED_REFERENCE!>+=<!> 10; }
}
// TESTCASE NUMBER: 2
@@ -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()
}
@@ -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? =