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.storage.StorageManager
|
||||
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.makeNotNullable
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
@@ -53,9 +54,11 @@ interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor {
|
||||
.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? {
|
||||
if (methodName.isSpecial()) return null
|
||||
@@ -85,19 +88,25 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
||||
if (!firstChar.isJavaIdentifierStart() || firstChar.isUpperCase()) return null
|
||||
|
||||
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 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)
|
||||
}
|
||||
|
||||
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()
|
||||
&& descriptor.getTypeParameters().isEmpty()
|
||||
&& descriptor.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local?
|
||||
&& !(descriptor.getReturnType()?.isUnit() ?: true)
|
||||
}
|
||||
|
||||
private fun isGoodSetMethod(descriptor: FunctionDescriptor, propertyType: JetType): Boolean {
|
||||
@@ -105,7 +114,7 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
||||
return parameter.getType() == propertyType
|
||||
&& parameter.getVarargElementType() == null
|
||||
&& descriptor.getTypeParameters().isEmpty()
|
||||
&& descriptor.getReturnType()?.let { KotlinBuiltIns.isUnit(it) } ?: false
|
||||
&& descriptor.getReturnType()?.let { it.isUnit() } ?: false
|
||||
&& descriptor.getVisibility() == Visibilities.PUBLIC
|
||||
}
|
||||
|
||||
@@ -156,14 +165,15 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
|
||||
return list
|
||||
}
|
||||
|
||||
//TODO: "is"?
|
||||
//TODO: methods like "getURL"?
|
||||
//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())
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@TestMetadata("IsNaming.kt")
|
||||
public void testIsNaming() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/syntheticExtensions/IsNaming.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("OnlyPublic.kt")
|
||||
public void testOnlyPublic() throws Exception {
|
||||
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.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> {
|
||||
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: "daemon", itemText: "daemon", tailText: " for Thread", typeText: "Boolean" }
|
||||
// ABSENT: getPriority
|
||||
// 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.Variance
|
||||
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.utils.addToStdlib.singletonOrEmptyList
|
||||
import java.util.*
|
||||
@@ -316,7 +316,7 @@ class CallableBuilder(val config: CallableBuilderConfiguration) {
|
||||
CallableKind.FUNCTION ->
|
||||
returnTypeCandidate?.theType?.isUnit() ?: false
|
||||
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.PROPERTY -> containingElement is JetBlockExpression
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user