Track lookups in JavaSyntheticPropertiesScope

This commit is contained in:
Zalim Bashorov
2015-10-23 17:53:54 +03:00
parent 412e078a6b
commit a5708c9c0d
15 changed files with 185 additions and 60 deletions
@@ -16,9 +16,10 @@
package org.jetbrains.kotlin.synthetic
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.resolve.lazy.FileScopeProvider
import org.jetbrains.kotlin.storage.StorageManager
class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager) : FileScopeProvider.AdditionalScopes {
override val scopes = listOf(JavaSyntheticPropertiesScope(storageManager), SamAdapterFunctionsScope(storageManager))
}
class AdditionalScopesWithJavaSyntheticExtensions(storageManager: StorageManager, lookupTracker: LookupTracker) : FileScopeProvider.AdditionalScopes {
override val scopes = listOf(JavaSyntheticPropertiesScope(storageManager, lookupTracker), SamAdapterFunctionsScope(storageManager))
}
@@ -23,7 +23,9 @@ import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.incremental.record
import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.DescriptorUtils
@@ -42,6 +44,8 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import java.util.*
import kotlin.properties.Delegates
private val POSSIBLE_GETTER_NAMES_CAPACITY = 3
interface SyntheticJavaPropertyDescriptor : PropertyDescriptor {
val getMethod: FunctionDescriptor
val setMethod: FunctionDescriptor?
@@ -69,31 +73,62 @@ interface SyntheticJavaPropertyDescriptor : PropertyDescriptor {
}
}
class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImportingScope(null) {
private val syntheticPropertyInClass = storageManager.createMemoizedFunctionWithNullableValues<Pair<ClassDescriptor, Name>, PropertyDescriptor> { pair ->
class JavaSyntheticPropertiesScope(storageManager: StorageManager, private val lookupTracker: LookupTracker) : BaseImportingScope(null) {
private val syntheticPropertyInClass = storageManager.createMemoizedFunction<Pair<ClassDescriptor, Name>, SyntheticPropertyHolder> { pair ->
syntheticPropertyInClassNotCached(pair.first, pair.second)
}
private fun syntheticPropertyInClassNotCached(ownerClass: ClassDescriptor, name: Name): PropertyDescriptor? {
if (name.isSpecial()) return null
private fun getSyntheticPropertyAndRecordLookups(classifier: ClassDescriptor, name: Name, location: LookupLocation): PropertyDescriptor? {
val (descriptor, lookedNames) = syntheticPropertyInClass(Pair(classifier, name))
if (location !is NoLookupLocation) {
lookedNames.forEach { lookupTracker.record(location, classifier.unsubstitutedMemberScope, it) }
}
return descriptor
}
private fun syntheticPropertyInClassNotCached(ownerClass: ClassDescriptor, name: Name): SyntheticPropertyHolder {
fun result(descriptor: PropertyDescriptor?, getterNames: Sequence<Name>, setterName: Name? = null): SyntheticPropertyHolder {
if (lookupTracker == LookupTracker.DO_NOTHING) {
return if (descriptor == null) SyntheticPropertyHolder.EMPTY else SyntheticPropertyHolder(descriptor, emptyList())
}
val names = ArrayList<Name>(POSSIBLE_GETTER_NAMES_CAPACITY + (setterName?.let { 1 } ?: 0))
names.addAll(getterNames)
names.addIfNotNull(setterName)
return SyntheticPropertyHolder(descriptor, names)
}
if (name.isSpecial) return SyntheticPropertyHolder.EMPTY
val identifier = name.identifier
if (identifier.isEmpty()) return null
if (identifier.isEmpty()) return SyntheticPropertyHolder.EMPTY
val firstChar = identifier[0]
if (!firstChar.isJavaIdentifierStart() || firstChar in 'A'..'Z') return null
if (!firstChar.isJavaIdentifierStart() || firstChar in 'A'..'Z') return SyntheticPropertyHolder.EMPTY
val memberScope = ownerClass.unsubstitutedMemberScope
val getMethod = possibleGetMethodNames(name)
.flatMap { memberScope.getFunctions(it, NoLookupLocation.UNSORTED).asSequence() }
val possibleGetMethodNames = possibleGetMethodNames(name)
val getMethod = possibleGetMethodNames
.flatMap { memberScope.getFunctions(it, NoLookupLocation.FROM_SYNTHETIC_SCOPE).asSequence() }
.singleOrNull {
isGoodGetMethod(it) && it.hasJavaOriginInHierarchy()
} ?: return null
} ?: return result(null, possibleGetMethodNames)
val setMethod = memberScope.getFunctions(setMethodName(getMethod.name), NoLookupLocation.UNSORTED)
val setMethodName = setMethodName(getMethod.name)
val setMethod = memberScope.getFunctions(setMethodName, NoLookupLocation.FROM_SYNTHETIC_SCOPE)
.singleOrNull { isGoodSetMethod(it, getMethod) }
val propertyType = getMethod.returnType ?: return null
return MyPropertyDescriptor.create(ownerClass, getMethod.original, setMethod?.original, name, propertyType)
val propertyType = getMethod.returnType!!
val descriptor = MyPropertyDescriptor.create(ownerClass, getMethod.original, setMethod?.original, name, propertyType)
return result(descriptor, possibleGetMethodNames, setMethodName);
}
private fun isGoodGetMethod(descriptor: FunctionDescriptor): Boolean {
@@ -131,12 +166,10 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
}
override fun getContributedSyntheticExtensionProperties(receiverTypes: Collection<KotlinType>, name: Name, location: LookupLocation): Collection<PropertyDescriptor> {
//TODO: use location parameter!
var result: SmartList<PropertyDescriptor>? = null
val processedTypes: MutableSet<TypeConstructor>? = if (receiverTypes.size() > 1) HashSet<TypeConstructor>() else null
for (type in receiverTypes) {
result = collectSyntheticPropertiesByName(result, type.constructor, name, processedTypes)
result = collectSyntheticPropertiesByName(result, type.constructor, name, processedTypes, location)
}
return when {
result == null -> emptyList()
@@ -145,7 +178,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
}
}
private fun collectSyntheticPropertiesByName(result: SmartList<PropertyDescriptor>?, type: TypeConstructor, name: Name, processedTypes: MutableSet<TypeConstructor>?): SmartList<PropertyDescriptor>? {
private fun collectSyntheticPropertiesByName(result: SmartList<PropertyDescriptor>?, type: TypeConstructor, name: Name, processedTypes: MutableSet<TypeConstructor>?, location: LookupLocation): SmartList<PropertyDescriptor>? {
if (processedTypes != null && !processedTypes.add(type)) return result
@Suppress("NAME_SHADOWING")
@@ -153,10 +186,10 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
val classifier = type.declarationDescriptor
if (classifier is ClassDescriptor) {
result = result.add(syntheticPropertyInClass(Pair(classifier, name)))
result = result.add(getSyntheticPropertyAndRecordLookups(classifier, name, location))
}
else {
type.supertypes.forEach { result = collectSyntheticPropertiesByName(result, it.constructor, name, processedTypes) }
type.supertypes.forEach { result = collectSyntheticPropertiesByName(result, it.constructor, name, processedTypes, location) }
}
return result
@@ -177,7 +210,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
for (descriptor in classifier.getUnsubstitutedMemberScope().getDescriptors(DescriptorKindFilter.FUNCTIONS)) {
if (descriptor is FunctionDescriptor) {
val propertyName = SyntheticJavaPropertyDescriptor.propertyNameByGetMethodName(descriptor.getName()) ?: continue
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)))
addIfNotNull(syntheticPropertyInClass(Pair(classifier, propertyName)).descriptor)
}
}
}
@@ -196,7 +229,7 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
//TODO: reuse code with generation?
private fun possibleGetMethodNames(propertyName: Name): Sequence<Name> {
val result = ArrayList<Name>(3)
val result = ArrayList<Name>(POSSIBLE_GETTER_NAMES_CAPACITY)
val identifier = propertyName.identifier
if (JvmAbi.startsWithIsPrefix(identifier)) {
@@ -228,6 +261,12 @@ class JavaSyntheticPropertiesScope(storageManager: StorageManager) : BaseImporti
p.println(javaClass.simpleName)
}
private data class SyntheticPropertyHolder(val descriptor: PropertyDescriptor?, val lookedNames: List<Name>) {
companion object {
val EMPTY = SyntheticPropertyHolder(null, emptyList())
}
}
private class MyPropertyDescriptor(
containingDeclaration: DeclarationDescriptor,
original: PropertyDescriptor?,