diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt index b68f95b6f91..fc73c7bc6b8 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowInformationProvider.kt @@ -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() diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt index 6c08a9e5085..e16ce3c408c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/ControlFlowProcessor.kt @@ -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 { diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index d743cc2a46b..02c499ad58c 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -667,6 +667,8 @@ public interface Errors { DiagnosticFactory1 UNUSED_VARIABLE = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); DiagnosticFactory1 UNUSED_PARAMETER = DiagnosticFactory1.create(WARNING, DECLARATION_NAME); + DiagnosticFactory1 UNUSED_DESTRUCTURED_PARAMETER_ENTRY = + DiagnosticFactory1.create(WARNING, DECLARATION_NAME); DiagnosticFactory2 UNUSED_TYPEALIAS_PARAMETER = DiagnosticFactory2.create(WARNING, DECLARATION_NAME); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 797a5d46f1f..a1b8b45c2d4 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -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); diff --git a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt index cb4b4cff7a1..aa2309c7e1e 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/DeprecatedSyntax.kt @@ -5,12 +5,12 @@ val receiverAndReturnType = { Int.(): Int -> 5 } val receiverAndReturnTypeWithParameter = { Int.(a: Int): Int -> 5 } val returnType = { (): Int -> 5 } -val returnTypeWithParameter = { (b: Int): Int -> 5 } +val returnTypeWithParameter = { (b: Int): Int -> 5 } val receiverWithFunctionType = { ((Int) -> Int).() -> } -val parenthesizedParameters = { (a: Int) -> } -val parenthesizedParameters2 = { (b) -> } +val parenthesizedParameters = { (a: Int) -> } +val parenthesizedParameters2 = { (b) -> } val none = { -> } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt index 3b42ee8c72e..dcd2b38fb2f 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/extensionComponents.kt @@ -31,7 +31,7 @@ fun bar() { } // From KEEP: Component-functions are resolved in the scope that contains the lambda - foobaz { (a, b) -> + foobaz { (a, b) -> } // From KEEP: Component-functions are resolved in the scope that contains the lambda diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt index f345b30d975..4422c7aa71d 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/redeclaration.kt @@ -6,12 +6,12 @@ data class B(val u: Double, val w: Short) fun foo(block: (A, B) -> Unit) { } fun bar() { - foo { (a, a), b -> + foo { (a, a), b -> a checkType { _() } b checkType { _() } } - foo { (a, b), a -> + foo { (a, b), a -> a checkType { _() } b checkType { _() } } @@ -21,7 +21,7 @@ fun bar() { b checkType { _() } } - foo { (a, b), (c, b) -> + foo { (a, b), (c, b) -> a checkType { _() } b checkType { _() } c checkType { _() } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt index c1d8eea2b53..d57f89a6d2a 100644 --- a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/underscore.kt @@ -46,7 +46,7 @@ fun bar() { _ checkType { _() } } - foo { (`_`, `_`) -> + foo { (`_`, `_`) -> _ checkType { _() } } diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.kt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.kt new file mode 100644 index 00000000000..dd5af1b2368 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.kt @@ -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, b) -> + a checkType { _() } + } + + foo { (a, b) -> + b checkType { _() } + } + + foo { (a: Int, b: String) -> + a checkType { _() } + } + + foo { (a: Int, b: String) -> + b checkType { _() } + } + + foobar { (a, b), c -> + a checkType { _() } + } + + foobar { a, (b, c) -> + c checkType { _() } + } + + foobar { (a, b), (c, d) -> + a checkType { _() } + d checkType { _() } + } + + foobar { (a, b), (c, d) -> + b checkType { _() } + c checkType { _() } + } +} diff --git a/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.txt b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.txt new file mode 100644 index 00000000000..71b3784c537 --- /dev/null +++ b/compiler/testData/diagnostics/tests/functionLiterals/destructuringInLambdas/unusedParameters.txt @@ -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 +} diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java index 666afac2aa4..d85cf6b440f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestGenerated.java @@ -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")