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:
committed by
Dmitriy Novozhilov
parent
8805675539
commit
d6907222cd
+2
-2
@@ -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()
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
@@ -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,
|
||||
|
||||
+6
-6
@@ -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")
|
||||
|
||||
+6
-6
@@ -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)
|
||||
|
||||
+11
-9
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+57
-10
@@ -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? =
|
||||
|
||||
+5
@@ -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
|
||||
|
||||
+30
-17
@@ -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
|
||||
|
||||
+1
-1
@@ -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!>{}<!>()
|
||||
}
|
||||
|
||||
+2
-2
@@ -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
|
||||
}
|
||||
|
||||
Vendored
+1
-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(){}<!>)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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!!
|
||||
|
||||
+2
-2
@@ -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 }
|
||||
|
||||
-1
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -8,4 +8,4 @@ class Test {
|
||||
open class StaticClass
|
||||
|
||||
open inner class InnerClass
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,4 +14,4 @@ class Outer {
|
||||
inner class Inner2 : FinalNested()
|
||||
inner class Inner3 : OpenInner()
|
||||
inner class Inner4 : FinalInner()
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -3,5 +3,5 @@ fun Any.foo1() : (i : Int) -> Unit {
|
||||
}
|
||||
|
||||
fun test(a : Any) {
|
||||
a.<!INAPPLICABLE_CANDIDATE!>foo1<!>()()
|
||||
}
|
||||
<!INAPPLICABLE_CANDIDATE!>a.foo1()<!>()
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -27,6 +27,6 @@ fun foo() {
|
||||
r.remAssign(1)
|
||||
|
||||
val m = JustMod
|
||||
<!UNRESOLVED_REFERENCE!>m %= 1<!>
|
||||
m <!UNRESOLVED_REFERENCE!>%=<!> 1
|
||||
m.modAssign(1)
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -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) {}
|
||||
|
||||
+3
-4
@@ -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
|
||||
}
|
||||
|
||||
|
||||
Vendored
+4
-4
@@ -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
|
||||
|
||||
+2
-2
@@ -16,5 +16,5 @@ fun test() {
|
||||
val c = C()
|
||||
c[0] += ""
|
||||
var c1 = C1()
|
||||
<!AMBIGUITY!>c1[0] += ""<!>
|
||||
}
|
||||
c1[0] <!AMBIGUITY!>+=<!> ""
|
||||
}
|
||||
|
||||
Vendored
+2
-2
@@ -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
|
||||
|
||||
Vendored
+1
-1
@@ -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<!>
|
||||
|
||||
Vendored
+2
-2
@@ -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)
|
||||
}
|
||||
|
||||
Vendored
+5
-5
@@ -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
-2
@@ -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)<!>("")
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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 {}
|
||||
|
||||
Vendored
+1
-1
@@ -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
|
||||
}
|
||||
|
||||
+1
-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!><!>
|
||||
}
|
||||
|
||||
|
||||
|
||||
+1
-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!><!>
|
||||
}
|
||||
|
||||
|
||||
|
||||
+4
-4
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+2
-2
@@ -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 {
|
||||
|
||||
+4
-4
@@ -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() }
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+2
-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()
|
||||
}
|
||||
|
||||
+8
-7
@@ -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? =
|
||||
|
||||
Reference in New Issue
Block a user