Create From Usage: Create class by annotation entry/super-call delegation specifier
This commit is contained in:
+1
-1
@@ -42,7 +42,7 @@ public class JetConstructorCalleeExpression extends JetExpressionImplStub<Kotlin
|
||||
}
|
||||
|
||||
@Nullable @IfNotParsed
|
||||
public JetReferenceExpression getConstructorReferenceExpression() {
|
||||
public JetSimpleNameExpression getConstructorReferenceExpression() {
|
||||
JetTypeReference typeReference = getTypeReference();
|
||||
if (typeReference == null) {
|
||||
return null;
|
||||
|
||||
@@ -18,9 +18,7 @@ package org.jetbrains.jet.plugin.quickfix;
|
||||
|
||||
import org.jetbrains.jet.lang.psi.JetClass;
|
||||
import org.jetbrains.jet.plugin.codeInsight.ImplementMethodsHandler;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createClass.CreateClassFromConstructorCallActionFactory;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createClass.CreateClassFromTypeReferenceActionFactory;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createClass.CreateClassFromReferenceExpressionActionFactory;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createClass.*;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createFunction.*;
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.createVariable.*;
|
||||
|
||||
@@ -277,5 +275,6 @@ public class QuickFixRegistrar {
|
||||
|
||||
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromTypeReferenceActionFactory.INSTANCE$);
|
||||
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromReferenceExpressionActionFactory.INSTANCE$);
|
||||
QuickFixes.factories.put(UNRESOLVED_REFERENCE, CreateClassFromCallWithConstructorCalleeActionFactory.INSTANCE$);
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -401,13 +401,14 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
psiFactory.createEnumEntry("$name ${if (hasParameters) ": ${targetParent.getName()}()" else ""}")
|
||||
}
|
||||
else -> {
|
||||
val openMod = if (open) "open " else ""
|
||||
val innerMod = if (inner) "inner " else ""
|
||||
val typeParamList = when (kind) {
|
||||
ClassKind.PLAIN_CLASS, ClassKind.TRAIT -> "<>"
|
||||
else -> ""
|
||||
}
|
||||
psiFactory.createDeclaration<JetClassOrObject>(
|
||||
"$innerMod${kind.keyword} $name$typeParamList$paramList$returnTypeString $classBody"
|
||||
"$openMod$innerMod${kind.keyword} $name$typeParamList$paramList$returnTypeString $classBody"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
package org.jetbrains.jet.plugin.quickfix.createFromUsage.createClass
|
||||
|
||||
import org.jetbrains.jet.lang.diagnostics.Diagnostic
|
||||
import com.intellij.codeInsight.intention.IntentionAction
|
||||
import org.jetbrains.jet.plugin.project.AnalyzerFacadeWithCache
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.TypeInfo
|
||||
import org.jetbrains.jet.lang.resolve.BindingContext
|
||||
import org.jetbrains.jet.lang.types.Variance
|
||||
import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns
|
||||
import org.jetbrains.jet.plugin.quickfix.createFromUsage.callableBuilder.ParameterInfo
|
||||
import org.jetbrains.jet.plugin.quickfix.JetSingleIntentionActionFactory
|
||||
import org.jetbrains.jet.lang.psi.JetFile
|
||||
import org.jetbrains.jet.lang.psi.JetAnnotationEntry
|
||||
import org.jetbrains.jet.lang.psi.JetUserType
|
||||
import com.intellij.psi.util.PsiTreeUtil
|
||||
import org.jetbrains.jet.lang.psi.JetDelegatorToSuperCall
|
||||
import org.jetbrains.jet.lang.psi.JetDelegatorToThisCall
|
||||
import org.jetbrains.jet.lang.psi.JetCallElement
|
||||
import org.jetbrains.jet.lang.psi.psiUtil.isAncestor
|
||||
import org.jetbrains.jet.lang.psi.JetConstructorCalleeExpression
|
||||
import org.jetbrains.jet.lang.psi.JetSimpleNameExpression
|
||||
import java.util.Collections
|
||||
|
||||
public object CreateClassFromCallWithConstructorCalleeActionFactory : JetSingleIntentionActionFactory() {
|
||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||
val diagElement = diagnostic.getPsiElement()
|
||||
|
||||
val callElement = PsiTreeUtil.getParentOfType(
|
||||
diagElement,
|
||||
javaClass<JetAnnotationEntry>(),
|
||||
javaClass<JetDelegatorToSuperCall>()
|
||||
) as? JetCallElement ?: return null
|
||||
|
||||
val isAnnotation = callElement is JetAnnotationEntry
|
||||
|
||||
val callee = callElement.getCalleeExpression() as? JetConstructorCalleeExpression ?: return null
|
||||
val calleeRef = callee.getConstructorReferenceExpression() ?: return null
|
||||
|
||||
if (!calleeRef.isAncestor(diagElement)) return null
|
||||
|
||||
val file = callElement.getContainingFile() as? JetFile ?: return null
|
||||
val typeRef = callee.getTypeReference() ?: return null
|
||||
val userType = typeRef.getTypeElement() as? JetUserType ?: return null
|
||||
|
||||
val context = AnalyzerFacadeWithCache.getContextForElement(userType)
|
||||
|
||||
val qualifier = userType.getQualifier()?.getReferenceExpression()
|
||||
val qualifierDescriptor = qualifier?.let { context[BindingContext.REFERENCE_TARGET, it] }
|
||||
|
||||
val targetParent = getTargetParentByQualifier(file, qualifier != null, qualifierDescriptor) ?: return null
|
||||
|
||||
val anyType = KotlinBuiltIns.getInstance().getNullableAnyType()
|
||||
val valueArguments = callElement.getValueArguments()
|
||||
val defaultParamName = if (valueArguments.size == 1) "value" else null
|
||||
val parameterInfos = valueArguments.map {
|
||||
ParameterInfo(
|
||||
it.getArgumentExpression()?.let { TypeInfo(it, Variance.IN_VARIANCE) } ?: TypeInfo(anyType, Variance.IN_VARIANCE),
|
||||
it.getArgumentName()?.getReferenceExpression()?.getReferencedName() ?: defaultParamName
|
||||
)
|
||||
}
|
||||
|
||||
val typeArgumentInfos = when {
|
||||
isAnnotation -> Collections.emptyList<TypeInfo>()
|
||||
else -> callElement.getTypeArguments().map { TypeInfo(it.getTypeReference(), Variance.INVARIANT) }
|
||||
}
|
||||
|
||||
val classInfo = ClassInfo(
|
||||
kind = if (isAnnotation) ClassKind.ANNOTATION_CLASS else ClassKind.PLAIN_CLASS,
|
||||
name = calleeRef.getReferencedName(),
|
||||
targetParent = targetParent,
|
||||
expectedTypeInfo = TypeInfo.Empty,
|
||||
parameterInfos = parameterInfos,
|
||||
open = !isAnnotation,
|
||||
typeArguments = typeArgumentInfos
|
||||
)
|
||||
return CreateClassFromUsageFix(callElement, classInfo)
|
||||
}
|
||||
}
|
||||
+1
@@ -53,6 +53,7 @@ public class ClassInfo(
|
||||
val targetParent: PsiElement,
|
||||
val expectedTypeInfo: TypeInfo,
|
||||
val inner: Boolean = false,
|
||||
val open: Boolean = false,
|
||||
val typeArguments: List<TypeInfo> = Collections.emptyList(),
|
||||
val parameterInfos: List<ParameterInfo> = Collections.emptyList()
|
||||
)
|
||||
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
foo(1, "2") fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo(val i: Int, val s: String)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo()] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo(1, "2")] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo(val i: Int, val s: String)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo(1, "2")] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo(val i: Int, val s: String)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo(1)] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo(val value: Int)
|
||||
+7
@@ -0,0 +1,7 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[foo(fooBar = 1)] fun test() {
|
||||
|
||||
}
|
||||
|
||||
annotation class foo(val fooBar: Int)
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
<caret>foo(1, "2") fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo] fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo()] fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo(1, "2")] fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo<String>(1, "2")] fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "false"
|
||||
// ACTION: Create function 'foo'
|
||||
// ERROR: Unresolved reference: foo
|
||||
|
||||
fun test() = <caret>foo(1, "2")
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo(1)] fun test() {
|
||||
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
// "Create annotation 'foo'" "true"
|
||||
|
||||
[<caret>foo(fooBar = 1)] fun test() {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: A(1, "2") {
|
||||
|
||||
}
|
||||
|
||||
open class A(i: Int, s: String) {
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class X {
|
||||
|
||||
open class A(i: Int, s: String) {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Foo: X.A(1, "2") {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: p.A(1, "2") {
|
||||
|
||||
}
|
||||
|
||||
open class A(i: Int, s: String) {
|
||||
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
class Foo: A(abc = 1, ghi = "2", def = B()) {
|
||||
|
||||
}
|
||||
|
||||
open class A(abc: Int, ghi: String, def: B) {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: A<Int, String>(1, "2") {
|
||||
|
||||
}
|
||||
|
||||
open class A<T, U>(t: T, u: U) {
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: <caret>A(1, "2") {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class X {
|
||||
|
||||
}
|
||||
|
||||
class Foo: X.<caret>A(1, "2") {
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: p.<caret>A(1, "2") {
|
||||
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class B {
|
||||
|
||||
}
|
||||
|
||||
class Foo: <caret>A(abc = 1, ghi = "2", def = B()) {
|
||||
|
||||
}
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
// "Create class 'A'" "true"
|
||||
package p
|
||||
|
||||
class Foo: <caret>A<Int, String>(1, "2") {
|
||||
|
||||
}
|
||||
@@ -628,13 +628,70 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createClass")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({CreateClass.CallExpression.class, CreateClass.DelegationSpecifier.class, CreateClass.ImportDirective.class, CreateClass.ReferenceExpression.class, CreateClass.TypeReference.class})
|
||||
@InnerTestClasses({CreateClass.AnnotationEntry.class, CreateClass.CallExpression.class, CreateClass.DelegationSpecifier.class, CreateClass.ImportDirective.class, CreateClass.ReferenceExpression.class, CreateClass.TypeReference.class})
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class CreateClass extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInCreateClass() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createClass"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class AnnotationEntry extends AbstractQuickFixTest {
|
||||
public void testAllFilesPresentInAnnotationEntry() throws Exception {
|
||||
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/quickfix/createFromUsage/createClass/annotationEntry"), Pattern.compile("^before(\\w+)\\.kt$"), true);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAnnotationNoBrackets.kt")
|
||||
public void testAnnotationNoBrackets() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeAnnotationNoBrackets.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAnnotationNoParamList.kt")
|
||||
public void testAnnotationNoParamList() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeAnnotationNoParamList.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAnnotationNoParams.kt")
|
||||
public void testAnnotationNoParams() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeAnnotationNoParams.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAnnotationWithParams.kt")
|
||||
public void testAnnotationWithParams() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeAnnotationWithParams.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeAnnotationWithTypeParams.kt")
|
||||
public void testAnnotationWithTypeParams() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeAnnotationWithTypeParams.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeNotAnnotation.kt")
|
||||
public void testNotAnnotation() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeNotAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeSingleArgAnnotation.kt")
|
||||
public void testSingleArgAnnotation() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeSingleArgAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeSingleNamedArgAnnotation.kt")
|
||||
public void testSingleNamedArgAnnotation() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/annotationEntry/beforeSingleNamedArgAnnotation.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("idea/testData/quickfix/createFromUsage/createClass/callExpression")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@InnerTestClasses({CallExpression.TypeArguments.class})
|
||||
@@ -914,6 +971,36 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDelegatorToSupercallNoReceiver.kt")
|
||||
public void testDelegatorToSupercallNoReceiver() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeDelegatorToSupercallNoReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDelegatorToSupercallWithClassQualifier.kt")
|
||||
public void testDelegatorToSupercallWithClassQualifier() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeDelegatorToSupercallWithClassQualifier.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDelegatorToSupercallWithPackageQualifier.kt")
|
||||
public void testDelegatorToSupercallWithPackageQualifier() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeDelegatorToSupercallWithPackageQualifier.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDelegatorToSupercallWithParamNames.kt")
|
||||
public void testDelegatorToSupercallWithParamNames() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeDelegatorToSupercallWithParamNames.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeDelegatorToSupercallWithTypeParams.kt")
|
||||
public void testDelegatorToSupercallWithTypeParams() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeDelegatorToSupercallWithTypeParams.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("beforeTraitDelegatorToSuperclass.kt")
|
||||
public void testTraitDelegatorToSuperclass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createClass/delegationSpecifier/beforeTraitDelegatorToSuperclass.kt");
|
||||
|
||||
Reference in New Issue
Block a user