allow returning multiple PsiMethod wrappers for a JetFunction or JetPropertyAccessor; use that for handling Java usages through old-style and new-style facades
#KT-9102 Fixed
This commit is contained in:
@@ -31,6 +31,7 @@ import com.intellij.psi.util.PsiTreeUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import com.intellij.util.SmartList
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -40,7 +41,6 @@ import org.jetbrains.kotlin.utils.rethrow
|
||||
import java.io.File
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
import java.util.*
|
||||
|
||||
public object LightClassUtil {
|
||||
private val LOG = Logger.getInstance(LightClassUtil::class.java)
|
||||
@@ -141,7 +141,7 @@ public object LightClassUtil {
|
||||
}
|
||||
|
||||
public fun getLightFieldForCompanionObject(companionObject: JetClassOrObject): PsiField? {
|
||||
val outerPsiClass = getWrappingClass(companionObject)
|
||||
val outerPsiClass = getWrappingClass(companionObject, true)
|
||||
if (outerPsiClass != null) {
|
||||
for (fieldOfParent in outerPsiClass.fields) {
|
||||
if ((fieldOfParent is KotlinLightElement<*, *>) && fieldOfParent.getOrigin() === companionObject) {
|
||||
@@ -163,7 +163,7 @@ public object LightClassUtil {
|
||||
}
|
||||
|
||||
private fun getLightClassBackingField(declaration: JetDeclaration): PsiField? {
|
||||
var psiClass: PsiClass = getWrappingClass(declaration) ?: return null
|
||||
var psiClass: PsiClass = getWrappingClass(declaration, true) ?: return null
|
||||
|
||||
if (psiClass is KotlinLightClass) {
|
||||
val origin = psiClass.getOrigin()
|
||||
@@ -194,16 +194,19 @@ public object LightClassUtil {
|
||||
return getPsiMethodWrapper(function)
|
||||
}
|
||||
|
||||
public fun getLightClassMethods(function: JetFunction): Collection<PsiMethod> {
|
||||
return getPsiMethodWrappers(function, true)
|
||||
}
|
||||
|
||||
private fun getPsiMethodWrapper(declaration: JetDeclaration): PsiMethod? {
|
||||
val wrappers = getPsiMethodWrappers(declaration, false)
|
||||
return if (!wrappers.isEmpty()) wrappers.get(0) else null
|
||||
return getPsiMethodWrappers(declaration, false).firstOrNull()
|
||||
}
|
||||
|
||||
private fun getPsiMethodWrappers(declaration: JetDeclaration, collectAll: Boolean): List<PsiMethod> {
|
||||
val psiClass = getWrappingClass(declaration) ?: return emptyList()
|
||||
val psiClasses = getWrappingClasses(declaration, collectAll)
|
||||
|
||||
val methods = SmartList<PsiMethod>()
|
||||
for (method in psiClass.methods) {
|
||||
for (method in psiClasses.flatMap { it.methods.asList() }) {
|
||||
try {
|
||||
if (method is KotlinLightMethod && method.getOrigin() === declaration) {
|
||||
methods.add(method)
|
||||
@@ -224,7 +227,17 @@ public object LightClassUtil {
|
||||
return methods
|
||||
}
|
||||
|
||||
private fun getWrappingClass(declaration: JetDeclaration): PsiClass? {
|
||||
private fun getWrappingClasses(declaration: JetDeclaration, collectAll: Boolean): Collection<PsiClass> {
|
||||
val wrappingClass = getWrappingClass(declaration, true)
|
||||
val oldPackagePartWrappingClass = if (declaration.parent is JetFile && collectAll)
|
||||
getWrappingClass(declaration, false)
|
||||
else
|
||||
null
|
||||
|
||||
return setOf(wrappingClass, oldPackagePartWrappingClass).filterNotNull()
|
||||
}
|
||||
|
||||
private fun getWrappingClass(declaration: JetDeclaration, useNewPackageParts: Boolean): PsiClass? {
|
||||
var declaration = declaration
|
||||
if (declaration is JetParameter) {
|
||||
val constructorClass = JetPsiUtil.getClassIfParameterIsProperty(declaration)
|
||||
@@ -254,7 +267,11 @@ public object LightClassUtil {
|
||||
|
||||
if (parent is JetFile) {
|
||||
// top-level declaration
|
||||
val fqName = PackageClassUtils.getPackageClassFqName(parent.packageFqName)
|
||||
val fqName = if (useNewPackageParts)
|
||||
JvmFileClassUtil.getFileClassInfoNoResolve(parent).facadeClassFqName
|
||||
else
|
||||
PackageClassUtils.getPackageClassFqName(parent.packageFqName)
|
||||
|
||||
val project = declaration.project
|
||||
return JavaElementFinder.getInstance(project).findClass(fqName.asString(), GlobalSearchScope.allScope(project))
|
||||
}
|
||||
@@ -276,6 +293,7 @@ public object LightClassUtil {
|
||||
specialGetter: PsiMethod?, specialSetter: PsiMethod?): PropertyAccessorsPsiMethods {
|
||||
var getterWrapper = specialGetter
|
||||
var setterWrapper = specialSetter
|
||||
val additionalAccessors = arrayListOf<PsiMethod>()
|
||||
|
||||
if (getterWrapper == null || setterWrapper == null) {
|
||||
// If some getter or setter isn't found yet try to get it from wrappers for general declaration
|
||||
@@ -284,29 +302,28 @@ public object LightClassUtil {
|
||||
it.name.startsWith(JvmAbi.GETTER_PREFIX) || it.name.startsWith(JvmAbi.SETTER_PREFIX)
|
||||
}
|
||||
|
||||
assert(wrappers.size() <= 2) { "Maximum two wrappers are expected to be generated for declaration: " + jetDeclaration.text }
|
||||
|
||||
for (wrapper in wrappers) {
|
||||
if (wrapper.getName().startsWith(JvmAbi.SETTER_PREFIX)) {
|
||||
assert(setterWrapper == null || setterWrapper === specialSetter) {
|
||||
"Setter accessor isn't expected to be reassigned (old: $setterWrapper, new: $wrapper)"
|
||||
if (setterWrapper == null || setterWrapper === specialSetter) {
|
||||
setterWrapper = wrapper
|
||||
}
|
||||
else {
|
||||
additionalAccessors.add(wrapper)
|
||||
}
|
||||
|
||||
setterWrapper = wrapper
|
||||
}
|
||||
else {
|
||||
assert(getterWrapper == null || getterWrapper === specialGetter) {
|
||||
"Getter accessor isn't expected to be reassigned (old: $getterWrapper, new: $wrapper)"
|
||||
if (getterWrapper == null || getterWrapper == specialGetter) {
|
||||
getterWrapper = wrapper
|
||||
}
|
||||
else {
|
||||
additionalAccessors.add(wrapper)
|
||||
}
|
||||
|
||||
getterWrapper = wrapper
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val backingField = getLightClassBackingField(jetDeclaration)
|
||||
return PropertyAccessorsPsiMethods(getterWrapper, setterWrapper, backingField)
|
||||
return PropertyAccessorsPsiMethods(getterWrapper, setterWrapper, backingField, additionalAccessors)
|
||||
}
|
||||
|
||||
public fun buildLightTypeParameterList(
|
||||
@@ -325,20 +342,19 @@ public object LightClassUtil {
|
||||
return builder
|
||||
}
|
||||
|
||||
public class PropertyAccessorsPsiMethods(public val getter: PsiMethod?, public val setter: PsiMethod?, public val backingField: PsiField?) : Iterable<PsiMethod> {
|
||||
private val accessors = ArrayList<PsiMethod>(2)
|
||||
public class PropertyAccessorsPsiMethods(public val getter: PsiMethod?,
|
||||
public val setter: PsiMethod?,
|
||||
public val backingField: PsiField?,
|
||||
additionalAccessors: List<PsiMethod>) : Iterable<PsiMethod> {
|
||||
private val allMethods = arrayListOf<PsiMethod>()
|
||||
val allDeclarations = arrayListOf<PsiNamedElement>()
|
||||
|
||||
init {
|
||||
if (getter != null) {
|
||||
accessors.add(getter)
|
||||
}
|
||||
if (setter != null) {
|
||||
accessors.add(setter)
|
||||
}
|
||||
listOf(getter, setter).filterNotNullTo(allMethods)
|
||||
listOf<PsiNamedElement?>(getter, setter, backingField).filterNotNullTo(allDeclarations)
|
||||
allDeclarations.addAll(additionalAccessors)
|
||||
}
|
||||
|
||||
override fun iterator(): Iterator<PsiMethod> {
|
||||
return accessors.iterator()
|
||||
}
|
||||
override fun iterator(): Iterator<PsiMethod> = allMethods.iterator()
|
||||
}
|
||||
}
|
||||
|
||||
+6
-8
@@ -223,8 +223,7 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
|
||||
|
||||
private fun searchPropertyMethods(queryParameters: ReferencesSearch.SearchParameters, parameter: JetParameter) {
|
||||
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(parameter) }
|
||||
searchNamedElement(queryParameters, propertyMethods.getter)
|
||||
searchNamedElement(queryParameters, propertyMethods.setter)
|
||||
propertyMethods.allDeclarations.forEach { searchNamedElement(queryParameters, it) }
|
||||
}
|
||||
|
||||
private fun searchDataClassComponentUsages(queryParameters: ReferencesSearch.SearchParameters,
|
||||
@@ -245,8 +244,10 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
|
||||
val function = element as JetFunction
|
||||
val name = function.getName()
|
||||
if (name != null) {
|
||||
val method = runReadAction { LightClassUtil.getLightClassMethod(function) }
|
||||
searchNamedElement(queryParameters, method)
|
||||
val methods = runReadAction { LightClassUtil.getLightClassMethods(function) }
|
||||
for (method in methods) {
|
||||
searchNamedElement(queryParameters, method)
|
||||
}
|
||||
}
|
||||
|
||||
val staticFromCompanionObject = runReadAction { findStaticMethodFromCompanionObject(element) }
|
||||
@@ -257,10 +258,7 @@ public class KotlinReferencesSearcher : QueryExecutorBase<PsiReference, Referenc
|
||||
|
||||
is JetProperty -> {
|
||||
val propertyMethods = runReadAction { LightClassUtil.getLightClassPropertyMethods(element) }
|
||||
searchNamedElement(queryParameters, propertyMethods.getter)
|
||||
searchNamedElement(queryParameters, propertyMethods.setter)
|
||||
searchNamedElement(queryParameters, propertyMethods.backingField)
|
||||
|
||||
propertyMethods.allDeclarations.forEach { searchNamedElement(queryParameters, it) }
|
||||
}
|
||||
|
||||
is JetParameter -> {
|
||||
|
||||
+5
-5
@@ -131,12 +131,12 @@ public abstract class KotlinFindMemberUsagesHandler<T : JetNamedDeclaration>
|
||||
val query = applyQueryFilters(element, options, ReferencesSearch.search(searchParameters))
|
||||
if (!query.forEach(referenceProcessor)) return false
|
||||
|
||||
val psiMethod: PsiMethod? = when (element) {
|
||||
is PsiMethod -> element
|
||||
is JetFunction -> runReadAction { LightClassUtil.getLightClassMethod(element) }
|
||||
else -> null
|
||||
val psiMethods = when (element) {
|
||||
is PsiMethod -> listOf(element)
|
||||
is JetFunction -> runReadAction { LightClassUtil.getLightClassMethods(element) }
|
||||
else -> listOf<PsiMethod>()
|
||||
}
|
||||
if (psiMethod != null) {
|
||||
for (psiMethod in psiMethods) {
|
||||
val query = applyQueryFilters(element, options, MethodReferencesSearch.search(psiMethod, options.searchScope, true))
|
||||
if (!query.forEach(referenceProcessor)) return false
|
||||
}
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package client;
|
||||
|
||||
import server.KotlinTopLevelMethodUsages_0Kt;
|
||||
|
||||
class JClient {
|
||||
String s = KotlinTopLevelMethodUsages_0Kt.processRequest();
|
||||
|
||||
String sendRequest() {
|
||||
return KotlinTopLevelMethodUsages_0Kt.processRequest();
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -2,4 +2,6 @@
|
||||
[kotlinTopLevelMethodUsages.1.kt] Function call (10: 9) processRequest()
|
||||
[kotlinTopLevelMethodUsages.1.kt] Usage in import (3: 15) import server.processRequest
|
||||
[kotlinTopLevelMethodUsages.2.java] Unclassified usage (6: 30) String s = ServerPackage.processRequest();
|
||||
[kotlinTopLevelMethodUsages.2.java] Unclassified usage (9: 30) return ServerPackage.processRequest();
|
||||
[kotlinTopLevelMethodUsages.2.java] Unclassified usage (9: 30) return ServerPackage.processRequest();
|
||||
[kotlinTopLevelMethodUsages.3.java] Unclassified usage (6: 47) String s = KotlinTopLevelMethodUsages_0Kt.processRequest();
|
||||
[kotlinTopLevelMethodUsages.3.java] Unclassified usage (9: 47) return KotlinTopLevelMethodUsages_0Kt.processRequest();
|
||||
Vendored
+7
@@ -0,0 +1,7 @@
|
||||
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetNamedFunction
|
||||
// OPTIONS: usages
|
||||
@file:JvmName("RequestProcessor")
|
||||
package server
|
||||
|
||||
fun <caret>processRequest() = "foo"
|
||||
|
||||
Vendored
+11
@@ -0,0 +1,11 @@
|
||||
package client;
|
||||
|
||||
import server.RequestProcessor;
|
||||
|
||||
class JClient {
|
||||
String s = RequestProcessor.processRequest();
|
||||
|
||||
String sendRequest() {
|
||||
return RequestProcessor.processRequest();
|
||||
}
|
||||
}
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
Unclassified usage (6: 33) String s = RequestProcessor.processRequest();
|
||||
Unclassified usage (9: 33) return RequestProcessor.processRequest();
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
package client;
|
||||
|
||||
import server.KotlinTopLevelPropertyUsages_0Kt;
|
||||
|
||||
class JClient {
|
||||
void fooBar() {
|
||||
System.out.println("foo = " + KotlinTopLevelPropertyUsages_0Kt.getFoo());
|
||||
System.out.println("length: " + KotlinTopLevelPropertyUsages_0Kt.getFoo().length());
|
||||
KotlinTopLevelPropertyUsages_0Kt.setFoo("");
|
||||
}
|
||||
}
|
||||
Vendored
+4
-1
@@ -3,4 +3,7 @@
|
||||
[kotlinTopLevelPropertyUsages.1.kt] Value read (7: 33) println("foo = ${server.foo}")
|
||||
[kotlinTopLevelPropertyUsages.2.java] Unclassified usage (7: 53) System.out.println("foo = " + ServerPackage.getFoo());
|
||||
[kotlinTopLevelPropertyUsages.2.java] Unclassified usage (8: 55) System.out.println("length: " + ServerPackage.getFoo().length());
|
||||
[kotlinTopLevelPropertyUsages.2.java] Unclassified usage (9: 23) ServerPackage.setFoo("");
|
||||
[kotlinTopLevelPropertyUsages.2.java] Unclassified usage (9: 23) ServerPackage.setFoo("");
|
||||
[kotlinTopLevelPropertyUsages.3.java] Unclassified usage (7: 72) System.out.println("foo = " + KotlinTopLevelPropertyUsages_0Kt.getFoo());
|
||||
[kotlinTopLevelPropertyUsages.3.java] Unclassified usage (8: 74) System.out.println("length: " + KotlinTopLevelPropertyUsages_0Kt.getFoo().length());
|
||||
[kotlinTopLevelPropertyUsages.3.java] Unclassified usage (9: 42) KotlinTopLevelPropertyUsages_0Kt.setFoo("");
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
@file:JvmName("Bartender")
|
||||
|
||||
package testing.rename
|
||||
|
||||
public fun bar() = 1
|
||||
|
||||
fun usage() {
|
||||
bar()
|
||||
}
|
||||
|
||||
val some = bar()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.Bartender;
|
||||
|
||||
class JavaClient {
|
||||
public void testing() {
|
||||
Bartender.bar();
|
||||
}
|
||||
}
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
@file:JvmName("Bartender")
|
||||
|
||||
package testing.rename
|
||||
|
||||
public fun foo() = 1
|
||||
|
||||
fun usage() {
|
||||
foo()
|
||||
}
|
||||
|
||||
val some = foo()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.Bartender;
|
||||
|
||||
class JavaClient {
|
||||
public void testing() {
|
||||
Bartender.foo();
|
||||
}
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"type": "JAVA_METHOD",
|
||||
"classId": "testing/rename/Bartender",
|
||||
"methodSignature": "int foo()",
|
||||
"newName": "bar"
|
||||
}
|
||||
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package testing.rename
|
||||
|
||||
var /*rename*/bar: String = "xyzzy"
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.RenameTopLevelVarPropertyKt;
|
||||
|
||||
class JavaClientNewFacade {
|
||||
public void foo() {
|
||||
String old = RenameTopLevelVarPropertyKt.getBar();
|
||||
RenameTopLevelVarPropertyKt.setBar(old + "new");
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.RenamePackage;
|
||||
|
||||
class JavaClientOldFacade {
|
||||
public void foo() {
|
||||
String old = RenamePackage.getBar();
|
||||
RenamePackage.setBar(old + "new");
|
||||
}
|
||||
}
|
||||
idea/testData/refactoring/rename/renameKotlinTopLevelVarProperty/before/RenameTopLevelVarProperty.kt
Vendored
+3
@@ -0,0 +1,3 @@
|
||||
package testing.rename
|
||||
|
||||
var /*rename*/foo: String = "xyzzy"
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.RenameTopLevelVarPropertyKt;
|
||||
|
||||
class JavaClientNewFacade {
|
||||
public void foo() {
|
||||
String old = RenameTopLevelVarPropertyKt.getFoo();
|
||||
RenameTopLevelVarPropertyKt.setFoo(old + "new");
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
package testing;
|
||||
|
||||
import testing.rename.RenamePackage;
|
||||
|
||||
class JavaClientOldFacade {
|
||||
public void foo() {
|
||||
String old = RenamePackage.getFoo();
|
||||
RenamePackage.setFoo(old + "new");
|
||||
}
|
||||
}
|
||||
Vendored
+5
@@ -0,0 +1,5 @@
|
||||
{
|
||||
"type": "MARKED_ELEMENT",
|
||||
"mainFile": "RenameTopLevelVarProperty.kt",
|
||||
"newName": "bar"
|
||||
}
|
||||
@@ -612,6 +612,12 @@ public class JetFindUsagesTestGenerated extends AbstractJetFindUsagesTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinTopLevelMethodUsagesWithRenamedFile.0.kt")
|
||||
public void testKotlinTopLevelMethodUsagesWithRenamedFile() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findFunctionUsages/kotlinTopLevelMethodUsagesWithRenamedFile.0.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kotlinTraitImplThroughDelegate.0.kt")
|
||||
public void testKotlinTraitImplThroughDelegate() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/findUsages/kotlin/findFunctionUsages/kotlinTraitImplThroughDelegate.0.kt");
|
||||
|
||||
@@ -323,6 +323,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameKotlinPackageFunctionFromJavaNewFacade/renameKotlinPackageFunctionFromJava.test")
|
||||
public void testRenameKotlinPackageFunctionFromJavaNewFacade_RenameKotlinPackageFunctionFromJava() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinPackageFunctionFromJavaNewFacade/renameKotlinPackageFunctionFromJava.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameKotlinPrimaryConstructorProperty/renameKotlinPrimaryConstructorProperty.test")
|
||||
public void testRenameKotlinPrimaryConstructorProperty_RenameKotlinPrimaryConstructorProperty() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinPrimaryConstructorProperty/renameKotlinPrimaryConstructorProperty.test");
|
||||
@@ -341,6 +347,12 @@ public class RenameTestGenerated extends AbstractRenameTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameKotlinTopLevelVarProperty/renameTopLevelVarProperty.test")
|
||||
public void testRenameKotlinTopLevelVarProperty_RenameTopLevelVarProperty() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinTopLevelVarProperty/renameTopLevelVarProperty.test");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("renameKotlinValProperty/renameAsJavaGetterForExplicitGetter.test")
|
||||
public void testRenameKotlinValProperty_RenameAsJavaGetterForExplicitGetter() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/refactoring/rename/renameKotlinValProperty/renameAsJavaGetterForExplicitGetter.test");
|
||||
|
||||
Reference in New Issue
Block a user