Unused symbol: handle functions with inline class parameters correctly

#KT-27357 Fixed
This commit is contained in:
Mikhail Glukhikh
2018-10-18 16:34:06 +03:00
parent 0678a56ca4
commit a5e508a083
7 changed files with 71 additions and 1 deletions
@@ -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
@@ -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 &quot;foo&quot; 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))
@@ -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()
@@ -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");