Initial implementation of usage search for get/set methods in form of synthetic extension

This commit is contained in:
Valentin Kipyatkov
2015-07-09 18:22:22 +03:00
parent 73dd4a214e
commit 13f0d3ca23
13 changed files with 68 additions and 44 deletions
@@ -39,6 +39,17 @@ import java.util.*
interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor { interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor {
val getMethod: FunctionDescriptor val getMethod: FunctionDescriptor
val setMethod: FunctionDescriptor? val setMethod: FunctionDescriptor?
companion object {
fun findByGetterOrSetter(getterOrSetter: FunctionDescriptor, resolutionScope: JetScope): SyntheticExtensionPropertyDescriptor? {
val owner = getterOrSetter.getContainingDeclaration()
if (owner !is JavaClassDescriptor) return null
return resolutionScope.getSyntheticExtensionProperties(owner.getDefaultType())
.filterIsInstance<SyntheticExtensionPropertyDescriptor>()
.firstOrNull { getterOrSetter == it.getMethod || getterOrSetter == it.setMethod }
}
}
} }
class AdditionalScopesWithSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes() { class AdditionalScopesWithSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes() {
@@ -45,32 +45,21 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
KotlinCacheService.getInstance(project)[this](element).second KotlinCacheService.getInstance(project)[this](element).second
} }
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor { fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor? {
val method = getOriginalElement() as PsiMethod val method = getOriginalElement() as PsiMethod
val resolver = JavaResolveExtension.getResolver(method.getProject(), method) val resolver = JavaResolveExtension.getResolver(method.getProject(), method)
val methodDescriptor = when { return when {
method.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(method)) method.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(method))
else -> resolver.resolveMethod(JavaMethodImpl(method)) else -> resolver.resolveMethod(JavaMethodImpl(method))
} }
assert(methodDescriptor != null) { "No descriptor found for " + method.getText() }
return methodDescriptor!!
} }
fun PsiClass.getJavaClassDescriptor(): ClassDescriptor { fun PsiClass.getJavaClassDescriptor(): ClassDescriptor? {
val resolver = JavaResolveExtension.getResolver(getProject(), this) return JavaResolveExtension.getResolver(getProject(), this).resolveClass(JavaClassImpl(this))
val classDescriptor = resolver.resolveClass(JavaClassImpl(this))
assert(classDescriptor != null) { "No descriptor found for " + getText() }
return classDescriptor!!
} }
fun PsiField.getJavaFieldDescriptor(): PropertyDescriptor { fun PsiField.getJavaFieldDescriptor(): PropertyDescriptor? {
val resolver = JavaResolveExtension.getResolver(getProject(), this) return JavaResolveExtension.getResolver(getProject(), this).resolveField(JavaFieldImpl(this))
val fieldDescriptor = resolver.resolveField(JavaFieldImpl(this))
assert(fieldDescriptor != null) { "No descriptor found for " + getText() }
return fieldDescriptor!!
} }
fun PsiMember.getJavaMemberDescriptor(): DeclarationDescriptor? { fun PsiMember.getJavaMemberDescriptor(): DeclarationDescriptor? {
+1 -1
View File
@@ -502,7 +502,7 @@
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/> <directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/> <definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
<annotatedElementsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAnnotatedElementsSearcher"/> <annotatedElementsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinAnnotatedElementsSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinLightPropertyAccessorsReferenceSearcher"/> <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinPropertyAccessorsReferenceSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConstructorDelegationCallReferenceSearcher"/> <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinConstructorDelegationCallReferenceSearcher"/>
<methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodReferenceSearcher"/> <methodReferencesSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinOverridingMethodReferenceSearcher"/>
@@ -88,7 +88,7 @@ class UsePropertyAccessSyntaxIntention : JetSelfTargetingOffsetIndependentIntent
} }
private fun findSyntheticProperty(function: FunctionDescriptor, resolutionScope: JetScope): SyntheticExtensionPropertyDescriptor? { private fun findSyntheticProperty(function: FunctionDescriptor, resolutionScope: JetScope): SyntheticExtensionPropertyDescriptor? {
findSyntheticPropertyNoOverriddenCheck(function, resolutionScope)?.let { return it } SyntheticExtensionPropertyDescriptor.findByGetterOrSetter(function, resolutionScope)?.let { return it }
for (overridden in function.getOverriddenDescriptors()) { for (overridden in function.getOverriddenDescriptors()) {
findSyntheticProperty(overridden, resolutionScope)?.let { return it } findSyntheticProperty(overridden, resolutionScope)?.let { return it }
@@ -97,15 +97,6 @@ class UsePropertyAccessSyntaxIntention : JetSelfTargetingOffsetIndependentIntent
return null return null
} }
private fun findSyntheticPropertyNoOverriddenCheck(function: FunctionDescriptor, resolutionScope: JetScope): SyntheticExtensionPropertyDescriptor? {
val owner = function.getContainingDeclaration()
if (owner !is JavaClassDescriptor) return null
return resolutionScope.getSyntheticExtensionProperties(owner.getDefaultType())
.filterIsInstance<SyntheticExtensionPropertyDescriptor>()
.firstOrNull { function == it.getMethod || function == it.setMethod }
}
private fun replaceWithPropertyGet(callExpression: JetCallExpression, propertyName: Name) { private fun replaceWithPropertyGet(callExpression: JetCallExpression, propertyName: Name) {
val newExpression = JetPsiFactory(callExpression).createExpression(propertyName.render()) val newExpression = JetPsiFactory(callExpression).createExpression(propertyName.render())
callExpression.replace(newExpression) callExpression.replace(newExpression)
@@ -388,7 +388,7 @@ public fun JetChangeInfo.getAffectedCallables(): Collection<UsageInfo> = methodD
public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMethodDescriptor): JetChangeInfo { public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMethodDescriptor): JetChangeInfo {
val method = getMethod() as PsiMethod val method = getMethod() as PsiMethod
val functionDescriptor = method.getJavaMethodDescriptor() val functionDescriptor = method.getJavaMethodDescriptor()!!
val parameterDescriptors = functionDescriptor.getValueParameters() val parameterDescriptors = functionDescriptor.getValueParameters()
//noinspection ConstantConditions //noinspection ConstantConditions
@@ -394,6 +394,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
if (!RefactoringPackage.isTrueJavaMethod(method)) return; if (!RefactoringPackage.isTrueJavaMethod(method)) return;
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method); FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
assert methodDescriptor != null;
DeclarationDescriptor containingDescriptor = methodDescriptor.getContainingDeclaration(); DeclarationDescriptor containingDescriptor = methodDescriptor.getContainingDeclaration();
if (!(containingDescriptor instanceof JavaClassDescriptor)) return; if (!(containingDescriptor instanceof JavaClassDescriptor)) return;
@@ -958,6 +959,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
boolean startedFromJava = method instanceof PsiMethod; boolean startedFromJava = method instanceof PsiMethod;
if (startedFromJava && originalJavaMethodDescriptor == null) { if (startedFromJava && originalJavaMethodDescriptor == null) {
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method); FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
assert methodDescriptor != null;
originalJavaMethodDescriptor = originalJavaMethodDescriptor =
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));; new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));;
@@ -83,7 +83,7 @@ public class KotlinMethodNode(
val descriptor = when (myMethod) { val descriptor = when (myMethod) {
is JetFunction -> myMethod.resolveToDescriptor() as FunctionDescriptor is JetFunction -> myMethod.resolveToDescriptor() as FunctionDescriptor
is JetClass -> (myMethod.resolveToDescriptor() as ClassDescriptor).getUnsubstitutedPrimaryConstructor() ?: return is JetClass -> (myMethod.resolveToDescriptor() as ClassDescriptor).getUnsubstitutedPrimaryConstructor() ?: return
is PsiMethod -> myMethod.getJavaMethodDescriptor() is PsiMethod -> myMethod.getJavaMethodDescriptor() ?: return
else -> throw AssertionError("Invalid declaration: ${myMethod.getElementTextWithContext()}") else -> throw AssertionError("Invalid declaration: ${myMethod.getElementTextWithContext()}")
} }
val containerName = sequence<DeclarationDescriptor>(descriptor) { it.getContainingDeclaration() } val containerName = sequence<DeclarationDescriptor>(descriptor) { it.getContainingDeclaration() }
@@ -89,7 +89,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe
val changeInfo = createChangeInfo(data, element) ?: return true val changeInfo = createChangeInfo(data, element) ?: return true
// Java method is already updated at this point // Java method is already updated at this point
val addedParameterType = data.getMethodToReplaceIn().getJavaMethodDescriptor().getValueParameters().last().getType() val addedParameterType = data.getMethodToReplaceIn().getJavaMethodDescriptor()!!.getValueParameters().last().getType()
changeInfo.getNewParameters().last().currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(addedParameterType) changeInfo.getNewParameters().last().currentTypeText = IdeDescriptorRenderers.SOURCE_CODE.renderType(addedParameterType)
val scope = element.getUseScope().let { val scope = element.getUseScope().let {
@@ -17,27 +17,27 @@
package org.jetbrains.kotlin.idea.search.ideaExtensions package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.openapi.application.QueryExecutorBase import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.UsageSearchContext import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.search.searches.MethodReferencesSearch import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.util.Processor import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.asJava.namedUnwrappedElement import org.jetbrains.kotlin.asJava.namedUnwrappedElement
import org.jetbrains.kotlin.idea.JetFileType
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMethodDescriptor
import org.jetbrains.kotlin.psi.JetProperty import org.jetbrains.kotlin.psi.JetProperty
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.synthetic.SyntheticExtensionPropertyDescriptor
import org.jetbrains.kotlin.synthetic.SyntheticExtensionsScope
public class KotlinLightPropertyAccessorsReferenceSearcher() : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) { public class KotlinPropertyAccessorsReferenceSearcher() : QueryExecutorBase<PsiReference, MethodReferencesSearch.SearchParameters>(true) {
override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) { override fun processQuery(queryParameters: MethodReferencesSearch.SearchParameters, consumer: Processor<PsiReference>) {
val method = queryParameters.getMethod() val method = queryParameters.getMethod()
val unwrapped = method.namedUnwrappedElement val propertyName = propertyName(method) ?: return
if (unwrapped !is JetProperty) return val onlyKotlinFiles = restrictToKotlinSources(queryParameters.getEffectiveSearchScope())
val propertyName = unwrapped.getName()
if (propertyName == null) return
val onlyKotlinFiles = restrictToKotlinSources(queryParameters.getScope())
queryParameters.getOptimizer()!!.searchWord( queryParameters.getOptimizer()!!.searchWord(
propertyName, propertyName,
@@ -47,10 +47,22 @@ public class KotlinLightPropertyAccessorsReferenceSearcher() : QueryExecutorBase
method) method)
} }
private fun restrictToKotlinSources(originalScope: SearchScope): SearchScope { private fun propertyName(method: PsiMethod): String? {
if (originalScope is GlobalSearchScope) { val unwrapped = method.namedUnwrappedElement
return GlobalSearchScope.getScopeRestrictedByFileTypes(originalScope as GlobalSearchScope, JetFileType.INSTANCE) if (unwrapped is JetProperty) {
return unwrapped.getName()
}
val functionDescriptor = method.getJavaMethodDescriptor() ?: return null
val syntheticExtensionsScope = SyntheticExtensionsScope(LockBasedStorageManager())
val property = SyntheticExtensionPropertyDescriptor.findByGetterOrSetter(functionDescriptor, syntheticExtensionsScope) ?: return null
return property.getName().asString()
}
private fun restrictToKotlinSources(originalScope: SearchScope): SearchScope {
return when (originalScope) {
is GlobalSearchScope -> GlobalSearchScope.getScopeRestrictedByFileTypes(originalScope, JetFileType.INSTANCE)
else -> originalScope
} }
return originalScope
} }
} }
@@ -0,0 +1,6 @@
// PSI_ELEMENT: com.intellij.psi.PsiMethod
// OPTIONS: usages
class JavaClass {
public int <caret>getSomething() { return 1; }
public void setSomething(int value) {}
}
@@ -0,0 +1,5 @@
fun foo(javaClass: JavaClass) {
print(javaClass.something)
javaClass.something = 1
javaClass.something++
}
@@ -0,0 +1,2 @@
Value read (2: 21) print(javaClass.something)
Value read (4: 15) javaClass.something++
@@ -1250,6 +1250,12 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/JKMethodUsages.0.java"); String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/JKMethodUsages.0.java");
doTest(fileName); doTest(fileName);
} }
@TestMetadata("SyntheticProperties.0.java")
public void testSyntheticProperties() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/java/findJavaMethodUsages/SyntheticProperties.0.java");
doTest(fileName);
}
} }
} }
} }