[FIR] Check rest OUTER_CLASS_ARGUMENTS_REQUIRED diagnostics on checkers stage
Add FirOuterClassArgumentsRequiredChecker
This commit is contained in:
committed by
TeamCityServer
parent
0fc8be4d60
commit
28a6928873
+1
@@ -88,6 +88,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
|||||||
FirFunInterfaceDeclarationChecker,
|
FirFunInterfaceDeclarationChecker,
|
||||||
FirNestedClassChecker,
|
FirNestedClassChecker,
|
||||||
FirInlineClassDeclarationChecker,
|
FirInlineClassDeclarationChecker,
|
||||||
|
FirOuterClassArgumentsRequiredChecker
|
||||||
)
|
)
|
||||||
|
|
||||||
override val constructorCheckers: Set<FirConstructorChecker>
|
override val constructorCheckers: Set<FirConstructorChecker>
|
||||||
|
|||||||
+109
@@ -0,0 +1,109 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.findClosest
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.checkers.extractArgumentTypeRefAndSource
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||||
|
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypeParameterRef
|
||||||
|
import org.jetbrains.kotlin.fir.declarations.FirTypedDeclaration
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.getClassThatContainsTypeParameter
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.isValidTypeParameter
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.resolve.toTypeProjections
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
|
||||||
|
import org.jetbrains.kotlin.fir.types.*
|
||||||
|
|
||||||
|
object FirOuterClassArgumentsRequiredChecker : FirRegularClassChecker() {
|
||||||
|
override fun check(declaration: FirRegularClass, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
for (superTypeRef in declaration.superTypeRefs) {
|
||||||
|
checkOuterClassArgumentsRequired(superTypeRef, declaration, context, reporter)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (subDecl in declaration.declarations) {
|
||||||
|
if (subDecl is FirTypedDeclaration) {
|
||||||
|
checkOuterClassArgumentsRequired(subDecl.returnTypeRef, declaration, context, reporter)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun checkOuterClassArgumentsRequired(
|
||||||
|
typeRef: FirTypeRef,
|
||||||
|
declaration: FirRegularClass?,
|
||||||
|
context: CheckerContext,
|
||||||
|
reporter: DiagnosticReporter
|
||||||
|
) {
|
||||||
|
val type: ConeKotlinType
|
||||||
|
|
||||||
|
if (typeRef is FirResolvedTypeRef) {
|
||||||
|
if (typeRef is FirErrorTypeRef) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
type = typeRef.type
|
||||||
|
val delegatedTypeRef = typeRef.delegatedTypeRef
|
||||||
|
|
||||||
|
if (delegatedTypeRef is FirUserTypeRef) {
|
||||||
|
|
||||||
|
if (type is ConeClassLikeType) {
|
||||||
|
val symbol = type.lookupTag.toSymbol(context.session)
|
||||||
|
|
||||||
|
if (symbol is FirRegularClassSymbol) {
|
||||||
|
var problemTypeParameter: FirTypeParameterRef? = null
|
||||||
|
val typeArguments = delegatedTypeRef.qualifier.toTypeProjections()
|
||||||
|
val argumentsFromOuterClassesAndParentsCount = symbol.fir.typeParameters.drop(typeArguments.size).sumOf {
|
||||||
|
val result = if (isValidTypeParameter(it, declaration, context.session)) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
if (problemTypeParameter == null) {
|
||||||
|
problemTypeParameter = it
|
||||||
|
}
|
||||||
|
0
|
||||||
|
}
|
||||||
|
return@sumOf result
|
||||||
|
}
|
||||||
|
val finalTypeArgumentsCount = typeArguments.size + argumentsFromOuterClassesAndParentsCount
|
||||||
|
|
||||||
|
if (finalTypeArgumentsCount != symbol.fir.typeParameters.size) {
|
||||||
|
val source = typeRef.source
|
||||||
|
if (problemTypeParameter != null) {
|
||||||
|
var outerClass: FirRegularClass? = null
|
||||||
|
context.findClosest<FirRegularClass> {
|
||||||
|
outerClass = getClassThatContainsTypeParameter(it, problemTypeParameter!!)
|
||||||
|
return@findClosest outerClass != null
|
||||||
|
}
|
||||||
|
if (outerClass != null) {
|
||||||
|
reporter.reportOn(source, FirErrors.OUTER_CLASS_ARGUMENTS_REQUIRED, outerClass!!, context)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reporter.reportOn(
|
||||||
|
source,
|
||||||
|
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS,
|
||||||
|
symbol.fir.typeParameters.size - argumentsFromOuterClassesAndParentsCount,
|
||||||
|
symbol,
|
||||||
|
context
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (typeRef is ConeKotlinType) {
|
||||||
|
type = typeRef
|
||||||
|
} else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for (index in type.typeArguments.indices) {
|
||||||
|
val firTypeRefSource = extractArgumentTypeRefAndSource(typeRef, index) ?: continue
|
||||||
|
firTypeRefSource.typeRef?.let { checkOuterClassArgumentsRequired(it, declaration, context, reporter) }
|
||||||
|
}
|
||||||
|
}
|
||||||
Vendored
-7
@@ -1,7 +0,0 @@
|
|||||||
interface Inv<X>
|
|
||||||
class Outer<E> {
|
|
||||||
inner class Inner
|
|
||||||
|
|
||||||
class Nested : Inv<Inner>
|
|
||||||
object Obj : Inv<Inner>
|
|
||||||
}
|
|
||||||
Vendored
+3
@@ -1,7 +1,10 @@
|
|||||||
|
// FIR_IDENTICAL
|
||||||
interface Inv<X>
|
interface Inv<X>
|
||||||
class Outer<E> {
|
class Outer<E> {
|
||||||
inner class Inner
|
inner class Inner
|
||||||
|
|
||||||
class Nested : Inv<<!OUTER_CLASS_ARGUMENTS_REQUIRED!>Inner<!>>
|
class Nested : Inv<<!OUTER_CLASS_ARGUMENTS_REQUIRED!>Inner<!>>
|
||||||
|
inner class Inner2 : Inv<Inner> // no error
|
||||||
object Obj : Inv<<!OUTER_CLASS_ARGUMENTS_REQUIRED!>Inner<!>>
|
object Obj : Inv<<!OUTER_CLASS_ARGUMENTS_REQUIRED!>Inner<!>>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Vendored
+8
@@ -19,6 +19,13 @@ public final class Outer</*0*/ E> {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public final inner class Inner2 /*captured type parameters: /*0*/ E*/ : Inv<Outer<E>.Inner> {
|
||||||
|
public constructor Inner2()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
public final class Nested : Inv<[ERROR : Inner]> {
|
public final class Nested : Inv<[ERROR : Inner]> {
|
||||||
public constructor Nested()
|
public constructor Nested()
|
||||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
@@ -33,3 +40,4 @@ public final class Outer</*0*/ E> {
|
|||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user