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 {
val getMethod: 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() {
@@ -45,32 +45,21 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
KotlinCacheService.getInstance(project)[this](element).second
}
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor? {
val method = getOriginalElement() as PsiMethod
val resolver = JavaResolveExtension.getResolver(method.getProject(), method)
val methodDescriptor = when {
return when {
method.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(method))
else -> resolver.resolveMethod(JavaMethodImpl(method))
}
assert(methodDescriptor != null) { "No descriptor found for " + method.getText() }
return methodDescriptor!!
}
fun PsiClass.getJavaClassDescriptor(): ClassDescriptor {
val resolver = JavaResolveExtension.getResolver(getProject(), this)
val classDescriptor = resolver.resolveClass(JavaClassImpl(this))
assert(classDescriptor != null) { "No descriptor found for " + getText() }
return classDescriptor!!
fun PsiClass.getJavaClassDescriptor(): ClassDescriptor? {
return JavaResolveExtension.getResolver(getProject(), this).resolveClass(JavaClassImpl(this))
}
fun PsiField.getJavaFieldDescriptor(): PropertyDescriptor {
val resolver = JavaResolveExtension.getResolver(getProject(), this)
val fieldDescriptor = resolver.resolveField(JavaFieldImpl(this))
assert(fieldDescriptor != null) { "No descriptor found for " + getText() }
return fieldDescriptor!!
fun PsiField.getJavaFieldDescriptor(): PropertyDescriptor? {
return JavaResolveExtension.getResolver(getProject(), this).resolveField(JavaFieldImpl(this))
}
fun PsiMember.getJavaMemberDescriptor(): DeclarationDescriptor? {
+1 -1
View File
@@ -502,7 +502,7 @@
<directClassInheritorsSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDirectInheritorsSearcher"/>
<definitionsScopedSearch implementation="org.jetbrains.kotlin.idea.search.ideaExtensions.KotlinDefinitionsSearcher"/>
<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.KotlinOverridingMethodReferenceSearcher"/>
@@ -88,7 +88,7 @@ class UsePropertyAccessSyntaxIntention : JetSelfTargetingOffsetIndependentIntent
}
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()) {
findSyntheticProperty(overridden, resolutionScope)?.let { return it }
@@ -97,15 +97,6 @@ class UsePropertyAccessSyntaxIntention : JetSelfTargetingOffsetIndependentIntent
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) {
val newExpression = JetPsiFactory(callExpression).createExpression(propertyName.render())
callExpression.replace(newExpression)
@@ -388,7 +388,7 @@ public fun JetChangeInfo.getAffectedCallables(): Collection<UsageInfo> = methodD
public fun ChangeInfo.toJetChangeInfo(originalChangeSignatureDescriptor: JetMethodDescriptor): JetChangeInfo {
val method = getMethod() as PsiMethod
val functionDescriptor = method.getJavaMethodDescriptor()
val functionDescriptor = method.getJavaMethodDescriptor()!!
val parameterDescriptors = functionDescriptor.getValueParameters()
//noinspection ConstantConditions
@@ -394,6 +394,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
if (!RefactoringPackage.isTrueJavaMethod(method)) return;
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
assert methodDescriptor != null;
DeclarationDescriptor containingDescriptor = methodDescriptor.getContainingDeclaration();
if (!(containingDescriptor instanceof JavaClassDescriptor)) return;
@@ -958,6 +959,7 @@ public class JetChangeSignatureUsageProcessor implements ChangeSignatureUsagePro
boolean startedFromJava = method instanceof PsiMethod;
if (startedFromJava && originalJavaMethodDescriptor == null) {
FunctionDescriptor methodDescriptor = ResolvePackage.getJavaMethodDescriptor((PsiMethod) method);
assert methodDescriptor != null;
originalJavaMethodDescriptor =
new JetChangeSignatureData(methodDescriptor, method, Collections.singletonList(methodDescriptor));;
@@ -83,7 +83,7 @@ public class KotlinMethodNode(
val descriptor = when (myMethod) {
is JetFunction -> myMethod.resolveToDescriptor() as FunctionDescriptor
is JetClass -> (myMethod.resolveToDescriptor() as ClassDescriptor).getUnsubstitutedPrimaryConstructor() ?: return
is PsiMethod -> myMethod.getJavaMethodDescriptor()
is PsiMethod -> myMethod.getJavaMethodDescriptor() ?: return
else -> throw AssertionError("Invalid declaration: ${myMethod.getElementTextWithContext()}")
}
val containerName = sequence<DeclarationDescriptor>(descriptor) { it.getContainingDeclaration() }
@@ -89,7 +89,7 @@ public class KotlinIntroduceParameterMethodUsageProcessor : IntroduceParameterMe
val changeInfo = createChangeInfo(data, element) ?: return true
// 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)
val scope = element.getUseScope().let {
@@ -17,27 +17,27 @@
package org.jetbrains.kotlin.idea.search.ideaExtensions
import com.intellij.openapi.application.QueryExecutorBase
import com.intellij.psi.PsiMethod
import com.intellij.psi.PsiReference
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.search.SearchScope
import com.intellij.psi.search.UsageSearchContext
import com.intellij.psi.search.searches.MethodReferencesSearch
import com.intellij.util.Processor
import org.jetbrains.kotlin.idea.JetFileType
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.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>) {
val method = queryParameters.getMethod()
val unwrapped = method.namedUnwrappedElement
val propertyName = propertyName(method) ?: return
if (unwrapped !is JetProperty) return
val propertyName = unwrapped.getName()
if (propertyName == null) return
val onlyKotlinFiles = restrictToKotlinSources(queryParameters.getScope())
val onlyKotlinFiles = restrictToKotlinSources(queryParameters.getEffectiveSearchScope())
queryParameters.getOptimizer()!!.searchWord(
propertyName,
@@ -47,10 +47,22 @@ public class KotlinLightPropertyAccessorsReferenceSearcher() : QueryExecutorBase
method)
}
private fun restrictToKotlinSources(originalScope: SearchScope): SearchScope {
if (originalScope is GlobalSearchScope) {
return GlobalSearchScope.getScopeRestrictedByFileTypes(originalScope as GlobalSearchScope, JetFileType.INSTANCE)
private fun propertyName(method: PsiMethod): String? {
val unwrapped = method.namedUnwrappedElement
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");
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);
}
}
}
}