Naming with "is" supported for synthetic extensions
This commit is contained in:
+20
-10
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
import org.jetbrains.kotlin.resolve.scopes.JetScope
|
||||||
import org.jetbrains.kotlin.storage.StorageManager
|
import org.jetbrains.kotlin.storage.StorageManager
|
||||||
import org.jetbrains.kotlin.types.JetType
|
import org.jetbrains.kotlin.types.JetType
|
||||||
|
import org.jetbrains.kotlin.types.typeUtil.isBoolean
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
import org.jetbrains.kotlin.types.typeUtil.makeNotNullable
|
||||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||||
@@ -53,9 +54,11 @@ interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor {
|
|||||||
.firstOrNull { getterOrSetter == it.getMethod || getterOrSetter == it.setMethod }
|
.firstOrNull { getterOrSetter == it.getMethod || getterOrSetter == it.setMethod }
|
||||||
}
|
}
|
||||||
|
|
||||||
fun propertyNameByGetMethodName(methodName: Name): Name? = propertyNameFromAccessorMethodName(methodName, "get")
|
fun propertyNameByGetMethodName(methodName: Name): Name?
|
||||||
|
= propertyNameFromAccessorMethodName(methodName, "get") ?: propertyNameFromAccessorMethodName(methodName, "is")
|
||||||
|
|
||||||
fun propertyNameBySetMethodName(methodName: Name): Name? = propertyNameFromAccessorMethodName(methodName, "set")
|
fun propertyNameBySetMethodName(methodName: Name): Name?
|
||||||
|
= propertyNameFromAccessorMethodName(methodName, "set")
|
||||||
|
|
||||||
private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String): Name? {
|
private fun propertyNameFromAccessorMethodName(methodName: Name, prefix: String): Name? {
|
||||||
if (methodName.isSpecial()) return null
|
if (methodName.isSpecial()) return null
|
||||||
@@ -85,19 +88,25 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
|||||||
if (!firstChar.isJavaIdentifierStart() || firstChar.isUpperCase()) return null
|
if (!firstChar.isJavaIdentifierStart() || firstChar.isUpperCase()) return null
|
||||||
|
|
||||||
val memberScope = javaClass.getMemberScope(type.getArguments())
|
val memberScope = javaClass.getMemberScope(type.getArguments())
|
||||||
val getMethod = memberScope.getFunctions(toGetMethodName(name)).singleOrNull { isGoodGetMethod(it) } ?: return null
|
val getMethod = possibleGetMethodNames(name)
|
||||||
|
.asSequence()
|
||||||
|
.flatMap { memberScope.getFunctions(it).asSequence() }
|
||||||
|
.singleOrNull { isGoodGetMethod(it) } ?: return null
|
||||||
|
|
||||||
val propertyType = getMethod.getReturnType() ?: return null
|
val propertyType = getMethod.getReturnType() ?: return null
|
||||||
val setMethod = memberScope.getFunctions(toSetMethodName(name)).singleOrNull { isGoodSetMethod(it, propertyType) }
|
val setMethod = memberScope.getFunctions(possibleSetMethodName(name)).singleOrNull { isGoodSetMethod(it, propertyType) }
|
||||||
|
|
||||||
return MyPropertyDescriptor(javaClass, getMethod, setMethod, name, propertyType, type)
|
return MyPropertyDescriptor(javaClass, getMethod, setMethod, name, propertyType, type)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
|
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
|
||||||
|
val returnType = descriptor.getReturnType() ?: return false
|
||||||
|
if (returnType.isUnit()) return false
|
||||||
|
if (descriptor.getName().asString().startsWith("is") && !returnType.isBoolean()) return false
|
||||||
|
|
||||||
return descriptor.getValueParameters().isEmpty()
|
return descriptor.getValueParameters().isEmpty()
|
||||||
&& descriptor.getTypeParameters().isEmpty()
|
&& descriptor.getTypeParameters().isEmpty()
|
||||||
&& descriptor.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local?
|
&& descriptor.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local?
|
||||||
&& !(descriptor.getReturnType()?.isUnit() ?: true)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isGoodSetMethod(descriptor: FunctionDescriptor, propertyType: JetType): Boolean {
|
private fun isGoodSetMethod(descriptor: FunctionDescriptor, propertyType: JetType): Boolean {
|
||||||
@@ -105,7 +114,7 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
|||||||
return parameter.getType() == propertyType
|
return parameter.getType() == propertyType
|
||||||
&& parameter.getVarargElementType() == null
|
&& parameter.getVarargElementType() == null
|
||||||
&& descriptor.getTypeParameters().isEmpty()
|
&& descriptor.getTypeParameters().isEmpty()
|
||||||
&& descriptor.getReturnType()?.let { KotlinBuiltIns.isUnit(it) } ?: false
|
&& descriptor.getReturnType()?.let { it.isUnit() } ?: false
|
||||||
&& descriptor.getVisibility() == Visibilities.PUBLIC
|
&& descriptor.getVisibility() == Visibilities.PUBLIC
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,14 +165,15 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
|||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: "is"?
|
|
||||||
//TODO: methods like "getURL"?
|
//TODO: methods like "getURL"?
|
||||||
//TODO: reuse code with generation?
|
//TODO: reuse code with generation?
|
||||||
private fun toGetMethodName(propertyName: Name): Name {
|
|
||||||
return Name.identifier("get" + propertyName.getIdentifier().capitalize())
|
private fun possibleGetMethodNames(propertyName: Name): Collection<Name> {
|
||||||
|
val capitalized = propertyName.getIdentifier().capitalize()
|
||||||
|
return listOf(Name.identifier("get" + capitalized), Name.identifier("is" + capitalized))
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun toSetMethodName(propertyName: Name): Name {
|
private fun possibleSetMethodName(propertyName: Name): Name {
|
||||||
return Name.identifier("set" + propertyName.getIdentifier().capitalize())
|
return Name.identifier("set" + propertyName.getIdentifier().capitalize())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
// FILE: KotlinFile.kt
|
||||||
|
fun foo(javaClass: JavaClass) {
|
||||||
|
javaClass.something = !javaClass.something
|
||||||
|
|
||||||
|
javaClass.<!UNRESOLVED_REFERENCE!>somethingWrong<!>
|
||||||
|
}
|
||||||
|
|
||||||
|
// FILE: JavaClass.java
|
||||||
|
public class JavaClass {
|
||||||
|
public boolean isSomething() { return true; }
|
||||||
|
public void setSomething(boolean value) { }
|
||||||
|
public int isSomethingWrong() { return 1; }
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
internal fun foo(/*0*/ javaClass: JavaClass): kotlin.Unit
|
||||||
|
|
||||||
|
public open class JavaClass {
|
||||||
|
public constructor JavaClass()
|
||||||
|
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||||
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
|
public open fun isSomething(): kotlin.Boolean
|
||||||
|
public open fun isSomethingWrong(): kotlin.Int
|
||||||
|
public open fun setSomething(/*0*/ value: kotlin.Boolean): kotlin.Unit
|
||||||
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
|
}
|
||||||
@@ -14058,6 +14058,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("IsNaming.kt")
|
||||||
|
public void testIsNaming() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/IsNaming.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("OnlyPublic.kt")
|
@TestMetadata("OnlyPublic.kt")
|
||||||
public void testOnlyPublic() throws Exception {
|
public void testOnlyPublic() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/OnlyPublic.kt");
|
||||||
|
|||||||
@@ -49,7 +49,8 @@ fun JetType.supertypes(): Set<JetType> = TypeUtils.getAllSupertypes(this)
|
|||||||
|
|
||||||
fun JetType.isNothing(): Boolean = KotlinBuiltIns.isNothing(this)
|
fun JetType.isNothing(): Boolean = KotlinBuiltIns.isNothing(this)
|
||||||
fun JetType.isUnit(): Boolean = KotlinBuiltIns.isUnit(this)
|
fun JetType.isUnit(): Boolean = KotlinBuiltIns.isUnit(this)
|
||||||
fun JetType.isAny(): Boolean = KotlinBuiltIns.isAnyOrNullableAny(this)
|
fun JetType.isAnyOrNullableAny(): Boolean = KotlinBuiltIns.isAnyOrNullableAny(this)
|
||||||
|
fun JetType.isBoolean(): Boolean = KotlinBuiltIns.isBoolean(this)
|
||||||
|
|
||||||
private fun JetType.getContainedTypeParameters(): Collection<TypeParameterDescriptor> {
|
private fun JetType.getContainedTypeParameters(): Collection<TypeParameterDescriptor> {
|
||||||
val declarationDescriptor = getConstructor().getDeclarationDescriptor()
|
val declarationDescriptor = getConstructor().getDeclarationDescriptor()
|
||||||
|
|||||||
@@ -3,5 +3,8 @@ fun Thread.foo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EXIST_JAVA_ONLY: { lookupString: "priority", itemText: "priority", tailText: " for Thread", typeText: "Int" }
|
// EXIST_JAVA_ONLY: { lookupString: "priority", itemText: "priority", tailText: " for Thread", typeText: "Int" }
|
||||||
|
// EXIST_JAVA_ONLY: { lookupString: "daemon", itemText: "daemon", tailText: " for Thread", typeText: "Boolean" }
|
||||||
// ABSENT: getPriority
|
// ABSENT: getPriority
|
||||||
// ABSENT: setPriority
|
// ABSENT: setPriority
|
||||||
|
// ABSENT: isDaemon
|
||||||
|
// ABSENT: setDaemon
|
||||||
|
|||||||
+2
-2
@@ -66,7 +66,7 @@ import org.jetbrains.kotlin.types.JetType
|
|||||||
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
import org.jetbrains.kotlin.types.TypeProjectionImpl
|
||||||
import org.jetbrains.kotlin.types.Variance
|
import org.jetbrains.kotlin.types.Variance
|
||||||
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
import org.jetbrains.kotlin.types.checker.JetTypeChecker
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isAny
|
import org.jetbrains.kotlin.types.typeUtil.isAnyOrNullableAny
|
||||||
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
import org.jetbrains.kotlin.types.typeUtil.isUnit
|
||||||
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
import org.jetbrains.kotlin.utils.addToStdlib.singletonOrEmptyList
|
||||||
import java.util.*
|
import java.util.*
|
||||||
@@ -316,7 +316,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
|||||||
CallableKind.FUNCTION ->
|
CallableKind.FUNCTION ->
|
||||||
returnTypeCandidate?.theType?.isUnit() ?: false
|
returnTypeCandidate?.theType?.isUnit() ?: false
|
||||||
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
CallableKind.CLASS_WITH_PRIMARY_CONSTRUCTOR ->
|
||||||
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAny() ?: false
|
callableInfo.returnTypeInfo == TypeInfo.Empty || returnTypeCandidate?.theType?.isAnyOrNullableAny() ?: false
|
||||||
CallableKind.SECONDARY_CONSTRUCTOR -> true
|
CallableKind.SECONDARY_CONSTRUCTOR -> true
|
||||||
CallableKind.PROPERTY -> containingElement is JetBlockExpression
|
CallableKind.PROPERTY -> containingElement is JetBlockExpression
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user