ReferencesSearch finds references of data class component functions in Java code

#KT-8808 Fixed
This commit is contained in:
Dmitry Jemerov
2015-08-21 15:46:59 +02:00
parent 056d8dfd9f
commit 24f45a382e
8 changed files with 41 additions and 8 deletions
@@ -131,4 +131,8 @@ public class KotlinLightParameter extends LightParameter implements KotlinLightE
JetParameter origin = getOrigin();
return origin != null ? origin.getUseScope() : GlobalSearchScope.EMPTY_SCOPE;
}
public KotlinLightMethod getMethod() {
return method;
}
}
@@ -25,12 +25,14 @@ import com.intellij.psi.search.searches.ReferencesSearch
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.KotlinLightMethod
import org.jetbrains.kotlin.asJava.KotlinLightParameter
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT
import org.jetbrains.kotlin.idea.search.usagesSearch.UsagesSearchLocation
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
@@ -159,6 +161,18 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
searchNamedElement(queryParameters, PsiTreeUtil.getParentOfType<JetProperty>(declaration, javaClass<JetProperty>()))
}
}
is KotlinLightParameter -> {
val componentFunctionDescriptor = element.getOrigin()?.dataClassComponentFunction()
if (componentFunctionDescriptor != null) {
val containingClass = element.method.containingClass
val componentFunction = containingClass?.methods?.find {
it.name == componentFunctionDescriptor.name.asString() && it.parameterList.parametersCount == 0
}
if (componentFunction != null) {
searchNamedElement(queryParameters, componentFunction)
}
}
}
}
}
@@ -25,6 +25,7 @@ import com.intellij.util.Processor
import com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
@@ -45,8 +46,7 @@ import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.ArrayList
import java.util.Collections
import java.util.*
val isTargetUsage = (PsiReference::matchesTarget).searchFilter
@@ -88,7 +88,7 @@ public fun PsiNamedElement.getSpecialNamesToSearch(): List<String> {
return when {
name == null || !Name.isValidIdentifier(name) -> Collections.emptyList<String>()
this is JetParameter -> {
val componentFunctionName = this.dataClassComponentFunctionName()
val componentFunctionName = this.dataClassComponentFunction()?.name
if (componentFunctionName == null) return Collections.emptyList<String>()
return listOf(componentFunctionName.asString(), JetTokens.LPAR.getValue())
@@ -97,7 +97,7 @@ public fun PsiNamedElement.getSpecialNamesToSearch(): List<String> {
}
}
fun JetParameter.dataClassComponentFunctionName(): Name? {
fun JetParameter.dataClassComponentFunction(): FunctionDescriptor? {
if (!hasValOrVar()) return null
// Forcing full resolve of owner class: otherwise DATA_CLASS_COMPONENT_FUNCTION won't be calculated.
@@ -107,9 +107,7 @@ fun JetParameter.dataClassComponentFunctionName(): Name? {
val context = this.analyze()
val paramDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? ValueParameterDescriptor
return context[BindingContext.DATA_CLASS_COMPONENT_FUNCTION, paramDescriptor]?.let {
it.getName()
}
return context[BindingContext.DATA_CLASS_COMPONENT_FUNCTION, paramDescriptor]
}
public abstract class UsagesSearchHelper<T : PsiNamedElement> {
@@ -159,7 +159,7 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
if (declaration is JetProperty && declaration.isSerializationImplicitlyUsedField()) return
if (isCompanionObject && (declaration as JetObjectDeclaration).hasSerializationImplicitlyUsedField()) return
// properties can be referred by component1/component2, which is too expensive to search, don't mark them as unused
if (declaration is JetParameter && declaration.dataClassComponentFunctionName() != null) return
if (declaration is JetParameter && declaration.dataClassComponentFunction() != null) return
// Main checks: finding reference usages && text usages
if (hasNonTrivialUsages(declaration)) return
@@ -0,0 +1,7 @@
package test;
public class A {
public void usage(RemData p) {
System.out.println(p.component1());
}
}
@@ -0,0 +1,3 @@
package test
data public class RemData(val remo<caret>vable: Int)
@@ -0,0 +1 @@
parameter removable has 1 usage that is not safe to delete.
@@ -1081,6 +1081,12 @@ public class JetSafeDeleteTestGenerated extends AbstractJetSafeDeleteTest {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameterWithJava"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("dataClassComponent.kt")
public void testDataClassComponent() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameterWithJava/dataClassComponent.kt");
doValueParameterTestWithJava(fileName);
}
@TestMetadata("hierarchyWithSafeUsages1.kt")
public void testHierarchyWithSafeUsages1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameterWithJava/hierarchyWithSafeUsages1.kt");