[FIR] Add REDUNDANT_NULLABLE diagnostics
This commit is contained in:
committed by
TeamCityServer
parent
4caf3c5e83
commit
51b73bb6ae
+6
@@ -1891,6 +1891,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.REDUNDANT_NULLABLE) { firDiagnostic ->
|
||||
RedundantNullableImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED) { firDiagnostic ->
|
||||
ExtensionInClassReferenceNotAllowedImpl(
|
||||
firSymbolBuilder.callableBuilder.buildCallableSymbol(firDiagnostic.a.fir),
|
||||
|
||||
+4
@@ -1348,6 +1348,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val isCastToNotNull: Boolean
|
||||
}
|
||||
|
||||
abstract class RedundantNullable : KtFirDiagnostic<KtTypeReference>() {
|
||||
override val diagnosticClass get() = RedundantNullable::class
|
||||
}
|
||||
|
||||
abstract class ExtensionInClassReferenceNotAllowed : KtFirDiagnostic<KtExpression>() {
|
||||
override val diagnosticClass get() = ExtensionInClassReferenceNotAllowed::class
|
||||
abstract val referencedDeclaration: KtCallableSymbol
|
||||
|
||||
+5
@@ -1617,6 +1617,11 @@ internal class SmartcastImpossibleImpl(
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.SmartcastImpossible(), KtAbstractFirDiagnostic<KtExpression>
|
||||
|
||||
internal class RedundantNullableImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.RedundantNullable(), KtAbstractFirDiagnostic<KtTypeReference>
|
||||
|
||||
internal class ExtensionInClassReferenceNotAllowedImpl(
|
||||
override val referencedDeclaration: KtCallableSymbol,
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
|
||||
+1
-1
@@ -90,7 +90,7 @@ private object CheckersFactory {
|
||||
}
|
||||
|
||||
private fun createTypeCheckers(useExtendedCheckers: Boolean): TypeCheckers? =
|
||||
if (useExtendedCheckers) null else CommonTypeCheckers
|
||||
if (useExtendedCheckers) ExtendedTypeCheckers else CommonTypeCheckers
|
||||
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
|
||||
+2
@@ -655,6 +655,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<String>("description")
|
||||
parameter<Boolean>("isCastToNotNull")
|
||||
}
|
||||
|
||||
val REDUNDANT_NULLABLE by warning<KtTypeReference>(PositioningStrategy.REDUNDANT_NULLABLE)
|
||||
}
|
||||
|
||||
val REFLECTION by object : DiagnosticGroup("Reflection") {
|
||||
|
||||
+1
@@ -111,6 +111,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
PROPERTY_DELEGATE,
|
||||
IMPORT_ALIAS,
|
||||
DECLARATION_START_TO_NAME,
|
||||
REDUNDANT_NULLABLE,
|
||||
|
||||
;
|
||||
|
||||
|
||||
@@ -395,6 +395,7 @@ object FirErrors {
|
||||
val TYPE_VARIANCE_CONFLICT by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val TYPE_VARIANCE_CONFLICT_IN_EXPANDED_TYPE by error4<PsiElement, FirTypeParameterSymbol, Variance, Variance, ConeKotlinType>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE_OR_DEFAULT)
|
||||
val SMARTCAST_IMPOSSIBLE by error4<KtExpression, ConeKotlinType, FirExpression, String, Boolean>()
|
||||
val REDUNDANT_NULLABLE by warning0<KtTypeReference>(SourceElementPositioningStrategies.REDUNDANT_NULLABLE)
|
||||
|
||||
// Reflection
|
||||
val EXTENSION_IN_CLASS_REFERENCE_NOT_ALLOWED by error1<KtExpression, FirCallableSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||
|
||||
+1
-1
@@ -12,6 +12,6 @@ object CommonTypeCheckers : TypeCheckers() {
|
||||
FirTypeAnnotationChecker,
|
||||
FirSuspendModifierChecker,
|
||||
FirDeprecatedTypeChecker,
|
||||
FirOptInUsageTypeRefChecker,
|
||||
FirOptInUsageTypeRefChecker
|
||||
)
|
||||
}
|
||||
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.extended.RedundantNullableChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.*
|
||||
|
||||
object ExtendedTypeCheckers : TypeCheckers() {
|
||||
override val typeRefCheckers: Set<FirTypeRefChecker> = setOf(
|
||||
RedundantNullableChecker
|
||||
)
|
||||
}
|
||||
+24
-4
@@ -6,13 +6,11 @@
|
||||
package org.jetbrains.kotlin.fir.analysis.checkers
|
||||
|
||||
import com.intellij.lang.LighterASTNode
|
||||
import com.intellij.openapi.util.Ref
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.PsiNameIdentifierOwner
|
||||
import com.intellij.psi.impl.source.tree.LeafPsiElement
|
||||
import org.jetbrains.kotlin.KtLightSourceElement
|
||||
import org.jetbrains.kotlin.KtPsiSourceElement
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.fir.FirElement
|
||||
import org.jetbrains.kotlin.diagnostics.getAncestors
|
||||
import org.jetbrains.kotlin.diagnostics.nameIdentifier
|
||||
@@ -40,6 +38,8 @@ interface SourceNavigator {
|
||||
|
||||
fun FirValueParameterSymbol.isCatchElementParameter(): Boolean
|
||||
|
||||
fun FirTypeRef.isRedundantNullable(): Boolean
|
||||
|
||||
companion object {
|
||||
|
||||
private val lightTreeInstance = LightTreeSourceNavigator()
|
||||
@@ -90,6 +90,19 @@ open class LightTreeSourceNavigator : SourceNavigator {
|
||||
return source?.getParentOfParent()?.tokenType == KtNodeTypes.CATCH
|
||||
}
|
||||
|
||||
override fun FirTypeRef.isRedundantNullable(): Boolean {
|
||||
val source = source ?: return false
|
||||
val ref = Ref<Array<LighterASTNode?>>()
|
||||
val firstChild = getNullableChild(source, source.lighterASTNode, ref) ?: return false
|
||||
return getNullableChild(source, firstChild, ref) != null
|
||||
}
|
||||
|
||||
private fun getNullableChild(source: KtSourceElement, node: LighterASTNode, ref: Ref<Array<LighterASTNode?>>): LighterASTNode? {
|
||||
source.treeStructure.getChildren(node, ref)
|
||||
val firstChild = ref.get().firstOrNull() ?: return null
|
||||
return if (firstChild.tokenType != KtNodeTypes.NULLABLE_TYPE) null else firstChild
|
||||
}
|
||||
|
||||
private fun KtSourceElement?.getParentOfParent(): LighterASTNode? {
|
||||
val source = this ?: return null
|
||||
var parent = source.treeStructure.getParent(source.lighterASTNode)
|
||||
@@ -131,4 +144,11 @@ object PsiSourceNavigator : LightTreeSourceNavigator() {
|
||||
override fun FirValueParameterSymbol.isCatchElementParameter(): Boolean {
|
||||
return source?.psi<PsiElement>()?.parent?.parent is KtCatchClause
|
||||
}
|
||||
|
||||
override fun FirTypeRef.isRedundantNullable(): Boolean {
|
||||
val source = source ?: return false
|
||||
val typeReference = (source.psi as? KtTypeReference) ?: return false
|
||||
val typeElement = typeReference.typeElement as? KtNullableType ?: return false
|
||||
return typeElement.innerType is KtNullableType
|
||||
}
|
||||
}
|
||||
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/*
|
||||
* 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.extended
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.diagnostics.reportOn
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.SourceNavigator
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.toClassLikeSymbol
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.type.FirTypeRefChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_NULLABLE
|
||||
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeAliasSymbol
|
||||
import org.jetbrains.kotlin.fir.types.*
|
||||
|
||||
object RedundantNullableChecker : FirTypeRefChecker() {
|
||||
override fun check(typeRef: FirTypeRef, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (typeRef !is FirResolvedTypeRef || typeRef.isMarkedNullable != true) return
|
||||
|
||||
var symbol = typeRef.toClassLikeSymbol(context.session)
|
||||
if (symbol is FirTypeAliasSymbol) {
|
||||
while (symbol is FirTypeAliasSymbol) {
|
||||
val resolvedExpandedTypeRef = symbol.resolvedExpandedTypeRef
|
||||
if (resolvedExpandedTypeRef.type.isMarkedNullable) {
|
||||
reporter.reportOn(typeRef.source, REDUNDANT_NULLABLE, context)
|
||||
break
|
||||
} else {
|
||||
symbol = resolvedExpandedTypeRef.toClassLikeSymbol(context.session)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
with(SourceNavigator.forElement(typeRef)) {
|
||||
if (typeRef.isRedundantNullable()) {
|
||||
reporter.reportOn(typeRef.source, REDUNDANT_NULLABLE, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+9
-7
@@ -236,14 +236,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INFIX_MODIFIER_RE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZATION_BEFORE_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INITIALIZER_TYPE_MISMATCH
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_RECURSIVE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_EXTEND_CLASSES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INLINE_CLASS_CONSTRUCTOR_WRONG_PARAMETERS_SIZE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_FINAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_TOP_LEVEL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INLINE_PROPERTY_WITH_BACKING_FIELD
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_INSIDE_VALUE_CLASS
|
||||
@@ -394,6 +387,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_LABEL_W
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER_FOR_TARGET
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_NULLABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_OPEN_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_PROJECTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_RETURN_UNIT_TYPE
|
||||
@@ -501,6 +495,13 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_ELVIS_RIG
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_IS_CHECK
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.USELESS_VARARG_ON_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_CLONEABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_BE_RECURSIVE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_EXTEND_CLASSES
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CANNOT_IMPLEMENT_INTERFACE_BY_DELEGATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_CONSTRUCTOR_NOT_FINAL_READ_ONLY_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_HAS_INAPPLICABLE_PARAMETER_TYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_FINAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_CLASS_NOT_TOP_LEVEL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_CATCH_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.VAL_OR_VAR_ON_FUN_PARAMETER
|
||||
@@ -622,6 +623,7 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
map.put(SUPERTYPE_IS_EXTENSION_FUNCTION_TYPE, "Extension function type is not allowed as supertypes")
|
||||
map.put(SINGLETON_IN_SUPERTYPE, "Cannot inherit from a singleton")
|
||||
map.put(NULLABLE_SUPERTYPE, "A supertype cannot be nullable")
|
||||
map.put(REDUNDANT_NULLABLE, "Redundant '?'")
|
||||
map.put(MANY_CLASSES_IN_SUPERTYPE_LIST, "Only one class may appear in a supertype list")
|
||||
map.put(SUPERTYPE_APPEARS_TWICE, "A supertype appears twice")
|
||||
map.put(CLASS_IN_SUPERTYPE_FOR_ENUM, "Enum class cannot inherit from classes")
|
||||
|
||||
@@ -19,6 +19,7 @@ fun FirSessionFactory.FirSessionConfigurator.registerCommonCheckers() {
|
||||
fun FirSessionFactory.FirSessionConfigurator.registerExtendedCommonCheckers() {
|
||||
useCheckers(ExtendedExpressionCheckers)
|
||||
useCheckers(ExtendedDeclarationCheckers)
|
||||
useCheckers(ExtendedTypeCheckers)
|
||||
}
|
||||
|
||||
fun FirSessionFactory.FirSessionConfigurator.registerJvmCheckers() {
|
||||
|
||||
@@ -62,20 +62,20 @@ fun FirExpression.isStableSmartcast(): Boolean {
|
||||
return this is FirExpressionWithSmartcast && this.isStable
|
||||
}
|
||||
|
||||
private val FirTypeRef.classLikeTypeOrNull: ConeClassLikeType?
|
||||
private val FirTypeRef.lookupTagBasedOrNull: ConeLookupTagBasedType?
|
||||
get() = when (this) {
|
||||
is FirImplicitBuiltinTypeRef -> type
|
||||
is FirResolvedTypeRef -> type as? ConeClassLikeType
|
||||
is FirResolvedTypeRef -> type as? ConeLookupTagBasedType
|
||||
else -> null
|
||||
}
|
||||
|
||||
private fun FirTypeRef.isBuiltinType(classId: ClassId, isNullable: Boolean): Boolean {
|
||||
val type = this.classLikeTypeOrNull ?: return false
|
||||
return type.lookupTag.classId == classId && type.isNullable == isNullable
|
||||
val type = this.lookupTagBasedOrNull ?: return false
|
||||
return (type as? ConeClassLikeType)?.lookupTag?.classId == classId && type.isNullable == isNullable
|
||||
}
|
||||
|
||||
val FirTypeRef.isMarkedNullable: Boolean?
|
||||
get() = classLikeTypeOrNull?.isMarkedNullable
|
||||
get() = if (this is FirTypeRefWithNullability) this.isMarkedNullable else lookupTagBasedOrNull?.isMarkedNullable
|
||||
|
||||
val FirFunctionTypeRef.parametersCount: Int
|
||||
get() = if (receiverTypeRef != null)
|
||||
|
||||
+35
-1
@@ -14,7 +14,6 @@ import com.intellij.util.diff.FlyweightCapableTreeStructure
|
||||
import org.jetbrains.kotlin.KtNodeType
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.KtSourceElement
|
||||
import org.jetbrains.kotlin.diagnostics.PositioningStrategies
|
||||
import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.MODALITY_MODIFIERS
|
||||
import org.jetbrains.kotlin.lexer.KtTokens.VISIBILITY_MODIFIERS
|
||||
@@ -827,6 +826,40 @@ object LightTreePositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val REDUNDANT_NULLABLE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>
|
||||
): List<TextRange> {
|
||||
val ref = Ref<Array<LighterASTNode?>>()
|
||||
var child: LighterASTNode? = node
|
||||
var lastQuest: LighterASTNode? = null
|
||||
var prevQuest: LighterASTNode? = null
|
||||
var quest: LighterASTNode? = null
|
||||
while (child != null) {
|
||||
child = getNullableChild(tree, child, ref)
|
||||
prevQuest = quest
|
||||
quest = ref.get().elementAtOrNull(1)
|
||||
if (lastQuest == null) {
|
||||
lastQuest = quest
|
||||
}
|
||||
}
|
||||
return markRange(prevQuest ?: lastQuest ?: node, lastQuest ?: node, startOffset, endOffset, tree, node)
|
||||
}
|
||||
|
||||
private fun getNullableChild(
|
||||
tree: FlyweightCapableTreeStructure<LighterASTNode>,
|
||||
node: LighterASTNode,
|
||||
ref: Ref<Array<LighterASTNode?>>
|
||||
): LighterASTNode? {
|
||||
tree.getChildren(node, ref)
|
||||
val firstChild = ref.get().firstOrNull() ?: return null
|
||||
return if (firstChild.tokenType != KtNodeTypes.NULLABLE_TYPE) null else firstChild
|
||||
}
|
||||
}
|
||||
|
||||
val QUESTION_MARK_BY_TYPE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
@@ -1154,6 +1187,7 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.referenceExpression(
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
fun FlyweightCapableTreeStructure<LighterASTNode>.unwrapParenthesesLabelsAndAnnotations(node: LighterASTNode): LighterASTNode {
|
||||
var unwrapped = node
|
||||
while (true) {
|
||||
|
||||
+25
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.diagnostics
|
||||
|
||||
import com.intellij.lang.ASTNode
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.tree.TokenSet
|
||||
@@ -549,6 +550,30 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val REDUNDANT_NULLABLE: PositioningStrategy<KtTypeReference> = object : PositioningStrategy<KtTypeReference>() {
|
||||
override fun mark(element: KtTypeReference): List<TextRange> {
|
||||
var typeElement = element.typeElement
|
||||
var question: ASTNode? = null
|
||||
var prevQuestion: ASTNode? = null
|
||||
var lastQuestion: ASTNode? = null
|
||||
while (typeElement is KtNullableType) {
|
||||
prevQuestion = question
|
||||
question = typeElement.questionMarkNode
|
||||
if (lastQuestion == null) {
|
||||
lastQuestion = question
|
||||
}
|
||||
typeElement = typeElement.innerType
|
||||
}
|
||||
|
||||
if (lastQuestion != null) {
|
||||
return markRange((prevQuestion ?: lastQuestion).psi, lastQuestion.psi)
|
||||
}
|
||||
|
||||
return super.mark(element)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val NULLABLE_TYPE: PositioningStrategy<KtNullableType> = object : PositioningStrategy<KtNullableType>() {
|
||||
override fun mark(element: KtNullableType): List<TextRange> {
|
||||
|
||||
+5
@@ -248,6 +248,11 @@ object SourceElementPositioningStrategies {
|
||||
PositioningStrategies.NAME_IDENTIFIER
|
||||
)
|
||||
|
||||
val REDUNDANT_NULLABLE = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.REDUNDANT_NULLABLE,
|
||||
PositioningStrategies.REDUNDANT_NULLABLE
|
||||
)
|
||||
|
||||
val QUESTION_MARK_BY_TYPE = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.QUESTION_MARK_BY_TYPE,
|
||||
PositioningStrategies.QUESTION_MARK_BY_TYPE
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
interface A<T> {}
|
||||
interface B<T> {}
|
||||
interface C<T> {}
|
||||
interface D<T> {}
|
||||
|
||||
interface Test : A<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>in<!> Int>, B<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>out<!> Int>, C<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>??<!NULLABLE_SUPERTYPE!>?<!>, D<Int> {}
|
||||
interface Test : A<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>in<!> Int>, B<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>out<!> Int>, C<<!PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE!>*<!>>?<!REDUNDANT_NULLABLE!>?<!NULLABLE_SUPERTYPE!>?<!><!>, D<Int> {}
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
interface B<T>
|
||||
class G<T>: B<T>
|
||||
|
||||
fun f(b: B<String>?) = b is G??
|
||||
@@ -1,3 +1,5 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
interface B<T>
|
||||
class G<T>: B<T>
|
||||
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
fun <NN: Any, NNN: NN> nonMisleadingNullable(
|
||||
nn: NN?,
|
||||
nnn: NNN?
|
||||
) {}
|
||||
|
||||
fun <T, N: T, INDIRECT: N> misleadingNullableSimple(
|
||||
t: T?,
|
||||
t2: T?,
|
||||
n: N?,
|
||||
ind: INDIRECT?
|
||||
) {}
|
||||
|
||||
fun <T> interactionWithRedundant(t: T??) {}
|
||||
+2
@@ -1,3 +1,5 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
fun <NN: Any, NNN: NN> nonMisleadingNullable(
|
||||
nn: NN?,
|
||||
nnn: NNN?
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
class Generic<T>
|
||||
|
||||
fun redundantNullable(
|
||||
i: Int??,
|
||||
three: Int???,
|
||||
gOut: Generic<Int>??,
|
||||
gIn: Generic<Int??>
|
||||
i: Int?<!REDUNDANT_NULLABLE!>?<!>,
|
||||
three: Int?<!REDUNDANT_NULLABLE!>??<!>,
|
||||
gOut: Generic<Int>?<!REDUNDANT_NULLABLE!>?<!>,
|
||||
gIn: Generic<Int?<!REDUNDANT_NULLABLE!>?<!>>
|
||||
) {
|
||||
}
|
||||
+3
-2
@@ -1,9 +1,10 @@
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
interface A
|
||||
interface X: A?<!NULLABLE_SUPERTYPE!>?<!> {
|
||||
interface X: A?<!NULLABLE_SUPERTYPE, REDUNDANT_NULLABLE!>?<!> {
|
||||
|
||||
}
|
||||
|
||||
fun <T> interaction(t: T) {
|
||||
if (t == null) {}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class Ann
|
||||
|
||||
typealias TString = String
|
||||
|
||||
typealias TNString = TString?
|
||||
|
||||
typealias TNAString = @Ann TString?
|
||||
|
||||
val test1: TNString = TODO()
|
||||
val test2: TNAString = TODO()
|
||||
val test3: List<TNString> = TODO()
|
||||
val test4: List<TNAString> = TODO()
|
||||
val test5: List<TNString?> = TODO()
|
||||
val test6: () -> List<TNString> = TODO()
|
||||
|
||||
fun test(x: TNString) {
|
||||
x<!UNSAFE_CALL!>.<!>hashCode()
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
// FIR_IDENTICAL
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
@Target(AnnotationTarget.TYPE)
|
||||
annotation class Ann
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_VARIABLE
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -108,7 +109,7 @@ fun case_8(x: TypealiasNullableString) {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: TypealiasNullableString?) {
|
||||
fun case_9(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>) {
|
||||
if (<!SENSELESS_COMPARISON!>x === null === null<!>) {
|
||||
|
||||
} else if (<!USELESS_IS_CHECK!>false is Boolean<!>) {
|
||||
@@ -138,7 +139,7 @@ fun case_10() {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 11
|
||||
fun case_11(x: TypealiasNullableStringIndirect?, y: TypealiasNullableStringIndirect) {
|
||||
fun case_11(x: TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>, y: TypealiasNullableStringIndirect) {
|
||||
val t: TypealiasNullableStringIndirect = null
|
||||
|
||||
if (<!EQUALITY_NOT_APPLICABLE!>x == null is Boolean<!>) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNREACHABLE_CODE
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Nothing?) {
|
||||
@@ -68,7 +69,7 @@ fun case_8(x: Nothing?) {
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: Nothing?) {
|
||||
if (!!(<!USELESS_IS_CHECK!>x !is TypealiasNullableStringIndirect?<!>)) else {
|
||||
if (!!(<!USELESS_IS_CHECK!>x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!><!>)) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Nothing?")!>x<!>?.<!UNRESOLVED_REFERENCE!>length<!>
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -70,8 +71,8 @@ fun case_8(x: Any?) {
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: Any?) {
|
||||
if (!!!(x !is TypealiasNullableStringIndirect?)) else {
|
||||
if (!(x !is TypealiasNullableStringIndirect?)) else {
|
||||
if (!!!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>)) else {
|
||||
if (!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>)) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>?.<!UNRESOLVED_REFERENCE!>get<!>(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// TODO: https://youtrack.jetbrains.com/issue/KT-49862
|
||||
|
||||
/*
|
||||
* KOTLIN DIAGNOSTICS NOT LINKED SPEC TEST (POSITIVE)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -68,7 +69,7 @@ fun case_8(x: Any?) {
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: Any?) {
|
||||
if (!!(x !is TypealiasNullableStringIndirect?)) else {
|
||||
if (!!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>)) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>?.get(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -80,7 +81,7 @@ fun case_8(x: Any?) {
|
||||
* ISSUES: KT-28329
|
||||
*/
|
||||
fun case_9(x: Any?) {
|
||||
if (true && true && !!(x !is TypealiasNullableStringIndirect?) && true && true && true && true) else {
|
||||
if (true && true && !!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>) && true && true && true && true) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any?")!>x<!>?.<!UNRESOLVED_REFERENCE!>get<!>(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -84,7 +85,7 @@ fun case_8(x: Any?) {
|
||||
* ISSUES: KT-28329
|
||||
*/
|
||||
fun case_9(x: Any?) {
|
||||
if (!!(x !is TypealiasNullableStringIndirect?) !== false === true) else {
|
||||
if (!!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>) !== false === true) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>?.get(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// TESTCASE NUMBER: 1
|
||||
fun case_1(x: Any?) {
|
||||
@@ -84,8 +85,8 @@ fun case_8(x: Any?) {
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: Any?) {
|
||||
if (!!!(x !is TypealiasNullableStringIndirect?)) else {
|
||||
if (!!(x !is TypealiasNullableStringIndirect?)) else {
|
||||
if (!!!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>)) else {
|
||||
if (!!(x !is TypealiasNullableStringIndirect<!REDUNDANT_NULLABLE!>?<!>)) else {
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>
|
||||
<!DEBUG_INFO_EXPRESSION_TYPE("kotlin.Any? & TypealiasNullableStringIndirect?")!>x<!>?.get(0)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_VARIABLE
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// FILE: other_package.kt
|
||||
|
||||
@@ -76,7 +77,7 @@ fun case_8(x: TypealiasNullableString) {
|
||||
* UNEXPECTED BEHAVIOUR
|
||||
* ISSUES: KT-28329
|
||||
*/
|
||||
fun case_9(x: TypealiasNullableString?) {
|
||||
fun case_9(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>) {
|
||||
if (true && true && true && true && x !== null) {
|
||||
|
||||
} else if (false) {
|
||||
@@ -96,7 +97,7 @@ fun case_10() {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 11
|
||||
fun case_11(x: TypealiasNullableString?, y: TypealiasNullableString) {
|
||||
fun case_11(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, y: TypealiasNullableString) {
|
||||
val z: TypealiasNullableString = null
|
||||
|
||||
if (x != null) {
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
// FIR_IGNORE
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_VARIABLE -UNREACHABLE_CODE -CAN_BE_VAL
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// FILE: other_types.kt
|
||||
|
||||
@@ -153,7 +154,7 @@ fun case_8(x: TypealiasNullableString) {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: TypealiasNullableString?, y: Nothing?) {
|
||||
fun case_9(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, y: Nothing?) {
|
||||
if (x === y) {
|
||||
|
||||
} else if (false) {
|
||||
@@ -192,7 +193,7 @@ fun case_10() {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 11
|
||||
fun case_11(x: TypealiasNullableString?, y: TypealiasNullableString) {
|
||||
fun case_11(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, y: TypealiasNullableString) {
|
||||
val z = null
|
||||
val u: TypealiasNullableString = null
|
||||
val v = null
|
||||
@@ -253,7 +254,7 @@ fun case_13(x: EmptyClass12_48?, z: Nothing?) =
|
||||
|
||||
// TESTCASE NUMBER: 14
|
||||
class Case14 {
|
||||
val x: TypealiasNullableString?
|
||||
val x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>
|
||||
init {
|
||||
x = TypealiasNullableString()
|
||||
}
|
||||
@@ -800,7 +801,7 @@ fun case_43(x: TypealiasNullableString) {
|
||||
* UNEXPECTED BEHAVIOUR
|
||||
* ISSUES: KT-28329
|
||||
*/
|
||||
fun case_44(x: TypealiasNullableString?, z1: Nothing?) {
|
||||
fun case_44(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, z1: Nothing?) {
|
||||
if (true && true && true && true && x !== z1) {
|
||||
|
||||
} else if (false) {
|
||||
@@ -831,7 +832,7 @@ fun case_45() {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 46
|
||||
fun case_46(x: TypealiasNullableString?, y: TypealiasNullableString) {
|
||||
fun case_46(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, y: TypealiasNullableString) {
|
||||
val t: TypealiasNullableString = null
|
||||
var z: Nothing? = null
|
||||
|
||||
@@ -879,7 +880,7 @@ fun case_48(x: EmptyClass12_48?, z: Nothing?) =
|
||||
|
||||
// TESTCASE NUMBER: 49
|
||||
class Case49 {
|
||||
val x: TypealiasNullableString?
|
||||
val x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>
|
||||
init {
|
||||
x = TypealiasNullableString()
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// !LANGUAGE: +NewInference
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION
|
||||
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_VARIABLE -UNREACHABLE_CODE -CAN_BE_VAL
|
||||
// SKIP_TXT
|
||||
// WITH_EXTENDED_CHECKERS
|
||||
|
||||
// FILE: other_package.kt
|
||||
|
||||
@@ -146,7 +147,7 @@ fun case_8(x: TypealiasString) {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 9
|
||||
fun case_9(x: TypealiasNullableString?) {
|
||||
fun case_9(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>) {
|
||||
if (x === null && <!SENSELESS_COMPARISON!>x === null<!> || <!SENSELESS_COMPARISON!>x === null<!>) {
|
||||
|
||||
} else if (<!SENSELESS_COMPARISON!>x === null<!> || <!SENSELESS_COMPARISON!>x === null<!>) {
|
||||
@@ -185,7 +186,7 @@ fun case_10() {
|
||||
}
|
||||
|
||||
// TESTCASE NUMBER: 11
|
||||
fun case_11(x: TypealiasNullableString?, y: TypealiasNullableString) {
|
||||
fun case_11(x: TypealiasNullableString<!REDUNDANT_NULLABLE!>?<!>, y: TypealiasNullableString) {
|
||||
val t: TypealiasNullableString = null
|
||||
|
||||
if (x == null) {
|
||||
|
||||
Reference in New Issue
Block a user