[FIR] Add DYNAMIC_UPPER_BOUND check
+Fix some failing diagnostic tests +Use PositioningStrategy to locate reified modifier
This commit is contained in:
committed by
TeamCityServer
parent
0d525bbe85
commit
3c093f57ba
+1
@@ -61,6 +61,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
INT_LITERAL_OUT_OF_RANGE,
|
||||
FLOAT_LITERAL_OUT_OF_RANGE,
|
||||
LONG_LITERAL_SUFFIX,
|
||||
REIFIED_MODIFIER,
|
||||
|
||||
;
|
||||
|
||||
|
||||
+3
-1
@@ -320,7 +320,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
|
||||
val BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED by error<FirSourceElement, KtTypeReference>()
|
||||
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error<FirSourceElement, PsiElement>()
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error<FirSourceElement, KtTypeParameter>(PositioningStrategy.REIFIED_MODIFIER)
|
||||
|
||||
val TYPE_PARAMETERS_NOT_ALLOWED by error<FirSourceElement, KtDeclaration>()
|
||||
|
||||
@@ -336,6 +336,8 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error<FirSourceElement, KtTypeParameterList>()
|
||||
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning<FirSourceElement, KtTypeParameter>()
|
||||
|
||||
val DYNAMIC_UPPER_BOUND by error<FirSourceElement, KtTypeReference>()
|
||||
}
|
||||
|
||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||
|
||||
+2
-1
@@ -236,13 +236,14 @@ object FirErrors {
|
||||
val CONFLICTING_UPPER_BOUNDS by error1<FirSourceElement, KtNamedDeclaration, FirTypeParameterSymbol>()
|
||||
val NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER by error2<FirSourceElement, KtSimpleNameExpression, Name, FirDeclaration>()
|
||||
val BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED by error0<FirSourceElement, KtTypeReference>()
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error0<FirSourceElement, PsiElement>()
|
||||
val REIFIED_TYPE_PARAMETER_NO_INLINE by error0<FirSourceElement, KtTypeParameter>(SourceElementPositioningStrategies.REIFIED_MODIFIER)
|
||||
val TYPE_PARAMETERS_NOT_ALLOWED by error0<FirSourceElement, KtDeclaration>()
|
||||
val TYPE_PARAMETER_OF_PROPERTY_NOT_USED_IN_RECEIVER by error0<FirSourceElement, KtTypeParameter>()
|
||||
val RETURN_TYPE_MISMATCH by error2<FirSourceElement, KtExpression, ConeKotlinType, ConeKotlinType>(SourceElementPositioningStrategies.WHOLE_ELEMENT)
|
||||
val CYCLIC_GENERIC_UPPER_BOUND by error0<FirSourceElement, PsiElement>()
|
||||
val DEPRECATED_TYPE_PARAMETER_SYNTAX by error0<FirSourceElement, KtTypeParameterList>()
|
||||
val MISPLACED_TYPE_PARAMETER_CONSTRAINTS by warning0<FirSourceElement, KtTypeParameter>()
|
||||
val DYNAMIC_UPPER_BOUND by error0<FirSourceElement, KtTypeReference>()
|
||||
|
||||
// Reflection
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<FirSourceElement, KtExpression, FirCallableDeclaration<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+2
-2
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
|
||||
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElement
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
|
||||
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
|
||||
@@ -15,7 +15,7 @@ object FirFunctionTypeParametersChecker : FirSimpleFunctionChecker() {
|
||||
|
||||
override fun check(declaration: FirSimpleFunction, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
declaration.source?.let { source ->
|
||||
if (source is FirFakeSourceElement<*>) return
|
||||
if (source.kind is FirFakeSourceElementKind) return
|
||||
|
||||
val typeParamsNode = source.treeStructure.typeParametersList(source.lighterASTNode)
|
||||
val nameNode = source.treeStructure.nameIdentifier(source.lighterASTNode)
|
||||
|
||||
+1
-3
@@ -10,7 +10,6 @@ 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.*
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
|
||||
object FirReifiedTypeParameterChecker : FirTypeParameterChecker() {
|
||||
override fun check(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
@@ -22,8 +21,7 @@ object FirReifiedTypeParameterChecker : FirTypeParameterChecker() {
|
||||
(containingDeclaration is FirProperty && !containingDeclaration.areAccessorsInline())
|
||||
|
||||
if (forbidReified) {
|
||||
val reportTarget = declaration.getModifier(KtTokens.REIFIED_KEYWORD)?.source
|
||||
reporter.reportOn(reportTarget, FirErrors.REIFIED_TYPE_PARAMETER_NO_INLINE, context)
|
||||
reporter.reportOn(declaration.source, FirErrors.REIFIED_TYPE_PARAMETER_NO_INLINE, context)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+14
-1
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.*
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.getAncestors
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
import org.jetbrains.kotlin.fir.typeContext
|
||||
@@ -43,6 +44,7 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
checkConflictingBounds(declaration, context, reporter)
|
||||
checkTypeAliasBound(declaration, containingDeclaration, context, reporter)
|
||||
checkBoundsPlacement(declaration, context, reporter)
|
||||
checkDynamicBounds(declaration, context, reporter)
|
||||
}
|
||||
|
||||
private fun checkFinalUpperBounds(
|
||||
@@ -105,7 +107,9 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
|
||||
private fun FirTypeRef.isInTypeConstraint(): Boolean {
|
||||
val source = source ?: return false
|
||||
return source.treeStructure.getParent(source.lighterASTNode)?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
|
||||
return source.treeStructure.getAncestors(source.lighterASTNode)
|
||||
.find { it.tokenType == KtNodeTypes.TYPE_CONSTRAINT || it.tokenType == KtNodeTypes.TYPE_PARAMETER }
|
||||
?.tokenType == KtNodeTypes.TYPE_CONSTRAINT
|
||||
}
|
||||
|
||||
|
||||
@@ -148,6 +152,7 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
//TODO should be moved to extended checkers (because this is basically a code-style warning)
|
||||
private fun checkBoundsPlacement(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (declaration.bounds.size < 2) return
|
||||
|
||||
@@ -157,6 +162,14 @@ object FirTypeParameterBoundsChecker : FirTypeParameterChecker() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkDynamicBounds(declaration: FirTypeParameter, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
declaration.bounds.forEach { bound ->
|
||||
if (bound is FirDynamicTypeRef) {
|
||||
reporter.reportOn(bound.source, FirErrors.DYNAMIC_UPPER_BOUND, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun KotlinTypeMarker.isRelated(context: TypeCheckerProviderContext, type: KotlinTypeMarker?): Boolean =
|
||||
isSubtypeOf(context, type) || isSupertypeOf(context, type)
|
||||
|
||||
|
||||
+7
-8
@@ -34,14 +34,13 @@ object FirAnonymousFunctionChecker : FirExpressionChecker<FirStatement>() {
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext
|
||||
) {
|
||||
expression.source?.let { source ->
|
||||
source.treeStructure.typeParametersList(source.lighterASTNode)?.let { typeParamsNode ->
|
||||
reporter.reportOn(
|
||||
typeParamsNode.toFirLightSourceElement(source.treeStructure),
|
||||
FirErrors.TYPE_PARAMETERS_NOT_ALLOWED,
|
||||
context
|
||||
)
|
||||
}
|
||||
val source = expression.source ?: return
|
||||
source.treeStructure.typeParametersList(source.lighterASTNode)?.let { typeParamsNode ->
|
||||
reporter.reportOn(
|
||||
typeParamsNode.toFirLightSourceElement(source.treeStructure),
|
||||
FirErrors.TYPE_PARAMETERS_NOT_ALLOWED,
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -92,7 +92,7 @@ abstract class AbstractDiagnosticCollector(
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Nothing?) {
|
||||
override fun visitTypeAlias(typeAlias: FirTypeAlias, data: Any?) {
|
||||
withSuppressedDiagnostics(typeAlias) {
|
||||
visitWithDeclaration(typeAlias)
|
||||
}
|
||||
|
||||
+3
@@ -81,6 +81,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DELEGATION_SUPER_
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_MODIFIER_PAIR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DEPRECATED_TYPE_PARAMETER_SYNTAX
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DESERIALIZATION_ERROR
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.DYNAMIC_UPPER_BOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EMPTY_RANGE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ENUM_AS_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_RESOLUTION
|
||||
@@ -521,6 +522,8 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
"If a type parameter has multiple constraints, they all need to be placed in the 'where' clause"
|
||||
)
|
||||
|
||||
map.put(DYNAMIC_UPPER_BOUND, "Dynamic type can not be used as an upper bound")
|
||||
|
||||
// Reflection
|
||||
map.put(
|
||||
EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED,
|
||||
|
||||
+6
@@ -542,6 +542,9 @@ object LightTreePositioningStrategies {
|
||||
|
||||
val LONG_LITERAL_SUFFIX = object : LightTreePositioningStrategy() {
|
||||
}
|
||||
|
||||
val REIFIED_MODIFIER: LightTreePositioningStrategy =
|
||||
ModifierSetBasedLightTreePositioningStrategy(TokenSet.create(KtTokens.REIFIED_KEYWORD))
|
||||
}
|
||||
|
||||
fun FirSourceElement.hasValOrVar(): Boolean =
|
||||
@@ -736,6 +739,9 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.findParentOfType(
|
||||
return null
|
||||
}
|
||||
|
||||
internal fun FlyweightCapableTreeStructure<LighterASTNode>.getAncestors(node: LighterASTNode): Sequence<LighterASTNode> =
|
||||
generateSequence(getParent(node)) { getParent(it) }
|
||||
|
||||
private fun FlyweightCapableTreeStructure<LighterASTNode>.firstChild(node: LighterASTNode): LighterASTNode? {
|
||||
val childrenRef = Ref<Array<LighterASTNode>>()
|
||||
getChildren(node, childrenRef)
|
||||
|
||||
+5
@@ -192,4 +192,9 @@ object SourceElementPositioningStrategies {
|
||||
LightTreePositioningStrategies.LONG_LITERAL_SUFFIX,
|
||||
PositioningStrategies.LONG_LITERAL_SUFFIX
|
||||
)
|
||||
|
||||
val REIFIED_MODIFIER = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.REIFIED_MODIFIER,
|
||||
PositioningStrategies.REIFIED_MODIFIER
|
||||
)
|
||||
}
|
||||
|
||||
@@ -780,6 +780,8 @@ object PositioningStrategies {
|
||||
val REFERENCE_BY_QUALIFIED: PositioningStrategy<PsiElement> = FindReferencePositioningStrategy(false)
|
||||
val REFERENCED_NAME_BY_QUALIFIED: PositioningStrategy<PsiElement> = FindReferencePositioningStrategy(true)
|
||||
|
||||
val REIFIED_MODIFIER: PositioningStrategy<KtModifierListOwner> = modifierSetPosition(KtTokens.REIFIED_KEYWORD)
|
||||
|
||||
val ASSIGNMENT_VALUE: PositioningStrategy<KtProperty> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
return markElement(if (element is KtProperty) element.initializer ?: element else element)
|
||||
|
||||
+6
@@ -1036,6 +1036,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.DYNAMIC_UPPER_BOUND) { firDiagnostic ->
|
||||
DynamicUpperBoundImpl(
|
||||
firDiagnostic as FirPsiDiagnostic<*>,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
||||
ExtensionInClassReferenceNotAllowedImpl(
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a as FirCallableDeclaration),
|
||||
|
||||
+5
-1
@@ -705,7 +705,7 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = BoundOnTypeAliasParameterNotAllowed::class
|
||||
}
|
||||
|
||||
abstract class ReifiedTypeParameterNoInline : KtFirDiagnostic<PsiElement>() {
|
||||
abstract class ReifiedTypeParameterNoInline : KtFirDiagnostic<KtTypeParameter>() {
|
||||
override val diagnosticClass get() = ReifiedTypeParameterNoInline::class
|
||||
}
|
||||
|
||||
@@ -735,6 +735,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = MisplacedTypeParameterConstraints::class
|
||||
}
|
||||
|
||||
abstract class DynamicUpperBound : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = DynamicUpperBound::class
|
||||
}
|
||||
|
||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
||||
abstract val referencedDeclaration: KtCallableSymbol
|
||||
|
||||
+8
-1
@@ -1141,7 +1141,7 @@ internal class BoundOnTypeAliasParameterNotAllowedImpl(
|
||||
internal class ReifiedTypeParameterNoInlineImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.ReifiedTypeParameterNoInline(), KtAbstractFirDiagnostic<PsiElement> {
|
||||
) : KtFirDiagnostic.ReifiedTypeParameterNoInline(), KtAbstractFirDiagnostic<KtTypeParameter> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
@@ -1189,6 +1189,13 @@ internal class MisplacedTypeParameterConstraintsImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class DynamicUpperBoundImpl(
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.DynamicUpperBound(), KtAbstractFirDiagnostic<KtTypeReference> {
|
||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class ExtensionInClassReferenceNotAllowedImpl(
|
||||
override val referencedDeclaration: KtCallableSymbol,
|
||||
firDiagnostic: FirPsiDiagnostic<*>,
|
||||
|
||||
Reference in New Issue
Block a user