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:
+36
@@ -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 }
|
||||
+20
-3
@@ -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
|
||||
|
||||
+58
-5
@@ -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> {
|
||||
|
||||
+5
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user