Create from Usage: Suggest synthetic function classes as extension receivers

This commit is contained in:
Alexey Sedunov
2015-09-29 19:14:40 +03:00
parent 1d83d75a82
commit 1f6f617546
5 changed files with 40 additions and 6 deletions
@@ -35,6 +35,7 @@ import com.intellij.psi.codeStyle.JavaCodeStyleManager
import com.intellij.psi.util.PsiTreeUtil
import com.intellij.util.IncorrectOperationException
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.cfg.pseudocode.Pseudocode
import org.jetbrains.kotlin.cfg.pseudocode.getContainingPseudocode
import org.jetbrains.kotlin.descriptors.*
@@ -435,7 +436,11 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
}
else null
val ownerTypeString = if (isExtension) "${receiverTypeCandidate!!.renderedType!!}." else ""
val ownerTypeString = if (isExtension) {
val renderedType = receiverTypeCandidate!!.renderedType!!
val isFunctionType = receiverTypeCandidate.theType.constructor.declarationDescriptor is FunctionClassDescriptor
if (isFunctionType) "($renderedType)." else "$renderedType."
} else ""
val classKind = (callableInfo as? PrimaryConstructorInfo)?.classInfo?.kind
@@ -22,16 +22,16 @@ import com.intellij.openapi.project.Project
import com.intellij.psi.PsiClass
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.builtins.functions.FunctionClassDescriptor
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.core.refactoring.canRefactor
import org.jetbrains.kotlin.idea.core.refactoring.chooseContainerElementIfNecessary
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.CreateFromUsageFixBase
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.psi.JetClassBody
import org.jetbrains.kotlin.psi.JetClassOrObject
import org.jetbrains.kotlin.psi.JetElement
import org.jetbrains.kotlin.psi.JetFile
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getElementTextWithContext
import java.util.HashSet
@@ -61,9 +61,18 @@ public abstract class CreateCallableFromUsageFixBase<E : JetElement>(
}
}
private fun getDeclaration(descriptor: ClassifierDescriptor, project: Project): PsiElement? {
if (descriptor is FunctionClassDescriptor) {
val psiFactory = JetPsiFactory(project)
val syntheticClass = psiFactory.createClass(IdeDescriptorRenderers.SOURCE_CODE_SHORT_NAMES_IN_TYPES.render(descriptor))
return psiFactory.createAnalyzableFile("${descriptor.name.asString()}.kt", "", element).add(syntheticClass)
}
return DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor)
}
private fun getDeclarationIfApplicable(project: Project, candidate: TypeCandidate): PsiElement? {
val descriptor = candidate.theType.constructor.declarationDescriptor ?: return null
val declaration = DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptor) ?: return null
val declaration = getDeclaration(descriptor, project) ?: return null
if (declaration !is JetClassOrObject && declaration !is PsiClass) return null
return if (isExtension || declaration.canRefactor()) declaration else null
}
@@ -0,0 +1,5 @@
// "Create extension function 'bar'" "true"
fun foo(block: (Int) -> String) {
block.b<caret>ar()
}
@@ -0,0 +1,9 @@
// "Create extension function 'bar'" "true"
fun foo(block: (Int) -> String) {
block.bar()
}
fun <P1, R> ((P1) -> R).bar() {
throw UnsupportedOperationException("not implemented") //To change body of created functions use File | Settings | File Templates.
}
@@ -1790,6 +1790,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("functionalTypeInReceiver.kt")
public void testFunctionalTypeInReceiver() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/functionalTypeInReceiver.kt");
doTest(fileName);
}
@TestMetadata("inLambda.kt")
public void testInLambda() throws Exception {
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createFunction/call/inLambda.kt");