[FIR] Avoid duplicate diagnostics on expression.typeRef

This commit is contained in:
Mikhail Glukhikh
2020-08-02 13:37:13 +03:00
parent dc46d51d9a
commit 951aa8185e
9 changed files with 82 additions and 42 deletions
@@ -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,
+3 -3
View File
@@ -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
} }
@@ -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
@@ -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
@@ -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()
} }
@@ -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
} }
@@ -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