Load special java methods as properites

Currently only those that override special builtin properties (e.g. `Collection.size`)
Their modality is defined by method's modality
This commit is contained in:
Denis Zharkov
2015-10-02 18:34:19 +03:00
parent a02b64f0e3
commit 547aa2cda6
36 changed files with 341 additions and 39 deletions
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.load.java
import org.jetbrains.kotlin.descriptors.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameUnsafe
import org.jetbrains.kotlin.utils.addToStdlib.check
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
private val BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES = setOf(FqName("kotlin.Collection.size"), FqName("kotlin.Map.size"))
private val BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES = BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES.map { it.shortName() }.toSet()
private fun DeclarationDescriptor.hasBuiltinSpecialPropertyFqName()
= name in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES
&& fqNameUnsafe.check { it.isSafe }?.toSafe() in BUILTIN_SPECIAL_PROPERTIES_FQ_NAMES
val Name.isBuiltinSpecialPropertyName: Boolean get() = this in BUILTIN_SPECIAL_PROPERTIES_SHORT_NAMES
val PropertyDescriptor.builtinSpecialOverridden: PropertyDescriptor?
get() = check { hasBuiltinSpecialPropertyFqName() } ?: overriddenDescriptors.firstNotNullResult { it.builtinSpecialOverridden }
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl;
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.types.JetType;
@@ -31,6 +32,7 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
public JavaPropertyDescriptor(
@NotNull DeclarationDescriptor containingDeclaration,
@NotNull Annotations annotations,
@NotNull Modality modality,
@NotNull Visibility visibility,
boolean isVar,
@NotNull Name name,
@@ -38,7 +40,7 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
@Nullable PropertyDescriptor original,
boolean isStaticFinal
) {
super(containingDeclaration, original, annotations, Modality.FINAL, visibility, isVar, name, Kind.DECLARATION, source,
super(containingDeclaration, original, annotations, modality, visibility, isVar, name, Kind.DECLARATION, source,
/* lateInit = */ false, /* isConst = */ false);
this.isStaticFinal = isStaticFinal;
@@ -59,6 +61,7 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
JavaPropertyDescriptor enhanced = new JavaPropertyDescriptor(
getContainingDeclaration(),
getAnnotations(),
getModality(),
getVisibility(),
isVar(),
getName(),
@@ -66,13 +69,27 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
getOriginal(),
isStaticFinal
);
assert getGetter() == null : "Field must not have a getter: " + this;
PropertyGetterDescriptorImpl newGetter = null;
PropertyGetterDescriptorImpl getter = getGetter();
if (getter != null) {
newGetter = new PropertyGetterDescriptorImpl(
enhanced, getter.getAnnotations(), getter.getModality(), getter.getVisibility(),
getter.hasBody(), getter.isDefault(), getKind(), getter, SourceElement.NO_SOURCE);
newGetter.initialize(enhancedReturnType);
}
assert getSetter() == null : "Field must not have a setter: " + this;
enhanced.initialize(null, null);
enhanced.initialize(newGetter, null);
enhanced.setSetterProjectedOut(isSetterProjectedOut());
if (compileTimeInitializer != null) {
enhanced.setCompileTimeInitializer(compileTimeInitializer);
}
for (PropertyDescriptor descriptor : getOverriddenDescriptors()) {
enhanced.addOverriddenDescriptor(descriptor);
}
enhanced.setType(
enhancedReturnType,
getTypeParameters(), // TODO
@@ -25,10 +25,13 @@ import org.jetbrains.kotlin.incremental.components.LookupLocation
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.load.java.JavaVisibilities
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.builtinSpecialOverridden
import org.jetbrains.kotlin.load.java.components.DescriptorResolverUtils
import org.jetbrains.kotlin.load.java.components.TypeUsage
import org.jetbrains.kotlin.load.java.descriptors.JavaConstructorDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
import org.jetbrains.kotlin.load.java.isBuiltinSpecialPropertyName
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
import org.jetbrains.kotlin.load.java.lazy.child
import org.jetbrains.kotlin.load.java.lazy.resolveAnnotations
@@ -44,6 +47,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils
import org.jetbrains.kotlin.types.checker.JetTypeChecker
import org.jetbrains.kotlin.utils.*
import java.util.*
@@ -75,6 +79,31 @@ public class LazyJavaClassMemberScope(
).toReadOnlyList()
}
override fun JavaMethodDescriptor.isVisibleAsFunction(): Boolean {
if (!canOverrideProperty) return true
return !doesOverrideAnySpecialProperty(getPropertiesFromSupertypes(name))
}
private val JavaMethodDescriptor.canOverrideProperty: Boolean
get() = valueParameters.isEmpty() && name.isBuiltinSpecialPropertyName
private fun JavaMethodDescriptor.doesOverridesSpecialBuiltinProperty(property: PropertyDescriptor): Boolean {
if (valueParameters.isNotEmpty()) return false
// TODO: is it always false?
if (name != property.name) return false
return JetTypeChecker.DEFAULT.isSubtypeOf(returnType ?: return false, property.type)
}
private fun JavaMethodDescriptor.doesOverrideAnySpecialProperty(properties: Collection<PropertyDescriptor>): Boolean {
return properties.any overridesProperty@{
property ->
val specialOverridden = property.builtinSpecialOverridden ?: return@overridesProperty false
doesOverridesSpecialBuiltinProperty(specialOverridden)
}
}
override fun computeNonDeclaredFunctions(result: MutableCollection<SimpleFunctionDescriptor>, name: Name) {
val functionsFromSupertypes = getFunctionsFromSupertypes(name, getContainingDeclaration())
result.addAll(DescriptorResolverUtils.resolveOverrides(name, functionsFromSupertypes, result, getContainingDeclaration(), c.components.errorReporter))
@@ -93,29 +122,53 @@ public class LazyJavaClassMemberScope(
val propertiesFromSupertypes = getPropertiesFromSupertypes(name)
addPropertyOverrideByMethod(name, propertiesFromSupertypes, result)
result.addAll(DescriptorResolverUtils.resolveOverrides(name, propertiesFromSupertypes, result, getContainingDeclaration(),
c.components.errorReporter))
}
private fun addPropertyOverrideByMethod(
name: Name,
propertiesFromSupertypes: Set<PropertyDescriptor>,
result: MutableCollection<PropertyDescriptor>
) {
val javaMethod = memberIndex()
.findMethodsByName(name)
.firstOrNull { it.valueParameters.isEmpty() && it.typeParameters.isEmpty() && it.visibility.isPublicAPI }
?: return
val methodDescriptor = resolveMethodToFunctionDescriptor(javaMethod)
if (methodDescriptor.doesOverrideAnySpecialProperty(propertiesFromSupertypes)) {
result.add(createPropertyDescriptorWithDefaultGetter(javaMethod, methodDescriptor.returnType, methodDescriptor.modality))
}
}
private fun computeAnnotationProperties(name: Name, result: MutableCollection<PropertyDescriptor>) {
val method = memberIndex().findMethodsByName(name).singleOrNull() ?: return
result.add(createPropertyDescriptorWithDefaultGetter(method, modality = Modality.FINAL))
}
private fun createPropertyDescriptorWithDefaultGetter(
method: JavaMethod, givenType: JetType? = null, modality: Modality
): JavaPropertyDescriptor {
val annotations = c.resolveAnnotations(method)
val propertyDescriptor = JavaPropertyDescriptor(
getContainingDeclaration(), annotations, method.getVisibility(),
/* isVar = */ false, method.getName(), c.components.sourceElementFactory.source(method), /* original */ null,
getContainingDeclaration(), annotations, modality, method.getVisibility(),
/* isVar = */ false, method.name, c.components.sourceElementFactory.source(method), /* original */ null,
/* isStaticFinal = */ false
)
// default getter is necessary because there is no real field in annotation
val getter = DescriptorFactory.createDefaultGetter(propertyDescriptor, Annotations.EMPTY)
propertyDescriptor.initialize(getter, null)
val returnType = computeMethodReturnType(method, annotations, c.child(propertyDescriptor, method))
val returnType = givenType ?: computeMethodReturnType(method, annotations, c.child(propertyDescriptor, method))
propertyDescriptor.setType(returnType, listOf(), getDispatchReceiverParameter(), null as JetType?)
getter.initialize(returnType)
result.add(propertyDescriptor)
return propertyDescriptor
}
private fun getPropertiesFromSupertypes(name: Name): Set<PropertyDescriptor> {
@@ -82,6 +82,8 @@ public abstract class LazyJavaScope(
for (method in memberIndex().findMethodsByName(name)) {
val descriptor = resolveMethodToFunctionDescriptor(method)
if (!descriptor.isVisibleAsFunction()) continue
c.components.javaResolverCache.recordMethod(method, descriptor)
result.add(descriptor)
if (method.isStatic) {
@@ -94,6 +96,8 @@ public abstract class LazyJavaScope(
enhanceSignatures(result).toReadOnlyList()
}
open protected fun JavaMethodDescriptor.isVisibleAsFunction() = true
protected data class MethodSignatureData(
val effectiveSignature: ExternalSignatureResolver.AlternativeMethodSignature,
val errors: List<String>
@@ -267,7 +271,7 @@ public abstract class LazyJavaScope(
val annotations = c.resolveAnnotations(field)
val propertyName = field.getName()
return JavaPropertyDescriptor(containingDeclaration, annotations, visibility, isVar, propertyName,
return JavaPropertyDescriptor(containingDeclaration, annotations, Modality.FINAL, visibility, isVar, propertyName,
c.components.sourceElementFactory.source(field), /* original = */ null, /*isConst= */ field.isFinalStatic)
}