[FIR] Avoid duplicate diagnostics on expression.typeRef
This commit is contained in:
+65
-25
@@ -17,11 +17,9 @@ import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
|||||||
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
import org.jetbrains.kotlin.fir.resolve.SessionHolder
|
||||||
import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers
|
import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers
|
||||||
import org.jetbrains.kotlin.fir.resolve.defaultType
|
import org.jetbrains.kotlin.fir.resolve.defaultType
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
import org.jetbrains.kotlin.fir.types.FirTypeRef
|
|
||||||
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
import org.jetbrains.kotlin.fir.types.builder.buildResolvedTypeRef
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
|
||||||
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
|
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
abstract class AbstractDiagnosticCollector(
|
abstract class AbstractDiagnosticCollector(
|
||||||
@@ -33,7 +31,7 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
throw IllegalStateException("Components are not initialized")
|
throw IllegalStateException("Components are not initialized")
|
||||||
}
|
}
|
||||||
initializeCollector()
|
initializeCollector()
|
||||||
firFile.accept(visitor)
|
firFile.accept(visitor, null)
|
||||||
return getCollectedDiagnostics()
|
return getCollectedDiagnostics()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +46,8 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
@Suppress("LeakingThis")
|
@Suppress("LeakingThis")
|
||||||
private var context = PersistentCheckerContext(this)
|
private var context = PersistentCheckerContext(this)
|
||||||
|
|
||||||
|
private var lastExpression: FirExpression? = null
|
||||||
|
|
||||||
fun initializeComponents(vararg components: AbstractDiagnosticCollectorComponent) {
|
fun initializeComponents(vararg components: AbstractDiagnosticCollectorComponent) {
|
||||||
if (componentsInitialized) {
|
if (componentsInitialized) {
|
||||||
throw IllegalStateException()
|
throw IllegalStateException()
|
||||||
@@ -56,29 +56,29 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
componentsInitialized = true
|
componentsInitialized = true
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class Visitor : FirVisitorVoid() {
|
private inner class Visitor : FirDefaultVisitor<Unit, Nothing?>() {
|
||||||
private fun <T : FirElement> T.runComponents() {
|
private fun <T : FirElement> T.runComponents() {
|
||||||
components.forEach {
|
components.forEach {
|
||||||
this.accept(it, context)
|
this.accept(it, context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitElement(element: FirElement) {
|
override fun visitElement(element: FirElement, data: Nothing?) {
|
||||||
element.runComponents()
|
element.runComponents()
|
||||||
element.acceptChildren(this)
|
element.acceptChildren(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun visitJump(loopJump: FirLoopJump) {
|
private fun visitJump(loopJump: FirLoopJump) {
|
||||||
loopJump.runComponents()
|
loopJump.runComponents()
|
||||||
loopJump.acceptChildren(this)
|
loopJump.acceptChildren(this, null)
|
||||||
loopJump.target.labeledElement.takeIf { it is FirErrorLoop }?.accept(this)
|
loopJump.target.labeledElement.takeIf { it is FirErrorLoop }?.accept(this, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitBreakExpression(breakExpression: FirBreakExpression) {
|
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: Nothing?) {
|
||||||
visitJump(breakExpression)
|
visitJump(breakExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitContinueExpression(continueExpression: FirContinueExpression) {
|
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: Nothing?) {
|
||||||
visitJump(continueExpression)
|
visitJump(continueExpression)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,23 +90,23 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitRegularClass(regularClass: FirRegularClass) {
|
override fun visitRegularClass(regularClass: FirRegularClass, data: Nothing?) {
|
||||||
visitClassAndChildren(regularClass, regularClass.defaultType())
|
visitClassAndChildren(regularClass, regularClass.defaultType())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) {
|
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: Nothing?) {
|
||||||
visitClassAndChildren(anonymousObject, anonymousObject.defaultType())
|
visitClassAndChildren(anonymousObject, anonymousObject.defaultType())
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
|
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: Nothing?) {
|
||||||
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverTypeRef)
|
visitWithDeclarationAndReceiver(simpleFunction, simpleFunction.name, simpleFunction.receiverTypeRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructor(constructor: FirConstructor) {
|
override fun visitConstructor(constructor: FirConstructor, data: Nothing?) {
|
||||||
visitWithDeclaration(constructor)
|
visitWithDeclaration(constructor)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction) {
|
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: Nothing?) {
|
||||||
val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) }
|
val labelName = anonymousFunction.label?.name?.let { Name.identifier(it) }
|
||||||
visitWithDeclarationAndReceiver(
|
visitWithDeclarationAndReceiver(
|
||||||
anonymousFunction,
|
anonymousFunction,
|
||||||
@@ -115,35 +115,65 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitProperty(property: FirProperty) {
|
override fun visitProperty(property: FirProperty, data: Nothing?) {
|
||||||
visitWithDeclaration(property)
|
visitWithDeclaration(property)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor) {
|
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor, data: Nothing?) {
|
||||||
val property = context.containingDeclarations.last() as FirProperty
|
val property = context.containingDeclarations.last() as FirProperty
|
||||||
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverTypeRef)
|
visitWithDeclarationAndReceiver(propertyAccessor, property.name, property.receiverTypeRef)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitValueParameter(valueParameter: FirValueParameter) {
|
override fun visitValueParameter(valueParameter: FirValueParameter, data: Nothing?) {
|
||||||
visitWithDeclaration(valueParameter)
|
visitWithDeclaration(valueParameter)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitEnumEntry(enumEntry: FirEnumEntry) {
|
override fun visitEnumEntry(enumEntry: FirEnumEntry, data: Nothing?) {
|
||||||
visitWithDeclaration(enumEntry)
|
visitWithDeclaration(enumEntry)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitFile(file: FirFile) {
|
override fun visitFile(file: FirFile, data: Nothing?) {
|
||||||
visitWithDeclaration(file)
|
visitWithDeclaration(file)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer) {
|
override fun visitAnonymousInitializer(anonymousInitializer: FirAnonymousInitializer, data: Nothing?) {
|
||||||
visitWithDeclaration(anonymousInitializer)
|
visitWithDeclaration(anonymousInitializer)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitExpression(expression: FirExpression, data: Nothing?) {
|
||||||
|
expression.runComponents()
|
||||||
|
withExpression(expression) {
|
||||||
|
expression.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitBlock(block: FirBlock, data: Nothing?) {
|
||||||
|
visitExpression(block, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeRef(typeRef: FirTypeRef, data: Nothing?) {
|
||||||
|
if (typeRef === lastExpression?.typeRef) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
super.visitTypeRef(typeRef, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitTypeOperatorCall(typeOperatorCall: FirTypeOperatorCall, data: Nothing?) {
|
||||||
|
typeOperatorCall.runComponents()
|
||||||
|
withExpression(typeOperatorCall) {
|
||||||
|
typeOperatorCall.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
if (typeOperatorCall.operation == FirOperation.AS) {
|
||||||
|
// NB: in this case conversionTypeRef === typeRef, so we *should* visit it explicitly
|
||||||
|
typeOperatorCall.conversionTypeRef.runComponents()
|
||||||
|
typeOperatorCall.conversionTypeRef.acceptChildren(this, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun visitWithDeclaration(declaration: FirDeclaration) {
|
private fun visitWithDeclaration(declaration: FirDeclaration) {
|
||||||
declaration.runComponents()
|
declaration.runComponents()
|
||||||
withDeclaration(declaration) {
|
withDeclaration(declaration) {
|
||||||
declaration.acceptChildren(this)
|
declaration.acceptChildren(this, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -155,7 +185,7 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
declaration,
|
declaration,
|
||||||
receiverTypeRef?.coneTypeSafe()
|
receiverTypeRef?.coneTypeSafe()
|
||||||
) {
|
) {
|
||||||
declaration.acceptChildren(this)
|
declaration.acceptChildren(this, null)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -171,6 +201,16 @@ abstract class AbstractDiagnosticCollector(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private inline fun <R> withExpression(expression: FirExpression, block: () -> R): R {
|
||||||
|
val previousExpression = lastExpression
|
||||||
|
lastExpression = expression
|
||||||
|
try {
|
||||||
|
return block()
|
||||||
|
} finally {
|
||||||
|
lastExpression = previousExpression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private inline fun <R> withLabelAndReceiverType(
|
private inline fun <R> withLabelAndReceiverType(
|
||||||
labelName: Name?,
|
labelName: Name?,
|
||||||
owner: FirDeclaration,
|
owner: FirDeclaration,
|
||||||
|
|||||||
@@ -12,15 +12,15 @@ class MyColor(val x: <!UNRESOLVED_REFERENCE!>Color.RED<!>, y: <!UNRESOLVED_REFER
|
|||||||
var z: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
var z: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
||||||
set(arg: Color.RED) { z = arg }
|
set(arg: Color.RED) { z = arg }
|
||||||
|
|
||||||
fun foo(arg: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
fun foo(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
||||||
|
|
||||||
fun bar(): <!UNRESOLVED_REFERENCE!>Color.RED<!> {
|
fun bar(): <!UNRESOLVED_REFERENCE!>Color.RED<!> {
|
||||||
class Local : <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
class Local : <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||||
fun local(arg: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
fun local(arg: <!UNRESOLVED_REFERENCE!>Color.RED<!>): <!UNRESOLVED_REFERENCE!>Color.RED<!> = arg
|
||||||
val temp: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
val temp: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!> = Color.RED
|
||||||
temp as? <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
temp as? <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||||
if (temp is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
if (temp is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
||||||
return temp as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Color.RED<!>
|
return temp as <!UNRESOLVED_REFERENCE!>Color.RED<!>
|
||||||
}
|
}
|
||||||
val obj = object : <!UNRESOLVED_REFERENCE!>Color.RED<!> {}
|
val obj = object : <!UNRESOLVED_REFERENCE!>Color.RED<!> {}
|
||||||
if (obj is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
if (obj is <!UNRESOLVED_REFERENCE!>Color.RED<!>) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
class P
|
class P
|
||||||
|
|
||||||
fun foo(p: P): Any {
|
fun foo(p: P): Any {
|
||||||
val v = p as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>G<!>
|
val v = p as <!UNRESOLVED_REFERENCE!>G<!>
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
+2
-2
@@ -15,12 +15,12 @@ fun case_3() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val x = object<T, K: Comparable<K>> {
|
val x = object<T, K: Comparable<K>> {
|
||||||
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!> // OK
|
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!> // OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fun case_4() {
|
fun case_4() {
|
||||||
val x = object<T> {
|
val x = object<T> {
|
||||||
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!>
|
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
val y = x.test() // type y is T
|
val y = x.test() // type y is T
|
||||||
|
|||||||
Vendored
+2
-2
@@ -15,12 +15,12 @@ fun case_3() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val x = object<T, K: Comparable<K>> {
|
val x = object<T, K: Comparable<K>> {
|
||||||
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!> // OK
|
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!> // OK
|
||||||
}
|
}
|
||||||
|
|
||||||
fun case_4() {
|
fun case_4() {
|
||||||
val x = object<T> {
|
val x = object<T> {
|
||||||
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!>
|
fun test() = 10 as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>T<!>
|
||||||
}
|
}
|
||||||
|
|
||||||
val y = x.test() // type y is T
|
val y = x.test() // type y is T
|
||||||
|
|||||||
+1
-1
@@ -22,7 +22,7 @@ fun <E> foo(x: Any, y: Any) : Any {
|
|||||||
return y
|
return y
|
||||||
}
|
}
|
||||||
|
|
||||||
y as <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Outer<*>.Inner<!>
|
y as <!UNRESOLVED_REFERENCE!>Outer<*>.Inner<!>
|
||||||
|
|
||||||
return C()
|
return C()
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ fun foo() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun bar(i: Int, a: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>U<!>) {
|
fun bar(i: Int, a: <!UNRESOLVED_REFERENCE!>U<!>) {
|
||||||
val r = if (true) i else a
|
val r = if (true) i else a
|
||||||
val b: Any = r
|
val b: Any = r
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+1
-1
@@ -6,7 +6,7 @@ open class Base {
|
|||||||
|
|
||||||
class Derived : Base()
|
class Derived : Base()
|
||||||
|
|
||||||
fun test(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Derived.Nested<!>) = x
|
fun test(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Derived.Nested<!>) = x
|
||||||
|
|
||||||
fun Base.testWithImplicitReceiver(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Nested<!>) {
|
fun Base.testWithImplicitReceiver(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>Nested<!>) {
|
||||||
val y: <!UNRESOLVED_REFERENCE!>Nested<!> = x
|
val y: <!UNRESOLVED_REFERENCE!>Nested<!> = x
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ class Outer<T> {
|
|||||||
typealias InnerAlias = Inner
|
typealias InnerAlias = Inner
|
||||||
typealias GenericInnerAlias<TT> = GenericInner<TT>
|
typealias GenericInnerAlias<TT> = GenericInner<TT>
|
||||||
|
|
||||||
fun test1(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>NestedAlias<!>) = x
|
fun test1(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>NestedAlias<!>) = x
|
||||||
fun test2(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericNestedAlias<Int><!>) = x
|
fun test2(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericNestedAlias<Int><!>) = x
|
||||||
fun <T> test3(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericNestedAlias<T><!>) = x
|
fun <T> test3(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericNestedAlias<T><!>) = x
|
||||||
fun test4(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>InnerAlias<!>) = x
|
fun test4(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>InnerAlias<!>) = x
|
||||||
fun test5(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericInnerAlias<Int><!>) = x
|
fun test5(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericInnerAlias<Int><!>) = x
|
||||||
fun <T> test6(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericInnerAlias<T><!>) = x
|
fun <T> test6(x: <!UNRESOLVED_REFERENCE, UNRESOLVED_REFERENCE!>GenericInnerAlias<T><!>) = x
|
||||||
}
|
}
|
||||||
fun test1(x: Outer<Int>.NestedAlias) = x
|
fun test1(x: Outer<Int>.NestedAlias) = x
|
||||||
fun <T> test2(x: Outer<T>.NestedAlias) = x
|
fun <T> test2(x: Outer<T>.NestedAlias) = x
|
||||||
|
|||||||
Reference in New Issue
Block a user