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(); JetParameter origin = getOrigin();
return origin != null ? origin.getUseScope() : GlobalSearchScope.EMPTY_SCOPE; 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.psi.util.PsiTreeUtil
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.asJava.KotlinLightMethod import org.jetbrains.kotlin.asJava.KotlinLightMethod
import org.jetbrains.kotlin.asJava.KotlinLightParameter
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.JetFileType import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference import org.jetbrains.kotlin.idea.references.JetSimpleNameReference
import org.jetbrains.kotlin.idea.search.KOTLIN_NAMED_ARGUMENT_SEARCH_CONTEXT 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.UsagesSearchLocation
import org.jetbrains.kotlin.idea.search.usagesSearch.dataClassComponentFunction
import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch import org.jetbrains.kotlin.idea.search.usagesSearch.getSpecialNamesToSearch
import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope import org.jetbrains.kotlin.idea.stubindex.JetSourceFilterScope
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil 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>())) 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 com.intellij.util.containers.ContainerUtil
import org.jetbrains.kotlin.asJava.LightClassUtil import org.jetbrains.kotlin.asJava.LightClassUtil
import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods import org.jetbrains.kotlin.asJava.LightClassUtil.PropertyAccessorsPsiMethods
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor import org.jetbrains.kotlin.descriptors.ValueParameterDescriptor
import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.analyze
import org.jetbrains.kotlin.idea.references.JetSimpleNameReference 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.BindingContext
import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver import org.jetbrains.kotlin.resolve.scopes.receivers.ClassReceiver
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
import java.util.ArrayList import java.util.*
import java.util.Collections
val isTargetUsage = (PsiReference::matchesTarget).searchFilter val isTargetUsage = (PsiReference::matchesTarget).searchFilter
@@ -88,7 +88,7 @@ public fun PsiNamedElement.getSpecialNamesToSearch(): List<String> {
return when { return when {
name == null || !Name.isValidIdentifier(name) -> Collections.emptyList<String>() name == null || !Name.isValidIdentifier(name) -> Collections.emptyList<String>()
this is JetParameter -> { this is JetParameter -> {
val componentFunctionName = this.dataClassComponentFunctionName() val componentFunctionName = this.dataClassComponentFunction()?.name
if (componentFunctionName == null) return Collections.emptyList<String>() if (componentFunctionName == null) return Collections.emptyList<String>()
return listOf(componentFunctionName.asString(), JetTokens.LPAR.getValue()) 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 if (!hasValOrVar()) return null
// Forcing full resolve of owner class: otherwise DATA_CLASS_COMPONENT_FUNCTION won't be calculated. // 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 context = this.analyze()
val paramDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? ValueParameterDescriptor val paramDescriptor = context[BindingContext.DECLARATION_TO_DESCRIPTOR, this] as? ValueParameterDescriptor
return context[BindingContext.DATA_CLASS_COMPONENT_FUNCTION, paramDescriptor]?.let { return context[BindingContext.DATA_CLASS_COMPONENT_FUNCTION, paramDescriptor]
it.getName()
}
} }
public abstract class UsagesSearchHelper<T : PsiNamedElement> { public abstract class UsagesSearchHelper<T : PsiNamedElement> {
@@ -159,7 +159,7 @@ public class UnusedSymbolInspection : AbstractKotlinInspection() {
if (declaration is JetProperty && declaration.isSerializationImplicitlyUsedField()) return if (declaration is JetProperty && declaration.isSerializationImplicitlyUsedField()) return
if (isCompanionObject && (declaration as JetObjectDeclaration).hasSerializationImplicitlyUsedField()) 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 // 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 // Main checks: finding reference usages && text usages
if (hasNonTrivialUsages(declaration)) return 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); 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") @TestMetadata("hierarchyWithSafeUsages1.kt")
public void testHierarchyWithSafeUsages1() throws Exception { public void testHierarchyWithSafeUsages1() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameterWithJava/hierarchyWithSafeUsages1.kt"); String fileName = JetTestUtils.navigationMetadata("idea/testData/safeDelete/deleteValueParameter/kotlinValueParameterWithJava/hierarchyWithSafeUsages1.kt");