Unused symbol: handle functions with inline class parameters correctly
#KT-27357 Fixed
This commit is contained in:
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.isInlineClassType
|
||||
import org.jetbrains.kotlin.util.findCallableMemberBySignature
|
||||
import java.awt.GridBagConstraints
|
||||
import java.awt.GridBagLayout
|
||||
@@ -309,7 +310,7 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
|
||||
if (referenceUsed) return true
|
||||
}
|
||||
|
||||
if (declaration is KtCallableDeclaration && !declaration.hasModifier(KtTokens.INTERNAL_KEYWORD)) {
|
||||
if (declaration is KtCallableDeclaration && declaration.canBeHandledByLightMethods(descriptor)) {
|
||||
val lightMethods = declaration.toLightMethods()
|
||||
if (lightMethods.isNotEmpty()) {
|
||||
val lightMethodsUsed = lightMethods.any { method ->
|
||||
@@ -323,6 +324,24 @@ class UnusedSymbolInspection : AbstractKotlinInspection() {
|
||||
return referenceUsed
|
||||
}
|
||||
|
||||
private fun KtCallableDeclaration.canBeHandledByLightMethods(descriptor: DeclarationDescriptor?): Boolean {
|
||||
return when {
|
||||
hasModifier(KtTokens.INTERNAL_KEYWORD) -> false
|
||||
this !is KtNamedFunction -> true
|
||||
descriptor !is FunctionDescriptor -> true
|
||||
else -> !descriptor.hasInlineClassParameters()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun FunctionDescriptor.hasInlineClassParameters(): Boolean {
|
||||
return when {
|
||||
dispatchReceiverParameter?.type?.isInlineClassType() == true -> true
|
||||
extensionReceiverParameter?.type?.isInlineClassType() == true -> true
|
||||
else -> valueParameters.any { it.type.isInlineClassType() }
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasOverrides(declaration: KtNamedDeclaration, useScope: SearchScope): Boolean =
|
||||
DefinitionsScopedSearch.search(declaration, useScope).findFirst() != null
|
||||
|
||||
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
inline class InlineClass(val x: Int)
|
||||
|
||||
// Unused
|
||||
fun foo(arg: InlineClass) {
|
||||
arg.x.hashCode()
|
||||
}
|
||||
@@ -78,4 +78,13 @@
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused symbol</problem_class>
|
||||
<description>Constructor is never used</description>
|
||||
</problem>
|
||||
|
||||
<problem>
|
||||
<file>functionWithInlineClassParam.kt</file>
|
||||
<line>4</line>
|
||||
<module>light_idea_test_case</module>
|
||||
<entry_point TYPE="file" FQNAME="temp:///src/functionWithInlineClassParam.kt" />
|
||||
<problem_class severity="WARNING" attribute_key="NOT_USED_ELEMENT_ATTRIBUTES">Unused symbol</problem_class>
|
||||
<description>Function "foo" is never used</description>
|
||||
</problem>
|
||||
</problems>
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
// PROBLEM: none
|
||||
|
||||
inline class InlineClass(val x: Int)
|
||||
|
||||
fun <caret>takeInline(inlineClass: InlineClass) = 1
|
||||
|
||||
val call = takeInline(InlineClass(1))
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// PROBLEM: none
|
||||
|
||||
inline class InlineClass(val x: Int)
|
||||
|
||||
fun InlineClass.<caret>takeInline() = 1
|
||||
|
||||
val call = InlineClass(1).takeInline()
|
||||
@@ -0,0 +1,7 @@
|
||||
// PROBLEM: none
|
||||
|
||||
inline class InlineClass(val x: Int) {
|
||||
fun <caret>takeInline() = 1
|
||||
}
|
||||
|
||||
val call = InlineClass(1).takeInline()
|
||||
+15
@@ -6377,6 +6377,16 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/dataInlineClassDeclaration.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionWithInlineClass.kt")
|
||||
public void testFunctionWithInlineClass() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/functionWithInlineClass.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("functionWithInlineClassReceiver.kt")
|
||||
public void testFunctionWithInlineClassReceiver() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/functionWithInlineClassReceiver.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inAnonymous.kt")
|
||||
public void testInAnonymous() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/inAnonymous.kt");
|
||||
@@ -6392,6 +6402,11 @@ public class LocalInspectionTestGenerated extends AbstractLocalInspectionTest {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/inAnonymousRunWrapped.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("inlineClassMemberFunction.kt")
|
||||
public void testInlineClassMemberFunction() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/inlineClassMemberFunction.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("internal.kt")
|
||||
public void testInternal() throws Exception {
|
||||
runTest("idea/testData/inspectionsLocal/unusedSymbol/internal.kt");
|
||||
|
||||
Reference in New Issue
Block a user