Create from usage: Support extension members for Java classes
This commit is contained in:
+34
-2
@@ -29,6 +29,15 @@ import org.jetbrains.kotlin.resolve.jvm.resolveMethod
|
|||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaMethodImpl
|
||||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaConstructorImpl
|
||||||
import org.jetbrains.kotlin.resolve.jvm.resolveConstructor
|
import org.jetbrains.kotlin.resolve.jvm.resolveConstructor
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||||
|
import com.intellij.psi.PsiField
|
||||||
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
|
import org.jetbrains.kotlin.resolve.jvm.resolveField
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.impl.JavaFieldImpl
|
||||||
|
import com.intellij.psi.PsiMember
|
||||||
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
|
||||||
public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDescriptorResolver, BindingContext>> {
|
public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDescriptorResolver, BindingContext>> {
|
||||||
override val platform: TargetPlatform = TargetPlatform.JVM
|
override val platform: TargetPlatform = TargetPlatform.JVM
|
||||||
@@ -48,8 +57,6 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
|
fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
|
||||||
if (this is KotlinLightMethod) throw AssertionError("Light methods are not allowed here: ${getOrigin()?.getText()}")
|
|
||||||
|
|
||||||
val resolver = JavaResolveExtension.getResolver(getProject(), this)
|
val resolver = JavaResolveExtension.getResolver(getProject(), this)
|
||||||
val methodDescriptor = when {
|
val methodDescriptor = when {
|
||||||
this.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(this))
|
this.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(this))
|
||||||
@@ -59,3 +66,28 @@ fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
|
|||||||
|
|
||||||
return methodDescriptor!!
|
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 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 PsiMember.getJavaMemberDescriptor(): DeclarationDescriptor? {
|
||||||
|
return when (this) {
|
||||||
|
is PsiClass -> getJavaClassDescriptor()
|
||||||
|
is PsiMethod -> getJavaMethodDescriptor()
|
||||||
|
is PsiField -> getJavaFieldDescriptor()
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
+4
-2
@@ -31,6 +31,8 @@ import org.jetbrains.kotlin.psi.JetExpression
|
|||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
import java.util.HashSet
|
import java.util.HashSet
|
||||||
import org.jetbrains.kotlin.psi.JetElement
|
import org.jetbrains.kotlin.psi.JetElement
|
||||||
|
import com.intellij.psi.PsiClass
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
|
||||||
public class CreateCallableFromUsageFix(
|
public class CreateCallableFromUsageFix(
|
||||||
originalExpression: JetExpression,
|
originalExpression: JetExpression,
|
||||||
@@ -71,11 +73,11 @@ public class CreateCallableFromUsageFix(
|
|||||||
val popupTitle = JetBundle.message("choose.target.class.or.trait.title")
|
val popupTitle = JetBundle.message("choose.target.class.or.trait.title")
|
||||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
||||||
if (receiverTypeCandidates.isNotEmpty()) {
|
if (receiverTypeCandidates.isNotEmpty()) {
|
||||||
// TODO: Support generation of Java class members
|
|
||||||
val containers = receiverTypeCandidates
|
val containers = receiverTypeCandidates
|
||||||
.map { candidate ->
|
.map { candidate ->
|
||||||
val descriptor = candidate.theType.getConstructor().getDeclarationDescriptor()
|
val descriptor = candidate.theType.getConstructor().getDeclarationDescriptor()
|
||||||
(DescriptorToDeclarationUtil.getDeclaration(file, descriptor) as? JetClassOrObject)?.let { candidate to it }
|
val declaration = DescriptorToDeclarationUtil.getDeclaration(file, descriptor)
|
||||||
|
if (declaration is JetClassOrObject || declaration is PsiClass) candidate to declaration else null
|
||||||
}
|
}
|
||||||
.filterNotNull()
|
.filterNotNull()
|
||||||
|
|
||||||
|
|||||||
@@ -73,6 +73,8 @@ import com.intellij.psi.PsiPackage
|
|||||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||||
import com.intellij.refactoring.util.RefactoringUIUtil
|
import com.intellij.refactoring.util.RefactoringUIUtil
|
||||||
|
import com.intellij.psi.PsiMember
|
||||||
|
import org.jetbrains.kotlin.idea.caches.resolve.getJavaMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind
|
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind
|
||||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||||
@@ -299,13 +301,13 @@ public fun chooseContainerElement<T>(
|
|||||||
editor: Editor,
|
editor: Editor,
|
||||||
title: String,
|
title: String,
|
||||||
highlightSelection: Boolean,
|
highlightSelection: Boolean,
|
||||||
toPsi: (T) -> JetElement,
|
toPsi: (T) -> PsiElement,
|
||||||
onSelect: (T) -> Unit) {
|
onSelect: (T) -> Unit) {
|
||||||
return getPsiElementPopup(
|
return getPsiElementPopup(
|
||||||
editor,
|
editor,
|
||||||
containers,
|
containers,
|
||||||
object : PsiElementListCellRenderer<JetElement>() {
|
object : PsiElementListCellRenderer<PsiElement>() {
|
||||||
private fun JetElement.renderName(): String {
|
private fun PsiElement.renderName(): String {
|
||||||
if (this is JetPropertyAccessor) {
|
if (this is JetPropertyAccessor) {
|
||||||
return (getParent() as JetProperty).renderName() + if (isGetter()) ".get" else ".set"
|
return (getParent() as JetProperty).renderName() + if (isGetter()) ".get" else ".set"
|
||||||
}
|
}
|
||||||
@@ -315,9 +317,13 @@ public fun chooseContainerElement<T>(
|
|||||||
return (this as? PsiNamedElement)?.getName() ?: "<anonymous>"
|
return (this as? PsiNamedElement)?.getName() ?: "<anonymous>"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JetElement.renderDeclaration(): String? {
|
private fun PsiElement.renderDeclaration(): String? {
|
||||||
|
val descriptor = when {
|
||||||
|
this is JetElement -> analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
|
||||||
|
this is PsiMember -> getJavaMemberDescriptor()
|
||||||
|
else -> null
|
||||||
|
} ?: return null
|
||||||
val name = renderName()
|
val name = renderName()
|
||||||
val descriptor = this.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
|
|
||||||
val params = (descriptor as? FunctionDescriptor)?.let { descriptor ->
|
val params = (descriptor as? FunctionDescriptor)?.let { descriptor ->
|
||||||
descriptor.getValueParameters()
|
descriptor.getValueParameters()
|
||||||
.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it.getType()) }
|
.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it.getType()) }
|
||||||
@@ -326,11 +332,11 @@ public fun chooseContainerElement<T>(
|
|||||||
return "$name$params"
|
return "$name$params"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JetElement.renderText(): String {
|
private fun PsiElement.renderText(): String {
|
||||||
return StringUtil.shortenTextWithEllipsis(getText()!!.collapseSpaces(), 53, 0)
|
return StringUtil.shortenTextWithEllipsis(getText()!!.collapseSpaces(), 53, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun JetElement.getRepresentativeElement(): JetElement {
|
private fun PsiElement.getRepresentativeElement(): PsiElement {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
is JetBlockExpression -> (getParent() as? JetDeclarationWithBody) ?: this
|
is JetBlockExpression -> (getParent() as? JetDeclarationWithBody) ?: this
|
||||||
is JetClassBody -> getParent() as JetClassOrObject
|
is JetClassBody -> getParent() as JetClassOrObject
|
||||||
@@ -338,20 +344,17 @@ public fun chooseContainerElement<T>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getElementText(element: JetElement): String? {
|
override fun getElementText(element: PsiElement): String? {
|
||||||
val representativeElement = element.getRepresentativeElement()
|
val representativeElement = element.getRepresentativeElement()
|
||||||
return when (representativeElement) {
|
return representativeElement.renderDeclaration() ?: representativeElement.renderText()
|
||||||
is JetFile, is JetDeclarationWithBody, is JetClassOrObject -> representativeElement.renderDeclaration()
|
|
||||||
else -> representativeElement.renderText()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getContainerText(element: JetElement?, name: String?): String? = null
|
override fun getContainerText(element: PsiElement, name: String?): String? = null
|
||||||
|
|
||||||
override fun getIconFlags(): Int = 0
|
override fun getIconFlags(): Int = 0
|
||||||
|
|
||||||
override fun getIcon(element: PsiElement?): Icon? =
|
override fun getIcon(element: PsiElement): Icon? =
|
||||||
super.getIcon((element as? JetElement)?.getRepresentativeElement())
|
super.getIcon(element.getRepresentativeElement())
|
||||||
},
|
},
|
||||||
title,
|
title,
|
||||||
highlightSelection,
|
highlightSelection,
|
||||||
@@ -368,7 +371,7 @@ public fun chooseContainerElementIfNecessary<T>(
|
|||||||
editor: Editor,
|
editor: Editor,
|
||||||
title: String,
|
title: String,
|
||||||
highlightSelection: Boolean,
|
highlightSelection: Boolean,
|
||||||
toPsi: (T) -> JetElement,
|
toPsi: (T) -> PsiElement,
|
||||||
onSelect: (T) -> Unit
|
onSelect: (T) -> Unit
|
||||||
) {
|
) {
|
||||||
when {
|
when {
|
||||||
|
|||||||
@@ -5,6 +5,6 @@ fun test(): Int {
|
|||||||
return A().foo(1, "2")
|
return A().foo(1, "2")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun Any.foo(i: Int, s: String): Int {
|
fun A.foo(i: Int, s: String): Int {
|
||||||
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user