Initial implementation of usage search for get/set methods in form of synthetic extension
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
+6
-17
@@ -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? {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+2
@@ -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));;
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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() }
|
||||||
|
|||||||
+1
-1
@@ -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 {
|
||||||
|
|||||||
+25
-13
@@ -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++
|
||||||
|
}
|
||||||
+2
@@ -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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user