Create from usage: Support extension members for Java classes

This commit is contained in:
Alexey Sedunov
2015-02-10 15:16:35 +03:00
parent 9f3ba50dc5
commit e75bd1b41b
4 changed files with 58 additions and 21 deletions
@@ -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
}
}
@@ -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.
}