Synthetic extensions suggested in completion

This commit is contained in:
Valentin Kipyatkov
2015-07-08 18:49:52 +03:00
parent 08754b9fc0
commit 17442617bb
27 changed files with 196 additions and 99 deletions
+1
View File
@@ -13,5 +13,6 @@
<orderEntry type="module" module-name="deserialization" />
<orderEntry type="module" module-name="descriptor.loader.java" exported="" />
<orderEntry type="module" module-name="util" />
<orderEntry type="module" module-name="util.runtime" />
</component>
</module>
@@ -31,6 +31,8 @@ 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.utils.addIfNotNull
import java.util.*
interface SyntheticExtensionPropertyDescriptor : PropertyDescriptor {
val getMethod: FunctionDescriptor
@@ -50,12 +52,12 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
private fun syntheticPropertyInClass(javaClass: JavaClassDescriptor, type: JetType, name: Name): PropertyDescriptor? {
val memberScope = javaClass.getMemberScope(type.getArguments())
val getMethod = memberScope.getFunctions(name.toGetMethodName()).singleOrNull {
val getMethod = memberScope.getFunctions(toGetMethodName(name)).singleOrNull {
it.getValueParameters().isEmpty() && it.getTypeParameters().isEmpty() && it.getVisibility() == Visibilities.PUBLIC //TODO: what about protected and package-local?
} ?: return null
val propertyType = getMethod.getReturnType() ?: return null
val setMethod = memberScope.getFunctions(name.toSetMethodName()).singleOrNull {
val setMethod = memberScope.getFunctions(toSetMethodName(name)).singleOrNull {
it.getValueParameters().singleOrNull()?.getType() == propertyType
&& it.getTypeParameters().isEmpty()
&& it.getReturnType()?.let { KotlinBuiltIns.isUnit(it) } ?: false
@@ -68,10 +70,10 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection<VariableDescriptor> {
if (name.isSpecial()) return emptyList()
if (name.getIdentifier()[0].isUpperCase()) return emptyList()
return collectSyntheticProperties(null, receiverType, name) ?: emptyList()
return collectSyntheticPropertiesByName(null, receiverType, name) ?: emptyList()
}
private fun collectSyntheticProperties(result: SmartList<PropertyDescriptor>?, type: JetType, name: Name): SmartList<PropertyDescriptor>? {
private fun collectSyntheticPropertiesByName(result: SmartList<PropertyDescriptor>?, type: JetType, name: Name): SmartList<PropertyDescriptor>? {
@suppress("NAME_SHADOWING")
var result = result
@@ -81,11 +83,32 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
result = result.add(syntheticPropertyInClass(Triple(classifier, type, name)))
}
typeConstructor.getSupertypes().forEach { result = collectSyntheticProperties(result, it, name) }
typeConstructor.getSupertypes().forEach { result = collectSyntheticPropertiesByName(result, it, name) }
return result
}
override fun getSyntheticExtensionProperties(receiverType: JetType): Collection<VariableDescriptor> {
val result = ArrayList<PropertyDescriptor>()
result.collectSyntheticProperties(receiverType)
return result
}
private fun MutableList<PropertyDescriptor>.collectSyntheticProperties(type: JetType) {
val typeConstructor = type.getConstructor()
val classifier = typeConstructor.getDeclarationDescriptor()
if (classifier is JavaClassDescriptor) {
for (descriptor in classifier.getMemberScope(type.getArguments()).getAllDescriptors()) {
if (descriptor is FunctionDescriptor) {
val propertyName = fromGetMethodName(descriptor.getName()) ?: continue
addIfNotNull(syntheticPropertyInClass(classifier, type, propertyName))
}
}
}
typeConstructor.getSupertypes().forEach { collectSyntheticProperties(it) }
}
private fun SmartList<PropertyDescriptor>?.add(property: PropertyDescriptor?): SmartList<PropertyDescriptor>? {
if (property == null) return this
val list = if (this != null) this else SmartList()
@@ -96,12 +119,19 @@ class SyntheticExtensionsScope(storageManager: StorageManager) : JetScope by Jet
//TODO: "is"?
//TODO: methods like "getURL"?
//TODO: reuse code with generation?
private fun Name.toGetMethodName(): Name {
return Name.identifier("get" + getIdentifier().capitalize())
private fun toGetMethodName(propertyName: Name): Name {
return Name.identifier("get" + propertyName.getIdentifier().capitalize())
}
private fun Name.toSetMethodName(): Name {
return Name.identifier("set" + getIdentifier().capitalize())
private fun toSetMethodName(propertyName: Name): Name {
return Name.identifier("set" + propertyName.getIdentifier().capitalize())
}
private fun fromGetMethodName(methodName: Name): Name? {
if (methodName.isSpecial()) return null
val identifier = methodName.getIdentifier()
if (!identifier.startsWith("get")) return null
return Name.identifier(identifier.removePrefix("get").decapitalize())
}
private class MyPropertyDescriptor(
@@ -57,6 +57,10 @@ class AllUnderImportsScope : JetScope {
return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType, name) }
}
override fun getSyntheticExtensionProperties(receiverType: JetType): Collection<VariableDescriptor> {
return scopes.flatMap { it.getSyntheticExtensionProperties(receiverType) }
}
override fun getPackage(name: Name): PackageViewDescriptor? = null // packages are not imported by all under imports
override fun getLocalVariable(name: Name): VariableDescriptor? = null
@@ -19,11 +19,11 @@ package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.utils.Printer
class SingleImportScope(private val aliasName: Name, private val descriptors: Collection<DeclarationDescriptor>) : JetScope {
class SingleImportScope(private val aliasName: Name, private val descriptors: Collection<DeclarationDescriptor>) : JetScopeImpl() {
override fun getClassifier(name: Name)
= if (name == aliasName) descriptors.filterIsInstance<ClassifierDescriptor>().singleOrNull() else null
@@ -36,20 +36,10 @@ class SingleImportScope(private val aliasName: Name, private val descriptors: Co
override fun getFunctions(name: Name)
= if (name == aliasName) descriptors.filterIsInstance<FunctionDescriptor>() else emptyList()
override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name): Collection<VariableDescriptor> = emptyList()
override fun getLocalVariable(name: Name): VariableDescriptor? = null
override fun getContainingDeclaration(): DeclarationDescriptor = throw UnsupportedOperationException()
override fun getDeclarationsByLabel(labelName: Name): Collection<DeclarationDescriptor> = emptyList()
override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean) = descriptors
override fun getImplicitReceiversHierarchy(): List<ReceiverParameterDescriptor> = emptyList()
override fun getOwnDeclaredDescriptors(): Collection<DeclarationDescriptor> = emptyList()
override fun printScopeStructure(p: Printer) {
p.println(javaClass.getSimpleName(), ": ", aliasName)
}
@@ -260,6 +260,17 @@ class LazyImportScope(
return importResolver.collectFromImports(name, LookupMode.EVERYTHING) { scope, name -> scope.getSyntheticExtensionProperties(receiverType, name) }
}
override fun getSyntheticExtensionProperties(receiverType: JetType): Collection<VariableDescriptor> {
// we do not perform any filtering by visibility here because all descriptors from both visible/invisible filter scopes are to be added anyway
if (filteringKind == FilteringKind.INVISIBLE_CLASSES) return listOf()
return importResolver.resolveSession.getStorageManager().compute {
importResolver.indexedImports.imports.flatMapTo(LinkedHashSet<VariableDescriptor>()) { import ->
importResolver.getImportScope(import, LookupMode.EVERYTHING).getSyntheticExtensionProperties(receiverType)
}
}
}
override fun getDeclarationsByLabel(labelName: Name): Collection<DeclarationDescriptor> = listOf()
override fun getDescriptors(kindFilter: DescriptorKindFilter, nameFilter: (Name) -> Boolean): Collection<DeclarationDescriptor> {
@@ -28,6 +28,7 @@ import org.jetbrains.kotlin.resolve.lazy.data.JetScriptInfo
import org.jetbrains.kotlin.resolve.lazy.declarations.DeclarationProvider
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.resolve.scopes.JetScope
import org.jetbrains.kotlin.resolve.scopes.JetScopeImpl
import org.jetbrains.kotlin.storage.MemoizedFunctionToNotNull
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.types.JetType
@@ -41,7 +42,7 @@ protected constructor(
protected val declarationProvider: DP,
protected val thisDescriptor: D,
protected val trace: BindingTrace
) : JetScope {
) : JetScopeImpl() {
protected val storageManager: StorageManager = c.storageManager
private val classDescriptors: MemoizedFunctionToNotNull<Name, List<ClassDescriptor>> = storageManager.createMemoizedFunction { resolveClassDescriptor(it) }
@@ -111,12 +112,6 @@ protected constructor(
protected abstract fun getNonDeclaredProperties(name: Name, result: MutableSet<VariableDescriptor>)
override fun getSyntheticExtensionProperties(receiverType: JetType, name: Name) = listOf<VariableDescriptor>()
override fun getLocalVariable(name: Name): VariableDescriptor? = null
override fun getDeclarationsByLabel(labelName: Name) = setOf<DeclarationDescriptor>()
protected fun computeDescriptorsFromDeclaredElements(kindFilter: DescriptorKindFilter,
nameFilter: (Name) -> Boolean): List<DeclarationDescriptor> {
val declarations = declarationProvider.getDeclarations(kindFilter, nameFilter)
@@ -163,8 +158,6 @@ protected constructor(
return result.toReadOnlyList()
}
override fun getImplicitReceiversHierarchy() = listOf<ReceiverParameterDescriptor>()
// Do not change this, override in concrete subclasses:
// it is very easy to compromise laziness of this class, and fail all the debugging
// a generic implementation can't do this properly