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:
Dmitry Jemerov
2015-09-11 19:50:49 +02:00
parent 4d09280aa8
commit ab58dc3586
24 changed files with 223 additions and 47 deletions
@@ -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()
}
}
@@ -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 -> {
@@ -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
}
@@ -0,0 +1,11 @@
package client;
import server.KotlinTopLevelMethodUsages_0Kt;
class JClient {
String s = KotlinTopLevelMethodUsages_0Kt.processRequest();
String sendRequest() {
return KotlinTopLevelMethodUsages_0Kt.processRequest();
}
}
@@ -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();
@@ -0,0 +1,7 @@
// PSI_ELEMENT: org.jetbrains.kotlin.psi.JetNamedFunction
// OPTIONS: usages
@file:JvmName("RequestProcessor")
package server
fun <caret>processRequest() = "foo"
@@ -0,0 +1,11 @@
package client;
import server.RequestProcessor;
class JClient {
String s = RequestProcessor.processRequest();
String sendRequest() {
return RequestProcessor.processRequest();
}
}
@@ -0,0 +1,2 @@
Unclassified usage (6: 33) String s = RequestProcessor.processRequest();
Unclassified usage (9: 33) return RequestProcessor.processRequest();
@@ -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("");
}
}
@@ -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("");
@@ -0,0 +1,11 @@
@file:JvmName("Bartender")
package testing.rename
public fun bar() = 1
fun usage() {
bar()
}
val some = bar()
@@ -0,0 +1,9 @@
package testing;
import testing.rename.Bartender;
class JavaClient {
public void testing() {
Bartender.bar();
}
}
@@ -0,0 +1,11 @@
@file:JvmName("Bartender")
package testing.rename
public fun foo() = 1
fun usage() {
foo()
}
val some = foo()
@@ -0,0 +1,9 @@
package testing;
import testing.rename.Bartender;
class JavaClient {
public void testing() {
Bartender.foo();
}
}
@@ -0,0 +1,6 @@
{
"type": "JAVA_METHOD",
"classId": "testing/rename/Bartender",
"methodSignature": "int foo()",
"newName": "bar"
}
@@ -0,0 +1,3 @@
package testing.rename
var /*rename*/bar: String = "xyzzy"
@@ -0,0 +1,10 @@
package testing;
import testing.rename.RenameTopLevelVarPropertyKt;
class JavaClientNewFacade {
public void foo() {
String old = RenameTopLevelVarPropertyKt.getBar();
RenameTopLevelVarPropertyKt.setBar(old + "new");
}
}
@@ -0,0 +1,10 @@
package testing;
import testing.rename.RenamePackage;
class JavaClientOldFacade {
public void foo() {
String old = RenamePackage.getBar();
RenamePackage.setBar(old + "new");
}
}
@@ -0,0 +1,3 @@
package testing.rename
var /*rename*/foo: String = "xyzzy"
@@ -0,0 +1,10 @@
package testing;
import testing.rename.RenameTopLevelVarPropertyKt;
class JavaClientNewFacade {
public void foo() {
String old = RenameTopLevelVarPropertyKt.getFoo();
RenameTopLevelVarPropertyKt.setFoo(old + "new");
}
}
@@ -0,0 +1,10 @@
package testing;
import testing.rename.RenamePackage;
class JavaClientOldFacade {
public void foo() {
String old = RenamePackage.getFoo();
RenamePackage.setFoo(old + "new");
}
}
@@ -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");