Create from Usage: Disable "Create property" (non-abstract) in interfaces. Make "Create function" (non-abstract) generate function body in interfaces

#KT-13365 Fixed
This commit is contained in:
Alexey Sedunov
2016-08-08 15:32:54 +03:00
parent f4d9f33f48
commit 562488b348
8 changed files with 45 additions and 5 deletions
+1
View File
@@ -216,6 +216,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-13262`](https://youtrack.jetbrains.com/issue/KT-13262) "Wrap with safe let call" quickfix produces wrong result for qualified function
- [`KT-13364`](https://youtrack.jetbrains.com/issue/KT-13364) Do not suggest creating annotations/enum classes for unresolved type parameter bounds
- [`KT-12627`](https://youtrack.jetbrains.com/issue/KT-12627) Allow warnings suppression for secondary constructor
- [`KT-13365`](https://youtrack.jetbrains.com/issue/KT-13365) Disable "Create property" (non-abstract) in interfaces. Make "Create function" (non-abstract) generate function body in interfaces
##### New features
@@ -447,6 +447,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
if (containingElement is KtClass && containingElement.isInterface()) "" else "abstract "
}
else if (containingElement is KtClassOrObject
&& !(containingElement is KtClass && containingElement.isInterface())
&& containingElement.isAncestor(config.originalElement)
&& callableInfo.kind != CallableKind.SECONDARY_CONSTRUCTOR) "private "
else ""
@@ -454,7 +455,6 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
val declaration: KtNamedDeclaration = when (callableInfo.kind) {
CallableKind.FUNCTION, CallableKind.SECONDARY_CONSTRUCTOR -> {
val body = when {
containingElement is KtClass && containingElement.isInterface() && !config.isExtension -> ""
callableInfo.kind == CallableKind.SECONDARY_CONSTRUCTOR -> ""
callableInfo.isAbstract -> ""
else -> "{}"
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde
import org.jetbrains.kotlin.idea.quickfix.createFromUsage.callableBuilder.*
import org.jetbrains.kotlin.idea.refactoring.canRefactor
import org.jetbrains.kotlin.idea.refactoring.getExtractionContainers
import org.jetbrains.kotlin.idea.refactoring.isInterfaceClass
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor
import org.jetbrains.kotlin.psi.*
@@ -183,7 +184,23 @@ sealed class CreateCallableFromCallActionFactory<E : KtExpression>(
return PropertyInfo(name, receiverType, returnType, varExpected, possibleContainers)
}
object Default : Property()
object Default : Property() {
override fun doCreateCallableInfo(
expression: KtSimpleNameExpression,
context: BindingContext,
name: String,
receiverType: TypeInfo,
possibleContainers: List<KtElement>
): CallableInfo? {
return super.doCreateCallableInfo(
expression,
context,
name,
receiverType,
possibleContainers.filterNot { it is KtClassBody && (it.parent as KtClassOrObject).isInterfaceClass() }
)
}
}
object Abstract : Property() {
override fun doCreateCallableInfo(
@@ -141,7 +141,10 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
val receiverInfo = callableInfos.first().receiverTypeInfo
if (receiverInfo is TypeInfo.Empty) return !isExtension
if (receiverInfo is TypeInfo.Empty) {
if (callableInfos.any { it is PropertyInfo && it.possibleContainers.isEmpty() }) return false
return !isExtension
}
// TODO: Remove after companion object extensions are supported
if (isExtension && receiverInfo.staticContextRequired) return false
@@ -158,6 +161,7 @@ abstract class CreateCallableFromUsageFixBase<E : KtElement>(
isFunction && insertToJavaInterface && receiverInfo.staticContextRequired ->
false
!isExtension && declaration is KtTypeParameter -> false
propertyInfo != null && !propertyInfo.isAbstract && declaration is KtClass && declaration.isInterface() -> false
else ->
declaration != null
}
@@ -1,7 +1,9 @@
// "Create member function 'T.foo'" "true"
interface T {
fun foo(s: String, i: Int): Boolean
fun foo(s: String, i: Int): Boolean {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
}
fun test(t: T) {
@@ -1,7 +1,6 @@
// "Create parameter 'foo'" "false"
// ACTION: Convert to expression body
// ACTION: Create local variable 'foo'
// ACTION: Create property 'foo'
// ACTION: Create abstract property 'foo'
// ACTION: Rename reference
// ERROR: Unresolved reference: foo
@@ -0,0 +1,11 @@
// "Create property 'foo'" "false"
// ACTION: Create abstract property 'foo'
// ACTION: Create local variable 'foo'
// ACTION: Create object 'foo'
// ACTION: Create parameter 'foo'
// ACTION: Rename reference
// ERROR: Unresolved reference: foo
interface IF1 {
fun af2() = <caret>foo
}
@@ -3564,6 +3564,12 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest {
doTest(fileName);
}
@TestMetadata("nonAbstractInInterface.kt")
public void testNonAbstractInInterface() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/nonAbstractInInterface.kt");
doTest(fileName);
}
@TestMetadata("objectMemberValNoReceiver.kt")
public void testObjectMemberValNoReceiver() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("idea/testData/quickfix/createFromUsage/createVariable/property/objectMemberValNoReceiver.kt");