[FIR] Add DYNAMIC_UPPER_BOUND check

+Fix some failing diagnostic tests
+Use PositioningStrategy to locate reified modifier
This commit is contained in:
Andrey Zinovyev
2021-04-13 11:18:18 +03:00
committed by TeamCityServer
parent 0d525bbe85
commit 3c093f57ba
15 changed files with 66 additions and 19 deletions
@@ -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,
;
@@ -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") {
@@ -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)
@@ -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)
@@ -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)
}
}
@@ -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)
@@ -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
)
}
}
}
@@ -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)
}
@@ -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,
@@ -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)
@@ -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)
@@ -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),
@@ -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
@@ -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<*>,