FIR checker: report REDUNDANT_LABEL_WARNING

Since many labels are not present in the FIR tree, this checker is
implemented as a syntax checker. Comparing with FE1.0, this change
reports some REDUNDANT_LABEL_WARNING that FE1.0 has missed, especially
LHS of assignments.
This commit is contained in:
Tianyu Geng
2021-09-24 10:18:02 -07:00
committed by TeamCityServer
parent cbc9d08623
commit 363b25504d
48 changed files with 255 additions and 266 deletions
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -3744,6 +3745,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.REDUNDANT_LABEL_WARNING) { firDiagnostic ->
RedundantLabelWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic -> add(FirJvmErrors.CONFLICTING_JVM_DECLARATIONS) { firDiagnostic ->
ConflictingJvmDeclarationsImpl( ConflictingJvmDeclarationsImpl(
firDiagnostic as FirPsiDiagnostic, firDiagnostic as FirPsiDiagnostic,
@@ -53,6 +53,7 @@ import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -2609,6 +2610,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = ReturnForBuiltInSuspend::class override val diagnosticClass get() = ReturnForBuiltInSuspend::class
} }
abstract class RedundantLabelWarning : KtFirDiagnostic<KtLabelReferenceExpression>() {
override val diagnosticClass get() = RedundantLabelWarning::class
}
abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() { abstract class ConflictingJvmDeclarations : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ConflictingJvmDeclarations::class override val diagnosticClass get() = ConflictingJvmDeclarations::class
} }
@@ -54,6 +54,7 @@ import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -3148,6 +3149,11 @@ internal class ReturnForBuiltInSuspendImpl(
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.ReturnForBuiltInSuspend(), KtAbstractFirDiagnostic<KtReturnExpression> ) : KtFirDiagnostic.ReturnForBuiltInSuspend(), KtAbstractFirDiagnostic<KtReturnExpression>
internal class RedundantLabelWarningImpl(
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.RedundantLabelWarning(), KtAbstractFirDiagnostic<KtLabelReferenceExpression>
internal class ConflictingJvmDeclarationsImpl( internal class ConflictingJvmDeclarationsImpl(
override val firDiagnostic: FirPsiDiagnostic, override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken, override val token: ValidityToken,
@@ -1353,6 +1353,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED) val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error<PsiElement>(PositioningStrategy.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>() val RETURN_FOR_BUILT_IN_SUSPEND by error<KtReturnExpression>()
} }
val LABEL by object : DiagnosticGroup("label") {
val REDUNDANT_LABEL_WARNING by warning<KtLabelReferenceExpression>(PositioningStrategy.LABEL)
}
} }
private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = { private val exposedVisibilityDiagnosticInit: DiagnosticBuilder.() -> Unit = {
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
import org.jetbrains.kotlin.psi.KtModifierListOwner import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration import org.jetbrains.kotlin.psi.KtNamedDeclaration
@@ -703,4 +704,7 @@ object FirErrors {
val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED) val MODIFIER_FORM_FOR_NON_BUILT_IN_SUSPEND by error0<PsiElement>(SourceElementPositioningStrategies.REFERENCED_NAME_BY_QUALIFIED)
val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>() val RETURN_FOR_BUILT_IN_SUSPEND by error0<KtReturnExpression>()
// label
val REDUNDANT_LABEL_WARNING by warning0<KtLabelReferenceExpression>(SourceElementPositioningStrategies.LABEL)
} }
@@ -30,6 +30,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirInvalidAndDangerousCharactersChecker, FirInvalidAndDangerousCharactersChecker,
FirAmbiguousAnonymousTypeChecker, FirAmbiguousAnonymousTypeChecker,
FirExplicitApiDeclarationChecker, FirExplicitApiDeclarationChecker,
FirRedundantLabelChecker,
) )
override val functionCheckers: Set<FirFunctionChecker> override val functionCheckers: Set<FirFunctionChecker>
@@ -0,0 +1,159 @@
/*
* 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.syntax
import com.intellij.lang.LighterASTNode
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiElement
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.buildChildSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getContainingClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.*
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.effectiveVisibility
import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.symbols.impl.FirRegularClassSymbol
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.psi.*
object FirRedundantLabelChecker : FirDeclarationSyntaxChecker<FirDeclaration, PsiElement>() {
override fun checkLightTree(
element: FirDeclaration,
source: FirLightSourceElement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
// Local declarations are already checked when the containing declaration is checked.
if (!isRootLabelContainer(element)) return
val allTraversalRoots = mutableSetOf<FirSourceElement>()
// First collect all labels in the declaration
element.accept(object : FirVisitorVoid() {
override fun visitElement(element: FirElement) {
element.acceptChildren(this)
}
override fun visitBlock(block: FirBlock) {
markTraversalRoot(block)
super.visitBlock(block)
}
override fun visitProperty(property: FirProperty) {
markTraversalRoot(property)
super.visitProperty(property)
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
markTraversalRoot(simpleFunction)
super.visitFunction(simpleFunction)
}
override fun visitPropertyAccessor(propertyAccessor: FirPropertyAccessor) {
markTraversalRoot(propertyAccessor)
super.visitPropertyAccessor(propertyAccessor)
}
override fun visitConstructor(constructor: FirConstructor) {
markTraversalRoot(constructor)
super.visitConstructor(constructor)
}
private fun markTraversalRoot(elem: FirElement) {
val elemSource = elem.source
if (elemSource?.kind is FirRealSourceElementKind) {
allTraversalRoots.add(elemSource)
}
}
})
for (root in allTraversalRoots) {
root.treeStructure.reportRedundantLabels(reporter, context, root as FirLightSourceElement, allTraversalRoots)
}
}
private fun FlyweightCapableTreeStructure<LighterASTNode>.reportRedundantLabels(
reporter: DiagnosticReporter,
context: CheckerContext,
source: FirLightSourceElement,
allTraversalRoots: Set<FirSourceElement>,
isChildNode: Boolean = false,
) {
if (isChildNode && source in allTraversalRoots) return // Prevent double traversal
val node = source.lighterASTNode
if (node.tokenType == KtNodeTypes.LABELED_EXPRESSION) {
val labelQualifier = findChildByType(node, KtNodeTypes.LABEL_QUALIFIER)
if (labelQualifier != null) {
findChildByType(labelQualifier, KtNodeTypes.LABEL)?.let { labelNode ->
when (unwrapParenthesesLabelsAndAnnotations(node).tokenType) {
KtNodeTypes.LAMBDA_EXPRESSION, KtNodeTypes.FOR, KtNodeTypes.WHILE, KtNodeTypes.DO_WHILE, KtNodeTypes.FUN -> {}
else -> reporter.reportOn(
source.buildChildSourceElement(labelNode),
FirErrors.REDUNDANT_LABEL_WARNING,
context
)
}
}
}
}
val childrenRef = Ref.create<Array<LighterASTNode?>>(null)
getChildren(node, childrenRef)
for (child in childrenRef.get() ?: return) {
if (child == null) continue
reportRedundantLabels(reporter, context, source.buildChildSourceElement(child), allTraversalRoots, true)
}
}
override fun checkPsi(
element: FirDeclaration,
source: FirPsiSourceElement,
psi: PsiElement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
// Local declarations are already checked when the containing declaration is checked.
if (!isRootLabelContainer(element)) return
// First collect all labels in the declaration
source.psi.accept(object : KtTreeVisitorVoid() {
override fun visitLabeledExpression(expression: KtLabeledExpression) {
val labelNameExpression = expression.getTargetLabel()
if (labelNameExpression != null) {
val deparenthesizedBaseExpression = KtPsiUtil.deparenthesize(expression)
if (deparenthesizedBaseExpression !is KtLambdaExpression &&
deparenthesizedBaseExpression !is KtLoopExpression &&
deparenthesizedBaseExpression !is KtNamedFunction
) {
reporter.reportOn(labelNameExpression.toFirPsiSourceElement(), FirErrors.REDUNDANT_LABEL_WARNING, context)
}
}
super.visitLabeledExpression(expression)
}
})
}
private fun isRootLabelContainer(element: FirDeclaration): Boolean {
if (element.source?.kind is FirFakeSourceElementKind) return false
if (element is FirCallableDeclaration && element.effectiveVisibility == EffectiveVisibility.Local) return false
return when (element) {
is FirAnonymousFunction -> false
is FirFunction -> true
is FirProperty -> true
// Consider class initializer of non local class as root label container.
is FirAnonymousInitializer -> {
val parentVisibility =
(element.getContainingClassSymbol(element.moduleData.session) as? FirRegularClassSymbol)?.effectiveVisibility
parentVisibility != null && parentVisibility != EffectiveVisibility.Local
}
else -> false
}
}
}
@@ -382,6 +382,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_CALL_OF
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICIT_BACKING_FIELD import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICIT_BACKING_FIELD
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICIT_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_EXPLICIT_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_INLINE_SUSPEND_FUNCTION_TYPE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_LABEL_WARNING
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODALITY_MODIFIER 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
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER_FOR_TARGET import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.REDUNDANT_MODIFIER_FOR_TARGET
@@ -1760,6 +1761,9 @@ class FirDefaultErrorMessages {
) )
map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited") map.put(RETURN_FOR_BUILT_IN_SUSPEND, "Using implicit label for this lambda is prohibited")
// Label
map.put(REDUNDANT_LABEL_WARNING, "Label is redundant, because it can not be referenced in either ''break'', ''continue'', or ''return'' expression")
// Extended checkers group // Extended checkers group
map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier") map.put(REDUNDANT_VISIBILITY_MODIFIER, "Redundant visibility modifier")
map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier") map.put(REDUNDANT_MODALITY_MODIFIER, "Redundant modality modifier")
@@ -518,7 +518,7 @@ object LightTreePositioningStrategies {
) { ) {
val lhs = tree.firstChildExpression(node) val lhs = tree.firstChildExpression(node)
lhs?.let { lhs?.let {
tree.unwrapParenthesesLabelsAndAnnotations(it)?.let { unwrapped -> tree.unwrapParenthesesLabelsAndAnnotations(it).let { unwrapped ->
return markElement(unwrapped, startOffset, endOffset, tree, node) return markElement(unwrapped, startOffset, endOffset, tree, node)
} }
} }
@@ -880,7 +880,7 @@ object LightTreePositioningStrategies {
tree.firstChildExpression(node) tree.firstChildExpression(node)
} }
lhs?.let { lhs?.let {
tree.unwrapParenthesesLabelsAndAnnotations(it)?.let { unwrapped -> tree.unwrapParenthesesLabelsAndAnnotations(it).let { unwrapped ->
return markElement(unwrapped, startOffset, endOffset, tree, node) return markElement(unwrapped, startOffset, endOffset, tree, node)
} }
} }
@@ -1153,8 +1153,7 @@ private fun FlyweightCapableTreeStructure<LighterASTNode>.referenceExpression(
} }
return result return result
} }
fun FlyweightCapableTreeStructure<LighterASTNode>.unwrapParenthesesLabelsAndAnnotations(node: LighterASTNode): LighterASTNode {
private fun FlyweightCapableTreeStructure<LighterASTNode>.unwrapParenthesesLabelsAndAnnotations(node: LighterASTNode): LighterASTNode? {
var unwrapped = node var unwrapped = node
while (true) { while (true) {
unwrapped = when (unwrapped.tokenType) { unwrapped = when (unwrapped.tokenType) {
@@ -6,12 +6,7 @@
package org.jetbrains.kotlin.fir.declarations.utils package org.jetbrains.kotlin.fir.declarations.utils
import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl
import org.jetbrains.kotlin.fir.render
import kotlin.contracts.ExperimentalContracts
import kotlin.contracts.contract
inline val FirMemberDeclaration.modality: Modality? get() = status.modality inline val FirMemberDeclaration.modality: Modality? get() = status.modality
inline val FirMemberDeclaration.isAbstract: Boolean get() = status.modality == Modality.ABSTRACT inline val FirMemberDeclaration.isAbstract: Boolean get() = status.modality == Modality.ABSTRACT
@@ -24,9 +19,13 @@ inline val FirMemberDeclaration.isFinal: Boolean
} }
inline val FirMemberDeclaration.visibility: Visibility get() = status.visibility inline val FirMemberDeclaration.visibility: Visibility get() = status.visibility
/**
* Gets the effective visibility. Note that it's assumed that the element or its non-local container has at least resolve phase
* [FirResolvePhase.STATUS], in which case, any declarations with unresolved status are effectively local.
*/
inline val FirMemberDeclaration.effectiveVisibility: EffectiveVisibility inline val FirMemberDeclaration.effectiveVisibility: EffectiveVisibility
get() = (status as? FirResolvedDeclarationStatus)?.effectiveVisibility get() = (status as? FirResolvedDeclarationStatus)?.effectiveVisibility ?: EffectiveVisibility.Local
?: error("Effective visibility for ${render(FirRenderer.RenderMode.NoBodies)} must be resolved")
inline val FirMemberDeclaration.allowsToHaveFakeOverride: Boolean inline val FirMemberDeclaration.allowsToHaveFakeOverride: Boolean
get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.InvisibleFake get() = !Visibilities.isPrivate(visibility) && visibility != Visibilities.InvisibleFake
+2 -2
View File
@@ -2,7 +2,7 @@ class C {
fun f (a : Boolean, b : Boolean) { fun f (a : Boolean, b : Boolean) {
b@ while (true) b@ while (true)
a@ { <!REDUNDANT_LABEL_WARNING!>a@<!> {
<!NOT_A_LOOP_LABEL!>break@f<!> <!NOT_A_LOOP_LABEL!>break@f<!>
break break
break@b break@b
@@ -12,7 +12,7 @@ class C {
<!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>continue<!> <!BREAK_OR_CONTINUE_OUTSIDE_A_LOOP!>continue<!>
b@ while (true) b@ while (true)
a@ { <!REDUNDANT_LABEL_WARNING!>a@<!> {
<!NOT_A_LOOP_LABEL!>continue@f<!> <!NOT_A_LOOP_LABEL!>continue@f<!>
continue continue
continue@b continue@b
-23
View File
@@ -1,23 +0,0 @@
// !CHECK_TYPE
fun test() : Unit {
var x : Int? = 0
var y : Int = 0
checkSubtype<Int?>(x)
checkSubtype<Int>(y)
checkSubtype<Int>(x as Int)
checkSubtype<Int>(y <!USELESS_CAST!>as Int<!>)
checkSubtype<Int?>(x as Int?)
checkSubtype<Int?>(y as Int?)
checkSubtype<Int?>(x as? Int)
checkSubtype<Int?>(y as? Int)
checkSubtype<Int?>(x as? Int?)
checkSubtype<Int?>(y as? Int?)
val s = "" as Any
("" as String?)?.length
(data@("" as String?))?.length
(<!WRONG_ANNOTATION_TARGET!>@MustBeDocumented()<!>( "" as String?))?.length
Unit
}
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !CHECK_TYPE // !CHECK_TYPE
fun test() : Unit { fun test() : Unit {
@@ -62,7 +62,7 @@ fun main1() {
{1}(); {1}();
(fun (x : Int) = x)(1) (fun (x : Int) = x)(1)
1.(<!FUNCTION_EXPECTED!>fun Int.(x : Int) = x<!>)(1); 1.(<!FUNCTION_EXPECTED!>fun Int.(x : Int) = x<!>)(1);
l@{1}() <!REDUNDANT_LABEL_WARNING!>l@<!>{1}()
1.((<!FUNCTION_EXPECTED!>fun Int.() = 1<!>))() 1.((<!FUNCTION_EXPECTED!>fun Int.() = 1<!>))()
1.(<!FUNCTION_EXPECTED!>f()<!>)() 1.(<!FUNCTION_EXPECTED!>f()<!>)()
1.<!FUNCTION_EXPECTED!>if(true){f()}else{f()}<!>() 1.<!FUNCTION_EXPECTED!>if(true){f()}else{f()}<!>()
+18 -18
View File
@@ -57,19 +57,19 @@ annotation class Ann
fun canBe(i0: Int, j: Int) { fun canBe(i0: Int, j: Int) {
var i = i0 var i = i0
(label@ i) = 34 (<!REDUNDANT_LABEL_WARNING!>label@<!> i) = 34
(label@ <!VAL_REASSIGNMENT!>j<!>) = 34 //repeat for j (<!REDUNDANT_LABEL_WARNING!>label@<!> <!VAL_REASSIGNMENT!>j<!>) = 34 //repeat for j
val a = A() val a = A()
(l@ a.a) = 3894 (<!REDUNDANT_LABEL_WARNING!>l@<!> a.a) = 3894
@Ann @Ann
l@ (i) = 123 <!REDUNDANT_LABEL_WARNING!>l@<!> (i) = 123
} }
fun canBe2(j: Int) { fun canBe2(j: Int) {
(label@ <!VAL_REASSIGNMENT!>j<!>) = 34 (<!REDUNDANT_LABEL_WARNING!>label@<!> <!VAL_REASSIGNMENT!>j<!>) = 34
} }
class A() { class A() {
@@ -79,29 +79,29 @@ class A() {
class Test() { class Test() {
fun testIllegalValues() { fun testIllegalValues() {
<!VARIABLE_EXPECTED!>1<!> += 23 <!VARIABLE_EXPECTED!>1<!> += 23
(l@ <!VARIABLE_EXPECTED!>1<!>) += 23 (<!REDUNDANT_LABEL_WARNING!>l@<!> <!VARIABLE_EXPECTED!>1<!>) += 23
<!VARIABLE_EXPECTED!>getInt()<!> += 343 <!VARIABLE_EXPECTED!>getInt()<!> += 343
(f@ <!VARIABLE_EXPECTED!>getInt()<!>) += 343 (<!REDUNDANT_LABEL_WARNING!>f@<!> <!VARIABLE_EXPECTED!>getInt()<!>) += 343
<!VARIABLE_EXPECTED!>1<!>++ <!VARIABLE_EXPECTED!>1<!>++
(r@ <!VARIABLE_EXPECTED!>1<!>)-- (<!REDUNDANT_LABEL_WARNING!>r@<!> <!VARIABLE_EXPECTED!>1<!>)--
<!VARIABLE_EXPECTED!>getInt()<!>++ <!VARIABLE_EXPECTED!>getInt()<!>++
(m@ <!VARIABLE_EXPECTED!>getInt()<!>)-- (<!REDUNDANT_LABEL_WARNING!>m@<!> <!VARIABLE_EXPECTED!>getInt()<!>)--
++<!VARIABLE_EXPECTED!>2<!> ++<!VARIABLE_EXPECTED!>2<!>
--(r@ <!VARIABLE_EXPECTED!>2<!>) --(<!REDUNDANT_LABEL_WARNING!>r@<!> <!VARIABLE_EXPECTED!>2<!>)
this<!UNRESOLVED_REFERENCE!>++<!> this<!UNRESOLVED_REFERENCE!>++<!>
var s : String = "r" var s : String = "r"
s += "ss" s += "ss"
s += this s += this
s += (a@ 2) s += (<!REDUNDANT_LABEL_WARNING!>a@<!> 2)
@Ann @Ann
l@ (<!VARIABLE_EXPECTED!>1<!>) = 123 <!REDUNDANT_LABEL_WARNING!>l@<!> (<!VARIABLE_EXPECTED!>1<!>) = 123
} }
fun testIncompleteSyntax() { fun testIncompleteSyntax() {
@@ -114,22 +114,22 @@ class Test() {
val b: Int = 34 val b: Int = 34
a += 34 a += 34
(l@ a) += 34 (<!REDUNDANT_LABEL_WARNING!>l@<!> a) += 34
<!VAL_REASSIGNMENT!>b<!> += 34 <!VAL_REASSIGNMENT!>b<!> += 34
a++ a++
(@Ann l@ a)-- (@Ann <!REDUNDANT_LABEL_WARNING!>l@<!> a)--
(a)++ (a)++
--a --a
++(@Ann l@ a) ++(@Ann <!REDUNDANT_LABEL_WARNING!>l@<!> a)
--(a) --(a)
} }
fun testVariables1() { fun testVariables1() {
val b: Int = 34 val b: Int = 34
(l@ <!VAL_REASSIGNMENT!>b<!>) += 34 (<!REDUNDANT_LABEL_WARNING!>l@<!> <!VAL_REASSIGNMENT!>b<!>) += 34
//repeat for b //repeat for b
(<!VAL_REASSIGNMENT!>b<!>) += 3 (<!VAL_REASSIGNMENT!>b<!>) += 3
} }
@@ -140,12 +140,12 @@ class Test() {
a[6] += 43 a[6] += 43
@Ann @Ann
a[7] = 7 a[7] = 7
(@Ann l@ (a))[8] = 8 (@Ann <!REDUNDANT_LABEL_WARNING!>l@<!> (a))[8] = 8
ab.getArray()[54] = 23 ab.getArray()[54] = 23
ab.getArray()[54]++ ab.getArray()[54]++
(f@ a)[3] = 4 (<!REDUNDANT_LABEL_WARNING!>f@<!> a)[3] = 4
this<!NO_SET_METHOD!>[54]<!> = 34 this<!NO_SET_METHOD!>[54]<!> = 34
} }
@@ -22,6 +22,6 @@ fun main() {
<!NO_COMPANION_OBJECT!>System<!> is Int <!NO_COMPANION_OBJECT!>System<!> is Int
<!INVISIBLE_REFERENCE!>System<!>() <!INVISIBLE_REFERENCE!>System<!>()
(<!NO_COMPANION_OBJECT!>System<!>) (<!NO_COMPANION_OBJECT!>System<!>)
foo@ <!NO_COMPANION_OBJECT!>System<!> <!REDUNDANT_LABEL_WARNING!>foo@<!> <!NO_COMPANION_OBJECT!>System<!>
null <!UNRESOLVED_REFERENCE!>in<!> System null <!UNRESOLVED_REFERENCE!>in<!> System
} }
+2 -2
View File
@@ -5,8 +5,8 @@
annotation class yield annotation class yield
fun bar(p: Int) { fun bar(p: Int) {
yield@ p <!REDUNDANT_LABEL_WARNING!>yield@<!> p
`yield`@ p <!REDUNDANT_LABEL_WARNING!>`yield`@<!> p
@yield() p @yield() p
@`yield`() p @`yield`() p
+1 -1
View File
@@ -21,7 +21,7 @@ fun <!UNDERSCORE_IS_RESERVED!>__<!>(<!UNDERSCORE_IS_RESERVED!>___<!>: Int, y: <!
fun localFun(<!UNDERSCORE_IS_RESERVED!>_<!>: String) = 1 fun localFun(<!UNDERSCORE_IS_RESERVED!>_<!>: String) = 1
<!UNDERSCORE_IS_RESERVED!>__<!>@ return if (y != null) <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>, y) else <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(`_`, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>______<!>) <!REDUNDANT_LABEL_WARNING!><!UNDERSCORE_IS_RESERVED!>__<!>@<!> return if (y != null) <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(<!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>____<!>, y) else <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>__<!>(`_`, <!UNDERSCORE_USAGE_WITHOUT_BACKTICKS!>______<!>)
} }
@@ -12,7 +12,7 @@ fun test2() {
<!UNREACHABLE_CODE!>bar(<!>11, todo()/*comment1*/, <!UNREACHABLE_CODE!>""/*comment2*/)<!> <!UNREACHABLE_CODE!>bar(<!>11, todo()/*comment1*/, <!UNREACHABLE_CODE!>""/*comment2*/)<!>
} }
fun test3() { fun test3() {
<!UNREACHABLE_CODE!>bar(<!>11, <!UNREACHABLE_CODE!>l@(<!>todo()/*comment*/<!UNREACHABLE_CODE!>), "")<!> <!UNREACHABLE_CODE!>bar(<!>11, <!UNREACHABLE_CODE!><!REDUNDANT_LABEL_WARNING!>l@<!>(<!>todo()/*comment*/<!UNREACHABLE_CODE!>), "")<!>
} }
fun todo(): Nothing = throw Exception() fun todo(): Nothing = throw Exception()
@@ -19,7 +19,7 @@ class TestObjectLiteral {
val y = obj val y = obj
} }
} }
val obj1: A = l@ ( object: A(obj1) { val obj1: A = <!REDUNDANT_LABEL_WARNING!>l@<!> ( object: A(obj1) {
init { init {
val x = obj1 val x = obj1
} }
@@ -51,12 +51,12 @@ fun testLoopLabelInReturn(xs: List<Int>) {
} }
fun testValLabelInReturn() { fun testValLabelInReturn() {
L@ val fn = { <!NOT_A_FUNCTION_LABEL!>return@L<!> } <!REDUNDANT_LABEL_WARNING!>L@<!> val fn = { <!NOT_A_FUNCTION_LABEL!>return@L<!> }
fn() fn()
} }
fun testHighOrderFunctionCallLabelInReturn() { fun testHighOrderFunctionCallLabelInReturn() {
L@ run { <!REDUNDANT_LABEL_WARNING!>L@<!> run {
<!NOT_A_FUNCTION_LABEL!>return@L<!> <!NOT_A_FUNCTION_LABEL!>return@L<!>
} }
} }
@@ -51,12 +51,12 @@ fun testLoopLabelInReturn(xs: List<Int>) {
} }
fun testValLabelInReturn() { fun testValLabelInReturn() {
L@ val fn = { <!NOT_A_FUNCTION_LABEL!>return@L<!> } <!REDUNDANT_LABEL_WARNING!>L@<!> val fn = { <!NOT_A_FUNCTION_LABEL!>return@L<!> }
fn() fn()
} }
fun testHighOrderFunctionCallLabelInReturn() { fun testHighOrderFunctionCallLabelInReturn() {
L@ run { <!REDUNDANT_LABEL_WARNING!>L@<!> run {
<!NOT_A_FUNCTION_LABEL!>return@L<!> <!NOT_A_FUNCTION_LABEL!>return@L<!>
} }
} }
@@ -1,39 +0,0 @@
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class Ann
fun testLambdaLabel() = l@ { 42 }
fun testAnonymousFunctionLabel() = l@ fun() {}
fun testAnnotatedLambdaLabel() = lambda@ @Ann {}
fun testParenthesizedLambdaLabel() = lambda@ ( {} )
fun testLabelBoundToInvokeOperatorExpression() = l@ { 42 }()
fun testLabelBoundToLambda() = (l@ { 42 })()
fun testWhileLoopLabel() {
L@ while (true) {}
}
fun testDoWhileLoopLabel() {
L@ do {} while (true)
}
fun testForLoopLabel(xs: List<Any>) {
L@ for (x in xs) {}
}
fun testValLabel() {
L@ val fn = {}
fn()
}
fun testHighOrderFunctionCallLabel() {
L@ run {}
}
fun testAnonymousObjectLabel() =
L@ object {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
@Target(AnnotationTarget.EXPRESSION) @Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE) @Retention(AnnotationRetention.SOURCE)
annotation class Ann annotation class Ann
@@ -1,11 +0,0 @@
import kotlin.reflect.KProperty
class A3 {
val a: String by l@ MyProperty()
class MyProperty<T> {}
operator fun <T> MyProperty<T>.getValue(thisRef: Any?, desc: KProperty<*>): T {
throw Exception("$thisRef $desc")
}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
class A3 { class A3 {
@@ -1,3 +1,3 @@
fun test() { fun test() {
(d@ val bar = 2) (<!REDUNDANT_LABEL_WARNING!>d@<!> val bar = 2)
} }
@@ -6,19 +6,19 @@ import checkSubtype
fun test(i: Int?) { fun test(i: Int?) {
if (i != null) { if (i != null) {
foo(l1@ i) foo(<!REDUNDANT_LABEL_WARNING!>l1@<!> i)
foo((i)) foo((i))
foo(l2@ (i)) foo(<!REDUNDANT_LABEL_WARNING!>l2@<!> (i))
foo((l3@ i)) foo((<!REDUNDANT_LABEL_WARNING!>l3@<!> i))
} }
val a: Int = <!INITIALIZER_TYPE_MISMATCH!>l4@ ""<!> val a: Int = <!INITIALIZER_TYPE_MISMATCH!><!REDUNDANT_LABEL_WARNING!>l4@<!> ""<!>
val b: Int = <!INITIALIZER_TYPE_MISMATCH!>("")<!> val b: Int = <!INITIALIZER_TYPE_MISMATCH!>("")<!>
val c: Int = checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>""<!>) val c: Int = checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)
val d: Int = <!INITIALIZER_TYPE_MISMATCH!>checkSubtype<Long>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!> val d: Int = <!INITIALIZER_TYPE_MISMATCH!>checkSubtype<Long>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
foo(l4@ <!ARGUMENT_TYPE_MISMATCH!>""<!>) foo(<!REDUNDANT_LABEL_WARNING!>l4@<!> <!ARGUMENT_TYPE_MISMATCH!>""<!>)
foo((<!ARGUMENT_TYPE_MISMATCH!>""<!>)) foo((<!ARGUMENT_TYPE_MISMATCH!>""<!>))
foo(checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)) foo(checkSubtype<Int>(<!ARGUMENT_TYPE_MISMATCH!>""<!>))
foo(<!ARGUMENT_TYPE_MISMATCH!>checkSubtype<Long>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>) foo(<!ARGUMENT_TYPE_MISMATCH!>checkSubtype<Long>(<!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>)
@@ -1,3 +0,0 @@
fun f(s : String?) : Boolean {
return foo@(s?.equals("a"))!!
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun f(s : String?) : Boolean { fun f(s : String?) : Boolean {
return <!REDUNDANT_LABEL_WARNING!>foo@<!>(s?.equals("a"))!! return <!REDUNDANT_LABEL_WARNING!>foo@<!>(s?.equals("a"))!!
} }
@@ -1,22 +0,0 @@
// !LANGUAGE: +ExpectedTypeFromCast
@Target(AnnotationTarget.EXPRESSION)
@Retention(AnnotationRetention.SOURCE)
annotation class bar
fun <T> foo(): T = TODO()
fun <V> id(value: V) = value
val par1 = (foo()) as String
val par2 = ((foo())) as String
val par3 = (dd@ (foo())) as String
val par4 = ( @bar() (foo())) as String
object X {
fun <T> foo(): T = TODO()
}
val par5 = ( @bar() X.foo()) as String
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !LANGUAGE: +ExpectedTypeFromCast // !LANGUAGE: +ExpectedTypeFromCast
@Target(AnnotationTarget.EXPRESSION) @Target(AnnotationTarget.EXPRESSION)
@@ -1,40 +0,0 @@
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
inline fun foo(bar1: (String.() -> Int) -> Int, bar2: (()->Int) -> Int) {
bar1 label@ {
this@label.length
}
bar1 {
this.length
}
//unmute after KT-4247 fix
//bar1 {
// this@bar1.length
//}
bar2 l@ {
11
}
bar2 {
12
}
}
inline fun foo2(bar1: (String.() -> Int) -> Int) {
l1@ <!USAGE_IS_NOT_INLINABLE!>bar1<!>
l2@ bar1 {
11
}
(l3@ bar1) {
11
}
(l5@ (l4@ bar1)) {
11
}
}
+1
View File
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE // !DIAGNOSTICS: -UNUSED_EXPRESSION -UNUSED_PARAMETER -UNUSED_VARIABLE
inline fun foo(bar1: (String.() -> Int) -> Int, bar2: (()->Int) -> Int) { inline fun foo(bar1: (String.() -> Int) -> Int, bar2: (()->Int) -> Int) {
@@ -1,27 +0,0 @@
// !CHECK_TYPE
inline fun inlineFunWithInvoke(s: (p: Int) -> Unit) {
(s)(11)
(s).invoke(11)
(s) <!INFIX_MODIFIER_REQUIRED!>invoke<!> 11
(<!USAGE_IS_NOT_INLINABLE!>s<!>)
}
<!NOTHING_TO_INLINE!>inline<!> fun Function1<Int, Unit>.inlineExt() {
(this).invoke(11)
(this) <!INFIX_MODIFIER_REQUIRED!>invoke<!> 11
(this)(11)
(this)
}
inline fun inlineFunWithInvoke2(s: (p: Int) -> Unit) {
(((s)))(11)
(((s))).invoke(11)
(((s))) <!INFIX_MODIFIER_REQUIRED!>invoke<!> 11
(((<!USAGE_IS_NOT_INLINABLE!>s<!>)))
}
inline fun propagation(s: (p: Int) -> Unit) {
inlineFunWithInvoke((label@ s))
inlineFunWithInvoke((label2@ label@ s))
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// !CHECK_TYPE // !CHECK_TYPE
inline fun inlineFunWithInvoke(s: (p: Int) -> Unit) { inline fun inlineFunWithInvoke(s: (p: Int) -> Unit) {
@@ -32,7 +32,7 @@ fun main() {
val w: Foo? = null val w: Foo? = null
w<!UNSAFE_CALL!>.<!>f = z w<!UNSAFE_CALL!>.<!>f = z
(w<!UNSAFE_CALL!>.<!>f) = z (w<!UNSAFE_CALL!>.<!>f) = z
(label@ w<!UNSAFE_CALL!>.<!>f) = z (<!REDUNDANT_LABEL_WARNING!>label@<!> w<!UNSAFE_CALL!>.<!>f) = z
w!!.f = z w!!.f = z
w.f = z w.f = z
w<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.f = z w<!UNNECESSARY_NOT_NULL_ASSERTION!>!!<!>.f = z
@@ -8,8 +8,8 @@ fun main() {
val h : String = v--; val h : String = v--;
val h1 : String = --v; val h1 : String = --v;
val i : String = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH!>!true<!>; val i : String = <!INITIALIZER_TYPE_MISMATCH, TYPE_MISMATCH!>!true<!>;
val j : String = <!INITIALIZER_TYPE_MISMATCH!>foo@ true<!>; val j : String = <!INITIALIZER_TYPE_MISMATCH!><!REDUNDANT_LABEL_WARNING!>foo@<!> true<!>;
val k : String = <!INITIALIZER_TYPE_MISMATCH!>foo@ bar@ true<!>; val k : String = <!INITIALIZER_TYPE_MISMATCH!><!REDUNDANT_LABEL_WARNING!>foo@<!> <!REDUNDANT_LABEL_WARNING!>bar@<!> true<!>;
val l : String = <!INITIALIZER_TYPE_MISMATCH!>-1<!>; val l : String = <!INITIALIZER_TYPE_MISMATCH!>-1<!>;
val m : String = <!INITIALIZER_TYPE_MISMATCH!>+1<!>; val m : String = <!INITIALIZER_TYPE_MISMATCH!>+1<!>;
} }
@@ -1,20 +0,0 @@
interface Foo<T>
class Bar {
operator fun <T> invoke(): Foo<T> = throw Exception()
}
class A {
val bar = Bar()
}
fun fooInt(l: Foo<Int>) = l
fun test(bar: Bar, a: A) {
// no elements with error types
fooInt((bar()))
fooInt(if (true) bar() else bar())
fooInt(label@ bar())
fooInt(a.bar())
fooInt(((label@ if (true) (a.bar()) else bar())))
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
interface Foo<T> interface Foo<T>
class Bar { class Bar {
@@ -1,23 +0,0 @@
fun testEquals(x: Int) {
if (<!SENSELESS_COMPARISON!>x == null<!>) {}
if (<!SENSELESS_COMPARISON!>x == (null)<!>) {}
if (<!SENSELESS_COMPARISON!>x == foo@ null<!>) {}
}
fun testEqualsFlipped(x: Int) {
if (<!SENSELESS_COMPARISON!>null == x<!>) {}
if (<!SENSELESS_COMPARISON!>(null) == x<!>) {}
if (<!SENSELESS_COMPARISON!>foo@ null == x<!>) {}
}
fun testNotEquals(x: Int) {
if (<!SENSELESS_COMPARISON!>x != null<!>) {}
if (<!SENSELESS_COMPARISON!>x != (null)<!>) {}
if (<!SENSELESS_COMPARISON!>x != foo@ null<!>) {}
}
fun testNotEqualsFlipped(x: Int) {
if (<!SENSELESS_COMPARISON!>null != x<!>) {}
if (<!SENSELESS_COMPARISON!>(null) != x<!>) {}
if (<!SENSELESS_COMPARISON!>foo@ null != x<!>) {}
}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
fun testEquals(x: Int) { fun testEquals(x: Int) {
if (<!SENSELESS_COMPARISON!>x == null<!>) {} if (<!SENSELESS_COMPARISON!>x == null<!>) {}
if (<!SENSELESS_COMPARISON!>x == (null)<!>) {} if (<!SENSELESS_COMPARISON!>x == (null)<!>) {}
@@ -31,7 +31,7 @@ inline fun case_4(block: () -> Unit) {
// TESTCASE NUMBER: 5 // TESTCASE NUMBER: 5
inline fun case_5(block: () -> Unit) { inline fun case_5(block: () -> Unit) {
test@ contract { <!REDUNDANT_LABEL_WARNING!>test@<!> contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE) callsInPlace(block, InvocationKind.EXACTLY_ONCE)
} }
return block() return block()