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.JavaConstructorImpl
|
||||
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>> {
|
||||
override val platform: TargetPlatform = TargetPlatform.JVM
|
||||
@@ -48,8 +57,6 @@ public object JavaResolveExtension : CacheExtension<(PsiElement) -> Pair<JavaDes
|
||||
}
|
||||
|
||||
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 methodDescriptor = when {
|
||||
this.isConstructor() -> resolver.resolveConstructor(JavaConstructorImpl(this))
|
||||
@@ -59,3 +66,28 @@ fun PsiMethod.getJavaMethodDescriptor(): FunctionDescriptor {
|
||||
|
||||
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 java.util.HashSet
|
||||
import org.jetbrains.kotlin.psi.JetElement
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiElement
|
||||
|
||||
public class CreateCallableFromUsageFix(
|
||||
originalExpression: JetExpression,
|
||||
@@ -71,11 +73,11 @@ public class CreateCallableFromUsageFix(
|
||||
val popupTitle = JetBundle.message("choose.target.class.or.trait.title")
|
||||
val receiverTypeCandidates = callableBuilder.computeTypeCandidates(callableInfo.receiverTypeInfo)
|
||||
if (receiverTypeCandidates.isNotEmpty()) {
|
||||
// TODO: Support generation of Java class members
|
||||
val containers = receiverTypeCandidates
|
||||
.map { candidate ->
|
||||
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()
|
||||
|
||||
|
||||
@@ -73,6 +73,8 @@ import com.intellij.psi.PsiPackage
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
import org.jetbrains.kotlin.psi.psiUtil.parents
|
||||
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.Kind
|
||||
import org.jetbrains.kotlin.resolve.OverridingUtil
|
||||
@@ -299,13 +301,13 @@ public fun chooseContainerElement<T>(
|
||||
editor: Editor,
|
||||
title: String,
|
||||
highlightSelection: Boolean,
|
||||
toPsi: (T) -> JetElement,
|
||||
toPsi: (T) -> PsiElement,
|
||||
onSelect: (T) -> Unit) {
|
||||
return getPsiElementPopup(
|
||||
editor,
|
||||
containers,
|
||||
object : PsiElementListCellRenderer<JetElement>() {
|
||||
private fun JetElement.renderName(): String {
|
||||
object : PsiElementListCellRenderer<PsiElement>() {
|
||||
private fun PsiElement.renderName(): String {
|
||||
if (this is JetPropertyAccessor) {
|
||||
return (getParent() as JetProperty).renderName() + if (isGetter()) ".get" else ".set"
|
||||
}
|
||||
@@ -315,9 +317,13 @@ public fun chooseContainerElement<T>(
|
||||
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 descriptor = this.analyze()[BindingContext.DECLARATION_TO_DESCRIPTOR, this]
|
||||
val params = (descriptor as? FunctionDescriptor)?.let { descriptor ->
|
||||
descriptor.getValueParameters()
|
||||
.map { DescriptorRenderer.SHORT_NAMES_IN_TYPES.renderType(it.getType()) }
|
||||
@@ -326,11 +332,11 @@ public fun chooseContainerElement<T>(
|
||||
return "$name$params"
|
||||
}
|
||||
|
||||
private fun JetElement.renderText(): String {
|
||||
private fun PsiElement.renderText(): String {
|
||||
return StringUtil.shortenTextWithEllipsis(getText()!!.collapseSpaces(), 53, 0)
|
||||
}
|
||||
|
||||
private fun JetElement.getRepresentativeElement(): JetElement {
|
||||
private fun PsiElement.getRepresentativeElement(): PsiElement {
|
||||
return when (this) {
|
||||
is JetBlockExpression -> (getParent() as? JetDeclarationWithBody) ?: this
|
||||
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()
|
||||
return when (representativeElement) {
|
||||
is JetFile, is JetDeclarationWithBody, is JetClassOrObject -> representativeElement.renderDeclaration()
|
||||
else -> representativeElement.renderText()
|
||||
}
|
||||
return representativeElement.renderDeclaration() ?: 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 getIcon(element: PsiElement?): Icon? =
|
||||
super.getIcon((element as? JetElement)?.getRepresentativeElement())
|
||||
override fun getIcon(element: PsiElement): Icon? =
|
||||
super.getIcon(element.getRepresentativeElement())
|
||||
},
|
||||
title,
|
||||
highlightSelection,
|
||||
@@ -368,7 +371,7 @@ public fun chooseContainerElementIfNecessary<T>(
|
||||
editor: Editor,
|
||||
title: String,
|
||||
highlightSelection: Boolean,
|
||||
toPsi: (T) -> JetElement,
|
||||
toPsi: (T) -> PsiElement,
|
||||
onSelect: (T) -> Unit
|
||||
) {
|
||||
when {
|
||||
|
||||
@@ -5,6 +5,6 @@ fun test(): Int {
|
||||
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.
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user