Report UNUSED_DESTRUCTURED_PARAMETER_ENTRY
on destructured lambda parameters #KT-14347 Fixed
This commit is contained in:
@@ -602,11 +602,17 @@ class ControlFlowInformationProvider private constructor(
|
||||
) {
|
||||
element.nameIdentifier ?: return
|
||||
if (!VariableUseState.isUsed(variableUseState)) {
|
||||
if (!element.isSingleUnderscore && KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
||||
report(Errors.UNUSED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
}
|
||||
else if (element is KtParameter) {
|
||||
processUnusedParameter(ctxt, element, variableDescriptor)
|
||||
if (element.isSingleUnderscore) return
|
||||
when {
|
||||
// KtDestructuringDeclarationEntry -> KtDestructuringDeclaration -> KtParameter -> KtParameterList
|
||||
element is KtDestructuringDeclarationEntry && element.parent?.parent?.parent is KtParameterList ->
|
||||
report(Errors.UNUSED_DESTRUCTURED_PARAMETER_ENTRY.on(element, variableDescriptor), ctxt)
|
||||
|
||||
KtPsiUtil.isRemovableVariableDeclaration(element) ->
|
||||
report(Errors.UNUSED_VARIABLE.on(element, variableDescriptor), ctxt)
|
||||
|
||||
element is KtParameter ->
|
||||
processUnusedParameter(ctxt, element, variableDescriptor)
|
||||
}
|
||||
}
|
||||
else if (variableUseState === ONLY_WRITTEN_NEVER_READ && KtPsiUtil.isRemovableVariableDeclaration(element)) {
|
||||
@@ -626,7 +632,6 @@ class ControlFlowInformationProvider private constructor(
|
||||
|
||||
private fun processUnusedParameter(ctxt: VariableUseContext, element: KtParameter, variableDescriptor: VariableDescriptor) {
|
||||
val owner = element.parent?.parent
|
||||
if (element.isSingleUnderscore) return
|
||||
when (owner) {
|
||||
is KtPrimaryConstructor -> if (!element.hasValOrVar()) {
|
||||
val containingClass = owner.getContainingClassOrObject()
|
||||
|
||||
@@ -40,7 +40,10 @@ import org.jetbrains.kotlin.lexer.KtTokens.*
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedElementSelector
|
||||
import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.BindingContextUtils
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.CompileTimeConstantUtils
|
||||
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ArgumentMatch
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
@@ -49,8 +52,8 @@ import org.jetbrains.kotlin.resolve.calls.tasks.ExplicitReceiverKind
|
||||
import org.jetbrains.kotlin.resolve.calls.tower.getFakeDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.calls.util.FakeCallableDescriptorForObject
|
||||
import org.jetbrains.kotlin.resolve.constants.evaluate.ConstantExpressionEvaluator
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.*
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.expressions.OperatorConventions
|
||||
import java.util.*
|
||||
|
||||
@@ -970,6 +973,10 @@ class ControlFlowProcessor(private val trace: BindingTrace) {
|
||||
builder.bindLabel(skipDefaultValue)
|
||||
}
|
||||
generateInitializer(parameter, computePseudoValueForParameter(parameter))
|
||||
|
||||
parameter.destructuringDeclaration?.let {
|
||||
visitDestructuringDeclaration(it, generateWriteForEntries = true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun computePseudoValueForParameter(parameter: KtParameter): PseudoValue {
|
||||
|
||||
@@ -667,6 +667,8 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory1<KtNamedDeclaration, VariableDescriptor> UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
DiagnosticFactory1<KtParameter, VariableDescriptor> UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
DiagnosticFactory1<KtDestructuringDeclarationEntry, VariableDescriptor> UNUSED_DESTRUCTURED_PARAMETER_ENTRY =
|
||||
DiagnosticFactory1.create(WARNING, DECLARATION_NAME);
|
||||
DiagnosticFactory2<KtTypeParameter, TypeParameterDescriptor, KotlinType> UNUSED_TYPEALIAS_PARAMETER =
|
||||
DiagnosticFactory2.create(WARNING, DECLARATION_NAME);
|
||||
|
||||
|
||||
+1
@@ -275,6 +275,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(UNINITIALIZED_ENUM_COMPANION, "Companion object of enum class ''{0}'' is uninitialized here", NAME);
|
||||
MAP.put(UNUSED_VARIABLE, "Variable ''{0}'' is never used", NAME);
|
||||
MAP.put(UNUSED_PARAMETER, "Parameter ''{0}'' is never used", NAME);
|
||||
MAP.put(UNUSED_DESTRUCTURED_PARAMETER_ENTRY, "Destructured parameter ''{0}'' is never used", NAME);
|
||||
MAP.put(ASSIGNED_BUT_NEVER_ACCESSED_VARIABLE, "Variable ''{0}'' is assigned but never accessed", NAME);
|
||||
MAP.put(VARIABLE_WITH_REDUNDANT_INITIALIZER, "Variable ''{0}'' initializer is redundant", NAME);
|
||||
MAP.put(UNUSED_VALUE, "The value ''{0}'' assigned to ''{1}'' is never used", ELEMENT_TEXT, FQ_NAMES_IN_TYPES);
|
||||
|
||||
@@ -5,12 +5,12 @@ val receiverAndReturnType = { Int.(<!SYNTAX!><!>)<!SYNTAX!>: Int -> 5<!> }
|
||||
val receiverAndReturnTypeWithParameter = { Int.(<!UNRESOLVED_REFERENCE!>a<!><!SYNTAX!><!SYNTAX!><!>: Int): Int -> 5<!> }
|
||||
|
||||
val returnType = { (<!SYNTAX!><!>): Int -> 5 }
|
||||
val returnTypeWithParameter = { (<!COMPONENT_FUNCTION_MISSING!>b: Int<!>): Int -> 5 }
|
||||
val returnTypeWithParameter = { (<!COMPONENT_FUNCTION_MISSING!><!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>: Int<!>): Int -> 5 }
|
||||
|
||||
val receiverWithFunctionType = { ((Int)<!SYNTAX!><!> <!SYNTAX!>-> Int).() -><!> }
|
||||
|
||||
val parenthesizedParameters = { <!CANNOT_INFER_PARAMETER_TYPE!>(a: Int)<!> -> }
|
||||
val parenthesizedParameters2 = { <!CANNOT_INFER_PARAMETER_TYPE!>(b)<!> -> }
|
||||
val parenthesizedParameters = { <!CANNOT_INFER_PARAMETER_TYPE!>(<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>: Int)<!> -> }
|
||||
val parenthesizedParameters2 = { <!CANNOT_INFER_PARAMETER_TYPE!>(<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>)<!> -> }
|
||||
|
||||
val none = { -> }
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -31,7 +31,7 @@ fun bar() {
|
||||
}
|
||||
|
||||
// From KEEP: Component-functions are resolved in the scope that contains the lambda
|
||||
foobaz { (<!COMPONENT_FUNCTION_MISSING!>a<!>, <!COMPONENT_FUNCTION_MISSING!>b<!>) ->
|
||||
foobaz { (<!COMPONENT_FUNCTION_MISSING, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>, <!COMPONENT_FUNCTION_MISSING, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>) ->
|
||||
}
|
||||
|
||||
// From KEEP: Component-functions are resolved in the scope that contains the lambda
|
||||
|
||||
Vendored
+3
-3
@@ -6,12 +6,12 @@ data class B(val u: Double, val w: Short)
|
||||
fun foo(block: (A, B) -> Unit) { }
|
||||
|
||||
fun bar() {
|
||||
foo { (<!REDECLARATION!>a<!>, <!REDECLARATION!>a<!>), b ->
|
||||
foo { (<!REDECLARATION, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>, <!REDECLARATION!>a<!>), b ->
|
||||
a checkType { <!TYPE_MISMATCH!>_<!><Int>() }
|
||||
b checkType { <!TYPE_MISMATCH!>_<!><String>() }
|
||||
}
|
||||
|
||||
foo { (<!REDECLARATION!>a<!>, b), <!REDECLARATION!>a<!> ->
|
||||
foo { (<!REDECLARATION, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>, b), <!REDECLARATION!>a<!> ->
|
||||
a checkType { <!TYPE_MISMATCH!>_<!><Int>() }
|
||||
b checkType { _<String>() }
|
||||
}
|
||||
@@ -21,7 +21,7 @@ fun bar() {
|
||||
b checkType { <!TYPE_MISMATCH!>_<!><String>() }
|
||||
}
|
||||
|
||||
foo { (a, <!REDECLARATION!>b<!>), (c, <!REDECLARATION!>b<!>) ->
|
||||
foo { (a, <!REDECLARATION, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>), (c, <!REDECLARATION!>b<!>) ->
|
||||
a checkType { _<Int>() }
|
||||
b checkType { <!TYPE_MISMATCH!>_<!><String>() }
|
||||
c checkType { <!TYPE_MISMATCH!>_<!><B>() }
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ fun bar() {
|
||||
_ checkType { _<String>() }
|
||||
}
|
||||
|
||||
foo { (<!REDECLARATION!>`_`<!>, <!REDECLARATION!>`_`<!>) ->
|
||||
foo { (<!REDECLARATION, UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>`_`<!>, <!REDECLARATION!>`_`<!>) ->
|
||||
_ checkType { _<String>() }
|
||||
}
|
||||
|
||||
|
||||
Vendored
+43
@@ -0,0 +1,43 @@
|
||||
// !CHECK_TYPE
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
data class A(val x: Int, val y: String)
|
||||
data class B(val u: Double, val w: Short)
|
||||
|
||||
fun foo(block: (A) -> Unit) { }
|
||||
fun foobar(block: (A, B) -> Unit) { }
|
||||
|
||||
fun bar() {
|
||||
foo { (a, <!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>) ->
|
||||
a checkType { _<Int>() }
|
||||
}
|
||||
|
||||
foo { (<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>, b) ->
|
||||
b checkType { _<String>() }
|
||||
}
|
||||
|
||||
foo { (a: Int, <!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>: String) ->
|
||||
a checkType { _<Int>() }
|
||||
}
|
||||
|
||||
foo { (<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>: Int, b: String) ->
|
||||
b checkType { _<String>() }
|
||||
}
|
||||
|
||||
foobar { (a, <!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>), c ->
|
||||
a checkType { _<Int>() }
|
||||
}
|
||||
|
||||
foobar { a, (<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>, c) ->
|
||||
c checkType { _<Short>() }
|
||||
}
|
||||
|
||||
foobar { (a, <!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>b<!>), (<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>c<!>, d) ->
|
||||
a checkType { _<Int>() }
|
||||
d checkType { _<Short>() }
|
||||
}
|
||||
|
||||
foobar { (<!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>a<!>, b), (c, <!UNUSED_DESTRUCTURED_PARAMETER_ENTRY!>d<!>) ->
|
||||
b checkType { _<String>() }
|
||||
c checkType { _<Double>() }
|
||||
}
|
||||
}
|
||||
Vendored
+29
@@ -0,0 +1,29 @@
|
||||
package
|
||||
|
||||
public fun bar(): kotlin.Unit
|
||||
public fun foo(/*0*/ block: (A) -> kotlin.Unit): kotlin.Unit
|
||||
public fun foobar(/*0*/ block: (A, B) -> kotlin.Unit): kotlin.Unit
|
||||
|
||||
public final data class A {
|
||||
public constructor A(/*0*/ x: kotlin.Int, /*1*/ y: kotlin.String)
|
||||
public final val x: kotlin.Int
|
||||
public final val y: kotlin.String
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.Int
|
||||
public final operator /*synthesized*/ fun component2(): kotlin.String
|
||||
public final /*synthesized*/ fun copy(/*0*/ x: kotlin.Int = ..., /*1*/ y: kotlin.String = ...): A
|
||||
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final data class B {
|
||||
public constructor B(/*0*/ u: kotlin.Double, /*1*/ w: kotlin.Short)
|
||||
public final val u: kotlin.Double
|
||||
public final val w: kotlin.Short
|
||||
public final operator /*synthesized*/ fun component1(): kotlin.Double
|
||||
public final operator /*synthesized*/ fun component2(): kotlin.Short
|
||||
public final /*synthesized*/ fun copy(/*0*/ u: kotlin.Double = ..., /*1*/ w: kotlin.Short = ...): B
|
||||
public open override /*1*/ /*synthesized*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*synthesized*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*synthesized*/ fun toString(): kotlin.String
|
||||
}
|
||||
@@ -7747,6 +7747,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unsupportedFeature.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("unusedParameters.kt")
|
||||
public void testUnusedParameters() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/diagnostics/tests/functionLiterals/return")
|
||||
|
||||
Reference in New Issue
Block a user